[libgda] Set SQLite version to 3.7.12.1 and SqlCipher to 2.0.6
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda] Set SQLite version to 3.7.12.1 and SqlCipher to 2.0.6
- Date: Mon, 27 Aug 2012 18:01:13 +0000 (UTC)
commit 786e4af0433886b2a0166456d5360311cac3f5be
Author: Vivien Malerba <malerba gnome-db org>
Date: Mon Aug 27 19:42:24 2012 +0200
Set SQLite version to 3.7.12.1 and SqlCipher to 2.0.6
libgda/sqlite/sqlite-src/PragmasPatch | 6 +-
libgda/sqlite/sqlite-src/sqlite3.c |15025 ++++++++++++++++++++++-----------
libgda/sqlite/sqlite-src/sqlite3.h | 382 +-
providers/sqlcipher/sqlcipher.patch | 5414 +++++++++++--
4 files changed, 15114 insertions(+), 5713 deletions(-)
---
diff --git a/libgda/sqlite/sqlite-src/PragmasPatch b/libgda/sqlite/sqlite-src/PragmasPatch
index 04b40c7..b622a53 100644
--- a/libgda/sqlite/sqlite-src/PragmasPatch
+++ b/libgda/sqlite/sqlite-src/PragmasPatch
@@ -1,6 +1,6 @@
---- sqlite3.c.orig 2011-11-01 13:31:21.000000000 +0100
-+++ sqlite3.c 2012-01-31 11:11:26.739621515 +0100
-@@ -91158,6 +91158,60 @@
+--- sqlite3.c.orig 2012-05-22 13:03:50.000000000 +0200
++++ sqlite3.c 2012-08-27 14:52:58.000000000 +0200
+@@ -93389,6 +93389,60 @@
#ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
/*
diff --git a/libgda/sqlite/sqlite-src/sqlite3.c b/libgda/sqlite/sqlite-src/sqlite3.c
index e54e1be..f9a6648 100644
--- a/libgda/sqlite/sqlite-src/sqlite3.c
+++ b/libgda/sqlite/sqlite-src/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.7.9. By combining all the individual C code files into this
+** version 3.7.12.1. 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
@@ -366,6 +366,14 @@
#endif
/*
+** Powersafe overwrite is on by default. But can be turned off using
+** the -DSQLITE_POWERSAFE_OVERWRITE=0 command-line option.
+*/
+#ifndef SQLITE_POWERSAFE_OVERWRITE
+# define SQLITE_POWERSAFE_OVERWRITE 1
+#endif
+
+/*
** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1.
** It determines whether or not the features related to
** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can
@@ -649,9 +657,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.7.9"
-#define SQLITE_VERSION_NUMBER 3007009
-#define SQLITE_SOURCE_ID "2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e"
+#define SQLITE_VERSION "3.7.12.1"
+#define SQLITE_VERSION_NUMBER 3007012
+#define SQLITE_SOURCE_ID "2012-05-22 02:45:53 6d326d44fd1d626aae0e8456e5fa2049f1ce0789"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -719,7 +727,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
** CAPI3REF: Test To See If The Library Is Threadsafe
**
** ^The sqlite3_threadsafe() function returns zero if and only if
-** SQLite was compiled mutexing code omitted due to the
+** SQLite was compiled with mutexing code omitted due to the
** [SQLITE_THREADSAFE] compile-time option being set to 0.
**
** SQLite can be compiled with or without mutexes. When
@@ -913,7 +921,7 @@ SQLITE_API int sqlite3_exec(
** KEYWORDS: {result code} {result codes}
**
** Many SQLite functions return an integer result code from the set shown
-** here in order to indicates success or failure.
+** here in order to indicate success or failure.
**
** New error codes may be added in future versions of SQLite.
**
@@ -1000,9 +1008,11 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
+#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
+#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -1051,7 +1061,11 @@ SQLITE_API int sqlite3_exec(
** first then the size of the file is extended, never the other
** way around. The SQLITE_IOCAP_SEQUENTIAL property means that
** information is written to disk in the same order as calls
-** to xWrite().
+** to xWrite(). The SQLITE_IOCAP_POWERSAFE_OVERWRITE property means that
+** after reboot following a crash or power loss, the only bytes in a
+** file that were written at the application level might have changed
+** and that adjacent bytes, even bytes within the same sector are
+** guaranteed to be unchanged.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -1065,6 +1079,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
+#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
/*
** CAPI3REF: File Locking Levels
@@ -1253,7 +1268,8 @@ struct sqlite3_io_methods {
** into an integer that the pArg argument points to. This capability
** is used during testing and only needs to be supported when SQLITE_TEST
** is defined.
-**
+** <ul>
+** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
** layer a hint of how large the database file will grow to be during the
** current transaction. This hint is not guaranteed to be accurate but it
@@ -1261,6 +1277,7 @@ struct sqlite3_io_methods {
** file space based on this hint in order to help writes to the database
** file run faster.
**
+** <li>[[SQLITE_FCNTL_CHUNK_SIZE]]
** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
** extends and truncates the database file in chunks of a size specified
** by the user. The fourth argument to [sqlite3_file_control()] should
@@ -1269,11 +1286,13 @@ struct sqlite3_io_methods {
** chunks (say 1MB at a time), may reduce file-system fragmentation and
** improve performance on some systems.
**
+** <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 the [sqlite3_file_control()] documentation for
** additional information.
**
+** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by
** SQLite and sent to all VFSes in place of a call to the xSync method
** when the database connection has [PRAGMA synchronous] set to OFF.)^
@@ -1284,14 +1303,15 @@ struct sqlite3_io_methods {
** opcode as doing so may disrupt the operation of the specialized VFSes
** that do require it.
**
+** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]]
** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
** retry counts and intervals for certain disk I/O operations for the
-** windows [VFS] in order to work to provide robustness against
+** windows [VFS] in order to provide robustness in the presence of
** anti-virus programs. By default, the windows VFS will retry file read,
** file write, and file delete operations up to 10 times, with a delay
** of 25 milliseconds before the first retry and with the delay increasing
** by an additional 25 milliseconds with each subsequent retry. This
-** opcode allows those to values (10 retries and 25 milliseconds of delay)
+** opcode allows these two values (10 retries and 25 milliseconds of delay)
** to be adjusted. The values are changed for all database connections
** within the same process. The argument is a pointer to an array of two
** integers where the first integer i the new retry count and the second
@@ -1300,8 +1320,9 @@ struct sqlite3_io_methods {
** into the array entry, allowing the current retry settings to be
** interrogated. The zDbName parameter is ignored.
**
+** <li>[[SQLITE_FCNTL_PERSIST_WAL]]
** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the
-** persistent [WAL | Write AHead Log] setting. By default, the auxiliary
+** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary
** write ahead log and shared memory files used for transaction control
** are automatically deleted when the latest connection to the database
** closes. Setting persistent WAL mode causes those files to persist after
@@ -1314,22 +1335,72 @@ struct sqlite3_io_methods {
** WAL mode. If the integer is -1, then it is overwritten with the current
** WAL persistence setting.
**
+** <li>[[SQLITE_FCNTL_POWERSAFE_OVERWRITE]]
+** ^The [SQLITE_FCNTL_POWERSAFE_OVERWRITE] opcode is used to set or query the
+** persistent "powersafe-overwrite" or "PSOW" setting. The PSOW setting
+** determines the [SQLITE_IOCAP_POWERSAFE_OVERWRITE] bit of the
+** xDeviceCharacteristics methods. The fourth parameter to
+** [sqlite3_file_control()] for this opcode should be a pointer to an integer.
+** That integer is 0 to disable zero-damage mode or 1 to enable zero-damage
+** mode. If the integer is -1, then it is overwritten with the current
+** zero-damage mode setting.
+**
+** <li>[[SQLITE_FCNTL_OVERWRITE]]
** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening
** a write transaction to indicate that, unless it is rolled back for some
** reason, the entire database file will be overwritten by the current
** transaction. This is used by VACUUM operations.
+**
+** <li>[[SQLITE_FCNTL_VFSNAME]]
+** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of
+** all [VFSes] in the VFS stack. The names are of all VFS shims and the
+** final bottom-level VFS are written into memory obtained from
+** [sqlite3_malloc()] and the result is stored in the char* variable
+** that the fourth parameter of [sqlite3_file_control()] points to.
+** The caller is responsible for freeing the memory when done. As with
+** all file-control actions, there is no guarantee that this will actually
+** do anything. Callers should initialize the char* variable to a NULL
+** pointer in case this file-control is not implemented. This file-control
+** is intended for diagnostic use 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
+** to the database file to which the pragma statement refers. ^The argument
+** to the [SQLITE_FCNTL_PRAGMA] file control is an array of
+** pointers to strings (char**) in which the second element of the array
+** is the name of the pragma and the third element is the argument to the
+** pragma or NULL if the pragma has no argument. ^The handler for an
+** [SQLITE_FCNTL_PRAGMA] file control can optionally make the first element
+** of the char** argument point to a string obtained from [sqlite3_mprintf()]
+** or the equivalent and that string will become the result of the pragma or
+** the error message if the pragma fails. ^If the
+** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal
+** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA]
+** file control returns [SQLITE_OK], then the parser assumes that the
+** VFS has handled the PRAGMA itself and the parser generates a no-op
+** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns
+** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means
+** that the VFS encountered an error while handling the [PRAGMA] and the
+** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
+** file control occurs at the beginning of pragma statement analysis and so
+** it is able to override built-in [PRAGMA] statements.
+** </ul>
*/
-#define SQLITE_FCNTL_LOCKSTATE 1
-#define SQLITE_GET_LOCKPROXYFILE 2
-#define SQLITE_SET_LOCKPROXYFILE 3
-#define SQLITE_LAST_ERRNO 4
-#define SQLITE_FCNTL_SIZE_HINT 5
-#define SQLITE_FCNTL_CHUNK_SIZE 6
-#define SQLITE_FCNTL_FILE_POINTER 7
-#define SQLITE_FCNTL_SYNC_OMITTED 8
-#define SQLITE_FCNTL_WIN32_AV_RETRY 9
-#define SQLITE_FCNTL_PERSIST_WAL 10
-#define SQLITE_FCNTL_OVERWRITE 11
+#define SQLITE_FCNTL_LOCKSTATE 1
+#define SQLITE_GET_LOCKPROXYFILE 2
+#define SQLITE_SET_LOCKPROXYFILE 3
+#define SQLITE_LAST_ERRNO 4
+#define SQLITE_FCNTL_SIZE_HINT 5
+#define SQLITE_FCNTL_CHUNK_SIZE 6
+#define SQLITE_FCNTL_FILE_POINTER 7
+#define SQLITE_FCNTL_SYNC_OMITTED 8
+#define SQLITE_FCNTL_WIN32_AV_RETRY 9
+#define SQLITE_FCNTL_PERSIST_WAL 10
+#define SQLITE_FCNTL_OVERWRITE 11
+#define SQLITE_FCNTL_VFSNAME 12
+#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13
+#define SQLITE_FCNTL_PRAGMA 14
/*
** CAPI3REF: Mutex Handle
@@ -1384,7 +1455,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** from xFullPathname() with an optional suffix added.
** ^If a suffix is added to the zFilename parameter, it will
** consist of a single "-" character followed by no more than
-** 10 alphanumeric and/or "-" characters.
+** 11 alphanumeric and/or "-" characters.
** ^SQLite further guarantees that
** the string will be valid and unchanged until xClose() is
** called. Because of the previous sentence,
@@ -1915,7 +1986,7 @@ struct sqlite3_mem_methods {
** <dd> ^This option specifies a static memory buffer that SQLite can use for
** the database page cache with the default page cache implementation.
** This configuration should not be used if an application-define page
-** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
+** cache implementation is loaded using the SQLITE_CONFIG_PCACHE2 option.
** There are three arguments to this option: A pointer to 8-byte aligned
** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument should be the size of the largest database page
@@ -1984,15 +2055,15 @@ struct sqlite3_mem_methods {
** verb to [sqlite3_db_config()] can be used to change the lookaside
** configuration on individual connections.)^ </dd>
**
-** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt>
+** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
** <dd> ^(This option takes a single argument which is a pointer to
-** an [sqlite3_pcache_methods] object. This object specifies the interface
+** an [sqlite3_pcache_methods2] object. This object specifies the interface
** to a custom page cache implementation.)^ ^SQLite makes a copy of the
** object and uses it for page cache memory allocations.</dd>
**
-** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt>
+** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt>
** <dd> ^(This option takes a single argument which is a pointer to an
-** [sqlite3_pcache_methods] object. SQLite copies of the current
+** [sqlite3_pcache_methods2] object. SQLite copies of the current
** page cache implementation into that object.)^ </dd>
**
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
@@ -2025,6 +2096,11 @@ struct sqlite3_mem_methods {
** database connection is opened. By default, URI handling is globally
** disabled. The default value may be changed by compiling with the
** [SQLITE_USE_URI] symbol defined.
+**
+** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]]
+** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
+** <dd> These options are obsolete and should not be used by new code.
+** They are retained for backwards compatibility but are now no-ops.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -2040,10 +2116,12 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */
-#define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */
+#define SQLITE_CONFIG_PCACHE 14 /* no-op */
+#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
#define SQLITE_CONFIG_URI 17 /* int */
+#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2528,7 +2606,7 @@ SQLITE_API void sqlite3_free_table(char **result);
** All of the usual printf() formatting options apply. In addition, there
** is are "%q", "%Q", and "%z" options.
**
-** ^(The %q option works like %s in that it substitutes a null-terminated
+** ^(The %q option works like %s in that it substitutes a nul-terminated
** string from the argument list. But %q also doubles every '\'' character.
** %q is designed for use inside a string literal.)^ By doubling each '\''
** character it escapes that character and allows it to be inserted into
@@ -3136,21 +3214,45 @@ SQLITE_API int sqlite3_open_v2(
/*
** CAPI3REF: Obtain Values For URI Parameters
**
-** This is a utility routine, useful to VFS implementations, that checks
+** These are utility routines, useful to VFS implementations, that check
** to see if a database file was a URI that contained a specific query
-** parameter, and if so obtains the value of the query parameter.
-**
-** The zFilename argument is the filename pointer passed into the xOpen()
-** method of a VFS implementation. The zParam argument is the name of the
-** query parameter we seek. This routine returns the value of the zParam
-** parameter if it exists. If the parameter does not exist, this routine
-** returns a NULL pointer.
-**
-** If the zFilename argument to this function is not a pointer that SQLite
-** passed into the xOpen VFS method, then the behavior of this routine
-** is undefined and probably undesirable.
+** parameter, and if so obtains the value of that query parameter.
+**
+** If F is the database filename pointer passed into the xOpen() method of
+** a VFS implementation when the flags parameter to xOpen() has one or
+** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and
+** P is the name of the query parameter, then
+** sqlite3_uri_parameter(F,P) returns the value of the P
+** parameter if it exists or a NULL pointer if P does not appear as a
+** query parameter on F. If P is a query parameter of F
+** has no explicit value, then sqlite3_uri_parameter(F,P) returns
+** a pointer to an empty string.
+**
+** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean
+** parameter and returns true (1) or false (0) according to the value
+** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the
+** value of query parameter P is one of "yes", "true", or "on" in any
+** case or if the value begins with a non-zero number. The
+** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of
+** query parameter P is one of "no", "false", or "off" in any case or
+** if the value begins with a numeric zero. If P is not a query
+** parameter on F or if the value of P is does not match any of the
+** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0).
+**
+** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a
+** 64-bit signed integer and returns that integer, or D if P does not
+** exist. If the value of P is something other than an integer, then
+** zero is returned.
+**
+** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
+** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and
+** is not a database file pathname pointer that SQLite passed into the xOpen
+** VFS method, then the behavior of this routine is undefined and probably
+** undesirable.
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
+SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
/*
@@ -3473,6 +3575,25 @@ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Determine If A Prepared Statement Has Been Reset
+**
+** ^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 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]
+** object, then the behavior is undefined and probably undesirable.
+**
+** This interface can be used in combination [sqlite3_next_stmt()]
+** to locate all prepared statements associated with a database
+** connection that are in need of being reset. This can be used,
+** for example, in diagnostic routines to search for prepared
+** statements that are holding a transaction open.
+*/
+SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
+
+/*
** CAPI3REF: Dynamically Typed Value Object
** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value}
**
@@ -4013,7 +4134,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** bytes in the string, not the number of characters.
**
** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(),
-** even empty strings, are always zero terminated. ^The return
+** even empty strings, are always zero-terminated. ^The return
** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
**
** ^The object returned by [sqlite3_column_value()] is an
@@ -4914,6 +5035,31 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3*);
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
/*
+** CAPI3REF: Return The Filename For A Database Connection
+**
+** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
+** associated with database N of connection D. ^The main database file
+** has the name "main". If there is no attached database N on the database
+** connection D, or if database N is a temporary or in-memory database, then
+** a NULL pointer is returned.
+**
+** ^The filename returned by this function is the output of the
+** xFullPathname method of the [VFS]. ^In other words, the filename
+** will be an absolute pathname, even if the filename used
+** to open the database originally was a URI or relative pathname.
+*/
+SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+
+/*
+** CAPI3REF: Determine if a database is read-only
+**
+** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N
+** of connection D is read-only, 0 if it is read/write, or -1 if N is not
+** the name of a database on connection D.
+*/
+SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
+
+/*
** CAPI3REF: Find the next prepared statement
**
** ^This interface returns a pointer to the next [prepared statement] after
@@ -4948,13 +5094,15 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
** on the same [database connection] D, or NULL for
** the first call for each function on D.
**
+** The commit and rollback hook callbacks are not reentrant.
** The callback implementation must not do anything that will modify
** the database connection that invoked the callback. Any actions
** to modify the database connection must be deferred until after the
** completion of the [sqlite3_step()] call that triggered the commit
** or rollback hook in the first place.
-** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
-** database connections for the meaning of "modify" in this paragraph.
+** Note that running any other SQL statements, including SELECT statements,
+** or merely calling [sqlite3_prepare_v2()] and [sqlite3_step()] will modify
+** the database connections for the meaning of "modify" in this paragraph.
**
** ^Registering a NULL function disables the callback.
**
@@ -5067,10 +5215,25 @@ SQLITE_API int sqlite3_enable_shared_cache(int);
** which might be more or less than the amount requested.
** ^The sqlite3_release_memory() routine is a no-op returning zero
** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT].
+**
+** See also: [sqlite3_db_release_memory()]
*/
SQLITE_API int sqlite3_release_memory(int);
/*
+** CAPI3REF: Free Memory Used By A Database Connection
+**
+** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap
+** memory as possible from database connection D. Unlike the
+** [sqlite3_release_memory()] interface, this interface is effect even
+** when then [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is
+** omitted.
+**
+** See also: [sqlite3_release_memory()]
+*/
+SQLITE_API int sqlite3_db_release_memory(sqlite3*);
+
+/*
** CAPI3REF: Impose A Limit On Heap Size
**
** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
@@ -5084,7 +5247,8 @@ SQLITE_API int sqlite3_release_memory(int);
** is advisory only.
**
** ^The return value from sqlite3_soft_heap_limit64() is the size of
-** the soft heap limit prior to the call. ^If the argument N is negative
+** the soft heap limit prior to the call, or negative in the case of an
+** error. ^If the argument N is negative
** then no change is made to the soft heap limit. Hence, the current
** size of the soft heap limit can be determined by invoking
** sqlite3_soft_heap_limit64() with a negative argument.
@@ -5100,7 +5264,7 @@ SQLITE_API int sqlite3_release_memory(int);
** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and
** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option.
** <li> An alternative page cache implementation is specified using
-** [sqlite3_config]([SQLITE_CONFIG_PCACHE],...).
+** [sqlite3_config]([SQLITE_CONFIG_PCACHE2],...).
** <li> The page cache allocates from its own memory pool supplied
** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than
** from the heap.
@@ -5842,7 +6006,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** <ul>
** <li> SQLITE_MUTEX_OS2
-** <li> SQLITE_MUTEX_PTHREAD
+** <li> SQLITE_MUTEX_PTHREADS
** <li> SQLITE_MUTEX_W32
** <li> SQLITE_MUTEX_NOOP
** </ul>)^
@@ -5850,7 +6014,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** ^The SQLITE_MUTEX_NOOP implementation is a set of routines
** that does no real locking and is appropriate for use in
** a single-threaded application. ^The SQLITE_MUTEX_OS2,
-** SQLITE_MUTEX_PTHREAD, and SQLITE_MUTEX_W32 implementations
+** SQLITE_MUTEX_PTHREADS, and SQLITE_MUTEX_W32 implementations
** are appropriate for use on OS/2, Unix, and Windows.
**
** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
@@ -6040,7 +6204,7 @@ struct sqlite3_mutex_methods {
** ^These routines should return true if the mutex in their argument
** is held or not held, respectively, by the calling thread.
**
-** ^The implementation is not required to provided versions of these
+** ^The implementation is not required to provide versions of these
** routines that actually work. If the implementation does not provide working
** versions of these routines, it should at least provide stubs that always
** return true so that one does not get spurious assertion failures.
@@ -6168,9 +6332,9 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_RESERVE 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_PGHDRSZ 17
-#define SQLITE_TESTCTRL_SCRATCHMALLOC 18
-#define SQLITE_TESTCTRL_LOCALTIME_FAULT 19
+#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
+#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
+#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
#define SQLITE_TESTCTRL_LAST 19
/*
@@ -6393,6 +6557,17 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS
** is always 0.
** </dd>
+**
+** [[SQLITE_DBSTATUS_CACHE_WRITE]] ^(<dt>SQLITE_DBSTATUS_CACHE_WRITE</dt>
+** <dd>This parameter returns the number of dirty cache entries that have
+** been written to disk. Specifically, the number of pages written to the
+** wal file in wal mode databases, or the number of pages written to the
+** database file in rollback mode databases. Any pages written as part of
+** transaction rollback or database recovery operations are not included.
+** If an IO or other error occurs while writing a page to disk, the effect
+** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The
+** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
+** </dd>
** </dl>
*/
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
@@ -6404,7 +6579,8 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6
#define SQLITE_DBSTATUS_CACHE_HIT 7
#define SQLITE_DBSTATUS_CACHE_MISS 8
-#define SQLITE_DBSTATUS_MAX 8 /* Largest defined DBSTATUS */
+#define SQLITE_DBSTATUS_CACHE_WRITE 9
+#define SQLITE_DBSTATUS_MAX 9 /* Largest defined DBSTATUS */
/*
@@ -6473,17 +6649,33 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
** sqlite3_pcache object except by holding and passing pointers
** to the object.
**
-** See [sqlite3_pcache_methods] for additional information.
+** See [sqlite3_pcache_methods2] for additional information.
*/
typedef struct sqlite3_pcache sqlite3_pcache;
/*
+** CAPI3REF: Custom Page Cache Object
+**
+** The sqlite3_pcache_page object represents a single page in the
+** page cache. The page cache will allocate instances of this
+** object. Various methods of the page cache use pointers to instances
+** of this object as parameters or as their return value.
+**
+** See [sqlite3_pcache_methods2] for additional information.
+*/
+typedef struct sqlite3_pcache_page sqlite3_pcache_page;
+struct sqlite3_pcache_page {
+ void *pBuf; /* The content of the page */
+ void *pExtra; /* Extra information associated with the page */
+};
+
+/*
** CAPI3REF: Application Defined Page Cache.
** KEYWORDS: {page cache}
**
-** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
+** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can
** register an alternative page cache implementation by passing in an
-** instance of the sqlite3_pcache_methods structure.)^
+** instance of the sqlite3_pcache_methods2 structure.)^
** In many applications, most of the heap memory allocated by
** SQLite is used for the page cache.
** By implementing a
@@ -6497,7 +6689,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** extreme measure that is only needed by the most demanding applications.
** The built-in page cache is recommended for most uses.
**
-** ^(The contents of the sqlite3_pcache_methods structure are copied to an
+** ^(The contents of the sqlite3_pcache_methods2 structure are copied to an
** internal buffer by SQLite within the call to [sqlite3_config]. Hence
** the application may discard the parameter after the call to
** [sqlite3_config()] returns.)^
@@ -6506,7 +6698,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** ^(The xInit() method is called once for each effective
** call to [sqlite3_initialize()])^
** (usually only once during the lifetime of the process). ^(The xInit()
-** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^
+** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^
** The intent of the xInit() method is to set up global data structures
** required by the custom page cache implementation.
** ^(If the xInit() method is NULL, then the
@@ -6533,17 +6725,15 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** SQLite will typically create one cache instance for each open database file,
** though this is not guaranteed. ^The
** first parameter, szPage, is the size in bytes of the pages that must
-** be allocated by the cache. ^szPage will not be a power of two. ^szPage
-** will the page size of the database file that is to be cached plus an
-** increment (here called "R") of less than 250. SQLite will use the
-** extra R bytes on each page to store metadata about the underlying
-** database page on disk. The value of R depends
+** be allocated by the cache. ^szPage will always a power of two. ^The
+** second parameter szExtra is a number of bytes of extra storage
+** associated with each page cache entry. ^The szExtra parameter will
+** a number less than 250. SQLite will use the
+** extra szExtra bytes on each page to store metadata about the underlying
+** database page on disk. The value passed into szExtra depends
** on the SQLite version, the target platform, and how SQLite was compiled.
-** ^(R is constant for a particular build of SQLite. Except, there are two
-** distinct values of R when SQLite is compiled with the proprietary
-** ZIPVFS extension.)^ ^The second argument to
-** xCreate(), bPurgeable, is true if the cache being created will
-** be used to cache database pages of a file stored on disk, or
+** ^The third argument to xCreate(), bPurgeable, is true if the cache being
+** created will be used to cache database pages of a file stored on disk, or
** false if it is used for an in-memory database. The cache implementation
** does not have to do anything special based with the value of bPurgeable;
** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
@@ -6567,11 +6757,16 @@ typedef struct sqlite3_pcache sqlite3_pcache;
**
** [[the xFetch() page cache methods]]
** The xFetch() method locates a page in the cache and returns a pointer to
-** the page, or a NULL pointer.
-** A "page", in this context, means a buffer of szPage bytes aligned at an
-** 8-byte boundary. The page to be fetched is determined by the key. ^The
-** minimum key value is 1. After it has been retrieved using xFetch, the page
-** is considered to be "pinned".
+** an sqlite3_pcache_page object associated with that page, or a NULL pointer.
+** The pBuf element of the returned sqlite3_pcache_page object will be a
+** pointer to a buffer of szPage bytes used to store the content of a
+** single database page. The pExtra element of sqlite3_pcache_page will be
+** a pointer to the szExtra bytes of extra storage that SQLite has requested
+** for each entry in the page cache.
+**
+** The page to be fetched is determined by the key. ^The minimum key value
+** is 1. After it has been retrieved using xFetch, the page is considered
+** to be "pinned".
**
** If the requested page is already in the page cache, then the page cache
** implementation must return a pointer to the page buffer with its content
@@ -6624,8 +6819,37 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** ^The xDestroy() method is used to delete a cache allocated by xCreate().
** All resources associated with the specified cache should be freed. ^After
** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
-** handle invalid, and will not use it with any other sqlite3_pcache_methods
+** handle invalid, and will not use it with any other sqlite3_pcache_methods2
** functions.
+**
+** [[the xShrink() page cache method]]
+** ^SQLite invokes the xShrink() method when it wants the page cache to
+** free up as much of heap memory as possible. The page cache implementation
+** is not obligated to free any memory, but well-behaved implementations should
+** do their best.
+*/
+typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2;
+struct sqlite3_pcache_methods2 {
+ int iVersion;
+ void *pArg;
+ int (*xInit)(void*);
+ void (*xShutdown)(void*);
+ sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable);
+ void (*xCachesize)(sqlite3_pcache*, int nCachesize);
+ int (*xPagecount)(sqlite3_pcache*);
+ sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
+ void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard);
+ void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
+ unsigned oldKey, unsigned newKey);
+ void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
+ void (*xDestroy)(sqlite3_pcache*);
+ void (*xShrink)(sqlite3_pcache*);
+};
+
+/*
+** This is the obsolete pcache_methods object that has now been replaced
+** by sqlite3_pcache_methods2. This object is not used by SQLite. It is
+** retained in the header file for backwards compatibility only.
*/
typedef struct sqlite3_pcache_methods sqlite3_pcache_methods;
struct sqlite3_pcache_methods {
@@ -6642,6 +6866,7 @@ struct sqlite3_pcache_methods {
void (*xDestroy)(sqlite3_pcache*);
};
+
/*
** CAPI3REF: Online Backup Object
**
@@ -6971,11 +7196,12 @@ SQLITE_API int sqlite3_unlock_notify(
/*
** CAPI3REF: String Comparison
**
-** ^The [sqlite3_strnicmp()] API allows applications and extensions to
-** compare the contents of two buffers containing UTF-8 strings in a
-** case-independent fashion, using the same definition of case independence
-** that SQLite uses internally when comparing identifiers.
+** ^The [sqlite3_stricmp()] and [sqlite3_strnicmp()] APIs allow applications
+** and extensions to compare the contents of two buffers containing UTF-8
+** strings in a case-independent fashion, using the same definition of "case
+** independence" that SQLite uses internally when comparing identifiers.
*/
+SQLITE_API int sqlite3_stricmp(const char *, const char *);
SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
/*
@@ -7310,7 +7536,11 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
SQLITE_API int sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
- int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes),
+#ifdef SQLITE_RTREE_INT_ONLY
+ int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes),
+#else
+ int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes),
+#endif
void *pContext
);
@@ -7645,7 +7875,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
*/
#define SQLITE_MAX_FILE_FORMAT 4
#ifndef SQLITE_DEFAULT_FILE_FORMAT
-# define SQLITE_DEFAULT_FILE_FORMAT 1
+# define SQLITE_DEFAULT_FILE_FORMAT 4
#endif
/*
@@ -7852,9 +8082,13 @@ struct BusyHandler {
/*
** The following value as a destructor means to use sqlite3DbFree().
-** This is an internal extension to SQLITE_STATIC and SQLITE_TRANSIENT.
+** 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.
*/
-#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3DbFree)
+#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3MallocSize)
/*
** When SQLITE_OMIT_WSD is defined, it means that the target platform does
@@ -8014,10 +8248,9 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
** pager.h.
*/
#define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */
-#define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */
-#define BTREE_MEMORY 4 /* This is an in-memory DB */
-#define BTREE_SINGLE 8 /* The file contains at most 1 b-tree */
-#define BTREE_UNORDERED 16 /* Use of a hash implementation is OK */
+#define BTREE_MEMORY 2 /* This is an in-memory DB */
+#define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */
+#define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */
SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
@@ -8035,7 +8268,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);
-SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*);
+SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags);
SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*);
@@ -8285,6 +8518,7 @@ struct SubProgram {
int nOp; /* Elements in aOp[] */
int nMem; /* Number of memory cells required */
int nCsr; /* Number of cursors required */
+ int nOnce; /* Number of OP_Once instructions */
void *token; /* id that may be used to recursive triggers */
SubProgram *pNext; /* Next sub-program already visited */
};
@@ -8531,10 +8765,10 @@ typedef struct VdbeOpList VdbeOpList;
#define OPFLG_OUT2 0x0020 /* out2: P2 is an output */
#define OPFLG_OUT3 0x0040 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
-/* 0 */ 0x00, 0x01, 0x05, 0x04, 0x04, 0x10, 0x00, 0x02,\
+/* 0 */ 0x00, 0x01, 0x01, 0x04, 0x04, 0x10, 0x00, 0x02,\
/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x24, 0x24,\
/* 16 */ 0x00, 0x00, 0x00, 0x24, 0x04, 0x05, 0x04, 0x00,\
-/* 24 */ 0x00, 0x01, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00,\
+/* 24 */ 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00, 0x00,\
/* 32 */ 0x02, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,\
/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11,\
/* 48 */ 0x11, 0x11, 0x08, 0x11, 0x11, 0x11, 0x11, 0x02,\
@@ -8689,8 +8923,7 @@ typedef struct PgHdr DbPage;
** NOTE: These values must match the corresponding BTREE_ values in btree.h.
*/
#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
-#define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */
-#define PAGER_MEMORY 0x0004 /* In-memory database */
+#define PAGER_MEMORY 0x0002 /* In-memory database */
/*
** Valid values for the second argument to sqlite3PagerLockingMode().
@@ -8734,6 +8967,7 @@ SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
+SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
@@ -8774,6 +9008,9 @@ 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_ZIPVFS
+SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
+#endif
/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
@@ -8842,11 +9079,12 @@ typedef struct PCache PCache;
** structure.
*/
struct PgHdr {
- void *pData; /* Content of this page */
+ sqlite3_pcache_page *pPage; /* Pcache object page handle */
+ void *pData; /* Page data */
void *pExtra; /* Extra content */
PgHdr *pDirty; /* Transient list of dirty pages */
- Pgno pgno; /* Page number for this page */
Pager *pPager; /* The pager this page is part of */
+ Pgno pgno; /* Page number for this page */
#ifdef SQLITE_CHECK_PAGES
u32 pageHash; /* Hash of page content */
#endif
@@ -8960,6 +9198,9 @@ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *, int);
SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *);
#endif
+/* Free up as much memory as possible from the page cache */
+SQLITE_PRIVATE void sqlite3PcacheShrink(PCache*);
+
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/* Try to return memory used by the pcache module to the main memory heap */
SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int);
@@ -9046,17 +9287,6 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
#endif
/*
-** Determine if we are dealing with WindowsCE - which has a much
-** reduced API.
-*/
-#if defined(_WIN32_WCE)
-# define SQLITE_OS_WINCE 1
-#else
-# define SQLITE_OS_WINCE 0
-#endif
-
-
-/*
** Define the maximum size of a temporary filename
*/
#if SQLITE_OS_WIN
@@ -9080,6 +9310,37 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
# define SQLITE_TEMPNAME_SIZE 200
#endif
+/*
+** Determine if we are dealing with Windows NT.
+**
+** We ought to be able to determine if we are compiling for win98 or winNT
+** using the _WIN32_WINNT macro as follows:
+**
+** #if defined(_WIN32_WINNT)
+** # define SQLITE_OS_WINNT 1
+** #else
+** # define SQLITE_OS_WINNT 0
+** #endif
+**
+** However, vs2005 does not set _WIN32_WINNT by default, as it ought to,
+** so the above test does not work. We'll just assume that everything is
+** winNT unless the programmer explicitly says otherwise by setting
+** SQLITE_OS_WINNT to 0.
+*/
+#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT)
+# define SQLITE_OS_WINNT 1
+#endif
+
+/*
+** Determine if we are dealing with WindowsCE - which has a much
+** reduced API.
+*/
+#if defined(_WIN32_WCE)
+# define SQLITE_OS_WINCE 1
+#else
+# define SQLITE_OS_WINCE 0
+#endif
+
/* If the SET_FULLSYNC macro is not defined above, then make it
** a no-op
*/
@@ -9091,7 +9352,7 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
** The default size of a disk sector
*/
#ifndef SQLITE_DEFAULT_SECTOR_SIZE
-# define SQLITE_DEFAULT_SECTOR_SIZE 512
+# define SQLITE_DEFAULT_SECTOR_SIZE 4096
#endif
/*
@@ -9224,6 +9485,7 @@ SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int);
SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int);
SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut);
SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*);
+SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
@@ -9232,6 +9494,7 @@ SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
+
/*
** Functions for accessing sqlite3_vfs methods
*/
@@ -9463,35 +9726,16 @@ struct FuncDefHash {
/*
** Each database connection is an instance of the following structure.
-**
-** The sqlite.lastRowid records the last insert rowid generated by an
-** insert statement. Inserts on views do not affect its value. Each
-** trigger has its own context, so that lastRowid can be updated inside
-** triggers as usual. The previous value will be restored once the trigger
-** exits. Upon entering a before or instead of trigger, lastRowid is no
-** longer (since after version 2.8.12) reset to -1.
-**
-** The sqlite.nChange does not count changes within triggers and keeps no
-** context. It is reset at start of sqlite3_exec.
-** The sqlite.lsChange represents the number of changes made by the last
-** insert, update, or delete statement. It remains constant throughout the
-** length of a statement and is then updated by OP_SetCounts. It keeps a
-** context stack just like lastRowid so that the count of changes
-** within a trigger is not seen outside the trigger. Changes to views do not
-** affect the value of lsChange.
-** The sqlite.csChange keeps track of the number of current changes (since
-** the last statement) and is used to update sqlite_lsChange.
-**
-** The member variables sqlite.errCode, sqlite.zErrMsg and sqlite.zErrMsg16
-** store the most recent error code and, if applicable, string. The
-** internal function sqlite3Error() is used to set these variables
-** consistently.
*/
struct sqlite3 {
sqlite3_vfs *pVfs; /* OS Interface */
- int nDb; /* Number of backends currently in use */
+ struct Vdbe *pVdbe; /* List of active virtual machines */
+ CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
+ sqlite3_mutex *mutex; /* Connection mutex */
Db *aDb; /* All backends */
+ int nDb; /* Number of backends currently in use */
int flags; /* Miscellaneous flags. See below */
+ i64 lastRowid; /* ROWID of most recent insert (see above) */
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
@@ -9502,27 +9746,23 @@ struct sqlite3 {
signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
u8 suppressErr; /* Do not issue error messages if true */
u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */
+ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
int nextPagesize; /* Pagesize after VACUUM if >0 */
- int nTable; /* Number of tables in the database */
- CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
- i64 lastRowid; /* ROWID of most recent insert (see above) */
u32 magic; /* Magic number for detect library misuse */
int nChange; /* Value returned by sqlite3_changes() */
int nTotalChange; /* Value returned by sqlite3_total_changes() */
- sqlite3_mutex *mutex; /* Connection mutex */
int aLimit[SQLITE_N_LIMIT]; /* Limits */
struct sqlite3InitInfo { /* Information used during initialization */
- int iDb; /* When back is being initialized */
int newTnum; /* Rootpage of table being initialized */
+ u8 iDb; /* Which db file is being initialized */
u8 busy; /* TRUE if currently initializing */
u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */
} init;
- int nExtension; /* Number of loaded extensions */
- void **aExtension; /* Array of shared library handles */
- struct Vdbe *pVdbe; /* List of active virtual machines */
int activeVdbeCnt; /* Number of VDBEs currently executing */
int writeVdbeCnt; /* Number of active VDBEs that are writing */
int vdbeExecCnt; /* Number of nested calls to VdbeExec() */
+ int nExtension; /* Number of loaded extensions */
+ void **aExtension; /* Array of shared library handles */
void (*xTrace)(void*,const char*); /* Trace function */
void *pTraceArg; /* Argument to the trace function */
void (*xProfile)(void*,const char*,u64); /* Profiling function */
@@ -9559,21 +9799,20 @@ struct sqlite3 {
int nProgressOps; /* Number of opcodes for progress callback */
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
+ int nVTrans; /* Allocated size of aVTrans */
Hash aModule; /* populated by sqlite3_create_module() */
VtabCtx *pVtabCtx; /* Context for active vtab connect/create */
VTable **aVTrans; /* Virtual tables with open transactions */
- int nVTrans; /* Allocated size of aVTrans */
VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
#endif
FuncDefHash aFunc; /* Hash table of connection functions */
Hash aCollSeq; /* All collating sequences */
BusyHandler busyHandler; /* Busy callback */
- int busyTimeout; /* Busy handler timeout, in msec */
Db aDbStatic[2]; /* Static space for the 2 default backends */
Savepoint *pSavepoint; /* List of active savepoints */
+ int busyTimeout; /* Busy handler timeout, in msec */
int nSavepoint; /* Number of non-transaction savepoints */
int nStatement; /* Number of nested statement-transactions */
- u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
i64 nDeferredCons; /* Net deferred constraints this transaction. */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
@@ -9616,8 +9855,7 @@ struct sqlite3 {
#define SQLITE_SqlTrace 0x00004000 /* Debug print SQL as it executes */
#define SQLITE_VdbeListing 0x00008000 /* Debug listings of VDBE programs */
#define SQLITE_WriteSchema 0x00010000 /* OK to update SQLITE_MASTER */
-#define SQLITE_NoReadlock 0x00020000 /* Readlocks are omitted when
- ** accessing read-only databases */
+ /* 0x00020000 Unused */
#define SQLITE_IgnoreChecks 0x00040000 /* Do not enforce check constraints */
#define SQLITE_ReadUncommitted 0x0080000 /* For shared-cache mode */
#define SQLITE_LegacyFileFmt 0x00100000 /* Create new databases in format 1 */
@@ -9700,15 +9938,18 @@ struct FuncDestructor {
};
/*
-** Possible values for FuncDef.flags
+** Possible values for FuncDef.flags. Note that the _LENGTH and _TYPEOF
+** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. There
+** are assert() statements in the code to verify this.
*/
#define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */
#define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */
#define SQLITE_FUNC_EPHEM 0x04 /* Ephemeral. Delete with VDBE */
#define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */
-#define SQLITE_FUNC_PRIVATE 0x10 /* Allowed for internal use only */
-#define SQLITE_FUNC_COUNT 0x20 /* Built-in count(*) aggregate */
-#define SQLITE_FUNC_COALESCE 0x40 /* Built-in coalesce() or ifnull() function */
+#define SQLITE_FUNC_COUNT 0x10 /* Built-in count(*) aggregate */
+#define SQLITE_FUNC_COALESCE 0x20 /* Built-in coalesce() or ifnull() function */
+#define SQLITE_FUNC_LENGTH 0x40 /* Built-in length() function */
+#define SQLITE_FUNC_TYPEOF 0x80 /* Built-in typeof() function */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -9736,7 +9977,10 @@ struct FuncDestructor {
** parameter.
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
- {nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
+ {nArg, SQLITE_UTF8, (bNC*SQLITE_FUNC_NEEDCOLL), \
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
+#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
+ {nArg, SQLITE_UTF8, (bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
{nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
@@ -9822,21 +10066,12 @@ struct Column {
struct CollSeq {
char *zName; /* Name of the collating sequence, UTF-8 encoded */
u8 enc; /* Text encoding handled by xCmp() */
- u8 type; /* One of the SQLITE_COLL_... values below */
void *pUser; /* First argument to xCmp() */
int (*xCmp)(void*,int, const void*, int, const void*);
void (*xDel)(void*); /* Destructor for pUser */
};
/*
-** Allowed values of CollSeq.type:
-*/
-#define SQLITE_COLL_BINARY 1 /* The default memcmp() collating sequence */
-#define SQLITE_COLL_NOCASE 2 /* The built-in NOCASE collating sequence */
-#define SQLITE_COLL_REVERSE 3 /* The built-in REVERSE collating sequence */
-#define SQLITE_COLL_USER 0 /* Any other user-defined collating sequence */
-
-/*
** A sort order can be either ASC or DESC.
*/
#define SQLITE_SO_ASC 0 /* Sort in ascending order */
@@ -9975,7 +10210,7 @@ struct Table {
FKey *pFKey; /* Linked list of all foreign keys in this table */
char *zColAff; /* String defining the affinity of each column */
#ifndef SQLITE_OMIT_CHECK
- Expr *pCheck; /* The AND of all CHECK constraints */
+ ExprList *pCheck; /* All CHECK constraints */
#endif
#ifndef SQLITE_OMIT_ALTERTABLE
int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
@@ -9998,8 +10233,6 @@ 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_NeedMetadata 0x20 /* aCol[].zType and aCol[].pColl missing */
-
/*
@@ -10121,7 +10354,7 @@ struct KeyInfo {
struct UnpackedRecord {
KeyInfo *pKeyInfo; /* Collation and sort-order information */
u16 nField; /* Number of entries in apMem[] */
- u16 flags; /* Boolean settings. UNPACKED_... below */
+ u8 flags; /* Boolean settings. UNPACKED_... below */
i64 rowid; /* Used by UNPACKED_PREFIX_SEARCH */
Mem *aMem; /* Values */
};
@@ -10129,12 +10362,9 @@ struct UnpackedRecord {
/*
** Allowed values of UnpackedRecord.flags
*/
-#define UNPACKED_NEED_FREE 0x0001 /* Memory is from sqlite3Malloc() */
-#define UNPACKED_NEED_DESTROY 0x0002 /* apMem[]s should all be destroyed */
-#define UNPACKED_IGNORE_ROWID 0x0004 /* Ignore trailing rowid on key1 */
-#define UNPACKED_INCRKEY 0x0008 /* Make this key an epsilon larger */
-#define UNPACKED_PREFIX_MATCH 0x0010 /* A prefix match is considered OK */
-#define UNPACKED_PREFIX_SEARCH 0x0020 /* A prefix match is considered OK */
+#define UNPACKED_INCRKEY 0x01 /* Make this key an epsilon larger */
+#define UNPACKED_PREFIX_MATCH 0x02 /* A prefix match is considered OK */
+#define UNPACKED_PREFIX_SEARCH 0x04 /* Ignore final (rowid) field */
/*
** Each SQL index is represented in memory by an
@@ -10164,19 +10394,19 @@ struct UnpackedRecord {
*/
struct Index {
char *zName; /* Name of this index */
- int nColumn; /* Number of columns in the table used by this index */
int *aiColumn; /* Which columns are used by this index. 1st is 0 */
tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */
Table *pTable; /* The SQL table being indexed */
- int tnum; /* Page containing root of this index in database file */
- u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
- u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
- u8 bUnordered; /* Use this index for == or IN queries only */
char *zColAff; /* String defining the affinity of each column */
Index *pNext; /* The next index associated with the same table */
Schema *pSchema; /* Schema containing this index */
u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */
char **azColl; /* Array of collation sequence names for index */
+ int nColumn; /* Number of columns in the table used by this index */
+ int tnum; /* Page containing root of this index in database file */
+ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
+ u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
+ u8 bUnordered; /* Use this index for == or IN queries only */
#ifdef SQLITE_ENABLE_STAT3
int nSample; /* Number of elements in aSample[] */
tRowcnt avgEq; /* Average nEq value for key values not in aSample */
@@ -10235,8 +10465,8 @@ struct AggInfo {
** than the source table */
int sortingIdx; /* Cursor number of the sorting index */
int sortingIdxPTab; /* Cursor number of pseudo-table */
- ExprList *pGroupBy; /* The group by clause */
int nSortingColumn; /* Number of columns in the sorting index */
+ ExprList *pGroupBy; /* The group by clause */
struct AggInfo_col { /* For each column used in source tables */
Table *pTab; /* Source table */
int iTable; /* Cursor number of the source table */
@@ -10246,7 +10476,6 @@ struct AggInfo {
Expr *pExpr; /* The original expression */
} *aCol;
int nColumn; /* Number of used entries in aCol[] */
- int nColumnAlloc; /* Number of slots allocated for aCol[] */
int nAccumulator; /* Number of columns that show through to the output.
** Additional columns are used only as parameters to
** aggregate functions */
@@ -10257,7 +10486,6 @@ struct AggInfo {
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
- int nFuncAlloc; /* Number of slots allocated for aFunc[] */
};
/*
@@ -10375,6 +10603,7 @@ struct Expr {
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
u8 flags2; /* Second set of flags. EP2_... */
u8 op2; /* If a TK_REGISTER, the original value of Expr.op */
+ /* If TK_COLUMN, the value of p5 for OP_Column */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
Table *pTab; /* Table for TK_COLUMN expressions. */
#if SQLITE_MAX_EXPR_DEPTH>0
@@ -10397,10 +10626,10 @@ struct Expr {
#define EP_FixedDest 0x0200 /* Result needed in a specific register */
#define EP_IntValue 0x0400 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */
-
-#define EP_Reduced 0x1000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
-#define EP_TokenOnly 0x2000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
-#define EP_Static 0x4000 /* Held in memory not obtained from malloc() */
+#define EP_Hint 0x1000 /* Not used */
+#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
+#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
+#define EP_Static 0x8000 /* Held in memory not obtained from malloc() */
/*
** The following are the meanings of bits in the Expr.flags2 field.
@@ -10454,17 +10683,16 @@ struct Expr {
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
- int nAlloc; /* Number of entries allocated below */
int iECursor; /* VDBE Cursor associated with this ExprList */
- struct ExprList_item {
+ struct ExprList_item { /* For each expression in the list */
Expr *pExpr; /* The list of expressions */
char *zName; /* Token associated with this expression */
char *zSpan; /* Original text of the expression */
u8 sortOrder; /* 1 for DESC or 0 for ASC */
u8 done; /* A flag to indicate when processing is finished */
- u16 iCol; /* For ORDER BY, column number in result set */
+ u16 iOrderByCol; /* For ORDER BY, column number in result set */
u16 iAlias; /* Index into Parse.aAlias[] for zName */
- } *a; /* One entry for each expression */
+ } *a; /* Alloc a power of two greater or equal to nExpr */
};
/*
@@ -10499,7 +10727,6 @@ struct IdList {
int idx; /* Index in some Table.aCol[] of a column named zName */
} *a;
int nId; /* Number of identifiers on the list */
- int nAlloc; /* Number of entries allocated for a[] below */
};
/*
@@ -10708,17 +10935,22 @@ struct NameContext {
Parse *pParse; /* The parser */
SrcList *pSrcList; /* One or more tables used to resolve names */
ExprList *pEList; /* Optional list of named expressions */
- int nRef; /* Number of names resolved by this context */
- int nErr; /* Number of errors encountered while resolving names */
- u8 allowAgg; /* Aggregate functions allowed here */
- u8 hasAgg; /* True if aggregates are seen */
- u8 isCheck; /* True if resolving names in a CHECK constraint */
- int nDepth; /* Depth of subquery recursion. 1 for no recursion */
AggInfo *pAggInfo; /* Information about aggregates at this level */
NameContext *pNext; /* Next outer name context. NULL for outermost */
+ int nRef; /* Number of names resolved by this context */
+ int nErr; /* Number of errors encountered while resolving names */
+ u8 ncFlags; /* Zero or more NC_* flags defined below */
};
/*
+** Allowed values for the NameContext, ncFlags field.
+*/
+#define NC_AllowAgg 0x01 /* Aggregate functions are allowed here */
+#define NC_HasAgg 0x02 /* One or more aggregate functions seen */
+#define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */
+#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */
+
+/*
** An instance of the following structure contains all information
** needed to generate code for a single SELECT statement.
**
@@ -10743,6 +10975,9 @@ struct Select {
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
char affinity; /* MakeRecord with this affinity for SRT_Set */
u16 selFlags; /* Various SF_* values */
+ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
+ int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
+ double nSelectRow; /* Estimated number of result rows */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
ExprList *pGroupBy; /* The GROUP BY clause */
@@ -10753,22 +10988,20 @@ struct Select {
Select *pRightmost; /* Right-most select in a compound select statement */
Expr *pLimit; /* LIMIT expression. NULL means not used. */
Expr *pOffset; /* OFFSET expression. NULL means not used. */
- int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
- int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
- double nSelectRow; /* Estimated number of result rows */
};
/*
** Allowed values for Select.selFlags. The "SF" prefix stands for
** "Select Flag".
*/
-#define SF_Distinct 0x0001 /* Output should be DISTINCT */
-#define SF_Resolved 0x0002 /* Identifiers have been resolved */
-#define SF_Aggregate 0x0004 /* Contains aggregate functions */
-#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
-#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
-#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
-#define SF_UseSorter 0x0040 /* Sort using a sorter */
+#define SF_Distinct 0x01 /* Output should be DISTINCT */
+#define SF_Resolved 0x02 /* Identifiers have been resolved */
+#define SF_Aggregate 0x04 /* Contains aggregate functions */
+#define SF_UsesEphemeral 0x08 /* Uses the OpenEphemeral opcode */
+#define SF_Expanded 0x10 /* sqlite3SelectExpand() called on this */
+#define SF_HasTypeInfo 0x20 /* FROM subqueries have Table metadata */
+#define SF_UseSorter 0x40 /* Sort using a sorter */
+#define SF_Values 0x80 /* Synthesized from VALUES clause */
/*
@@ -10846,10 +11079,10 @@ struct AutoincInfo {
*/
struct TriggerPrg {
Trigger *pTrigger; /* Trigger this program was coded from */
- int orconf; /* Default ON CONFLICT policy */
+ TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */
SubProgram *pProgram; /* Program implementing pTrigger/orconf */
+ int orconf; /* Default ON CONFLICT policy */
u32 aColmask[2]; /* Masks of old.*, new.* columns accessed */
- TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */
};
/*
@@ -10879,16 +11112,18 @@ struct TriggerPrg {
*/
struct Parse {
sqlite3 *db; /* The main database structure */
- int rc; /* Return code from execution */
char *zErrMsg; /* An error message */
Vdbe *pVdbe; /* An engine for executing database bytecode */
+ int rc; /* Return code from execution */
u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
- u8 nameClash; /* A permanent table name clashes with temp table name */
u8 checkSchema; /* Causes schema cookie check after an error */
u8 nested; /* Number of nested calls to the parser/code generator */
- u8 parseError; /* True after a parsing error. Ticket #1794 */
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
u8 nTempInUse; /* Number of aTempReg[] currently checked out */
+ u8 nColCache; /* Number of entries in aColCache[] */
+ u8 iColCache; /* Next entry in aColCache[] to replace */
+ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
+ u8 mayAbort; /* True if statement may throw an ABORT exception */
int aTempReg[8]; /* Holding area for temporary registers */
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
@@ -10896,11 +11131,10 @@ struct Parse {
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
int nSet; /* Number of sets used so far */
+ int nOnce; /* Number of OP_Once instructions so far */
int ckBase; /* Base register of data during check constraints */
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
- u8 nColCache; /* Number of entries in the column cache */
- u8 iColCache; /* Next entry of the cache to replace */
struct yColCache {
int iTable; /* Table cursor number */
int iColumn; /* Table column number */
@@ -10911,62 +11145,64 @@ struct Parse {
} aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
- u8 isMultiWrite; /* True if statement may affect/insert multiple rows */
- u8 mayAbort; /* True if statement may throw an ABORT exception */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */
+ int regRowid; /* Register holding rowid of CREATE TABLE entry */
+ int regRoot; /* Register holding root page number for new objects */
+ int nMaxArg; /* Max args passed to user function by sub-program */
+ Token constraintName;/* Name of the constraint currently being parsed */
#ifndef SQLITE_OMIT_SHARED_CACHE
int nTableLock; /* Number of locks in aTableLock */
TableLock *aTableLock; /* Required table locks for shared-cache mode */
#endif
- int regRowid; /* Register holding rowid of CREATE TABLE entry */
- int regRoot; /* Register holding root page number for new objects */
AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */
- int nMaxArg; /* Max args passed to user function by sub-program */
/* Information used while coding trigger programs. */
Parse *pToplevel; /* Parse structure for main program (or NULL) */
Table *pTriggerTab; /* Table triggers are being coded for */
+ double nQueryLoop; /* Estimated number of iterations of a query */
u32 oldmask; /* Mask of old.* columns referenced */
u32 newmask; /* Mask of new.* columns referenced */
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
u8 disableTriggers; /* True to disable triggers */
- double nQueryLoop; /* Estimated number of iterations of a query */
/* Above is constant between recursions. Below is reset before and after
** each recursion */
- int nVar; /* Number of '?' variables seen in the SQL so far */
- int nzVar; /* Number of available slots in azVar[] */
- char **azVar; /* Pointers to names of parameters */
- Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
- int nAlias; /* Number of aliased result set columns */
- int nAliasAlloc; /* Number of allocated slots for aAlias[] */
- int *aAlias; /* Register used to hold aliased result */
- u8 explain; /* True if the EXPLAIN flag is found on the query */
- Token sNameToken; /* Token with unqualified schema object name */
- Token sLastToken; /* The last token parsed */
- const char *zTail; /* All SQL text past the last semicolon parsed */
- Table *pNewTable; /* A table being constructed by CREATE TABLE */
- Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
- const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
+ int nVar; /* Number of '?' variables seen in the SQL so far */
+ int nzVar; /* Number of available slots in azVar[] */
+ u8 explain; /* True if the EXPLAIN flag is found on the query */
#ifndef SQLITE_OMIT_VIRTUALTABLE
- Token sArg; /* Complete text of a module argument */
- u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
- int nVtabLock; /* Number of virtual tables to lock */
- Table **apVtabLock; /* Pointer to virtual tables needing locking */
+ u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
+ int nVtabLock; /* Number of virtual tables to lock */
#endif
- int nHeight; /* Expression tree height of current sub-select */
- Table *pZombieTab; /* List of Table objects to delete after code gen */
- TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
-
+ int nAlias; /* Number of aliased result set columns */
+ int nHeight; /* Expression tree height of current sub-select */
#ifndef SQLITE_OMIT_EXPLAIN
- int iSelectId;
- int iNextSelectId;
+ int iSelectId; /* ID of current select for EXPLAIN output */
+ int iNextSelectId; /* Next available select ID for EXPLAIN output */
+#endif
+ char **azVar; /* Pointers to names of parameters */
+ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
+ int *aAlias; /* Register used to hold aliased result */
+ const char *zTail; /* All SQL text past the last semicolon parsed */
+ Table *pNewTable; /* A table being constructed by CREATE TABLE */
+ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
+ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
+ Token sNameToken; /* Token with unqualified schema object name */
+ Token sLastToken; /* The last token parsed */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ Token sArg; /* Complete text of a module argument */
+ Table **apVtabLock; /* Pointer to virtual tables needing locking */
#endif
+ Table *pZombieTab; /* List of Table objects to delete after code gen */
+ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
};
+/*
+** Return true if currently inside an sqlite3_declare_vtab() call.
+*/
#ifdef SQLITE_OMIT_VIRTUALTABLE
#define IN_DECLARE_VTAB 0
#else
@@ -10983,7 +11219,7 @@ struct AuthContext {
};
/*
-** Bitfield flags for P5 value in OP_Insert and OP_Delete
+** Bitfield flags for P5 value in various opcodes.
*/
#define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */
#define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */
@@ -10991,6 +11227,8 @@ struct AuthContext {
#define OPFLAG_APPEND 0x08 /* This is likely to be an append */
#define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */
#define OPFLAG_CLEARCACHE 0x20 /* Clear pseudo-table cache in OP_Column */
+#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
+#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
/*
* Each trigger present in the database schema is stored as an instance of
@@ -11117,8 +11355,8 @@ struct StrAccum {
*/
typedef struct {
sqlite3 *db; /* The database being initialized */
- int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
char **pzErrMsg; /* Error message stored here */
+ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
int rc; /* Result code stored here */
} InitData;
@@ -11137,7 +11375,7 @@ struct Sqlite3Config {
int nLookaside; /* Default lookaside buffer count */
sqlite3_mem_methods m; /* Low-level memory allocation interface */
sqlite3_mutex_methods mutex; /* Low-level mutex interface */
- sqlite3_pcache_methods pcache; /* Low-level page-cache interface */
+ sqlite3_pcache_methods2 pcache2; /* Low-level page-cache interface */
void *pHeap; /* Heap storage space */
int nHeap; /* Size of pHeap[] */
int mnReq, mxReq; /* Min and max heap requests sizes */
@@ -11173,6 +11411,7 @@ struct Walker {
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
int i; /* Integer value */
+ SrcList *pSrcList; /* FROM clause */
} u;
};
@@ -11260,7 +11499,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
/*
** Internal function prototypes
*/
-SQLITE_PRIVATE int sqlite3StrICmp(const char *, const char *);
+#define sqlite3StrICmp sqlite3_stricmp
SQLITE_PRIVATE int sqlite3Strlen30(const char*);
#define sqlite3StrNICmp sqlite3_strnicmp
@@ -11343,6 +11582,29 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char*, ...);
#if defined(SQLITE_TEST)
SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*);
#endif
+
+/* Output formatting for SQLITE_TESTCTRL_EXPLAIN */
+#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
+SQLITE_PRIVATE void sqlite3ExplainBegin(Vdbe*);
+SQLITE_PRIVATE void sqlite3ExplainPrintf(Vdbe*, const char*, ...);
+SQLITE_PRIVATE void sqlite3ExplainNL(Vdbe*);
+SQLITE_PRIVATE void sqlite3ExplainPush(Vdbe*);
+SQLITE_PRIVATE void sqlite3ExplainPop(Vdbe*);
+SQLITE_PRIVATE void sqlite3ExplainFinish(Vdbe*);
+SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe*, Select*);
+SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe*, Expr*);
+SQLITE_PRIVATE void sqlite3ExplainExprList(Vdbe*, ExprList*);
+SQLITE_PRIVATE const char *sqlite3VdbeExplanation(Vdbe*);
+#else
+# define sqlite3ExplainBegin(X)
+# define sqlite3ExplainSelect(A,B)
+# define sqlite3ExplainExpr(A,B)
+# define sqlite3ExplainExprList(A,B)
+# define sqlite3ExplainFinish(X)
+# define sqlite3VdbeExplanation(X) 0
+#endif
+
+
SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*, ...);
SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...);
SQLITE_PRIVATE int sqlite3Dequote(char*);
@@ -11353,6 +11615,7 @@ SQLITE_PRIVATE int sqlite3GetTempReg(Parse*);
SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int);
SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int);
SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int);
+SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*);
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*);
@@ -11384,6 +11647,8 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,Select*);
SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
sqlite3_vfs**,char**,char **);
+SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
+SQLITE_PRIVATE int sqlite3CodeOnce(Parse *);
SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32);
SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32);
@@ -11418,7 +11683,7 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse);
# define sqlite3AutoincrementEnd(X)
#endif
SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
-SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int,int*,int*,int*);
+SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*);
SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int);
@@ -11448,7 +11713,7 @@ 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);
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
-SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
+SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, int, int, int);
@@ -11482,7 +11747,7 @@ SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);
SQLITE_PRIVATE void sqlite3PrngSaveState(void);
SQLITE_PRIVATE void sqlite3PrngRestoreState(void);
SQLITE_PRIVATE void sqlite3PrngResetState(void);
-SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*);
+SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int);
SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int);
SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int);
@@ -11515,7 +11780,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*);
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int);
SQLITE_PRIVATE void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
-SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int);
+SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8);
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3*);
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void);
@@ -11656,7 +11921,7 @@ SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*);
#else
# define sqlite3FileSuffix3(X,Y)
#endif
-SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z);
+SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,int);
SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
@@ -11722,6 +11987,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, char*, int, int);
SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum*,const char*,int);
+SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum*,int);
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*);
SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum*);
SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int);
@@ -11781,7 +12047,7 @@ SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*);
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
#endif
SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*);
-SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
+SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int);
SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*);
SQLITE_PRIVATE void sqlite3VtabArgInit(Parse*);
SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse*, Token*);
@@ -12101,7 +12367,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
500, /* nLookaside */
{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}, /* pcache */
+ {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
(void*)0, /* pHeap */
0, /* nHeap */
0, 0, /* mnHeap, mxHeap */
@@ -12628,6 +12894,9 @@ typedef unsigned char Bool;
/* Opaque type used by code in vdbesort.c */
typedef struct VdbeSorter VdbeSorter;
+/* Opaque type used by the explainer */
+typedef struct Explain Explain;
+
/*
** 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
@@ -12707,19 +12976,21 @@ typedef struct VdbeCursor VdbeCursor;
typedef struct VdbeFrame VdbeFrame;
struct VdbeFrame {
Vdbe *v; /* VM this frame belongs to */
- int pc; /* Program Counter in parent (calling) frame */
+ VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
Op *aOp; /* Program instructions for parent frame */
- int nOp; /* Size of aOp array */
Mem *aMem; /* Array of memory cells for parent frame */
- int nMem; /* Number of entries in aMem */
+ u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
- u16 nCursor; /* Number of entries in apCsr */
void *token; /* Copy of SubProgram.token */
+ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
+ u16 nCursor; /* Number of entries in apCsr */
+ int pc; /* Program Counter in parent (calling) frame */
+ int nOp; /* Size of aOp array */
+ int nMem; /* Number of entries in aMem */
+ int nOnceFlag; /* Number of entries in aOnceFlag */
int nChildMem; /* Number of memory cells for child frame */
int nChildCsr; /* Number of cursors for child frame */
- i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
int nChange; /* Statement changes (Vdbe.nChanges) */
- VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
};
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
@@ -12846,8 +13117,21 @@ struct sqlite3_context {
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
Mem s; /* The return value is stored here */
Mem *pMem; /* Memory cell used to store aggregate context */
- int isError; /* Error code returned by the function. */
CollSeq *pColl; /* Collating sequence */
+ int isError; /* Error code returned by the function. */
+ int skipFlag; /* Skip skip accumulator loading if true */
+};
+
+/*
+** An Explain object accumulates indented output which is helpful
+** in describing recursive data structures.
+*/
+struct Explain {
+ Vdbe *pVdbe; /* Attach the explanation to this Vdbe */
+ StrAccum str; /* The string being accumulated */
+ int nIndent; /* Number of elements in aIndent */
+ u16 aIndent[100]; /* Levels of indentation */
+ char zBase[100]; /* Initial space */
};
/*
@@ -12876,7 +13160,6 @@ struct Vdbe {
int nOp; /* Number of instructions in the program */
int nOpAlloc; /* Number of slots allocated for aOp[] */
int nLabel; /* Number of labels used */
- int nLabelAlloc; /* Number of slots allocated in aLabel[] */
int *aLabel; /* Space to hold the labels */
u16 nResColumn; /* Number of columns in one row of the result set */
u16 nCursor; /* Number of slots in apCsr[] */
@@ -12916,11 +13199,17 @@ struct Vdbe {
#ifdef SQLITE_DEBUG
FILE *trace; /* Write an execution trace here, if not NULL */
#endif
+#ifdef SQLITE_ENABLE_TREE_EXPLAIN
+ Explain *pExplain; /* The explainer */
+ char *zExplain; /* Explanation of data structures */
+#endif
VdbeFrame *pFrame; /* Parent frame */
VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */
int nFrame; /* Number of frames in pFrame list */
u32 expmask; /* Binding to these vars invalidates VM */
SubProgram *pProgram; /* Linked list of all sub-programs used by VM */
+ int nOnceFlag; /* Size of array aOnceFlag[] */
+ u8 *aOnceFlag; /* Flags for OP_Once */
};
/*
@@ -12980,7 +13269,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p);
-#define MemReleaseExt(X) \
+#define VdbeMemRelease(X) \
if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \
sqlite3VdbeMemReleaseExternal(X);
SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
@@ -13019,7 +13308,7 @@ SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*);
#endif
#ifdef SQLITE_DEBUG
-SQLITE_PRIVATE void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem*);
+SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*);
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
@@ -13037,8 +13326,10 @@ SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem);
#ifndef SQLITE_OMIT_INCRBLOB
SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *);
+ #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0)
#else
#define sqlite3VdbeMemExpandBlob(x) SQLITE_OK
+ #define ExpandBlob(P) SQLITE_OK
#endif
#endif /* !defined(_VDBEINT_H_) */
@@ -13254,10 +13545,12 @@ SQLITE_API int sqlite3_db_status(
** to zero.
*/
case SQLITE_DBSTATUS_CACHE_HIT:
- case SQLITE_DBSTATUS_CACHE_MISS: {
+ case SQLITE_DBSTATUS_CACHE_MISS:
+ case SQLITE_DBSTATUS_CACHE_WRITE:{
int i;
int nRet = 0;
assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 );
+ assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 );
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt ){
@@ -14438,11 +14731,18 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
** The following functions are instrumented for malloc() failure
** testing:
**
-** sqlite3OsOpen()
** sqlite3OsRead()
** sqlite3OsWrite()
** sqlite3OsSync()
+** sqlite3OsFileSize()
** sqlite3OsLock()
+** sqlite3OsCheckReservedLock()
+** sqlite3OsFileControl()
+** sqlite3OsShmMap()
+** sqlite3OsOpen()
+** sqlite3OsDelete()
+** sqlite3OsAccess()
+** sqlite3OsFullPathname()
**
*/
#if defined(SQLITE_TEST)
@@ -14501,9 +14801,23 @@ SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
DO_OS_MALLOC_TEST(id);
return id->pMethods->xCheckReservedLock(id, pResOut);
}
+
+/*
+** Use sqlite3OsFileControl() when we are doing something that might fail
+** and we need to know about the failures. Use sqlite3OsFileControlHint()
+** when simply tossing information over the wall to the VFS and we do not
+** really care if the VFS receives and understands the information since it
+** is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
+** routine has no return value since the return value would be meaningless.
+*/
SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
+ DO_OS_MALLOC_TEST(id);
return id->pMethods->xFileControl(id, op, pArg);
}
+SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
+ (void)id->pMethods->xFileControl(id, op, pArg);
+}
+
SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
@@ -14527,6 +14841,7 @@ SQLITE_PRIVATE int sqlite3OsShmMap(
int bExtend, /* True to extend file if necessary */
void volatile **pp /* OUT: Pointer to mapping */
){
+ DO_OS_MALLOC_TEST(id);
return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
}
@@ -14543,7 +14858,7 @@ SQLITE_PRIVATE int sqlite3OsOpen(
){
int rc;
DO_OS_MALLOC_TEST(0);
- /* 0x87f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
+ /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */
@@ -14552,6 +14867,8 @@ SQLITE_PRIVATE int sqlite3OsOpen(
return rc;
}
SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ DO_OS_MALLOC_TEST(0);
+ assert( dirSync==0 || dirSync==1 );
return pVfs->xDelete(pVfs, zPath, dirSync);
}
SQLITE_PRIVATE int sqlite3OsAccess(
@@ -14569,6 +14886,7 @@ SQLITE_PRIVATE int sqlite3OsFullPathname(
int nPathOut,
char *zPathOut
){
+ DO_OS_MALLOC_TEST(0);
zPathOut[0] = 0;
return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
}
@@ -14910,7 +15228,31 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
** to obtain the memory it needs.
**
** This file contains implementations of the low-level memory allocation
-** routines specified in the sqlite3_mem_methods object.
+** routines specified in the sqlite3_mem_methods object. The content of
+** this file is only used if SQLITE_SYSTEM_MALLOC is defined. The
+** SQLITE_SYSTEM_MALLOC macro is defined automatically if neither the
+** SQLITE_MEMDEBUG nor the SQLITE_WIN32_MALLOC macros are defined. The
+** default configuration is to use memory allocation routines in this
+** file.
+**
+** C-preprocessor macro summary:
+**
+** HAVE_MALLOC_USABLE_SIZE The configure script sets this symbol if
+** the malloc_usable_size() interface exists
+** on the target platform. Or, this symbol
+** can be set manually, if desired.
+** If an equivalent interface exists by
+** a different name, using a separate -D
+** option to rename it.
+**
+** SQLITE_WITHOUT_ZONEMALLOC Some older macs lack support for the zone
+** memory allocator. Set this symbol to enable
+** building on older macs.
+**
+** SQLITE_WITHOUT_MSIZE Set this symbol to disable the use of
+** _msize() on windows systems. This might
+** be necessary when compiling for Delphi,
+** for example.
*/
/*
@@ -14921,6 +15263,55 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
#ifdef SQLITE_SYSTEM_MALLOC
/*
+** The MSVCRT has malloc_usable_size() but it is called _msize().
+** The use of _msize() is automatic, but can be disabled by compiling
+** with -DSQLITE_WITHOUT_MSIZE
+*/
+#if defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE)
+# define SQLITE_MALLOCSIZE _msize
+#endif
+
+#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC)
+
+/*
+** Use the zone allocator available on apple products unless the
+** SQLITE_WITHOUT_ZONEMALLOC symbol is defined.
+*/
+#include <sys/sysctl.h>
+#include <malloc/malloc.h>
+#include <libkern/OSAtomic.h>
+static malloc_zone_t* _sqliteZone_;
+#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
+#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
+#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))
+#define SQLITE_MALLOCSIZE(x) \
+ (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x))
+
+#else /* if not __APPLE__ */
+
+/*
+** Use standard C library malloc and free on non-Apple systems.
+** Also used by Apple systems if SQLITE_WITHOUT_ZONEMALLOC is defined.
+*/
+#define SQLITE_MALLOC(x) malloc(x)
+#define SQLITE_FREE(x) free(x)
+#define SQLITE_REALLOC(x,y) realloc((x),(y))
+
+#if (defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE)) \
+ || (defined(HAVE_MALLOC_H) && defined(HAVE_MALLOC_USABLE_SIZE))
+# include <malloc.h> /* Needed for malloc_usable_size on linux */
+#endif
+#ifdef HAVE_MALLOC_USABLE_SIZE
+# ifndef SQLITE_MALLOCSIZE
+# define SQLITE_MALLOCSIZE(x) malloc_usable_size(x)
+# endif
+#else
+# undef SQLITE_MALLOCSIZE
+#endif
+
+#endif /* __APPLE__ or not __APPLE__ */
+
+/*
** Like malloc(), but remember the size of the allocation
** so that we can find it later using sqlite3MemSize().
**
@@ -14929,10 +15320,18 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
** routines.
*/
static void *sqlite3MemMalloc(int nByte){
+#ifdef SQLITE_MALLOCSIZE
+ void *p = SQLITE_MALLOC( nByte );
+ if( p==0 ){
+ testcase( sqlite3GlobalConfig.xLog!=0 );
+ sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
+ }
+ return p;
+#else
sqlite3_int64 *p;
assert( nByte>0 );
nByte = ROUND8(nByte);
- p = malloc( nByte+8 );
+ p = SQLITE_MALLOC( nByte+8 );
if( p ){
p[0] = nByte;
p++;
@@ -14941,6 +15340,7 @@ static void *sqlite3MemMalloc(int nByte){
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
}
return (void *)p;
+#endif
}
/*
@@ -14952,10 +15352,14 @@ static void *sqlite3MemMalloc(int nByte){
** by higher-level routines.
*/
static void sqlite3MemFree(void *pPrior){
+#ifdef SQLITE_MALLOCSIZE
+ SQLITE_FREE(pPrior);
+#else
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 );
p--;
- free(p);
+ SQLITE_FREE(p);
+#endif
}
/*
@@ -14963,11 +15367,15 @@ static void sqlite3MemFree(void *pPrior){
** or xRealloc().
*/
static int sqlite3MemSize(void *pPrior){
+#ifdef SQLITE_MALLOCSIZE
+ return pPrior ? (int)SQLITE_MALLOCSIZE(pPrior) : 0;
+#else
sqlite3_int64 *p;
if( pPrior==0 ) return 0;
p = (sqlite3_int64*)pPrior;
p--;
return (int)p[0];
+#endif
}
/*
@@ -14981,11 +15389,21 @@ static int sqlite3MemSize(void *pPrior){
** routines and redirected to xFree.
*/
static void *sqlite3MemRealloc(void *pPrior, int nByte){
+#ifdef SQLITE_MALLOCSIZE
+ void *p = SQLITE_REALLOC(pPrior, nByte);
+ if( p==0 ){
+ testcase( sqlite3GlobalConfig.xLog!=0 );
+ sqlite3_log(SQLITE_NOMEM,
+ "failed memory resize %u to %u bytes",
+ SQLITE_MALLOCSIZE(pPrior), nByte);
+ }
+ return p;
+#else
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 && nByte>0 );
assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
p--;
- p = realloc(p, nByte+8 );
+ p = SQLITE_REALLOC(p, nByte+8 );
if( p ){
p[0] = nByte;
p++;
@@ -14996,6 +15414,7 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
sqlite3MemSize(pPrior), nByte);
}
return (void*)p;
+#endif
}
/*
@@ -15009,6 +15428,34 @@ static int sqlite3MemRoundup(int n){
** Initialize this module.
*/
static int sqlite3MemInit(void *NotUsed){
+#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC)
+ int cpuCount;
+ size_t len;
+ if( _sqliteZone_ ){
+ return SQLITE_OK;
+ }
+ len = sizeof(cpuCount);
+ /* One usually wants to use hw.acctivecpu for MT decisions, but not here */
+ sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0);
+ if( cpuCount>1 ){
+ /* defer MT decisions to system malloc */
+ _sqliteZone_ = malloc_default_zone();
+ }else{
+ /* only 1 core, use our own zone to contention over global locks,
+ ** e.g. we have our own dedicated locks */
+ bool success;
+ malloc_zone_t* newzone = malloc_create_zone(4096, 0);
+ malloc_set_zone_name(newzone, "Sqlite_Heap");
+ do{
+ success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone,
+ (void * volatile *)&_sqliteZone_);
+ }while(!_sqliteZone_);
+ if( !success ){
+ /* somebody registered a zone first */
+ malloc_destroy_zone(newzone);
+ }
+ }
+#endif
UNUSED_PARAMETER(NotUsed);
return SQLITE_OK;
}
@@ -16998,7 +17445,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
}
#endif
-#endif /* SQLITE_MUTEX_OMIT */
+#endif /* !defined(SQLITE_MUTEX_OMIT) */
/************** End of mutex.c ***********************************************/
/************** Begin file mutex_noop.c **************************************/
@@ -17205,8 +17652,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){
SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
return sqlite3NoopMutex();
}
-#endif /* SQLITE_MUTEX_NOOP */
-#endif /* SQLITE_MUTEX_OMIT */
+#endif /* defined(SQLITE_MUTEX_NOOP) */
+#endif /* !defined(SQLITE_MUTEX_OMIT) */
/************** End of mutex_noop.c ******************************************/
/************** Begin file mutex_os2.c ***************************************/
@@ -17835,7 +18282,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
return &sMutex;
}
-#endif /* SQLITE_MUTEX_PTHREAD */
+#endif /* SQLITE_MUTEX_PTHREADS */
/************** End of mutex_unix.c ******************************************/
/************** Begin file mutex_w32.c ***************************************/
@@ -18304,7 +18751,8 @@ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
sqlite3_int64 priorLimit;
sqlite3_int64 excess;
#ifndef SQLITE_OMIT_AUTOINIT
- sqlite3_initialize();
+ int rc = sqlite3_initialize();
+ if( rc ) return -1;
#endif
sqlite3_mutex_enter(mem0.mutex);
priorLimit = mem0.alarmThreshold;
@@ -18664,6 +19112,10 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
}
if( isLookaside(db, p) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
+#if SQLITE_DEBUG
+ /* Trash all content in the buffer being freed */
+ memset(p, 0xaa, db->lookaside.sz);
+#endif
pBuf->pNext = db->lookaside.pFree;
db->lookaside.pFree = pBuf;
db->lookaside.nOut--;
@@ -19089,7 +19541,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
/*
** Append N space characters to the given string buffer.
*/
-static void appendSpace(StrAccum *pAccum, int N){
+SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *pAccum, int N){
static const char zSpaces[] = " ";
while( N>=(int)sizeof(zSpaces)-1 ){
sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
@@ -19617,7 +20069,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
register int nspace;
nspace = width-length;
if( nspace>0 ){
- appendSpace(pAccum, nspace);
+ sqlite3AppendSpace(pAccum, nspace);
}
}
if( length>0 ){
@@ -19627,7 +20079,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
register int nspace;
nspace = width-length;
if( nspace>0 ){
- appendSpace(pAccum, nspace);
+ sqlite3AppendSpace(pAccum, nspace);
}
}
sqlite3_free(zExtra);
@@ -20849,13 +21301,13 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){
** Some systems have stricmp(). Others have strcasecmp(). Because
** there is no consistency, we will define our own.
**
-** IMPLEMENTATION-OF: R-20522-24639 The sqlite3_strnicmp() API allows
-** applications and extensions to compare the contents of two buffers
-** containing UTF-8 strings in a case-independent fashion, using the same
-** definition of case independence that SQLite uses internally when
-** comparing identifiers.
+** IMPLEMENTATION-OF: R-30243-02494 The sqlite3_stricmp() and
+** sqlite3_strnicmp() APIs allow applications and extensions to compare
+** the contents of two buffers containing UTF-8 strings in a
+** case-independent fashion, using the same definition of "case
+** independence" that SQLite uses internally when comparing identifiers.
*/
-SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){
+SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){
register unsigned char *a, *b;
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
@@ -21802,18 +22254,17 @@ SQLITE_PRIVATE int sqlite3AbsInt32(int x){
** test.db-journal => test.nal
** test.db-wal => test.wal
** test.db-shm => test.shm
+** test.db-mj7f3319fa => test.9fa
*/
SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
#if SQLITE_ENABLE_8_3_NAMES<2
- const char *zOk;
- zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names");
- if( zOk && sqlite3GetBoolean(zOk) )
+ if( sqlite3_uri_boolean(zBaseFilename, "8_3_names", 0) )
#endif
{
int i, sz;
sz = sqlite3Strlen30(z);
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
- if( z[i]=='.' && ALWAYS(sz>i+4) ) memcpy(&z[i+1], &z[sz-3], 4);
+ if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
}
}
#endif
@@ -24519,6 +24970,7 @@ SQLITE_API int sqlite3_os_end(void){
#include <sys/mman.h>
#endif
+
#if SQLITE_ENABLE_LOCKING_STYLE
# include <sys/ioctl.h>
# if OS_VXWORKS
@@ -24560,8 +25012,8 @@ SQLITE_API int sqlite3_os_end(void){
#endif
/*
- ** Default permissions when creating auto proxy dir
- */
+** Default permissions when creating auto proxy dir
+*/
#ifndef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
# define SQLITE_DEFAULT_PROXYDIR_PERMISSIONS 0755
#endif
@@ -24602,10 +25054,11 @@ struct UnixUnusedFd {
typedef struct unixFile unixFile;
struct unixFile {
sqlite3_io_methods const *pMethod; /* Always the first entry */
+ sqlite3_vfs *pVfs; /* The VFS that created this unixFile */
unixInodeInfo *pInode; /* Info about locks on this inode */
int h; /* The file descriptor */
unsigned char eFileLock; /* The type of lock held on this fd */
- unsigned char ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
+ unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
int lastErrno; /* The unix errno from last I/O error */
void *lockingContext; /* Locking style specific state */
UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
@@ -24619,7 +25072,6 @@ struct unixFile {
unsigned fsFlags; /* cached details from statfs() */
#endif
#if OS_VXWORKS
- int isDelete; /* Delete on close if true */
struct vxworksFileId *pId; /* Unique file ID */
#endif
#ifndef NDEBUG
@@ -24653,6 +25105,11 @@ struct unixFile {
#else
# define UNIXFILE_DIRSYNC 0x00
#endif
+#define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
+#define UNIXFILE_DELETE 0x20 /* Delete on close */
+#define UNIXFILE_URI 0x40 /* Filename might have query parameters */
+#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */
+#define UNIXFILE_CHOWN 0x100 /* File ownership was changed */
/*
** Include code that is common to all os_*.c files
@@ -25011,6 +25468,18 @@ static struct unix_syscall {
{ "openDirectory", (sqlite3_syscall_ptr)openDirectory, 0 },
#define osOpenDirectory ((int(*)(const char*,int*))aSyscall[17].pCurrent)
+ { "mkdir", (sqlite3_syscall_ptr)mkdir, 0 },
+#define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent)
+
+ { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
+#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
+
+ { "fchown", (sqlite3_syscall_ptr)fchown, 0 },
+#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
+
+ { "umask", (sqlite3_syscall_ptr)umask, 0 },
+#define osUmask ((mode_t(*)(mode_t))aSyscall[21].pCurrent)
+
}; /* End of the overrideable system calls */
/*
@@ -25097,12 +25566,46 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
}
/*
-** Retry open() calls that fail due to EINTR
+** Invoke open(). Do so multiple times, until it either succeeds or
+** fails for some reason other than EINTR.
+**
+** If the file creation mode "m" is 0 then set it to the default for
+** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
+** 0644) as modified by the system umask. If m is not 0, then
+** make the file creation mode be exactly m ignoring the umask.
+**
+** The m parameter will be non-zero only when creating -wal, -journal,
+** and -shm files. We want those files to have *exactly* the same
+** permissions as their original database, unadulterated by the umask.
+** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
+** transaction crashes and leaves behind hot journals, then any
+** process that is able to write to the database will also be able to
+** recover the hot journals.
*/
-static int robust_open(const char *z, int f, int m){
- int rc;
- do{ rc = osOpen(z,f,m); }while( rc<0 && errno==EINTR );
- return rc;
+static int robust_open(const char *z, int f, mode_t m){
+ int fd;
+ mode_t m2;
+ mode_t origM = 0;
+ if( m==0 ){
+ m2 = SQLITE_DEFAULT_FILE_PERMISSIONS;
+ }else{
+ m2 = m;
+ origM = osUmask(0);
+ }
+ do{
+#if defined(O_CLOEXEC)
+ fd = osOpen(z,f|O_CLOEXEC,m2);
+#else
+ fd = osOpen(z,f,m2);
+#endif
+ }while( fd<0 && errno==EINTR );
+ if( m ){
+ osUmask(origM);
+ }
+#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
+ if( fd>=0 ) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+#endif
+ return fd;
}
/*
@@ -26360,7 +26863,7 @@ static int closeUnixFile(sqlite3_file *id){
}
#if OS_VXWORKS
if( pFile->pId ){
- if( pFile->isDelete ){
+ if( pFile->ctrlFlags & UNIXFILE_DELETE ){
osUnlink(pFile->pId->zCanonicalName);
}
vxworksReleaseFileId(pFile->pId);
@@ -26449,8 +26952,8 @@ static int nolockClose(sqlite3_file *id) {
************************* Begin dot-file Locking ******************************
**
** The dotfile locking implementation uses the existance of separate lock
-** files in order to control access to the database. This works on just
-** about every filesystem imaginable. But there are serious downsides:
+** files (really a directory) to control access to the database. This works
+** on just about every filesystem imaginable. But there are serious downsides:
**
** (1) There is zero concurrency. A single reader blocks all other
** connections from reading or writing the database.
@@ -26461,15 +26964,15 @@ static int nolockClose(sqlite3_file *id) {
** Nevertheless, a dotlock is an appropriate locking mode for use if no
** other locking strategy is available.
**
-** Dotfile locking works by creating a file in the same directory as the
-** database and with the same name but with a ".lock" extension added.
-** The existance of a lock file implies an EXCLUSIVE lock. All other lock
-** types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE.
+** Dotfile locking works by creating a subdirectory in the same directory as
+** the database and with the same name but with a ".lock" extension added.
+** The existance of a lock directory implies an EXCLUSIVE lock. All other
+** lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE.
*/
/*
** The file suffix added to the data base filename in order to create the
-** lock file.
+** lock directory.
*/
#define DOTLOCK_SUFFIX ".lock"
@@ -26536,7 +27039,6 @@ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
*/
static int dotlockLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
- int fd;
char *zLockFile = (char *)pFile->lockingContext;
int rc = SQLITE_OK;
@@ -26556,9 +27058,9 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
}
/* grab an exclusive lock */
- fd = robust_open(zLockFile,O_RDONLY|O_CREAT|O_EXCL,0600);
- if( fd<0 ){
- /* failed to open/create the file, someone else may have stolen the lock */
+ rc = osMkdir(zLockFile, 0777);
+ if( rc<0 ){
+ /* failed to open/create the lock directory */
int tErrno = errno;
if( EEXIST == tErrno ){
rc = SQLITE_BUSY;
@@ -26570,7 +27072,6 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
}
return rc;
}
- robust_close(pFile, fd, __LINE__);
/* got it, set the type and return ok */
pFile->eFileLock = eFileLock;
@@ -26589,6 +27090,7 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
char *zLockFile = (char *)pFile->lockingContext;
+ int rc;
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock,
@@ -26610,9 +27112,11 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
/* To fully unlock the database, delete the lock file */
assert( eFileLock==NO_LOCK );
- if( osUnlink(zLockFile) ){
- int rc = 0;
+ rc = osRmdir(zLockFile);
+ if( rc<0 && errno==ENOTDIR ) rc = osUnlink(zLockFile);
+ if( rc<0 ){
int tErrno = errno;
+ rc = 0;
if( ENOENT != tErrno ){
rc = SQLITE_IOERR_UNLOCK;
}
@@ -27548,35 +28052,48 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
*/
static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
int got;
+ int prior = 0;
#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
i64 newOffset;
#endif
TIMER_START;
+ do{
#if defined(USE_PREAD)
- do{ got = osPread(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
- SimulateIOError( got = -1 );
+ got = osPread(id->h, pBuf, cnt, offset);
+ SimulateIOError( got = -1 );
#elif defined(USE_PREAD64)
- do{ got = osPread64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR);
- SimulateIOError( got = -1 );
+ got = osPread64(id->h, pBuf, cnt, offset);
+ SimulateIOError( got = -1 );
#else
- newOffset = lseek(id->h, offset, SEEK_SET);
- SimulateIOError( newOffset-- );
- if( newOffset!=offset ){
- if( newOffset == -1 ){
- ((unixFile*)id)->lastErrno = errno;
- }else{
- ((unixFile*)id)->lastErrno = 0;
+ newOffset = lseek(id->h, offset, SEEK_SET);
+ SimulateIOError( newOffset-- );
+ if( newOffset!=offset ){
+ if( newOffset == -1 ){
+ ((unixFile*)id)->lastErrno = errno;
+ }else{
+ ((unixFile*)id)->lastErrno = 0;
+ }
+ return -1;
}
- return -1;
- }
- do{ got = osRead(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
+ got = osRead(id->h, pBuf, cnt);
#endif
+ if( got==cnt ) break;
+ if( got<0 ){
+ if( errno==EINTR ){ got = 1; continue; }
+ prior = 0;
+ ((unixFile*)id)->lastErrno = errno;
+ break;
+ }else if( got>0 ){
+ cnt -= got;
+ offset += got;
+ prior += got;
+ pBuf = (void*)(got + (char*)pBuf);
+ }
+ }while( got>0 );
TIMER_END;
- if( got<0 ){
- ((unixFile*)id)->lastErrno = errno;
- }
- OSTRACE(("READ %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
- return got;
+ OSTRACE(("READ %-3d %5d %7lld %llu\n",
+ id->h, got+prior, offset-prior, TIMER_ELAPSED));
+ return got+prior;
}
/*
@@ -27883,9 +28400,6 @@ static int openDirectory(const char *zFilename, int *pFd){
zDirname[ii] = '\0';
fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
if( fd>=0 ){
-#ifdef FD_CLOEXEC
- osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
-#endif
OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
}
}
@@ -27968,7 +28482,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
** actual file size after the operation may be larger than the requested
** size).
*/
- if( pFile->szChunk ){
+ if( pFile->szChunk>0 ){
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
}
@@ -28082,6 +28596,22 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
}
/*
+** If *pArg is inititially negative then this is a query. Set *pArg to
+** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
+**
+** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
+*/
+static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
+ if( *pArg<0 ){
+ *pArg = (pFile->ctrlFlags & mask)!=0;
+ }else if( (*pArg)==0 ){
+ pFile->ctrlFlags &= ~mask;
+ }else{
+ pFile->ctrlFlags |= mask;
+ }
+}
+
+/*
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
@@ -28107,14 +28637,15 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
return rc;
}
case SQLITE_FCNTL_PERSIST_WAL: {
- int bPersist = *(int*)pArg;
- if( bPersist<0 ){
- *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0;
- }else if( bPersist==0 ){
- pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL;
- }else{
- pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL;
- }
+ unixModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg);
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
+ unixModeBit(pFile, UNIXFILE_PSOW, (int*)pArg);
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_VFSNAME: {
+ *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
return SQLITE_OK;
}
#ifndef NDEBUG
@@ -28134,9 +28665,6 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
return proxyFileControl(id,op,pArg);
}
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
- case SQLITE_FCNTL_SYNC_OMITTED: {
- return SQLITE_OK; /* A no-op */
- }
}
return SQLITE_NOTFOUND;
}
@@ -28151,17 +28679,31 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
** a database and its journal file) that the sector size will be the
** same for both.
*/
-static int unixSectorSize(sqlite3_file *NotUsed){
- UNUSED_PARAMETER(NotUsed);
+static int unixSectorSize(sqlite3_file *pFile){
+ (void)pFile;
return SQLITE_DEFAULT_SECTOR_SIZE;
}
/*
-** Return the device characteristics for the file. This is always 0 for unix.
+** Return the device characteristics for the file.
+**
+** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default.
+** However, that choice is contraversial since technically the underlying
+** file system does not always provide powersafe overwrites. (In other
+** words, after a power-loss event, parts of the file that were never
+** written might end up being altered.) However, non-PSOW behavior is very,
+** very rare. And asserting PSOW makes a large reduction in the amount
+** of required I/O for journaling, since a lot of padding is eliminated.
+** Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control
+** available to turn it off and URI query parameter available to turn it off.
*/
-static int unixDeviceCharacteristics(sqlite3_file *NotUsed){
- UNUSED_PARAMETER(NotUsed);
- return 0;
+static int unixDeviceCharacteristics(sqlite3_file *id){
+ unixFile *p = (unixFile*)id;
+ if( p->ctrlFlags & UNIXFILE_PSOW ){
+ return SQLITE_IOCAP_POWERSAFE_OVERWRITE;
+ }else{
+ return 0;
+ }
}
#ifndef SQLITE_OMIT_WAL
@@ -28407,8 +28949,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
/* Call fstat() to figure out the permissions on the database file. If
** a new *-shm file is created, an attempt will be made to create it
- ** with the same permissions. The actual permissions the file is created
- ** with are subject to the current umask setting.
+ ** with the same permissions.
*/
if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
rc = SQLITE_IOERR_FSTAT;
@@ -28416,16 +28957,16 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
}
#ifdef SQLITE_SHM_DIRECTORY
- nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 30;
+ nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31;
#else
- nShmFilename = 5 + (int)strlen(pDbFd->zPath);
+ nShmFilename = 6 + (int)strlen(pDbFd->zPath);
#endif
pShmNode = sqlite3_malloc( sizeof(*pShmNode) + nShmFilename );
if( pShmNode==0 ){
rc = SQLITE_NOMEM;
goto shm_open_err;
}
- memset(pShmNode, 0, sizeof(*pShmNode));
+ memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename);
zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1];
#ifdef SQLITE_SHM_DIRECTORY
sqlite3_snprintf(nShmFilename, zShmFilename,
@@ -28445,19 +28986,26 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
}
if( pInode->bProcessLock==0 ){
- const char *zRO;
int openFlags = O_RDWR | O_CREAT;
- zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm");
- if( zRO && sqlite3GetBoolean(zRO) ){
+ if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
openFlags = O_RDONLY;
pShmNode->isReadonly = 1;
}
pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
if( pShmNode->h<0 ){
- if( pShmNode->h<0 ){
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
- goto shm_open_err;
- }
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
+ goto shm_open_err;
+ }
+
+ /* If this process is running as root, make sure that the SHM file
+ ** is owned by the same user that owns the original database. Otherwise,
+ ** the original owner will not be able to connect. If this process is
+ ** not root, the following fchown() will fail, but we don't care. The
+ ** if(){..} and the UNIXFILE_CHOWN flag are purely to silence compiler
+ ** warnings.
+ */
+ if( osFchown(pShmNode->h, sStat.st_uid, sStat.st_gid)==0 ){
+ pDbFd->ctrlFlags |= UNIXFILE_CHOWN;
}
/* Check to see if another process is holding the dead-man switch.
@@ -29110,12 +29658,9 @@ typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*);
static int fillInUnixFile(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
int h, /* Open file descriptor of file being opened */
- int syncDir, /* True to sync directory on first sync */
sqlite3_file *pId, /* Write to the unixFile structure here */
const char *zFilename, /* Name of the file being opened */
- int noLock, /* Omit locking if true */
- int isDelete, /* Delete on close if true */
- int isReadOnly /* True if the file is opened read-only */
+ int ctrlFlags /* Zero or more UNIXFILE_* values */
){
const sqlite3_io_methods *pLockingStyle;
unixFile *pNew = (unixFile *)pId;
@@ -29123,11 +29668,6 @@ static int fillInUnixFile(
assert( pNew->pInode==NULL );
- /* Parameter isDelete is only used on vxworks. Express this explicitly
- ** here to prevent compiler warnings about unused parameters.
- */
- UNUSED_PARAMETER(isDelete);
-
/* Usually the path zFilename should not be a relative pathname. The
** exception is when opening the proxy "conch" file in builds that
** include the special Apple locking styles.
@@ -29140,32 +29680,30 @@ static int fillInUnixFile(
#endif
/* No locking occurs in temporary files */
- assert( zFilename!=0 || noLock );
+ assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 );
OSTRACE(("OPEN %-3d %s\n", h, zFilename));
pNew->h = h;
+ pNew->pVfs = pVfs;
pNew->zPath = zFilename;
- if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
- pNew->ctrlFlags = UNIXFILE_EXCL;
- }else{
- pNew->ctrlFlags = 0;
- }
- if( isReadOnly ){
- pNew->ctrlFlags |= UNIXFILE_RDONLY;
+ pNew->ctrlFlags = (u8)ctrlFlags;
+ if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
+ "psow", SQLITE_POWERSAFE_OVERWRITE) ){
+ pNew->ctrlFlags |= UNIXFILE_PSOW;
}
- if( syncDir ){
- pNew->ctrlFlags |= UNIXFILE_DIRSYNC;
+ if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
+ pNew->ctrlFlags |= UNIXFILE_EXCL;
}
#if OS_VXWORKS
pNew->pId = vxworksFindFileId(zFilename);
if( pNew->pId==0 ){
- noLock = 1;
+ ctrlFlags |= UNIXFILE_NOLOCK;
rc = SQLITE_NOMEM;
}
#endif
- if( noLock ){
+ if( ctrlFlags & UNIXFILE_NOLOCK ){
pLockingStyle = &nolockIoMethods;
}else{
pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew);
@@ -29286,7 +29824,7 @@ static int fillInUnixFile(
osUnlink(zFilename);
isDelete = 0;
}
- pNew->isDelete = isDelete;
+ if( isDelete ) pNew->ctrlFlags |= UNIXFILE_DELETE;
#endif
if( rc!=SQLITE_OK ){
if( h>=0 ) robust_close(pNew, h, __LINE__);
@@ -29351,18 +29889,19 @@ static int unixGetTempname(int nBuf, char *zBuf){
/* 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) + 17) >= (size_t)nBuf ){
+ if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 18) >= (size_t)nBuf ){
return SQLITE_ERROR;
}
do{
- sqlite3_snprintf(nBuf-17, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
+ 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;
}
@@ -29441,12 +29980,10 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
** written to *pMode. If an IO error occurs, an SQLite error code is
** returned and the value of *pMode is not modified.
**
-** If the file being opened is a temporary file, it is always created with
-** the octal permissions 0600 (read/writable by owner only). If the file
-** is a database or master journal file, it is created with the permissions
-** mask SQLITE_DEFAULT_FILE_PERMISSIONS.
-**
-** Finally, if the file being opened is a WAL or regular journal file, then
+** In most cases cases, this routine sets *pMode to 0, which will become
+** an indication to robust_open() to create the file using
+** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask.
+** But if the file being opened is a WAL or regular journal file, then
** this function queries the file-system for the permissions on the
** corresponding database file and sets *pMode to this value. Whenever
** possible, WAL and journal files are created using the same permissions
@@ -29460,10 +29997,14 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
static int findCreateFileMode(
const char *zPath, /* Path of file (possibly) being created */
int flags, /* Flags passed as 4th argument to xOpen() */
- mode_t *pMode /* OUT: Permissions to open file with */
+ mode_t *pMode, /* OUT: Permissions to open file with */
+ uid_t *pUid, /* OUT: uid to set on the file */
+ gid_t *pGid /* OUT: gid to set on the file */
){
int rc = SQLITE_OK; /* Return Code */
- *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;
+ *pMode = 0;
+ *pUid = 0;
+ *pGid = 0;
if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
char zDb[MAX_PATHNAME+1]; /* Database file path */
int nDb; /* Number of valid bytes in zDb */
@@ -29483,7 +30024,7 @@ static int findCreateFileMode(
*/
nDb = sqlite3Strlen30(zPath) - 1;
#ifdef SQLITE_ENABLE_8_3_NAMES
- while( nDb>0 && !sqlite3Isalnum(zPath[nDb]) ) nDb--;
+ while( nDb>0 && sqlite3Isalnum(zPath[nDb]) ) nDb--;
if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK;
#else
while( zPath[nDb]!='-' ){
@@ -29497,6 +30038,8 @@ static int findCreateFileMode(
if( 0==osStat(zDb, &sStat) ){
*pMode = sStat.st_mode & 0777;
+ *pUid = sStat.st_uid;
+ *pGid = sStat.st_gid;
}else{
rc = SQLITE_IOERR_FSTAT;
}
@@ -29541,6 +30084,7 @@ static int unixOpen(
int eType = flags&0xFFFFFF00; /* Type of file to open */
int noLock; /* True to omit locking primitives */
int rc = SQLITE_OK; /* Function Return Code */
+ int ctrlFlags = 0; /* UNIXFILE_* flags */
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
@@ -29567,7 +30111,7 @@ static int unixOpen(
/* If argument zPath is a NULL pointer, this function is required to open
** a temporary file. Use this buffer to store the file name in.
*/
- char zTmpname[MAX_PATHNAME+1];
+ char zTmpname[MAX_PATHNAME+2];
const char *zName = zPath;
/* Check the following statements are true:
@@ -29610,14 +30154,24 @@ static int unixOpen(
}
}
p->pUnused = pUnused;
+
+ /* Database filenames are double-zero terminated if they are not
+ ** URIs with parameters. Hence, they can always be passed into
+ ** sqlite3_uri_parameter(). */
+ assert( (flags & SQLITE_OPEN_URI) || zName[strlen(zName)+1]==0 );
+
}else if( !zName ){
/* If zName is NULL, the upper layer is requesting a temp file. */
assert(isDelete && !syncDir);
- rc = unixGetTempname(MAX_PATHNAME+1, zTmpname);
+ rc = unixGetTempname(MAX_PATHNAME+2, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
}
zName = zTmpname;
+
+ /* Generated temporary filenames are always double-zero terminated
+ ** for use by sqlite3_uri_parameter(). */
+ assert( zName[strlen(zName)+1]==0 );
}
/* Determine the value of the flags parameter passed to POSIX function
@@ -29632,7 +30186,9 @@ static int unixOpen(
if( fd<0 ){
mode_t openMode; /* Permissions to create file with */
- rc = findCreateFileMode(zName, flags, &openMode);
+ uid_t uid; /* Userid for the file */
+ gid_t gid; /* Groupid for the file */
+ rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
if( rc!=SQLITE_OK ){
assert( !p->pUnused );
assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
@@ -29653,6 +30209,17 @@ static int unixOpen(
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
goto open_finished;
}
+
+ /* If this process is running as root and if creating a new rollback
+ ** journal or WAL file, set the ownership of the journal or WAL to be
+ ** the same as the original database. If we are not running as root,
+ ** then the fchown() call will fail, but that's ok. The "if(){}" and
+ ** the setting of the UNIXFILE_CHOWN flag are purely to silence compiler
+ ** warnings from gcc.
+ */
+ if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
+ if( osFchown(fd, uid, gid)==0 ){ p->ctrlFlags |= UNIXFILE_CHOWN; }
+ }
}
assert( fd>=0 );
if( pOutFlags ){
@@ -29677,10 +30244,6 @@ static int unixOpen(
}
#endif
-#ifdef FD_CLOEXEC
- osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
-#endif
-
noLock = eType!=SQLITE_OPEN_MAIN_DB;
@@ -29694,7 +30257,14 @@ static int unixOpen(
((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
}
#endif
-
+
+ /* Set up appropriate ctrlFlags */
+ if( isDelete ) ctrlFlags |= UNIXFILE_DELETE;
+ if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
+ if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
+ if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
+ if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
+
#if SQLITE_ENABLE_LOCKING_STYLE
#if SQLITE_PREFER_PROXY_LOCKING
isAutoProxy = 1;
@@ -29724,8 +30294,7 @@ static int unixOpen(
useProxy = !(fsInfo.f_flags&MNT_LOCAL);
}
if( useProxy ){
- rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock,
- isDelete, isReadonly);
+ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
if( rc==SQLITE_OK ){
rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
if( rc!=SQLITE_OK ){
@@ -29742,8 +30311,8 @@ static int unixOpen(
}
#endif
- rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock,
- isDelete, isReadonly);
+ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
+
open_finished:
if( rc!=SQLITE_OK ){
sqlite3_free(p->pUnused);
@@ -29768,7 +30337,7 @@ static int unixDelete(
return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
}
#ifndef SQLITE_DISABLE_DIRSYNC
- if( dirSync ){
+ if( (dirSync & 1)!=0 ){
int fd;
rc = osOpenDirectory(zPath, &fd);
if( rc==SQLITE_OK ){
@@ -29958,7 +30527,7 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
memset(zBuf, 0, nBuf);
#if !defined(SQLITE_TEST)
{
- int pid, fd;
+ int pid, fd, got;
fd = robust_open("/dev/urandom", O_RDONLY, 0);
if( fd<0 ){
time_t t;
@@ -29969,7 +30538,7 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
nBuf = sizeof(t) + sizeof(pid);
}else{
- do{ nBuf = osRead(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR );
+ do{ got = osRead(fd, zBuf, nBuf); }while( got<0 && errno==EINTR );
robust_close(0, fd, __LINE__);
}
}
@@ -30319,7 +30888,7 @@ static int proxyCreateLockPath(const char *lockPath){
if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/')
|| (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){
buf[i]='\0';
- if( mkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
+ if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
int err=errno;
if( err!=EEXIST ) {
OSTRACE(("CREATELOCKPATH FAILED creating %s, "
@@ -30373,17 +30942,17 @@ static int proxyCreateUnixFile(
}
}
if( fd<0 ){
- fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
+ fd = robust_open(path, openFlags, 0);
terrno = errno;
if( fd<0 && errno==ENOENT && islockfile ){
if( proxyCreateLockPath(path) == SQLITE_OK ){
- fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
+ fd = robust_open(path, openFlags, 0);
}
}
}
if( fd<0 ){
openFlags = O_RDONLY;
- fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
+ fd = robust_open(path, openFlags, 0);
terrno = errno;
}
if( fd<0 ){
@@ -30414,7 +30983,7 @@ static int proxyCreateUnixFile(
pUnused->flags = openFlags;
pNew->pUnused = pUnused;
- rc = fillInUnixFile(&dummyVfs, fd, 0, (sqlite3_file*)pNew, path, 0, 0, 0);
+ rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0);
if( rc==SQLITE_OK ){
*ppFile = pNew;
return SQLITE_OK;
@@ -30507,8 +31076,7 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
goto end_breaklock;
}
/* write it out to the temporary break file */
- fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL),
- SQLITE_DEFAULT_FILE_PERMISSIONS);
+ fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL), 0);
if( fd<0 ){
sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
goto end_breaklock;
@@ -30785,8 +31353,7 @@ static int proxyTakeConch(unixFile *pFile){
robust_close(pFile, pFile->h, __LINE__);
}
pFile->h = -1;
- fd = robust_open(pCtx->dbPath, pFile->openFlags,
- SQLITE_DEFAULT_FILE_PERMISSIONS);
+ fd = robust_open(pCtx->dbPath, pFile->openFlags, 0);
OSTRACE(("TRANSPROXY: OPEN %d\n", fd));
if( fd>=0 ){
pFile->h = fd;
@@ -31355,7 +31922,7 @@ SQLITE_API int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==18 );
+ assert( ArraySize(aSyscall)==22 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
@@ -31391,51 +31958,15 @@ SQLITE_API int sqlite3_os_end(void){
**
******************************************************************************
**
-** This file contains code that is specific to windows.
-*/
-#if SQLITE_OS_WIN /* This file is used for windows only */
-
-
-/*
-** A Note About Memory Allocation:
-**
-** This driver uses malloc()/free() directly rather than going through
-** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers
-** are designed for use on embedded systems where memory is scarce and
-** malloc failures happen frequently. Win32 does not typically run on
-** embedded systems, and when it does the developers normally have bigger
-** problems to worry about than running out of memory. So there is not
-** a compelling need to use the wrappers.
-**
-** But there is a good reason to not use the wrappers. If we use the
-** wrappers then we will get simulated malloc() failures within this
-** driver. And that causes all kinds of problems for our tests. We
-** could enhance SQLite to deal with simulated malloc failures within
-** the OS driver, but the code to deal with those failure would not
-** be exercised on Linux (which does not need to malloc() in the driver)
-** and so we would have difficulty writing coverage tests for that
-** code. Better to leave the code out, we think.
-**
-** The point of this discussion is as follows: When creating a new
-** OS layer for an embedded system, if you use this file as an example,
-** avoid the use of malloc()/free(). Those routines work ok on windows
-** desktops but not so well in embedded systems.
+** This file contains code that is specific to Windows.
*/
-
-#include <winbase.h>
+#if SQLITE_OS_WIN /* This file is used for Windows only */
#ifdef __CYGWIN__
# include <sys/cygwin.h>
#endif
/*
-** Macros used to determine whether or not to use threads.
-*/
-#if defined(THREADSAFE) && THREADSAFE
-# define SQLITE_W32_THREADS 1
-#endif
-
-/*
** Include code that is common to all os_*.c files
*/
/************** Include os_common.h in the middle of os_win.c ****************/
@@ -31649,21 +32180,12 @@ SQLITE_API int sqlite3_open_file_count = 0;
/************** Continuing where we left off in os_win.c *********************/
/*
-** Some microsoft compilers lack this definition.
+** Some Microsoft compilers lack this definition.
*/
#ifndef INVALID_FILE_ATTRIBUTES
# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
-/*
-** Determine if we are dealing with WindowsCE - which has a much
-** reduced API.
-*/
-#if SQLITE_OS_WINCE
-# define AreFileApisANSI() 1
-# define FormatMessageW(a,b,c,d,e,f,g) 0
-#endif
-
/* Forward references */
typedef struct winShm winShm; /* A connection to shared-memory */
typedef struct winShmNode winShmNode; /* A region of shared-memory */
@@ -31692,14 +32214,13 @@ struct winFile {
HANDLE h; /* Handle for accessing the file */
u8 locktype; /* Type of lock currently held on this file */
short sharedLockByte; /* Randomly chosen byte used as a shared lock */
- u8 bPersistWal; /* True to persist WAL files */
+ u8 ctrlFlags; /* Flags. See WINFILE_* below */
DWORD lastErrno; /* The Windows errno from the last I/O error */
- DWORD sectorSize; /* Sector size of the device file is on */
winShm *pShm; /* Instance of shared memory on this file */
const char *zPath; /* Full pathname of this file */
int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
#if SQLITE_OS_WINCE
- WCHAR *zDeleteOnClose; /* Name of file to delete when closing */
+ LPWSTR zDeleteOnClose; /* Name of file to delete when closing */
HANDLE hMutex; /* Mutex used to control access to shared lock */
HANDLE hShared; /* Shared memory segment used for locking */
winceLock local; /* Locks obtained by this instance of winFile */
@@ -31708,6 +32229,12 @@ struct winFile {
};
/*
+** Allowed values for winFile.ctrlFlags
+*/
+#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
+#define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
+
+/*
* If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
* various Win32 API heap functions instead of our own.
*/
@@ -31779,20 +32306,12 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void);
#endif /* SQLITE_WIN32_MALLOC */
/*
-** Forward prototypes.
-*/
-static int getSectorSize(
- sqlite3_vfs *pVfs,
- const char *zRelative /* UTF-8 file name */
-);
-
-/*
** The following variable is (normally) set once and never changes
-** thereafter. It records whether the operating system is Win95
+** thereafter. It records whether the operating system is Win9x
** or WinNT.
**
** 0: Operating system unknown.
-** 1: Operating system is Win95.
+** 1: Operating system is Win9x.
** 2: Operating system is WinNT.
**
** In order to facilitate testing on a WinNT system, the test fixture
@@ -31805,6 +32324,536 @@ static int sqlite3_os_type = 0;
#endif
/*
+** Many system calls are accessed through pointer-to-functions so that
+** they may be overridden at runtime to facilitate fault injection during
+** testing and sandboxing. The following array holds the names and pointers
+** to all overrideable system calls.
+*/
+#if !SQLITE_OS_WINCE
+# define SQLITE_WIN32_HAS_ANSI
+#endif
+
+#if SQLITE_OS_WINCE || SQLITE_OS_WINNT
+# define SQLITE_WIN32_HAS_WIDE
+#endif
+
+#ifndef SYSCALL
+# define SYSCALL sqlite3_syscall_ptr
+#endif
+
+#if SQLITE_OS_WINCE
+/*
+** These macros are necessary because Windows CE does not natively support the
+** Win32 APIs LockFile, UnlockFile, and LockFileEx.
+ */
+
+# define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e)
+# define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e)
+# define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f)
+
+/*
+** These are the special syscall hacks for Windows CE. The locking related
+** defines here refer to the macros defined just above.
+ */
+
+# define osAreFileApisANSI() 1
+# define osLockFile LockFile
+# define osUnlockFile UnlockFile
+# define osLockFileEx LockFileEx
+#endif
+
+static struct win_syscall {
+ const char *zName; /* Name of the sytem call */
+ sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
+ sqlite3_syscall_ptr pDefault; /* Default value */
+} aSyscall[] = {
+#if !SQLITE_OS_WINCE
+ { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 },
+
+#define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent)
+#else
+ { "AreFileApisANSI", (SYSCALL)0, 0 },
+#endif
+
+#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
+ { "CharLowerW", (SYSCALL)CharLowerW, 0 },
+#else
+ { "CharLowerW", (SYSCALL)0, 0 },
+#endif
+
+#define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent)
+
+#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
+ { "CharUpperW", (SYSCALL)CharUpperW, 0 },
+#else
+ { "CharUpperW", (SYSCALL)0, 0 },
+#endif
+
+#define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent)
+
+ { "CloseHandle", (SYSCALL)CloseHandle, 0 },
+
+#define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_ANSI)
+ { "CreateFileA", (SYSCALL)CreateFileA, 0 },
+#else
+ { "CreateFileA", (SYSCALL)0, 0 },
+#endif
+
+#define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \
+ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+ { "CreateFileW", (SYSCALL)CreateFileW, 0 },
+#else
+ { "CreateFileW", (SYSCALL)0, 0 },
+#endif
+
+#define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \
+ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
+
+ { "CreateFileMapping", (SYSCALL)CreateFileMapping, 0 },
+
+#define osCreateFileMapping ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
+ DWORD,DWORD,DWORD,LPCTSTR))aSyscall[6].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+ { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 },
+#else
+ { "CreateFileMappingW", (SYSCALL)0, 0 },
+#endif
+
+#define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
+ DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+ { "CreateMutexW", (SYSCALL)CreateMutexW, 0 },
+#else
+ { "CreateMutexW", (SYSCALL)0, 0 },
+#endif
+
+#define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \
+ LPCWSTR))aSyscall[8].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_ANSI)
+ { "DeleteFileA", (SYSCALL)DeleteFileA, 0 },
+#else
+ { "DeleteFileA", (SYSCALL)0, 0 },
+#endif
+
+#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+ { "DeleteFileW", (SYSCALL)DeleteFileW, 0 },
+#else
+ { "DeleteFileW", (SYSCALL)0, 0 },
+#endif
+
+#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent)
+
+#if SQLITE_OS_WINCE
+ { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 },
+#else
+ { "FileTimeToLocalFileTime", (SYSCALL)0, 0 },
+#endif
+
+#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
+ LPFILETIME))aSyscall[11].pCurrent)
+
+#if SQLITE_OS_WINCE
+ { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 },
+#else
+ { "FileTimeToSystemTime", (SYSCALL)0, 0 },
+#endif
+
+#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
+ LPSYSTEMTIME))aSyscall[12].pCurrent)
+
+ { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 },
+
+#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_ANSI)
+ { "FormatMessageA", (SYSCALL)FormatMessageA, 0 },
+#else
+ { "FormatMessageA", (SYSCALL)0, 0 },
+#endif
+
+#define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \
+ DWORD,va_list*))aSyscall[14].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+ { "FormatMessageW", (SYSCALL)FormatMessageW, 0 },
+#else
+ { "FormatMessageW", (SYSCALL)0, 0 },
+#endif
+
+#define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
+ DWORD,va_list*))aSyscall[15].pCurrent)
+
+ { "FreeLibrary", (SYSCALL)FreeLibrary, 0 },
+
+#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
+
+ { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 },
+
+#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent)
+
+#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
+ { "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 },
+#else
+ { "GetDiskFreeSpaceA", (SYSCALL)0, 0 },
+#endif
+
+#define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \
+ LPDWORD))aSyscall[18].pCurrent)
+
+#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
+ { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 },
+#else
+ { "GetDiskFreeSpaceW", (SYSCALL)0, 0 },
+#endif
+
+#define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \
+ LPDWORD))aSyscall[19].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_ANSI)
+ { "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 },
+#else
+ { "GetFileAttributesA", (SYSCALL)0, 0 },
+#endif
+
+#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+ { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 },
+#else
+ { "GetFileAttributesW", (SYSCALL)0, 0 },
+#endif
+
+#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+ { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 },
+#else
+ { "GetFileAttributesExW", (SYSCALL)0, 0 },
+#endif
+
+#define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \
+ LPVOID))aSyscall[22].pCurrent)
+
+ { "GetFileSize", (SYSCALL)GetFileSize, 0 },
+
+#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent)
+
+#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
+ { "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 },
+#else
+ { "GetFullPathNameA", (SYSCALL)0, 0 },
+#endif
+
+#define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \
+ LPSTR*))aSyscall[24].pCurrent)
+
+#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
+ { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 },
+#else
+ { "GetFullPathNameW", (SYSCALL)0, 0 },
+#endif
+
+#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
+ LPWSTR*))aSyscall[25].pCurrent)
+
+ { "GetLastError", (SYSCALL)GetLastError, 0 },
+
+#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
+
+#if SQLITE_OS_WINCE
+ /* The GetProcAddressA() routine is only available on Windows CE. */
+ { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 },
+#else
+ /* All other Windows platforms expect GetProcAddress() to take
+ ** an ANSI string regardless of the _UNICODE setting */
+ { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 },
+#endif
+
+#define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \
+ LPCSTR))aSyscall[27].pCurrent)
+
+ { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 },
+
+#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent)
+
+ { "GetSystemTime", (SYSCALL)GetSystemTime, 0 },
+
+#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent)
+
+#if !SQLITE_OS_WINCE
+ { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 },
+#else
+ { "GetSystemTimeAsFileTime", (SYSCALL)0, 0 },
+#endif
+
+#define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \
+ LPFILETIME))aSyscall[30].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_ANSI)
+ { "GetTempPathA", (SYSCALL)GetTempPathA, 0 },
+#else
+ { "GetTempPathA", (SYSCALL)0, 0 },
+#endif
+
+#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+ { "GetTempPathW", (SYSCALL)GetTempPathW, 0 },
+#else
+ { "GetTempPathW", (SYSCALL)0, 0 },
+#endif
+
+#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent)
+
+ { "GetTickCount", (SYSCALL)GetTickCount, 0 },
+
+#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_ANSI)
+ { "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
+#else
+ { "GetVersionExA", (SYSCALL)0, 0 },
+#endif
+
+#define osGetVersionExA ((BOOL(WINAPI*)( \
+ LPOSVERSIONINFOA))aSyscall[34].pCurrent)
+
+ { "HeapAlloc", (SYSCALL)HeapAlloc, 0 },
+
+#define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \
+ SIZE_T))aSyscall[35].pCurrent)
+
+ { "HeapCreate", (SYSCALL)HeapCreate, 0 },
+
+#define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \
+ SIZE_T))aSyscall[36].pCurrent)
+
+ { "HeapDestroy", (SYSCALL)HeapDestroy, 0 },
+
+#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[37].pCurrent)
+
+ { "HeapFree", (SYSCALL)HeapFree, 0 },
+
+#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[38].pCurrent)
+
+ { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 },
+
+#define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \
+ SIZE_T))aSyscall[39].pCurrent)
+
+ { "HeapSize", (SYSCALL)HeapSize, 0 },
+
+#define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \
+ LPCVOID))aSyscall[40].pCurrent)
+
+ { "HeapValidate", (SYSCALL)HeapValidate, 0 },
+
+#define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
+ LPCVOID))aSyscall[41].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_ANSI)
+ { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 },
+#else
+ { "LoadLibraryA", (SYSCALL)0, 0 },
+#endif
+
+#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+ { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 },
+#else
+ { "LoadLibraryW", (SYSCALL)0, 0 },
+#endif
+
+#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[43].pCurrent)
+
+ { "LocalFree", (SYSCALL)LocalFree, 0 },
+
+#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[44].pCurrent)
+
+#if !SQLITE_OS_WINCE
+ { "LockFile", (SYSCALL)LockFile, 0 },
+
+#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+ DWORD))aSyscall[45].pCurrent)
+#else
+ { "LockFile", (SYSCALL)0, 0 },
+#endif
+
+#if !SQLITE_OS_WINCE
+ { "LockFileEx", (SYSCALL)LockFileEx, 0 },
+
+#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \
+ LPOVERLAPPED))aSyscall[46].pCurrent)
+#else
+ { "LockFileEx", (SYSCALL)0, 0 },
+#endif
+
+ { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 },
+
+#define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+ SIZE_T))aSyscall[47].pCurrent)
+
+ { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 },
+
+#define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \
+ int))aSyscall[48].pCurrent)
+
+ { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 },
+
+#define osQueryPerformanceCounter ((BOOL(WINAPI*)( \
+ LARGE_INTEGER*))aSyscall[49].pCurrent)
+
+ { "ReadFile", (SYSCALL)ReadFile, 0 },
+
+#define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \
+ LPOVERLAPPED))aSyscall[50].pCurrent)
+
+ { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 },
+
+#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[51].pCurrent)
+
+ { "SetFilePointer", (SYSCALL)SetFilePointer, 0 },
+
+#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \
+ DWORD))aSyscall[52].pCurrent)
+
+ { "Sleep", (SYSCALL)Sleep, 0 },
+
+#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[53].pCurrent)
+
+ { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
+
+#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
+ LPFILETIME))aSyscall[54].pCurrent)
+
+#if !SQLITE_OS_WINCE
+ { "UnlockFile", (SYSCALL)UnlockFile, 0 },
+
+#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+ DWORD))aSyscall[55].pCurrent)
+#else
+ { "UnlockFile", (SYSCALL)0, 0 },
+#endif
+
+#if !SQLITE_OS_WINCE
+ { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 },
+
+#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+ LPOVERLAPPED))aSyscall[56].pCurrent)
+#else
+ { "UnlockFileEx", (SYSCALL)0, 0 },
+#endif
+
+ { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
+
+#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[57].pCurrent)
+
+ { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 },
+
+#define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \
+ LPCSTR,LPBOOL))aSyscall[58].pCurrent)
+
+ { "WriteFile", (SYSCALL)WriteFile, 0 },
+
+#define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \
+ LPOVERLAPPED))aSyscall[59].pCurrent)
+
+}; /* End of the overrideable system calls */
+
+/*
+** This is the xSetSystemCall() method of sqlite3_vfs for all of the
+** "win32" VFSes. Return SQLITE_OK opon successfully updating the
+** system call pointer, or SQLITE_NOTFOUND if there is no configurable
+** system call named zName.
+*/
+static int winSetSystemCall(
+ sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */
+ const char *zName, /* Name of system call to override */
+ sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */
+){
+ unsigned int i;
+ int rc = SQLITE_NOTFOUND;
+
+ UNUSED_PARAMETER(pNotUsed);
+ if( zName==0 ){
+ /* If no zName is given, restore all system calls to their default
+ ** settings and return NULL
+ */
+ rc = SQLITE_OK;
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
+ if( aSyscall[i].pDefault ){
+ aSyscall[i].pCurrent = aSyscall[i].pDefault;
+ }
+ }
+ }else{
+ /* If zName is specified, operate on only the one system call
+ ** specified.
+ */
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
+ if( strcmp(zName, aSyscall[i].zName)==0 ){
+ if( aSyscall[i].pDefault==0 ){
+ aSyscall[i].pDefault = aSyscall[i].pCurrent;
+ }
+ rc = SQLITE_OK;
+ if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault;
+ aSyscall[i].pCurrent = pNewFunc;
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+** Return the value of a system call. Return NULL if zName is not a
+** recognized system call name. NULL is also returned if the system call
+** is currently undefined.
+*/
+static sqlite3_syscall_ptr winGetSystemCall(
+ sqlite3_vfs *pNotUsed,
+ const char *zName
+){
+ unsigned int i;
+
+ UNUSED_PARAMETER(pNotUsed);
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
+ if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
+ }
+ return 0;
+}
+
+/*
+** Return the name of the first system call after zName. If zName==NULL
+** then return the name of the first system call. Return NULL if zName
+** is the last system call or if zName is not the name of a valid
+** system call.
+*/
+static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
+ int i = -1;
+
+ UNUSED_PARAMETER(p);
+ if( zName ){
+ for(i=0; i<ArraySize(aSyscall)-1; i++){
+ if( strcmp(zName, aSyscall[i].zName)==0 ) break;
+ }
+ }
+ for(i++; i<ArraySize(aSyscall); i++){
+ if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
+ }
+ return 0;
+}
+
+/*
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
** or WinCE. Return false (zero) for Win95, Win98, or WinME.
**
@@ -31820,9 +32869,9 @@ static int sqlite3_os_type = 0;
#else
static int isNT(void){
if( sqlite3_os_type==0 ){
- OSVERSIONINFO sInfo;
+ OSVERSIONINFOA sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
- GetVersionEx(&sInfo);
+ osGetVersionExA(&sInfo);
sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
}
return sqlite3_os_type==2;
@@ -31842,13 +32891,13 @@ static void *winMemMalloc(int nBytes){
assert( hHeap!=0 );
assert( hHeap!=INVALID_HANDLE_VALUE );
#ifdef SQLITE_WIN32_MALLOC_VALIDATE
- assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
+ assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
#endif
assert( nBytes>=0 );
- p = HeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
+ p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
if( !p ){
sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%d), heap=%p",
- nBytes, GetLastError(), (void*)hHeap);
+ nBytes, osGetLastError(), (void*)hHeap);
}
return p;
}
@@ -31864,12 +32913,12 @@ static void winMemFree(void *pPrior){
assert( hHeap!=0 );
assert( hHeap!=INVALID_HANDLE_VALUE );
#ifdef SQLITE_WIN32_MALLOC_VALIDATE
- assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
+ assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
#endif
if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */
- if( !HeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){
+ if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){
sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%d), heap=%p",
- pPrior, GetLastError(), (void*)hHeap);
+ pPrior, osGetLastError(), (void*)hHeap);
}
}
@@ -31885,18 +32934,18 @@ static void *winMemRealloc(void *pPrior, int nBytes){
assert( hHeap!=0 );
assert( hHeap!=INVALID_HANDLE_VALUE );
#ifdef SQLITE_WIN32_MALLOC_VALIDATE
- assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
+ assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
#endif
assert( nBytes>=0 );
if( !pPrior ){
- p = HeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
+ p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
}else{
- p = HeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes);
+ p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes);
}
if( !p ){
sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%d), heap=%p",
- pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, GetLastError(),
- (void*)hHeap);
+ pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(),
+ (void*)hHeap);
}
return p;
}
@@ -31913,13 +32962,13 @@ static int winMemSize(void *p){
assert( hHeap!=0 );
assert( hHeap!=INVALID_HANDLE_VALUE );
#ifdef SQLITE_WIN32_MALLOC_VALIDATE
- assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
+ assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
#endif
if( !p ) return 0;
- n = HeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p);
+ n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p);
if( n==(SIZE_T)-1 ){
sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%d), heap=%p",
- p, GetLastError(), (void*)hHeap);
+ p, osGetLastError(), (void*)hHeap);
return 0;
}
return (int)n;
@@ -31941,14 +32990,14 @@ static int winMemInit(void *pAppData){
if( !pWinMemData ) return SQLITE_ERROR;
assert( pWinMemData->magic==WINMEM_MAGIC );
if( !pWinMemData->hHeap ){
- pWinMemData->hHeap = HeapCreate(SQLITE_WIN32_HEAP_FLAGS,
- SQLITE_WIN32_HEAP_INIT_SIZE,
- SQLITE_WIN32_HEAP_MAX_SIZE);
+ pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS,
+ SQLITE_WIN32_HEAP_INIT_SIZE,
+ SQLITE_WIN32_HEAP_MAX_SIZE);
if( !pWinMemData->hHeap ){
sqlite3_log(SQLITE_NOMEM,
"failed to HeapCreate (%d), flags=%u, initSize=%u, maxSize=%u",
- GetLastError(), SQLITE_WIN32_HEAP_FLAGS, SQLITE_WIN32_HEAP_INIT_SIZE,
- SQLITE_WIN32_HEAP_MAX_SIZE);
+ osGetLastError(), SQLITE_WIN32_HEAP_FLAGS,
+ SQLITE_WIN32_HEAP_INIT_SIZE, SQLITE_WIN32_HEAP_MAX_SIZE);
return SQLITE_NOMEM;
}
pWinMemData->bOwned = TRUE;
@@ -31956,7 +33005,7 @@ static int winMemInit(void *pAppData){
assert( pWinMemData->hHeap!=0 );
assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
#ifdef SQLITE_WIN32_MALLOC_VALIDATE
- assert( HeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
+ assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
#endif
return SQLITE_OK;
}
@@ -31971,12 +33020,12 @@ static void winMemShutdown(void *pAppData){
if( pWinMemData->hHeap ){
assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
#ifdef SQLITE_WIN32_MALLOC_VALIDATE
- assert( HeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
+ assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
#endif
if( pWinMemData->bOwned ){
- if( !HeapDestroy(pWinMemData->hHeap) ){
+ if( !osHeapDestroy(pWinMemData->hHeap) ){
sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%d), heap=%p",
- GetLastError(), (void*)pWinMemData->hHeap);
+ osGetLastError(), (void*)pWinMemData->hHeap);
}
pWinMemData->bOwned = FALSE;
}
@@ -32012,95 +33061,110 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
#endif /* SQLITE_WIN32_MALLOC */
/*
-** Convert a UTF-8 string to microsoft unicode (UTF-16?).
+** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
**
** Space to hold the returned string is obtained from malloc.
*/
-static WCHAR *utf8ToUnicode(const char *zFilename){
+static LPWSTR utf8ToUnicode(const char *zFilename){
int nChar;
- WCHAR *zWideFilename;
+ LPWSTR zWideFilename;
- nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
- zWideFilename = malloc( nChar*sizeof(zWideFilename[0]) );
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
+ if( nChar==0 ){
+ return 0;
+ }
+ zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
return 0;
}
- nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
+ nChar);
if( nChar==0 ){
- free(zWideFilename);
+ sqlite3_free(zWideFilename);
zWideFilename = 0;
}
return zWideFilename;
}
/*
-** Convert microsoft unicode to UTF-8. Space to hold the returned string is
-** obtained from malloc().
+** Convert Microsoft Unicode to UTF-8. Space to hold the returned string is
+** obtained from sqlite3_malloc().
*/
-static char *unicodeToUtf8(const WCHAR *zWideFilename){
+static char *unicodeToUtf8(LPCWSTR zWideFilename){
int nByte;
char *zFilename;
- nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
- zFilename = malloc( nByte );
+ nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
+ if( nByte == 0 ){
+ return 0;
+ }
+ zFilename = sqlite3_malloc( nByte );
if( zFilename==0 ){
return 0;
}
- nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
- 0, 0);
+ nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
+ 0, 0);
if( nByte == 0 ){
- free(zFilename);
+ sqlite3_free(zFilename);
zFilename = 0;
}
return zFilename;
}
/*
-** Convert an ansi string to microsoft unicode, based on the
+** Convert an ANSI string to Microsoft Unicode, based on the
** current codepage settings for file apis.
**
** Space to hold the returned string is obtained
-** from malloc.
+** from sqlite3_malloc.
*/
-static WCHAR *mbcsToUnicode(const char *zFilename){
+static LPWSTR mbcsToUnicode(const char *zFilename){
int nByte;
- WCHAR *zMbcsFilename;
- int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+ LPWSTR zMbcsFilename;
+ int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
- nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*sizeof(WCHAR);
- zMbcsFilename = malloc( nByte*sizeof(zMbcsFilename[0]) );
+ nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL,
+ 0)*sizeof(WCHAR);
+ if( nByte==0 ){
+ return 0;
+ }
+ zMbcsFilename = sqlite3_malloc( nByte*sizeof(zMbcsFilename[0]) );
if( zMbcsFilename==0 ){
return 0;
}
- nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte);
+ nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename,
+ nByte);
if( nByte==0 ){
- free(zMbcsFilename);
+ sqlite3_free(zMbcsFilename);
zMbcsFilename = 0;
}
return zMbcsFilename;
}
/*
-** Convert microsoft unicode to multibyte character string, based on the
-** user's Ansi codepage.
+** Convert Microsoft Unicode to multi-byte character string, based on the
+** user's ANSI codepage.
**
** Space to hold the returned string is obtained from
-** malloc().
+** sqlite3_malloc().
*/
-static char *unicodeToMbcs(const WCHAR *zWideFilename){
+static char *unicodeToMbcs(LPCWSTR zWideFilename){
int nByte;
char *zFilename;
- int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+ int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
- nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
- zFilename = malloc( nByte );
+ nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
+ if( nByte == 0 ){
+ return 0;
+ }
+ zFilename = sqlite3_malloc( nByte );
if( zFilename==0 ){
return 0;
}
- nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte,
- 0, 0);
+ nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename,
+ nByte, 0, 0);
if( nByte == 0 ){
- free(zFilename);
+ sqlite3_free(zFilename);
zFilename = 0;
}
return zFilename;
@@ -32108,35 +33172,35 @@ static char *unicodeToMbcs(const WCHAR *zWideFilename){
/*
** Convert multibyte character string to UTF-8. Space to hold the
-** returned string is obtained from malloc().
+** returned string is obtained from sqlite3_malloc().
*/
SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
char *zFilenameUtf8;
- WCHAR *zTmpWide;
+ LPWSTR zTmpWide;
zTmpWide = mbcsToUnicode(zFilename);
if( zTmpWide==0 ){
return 0;
}
zFilenameUtf8 = unicodeToUtf8(zTmpWide);
- free(zTmpWide);
+ sqlite3_free(zTmpWide);
return zFilenameUtf8;
}
/*
** Convert UTF-8 to multibyte character string. Space to hold the
-** returned string is obtained from malloc().
+** returned string is obtained from sqlite3_malloc().
*/
SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
char *zFilenameMbcs;
- WCHAR *zTmpWide;
+ LPWSTR zTmpWide;
zTmpWide = utf8ToUnicode(zFilename);
if( zTmpWide==0 ){
return 0;
}
zFilenameMbcs = unicodeToMbcs(zTmpWide);
- free(zTmpWide);
+ sqlite3_free(zTmpWide);
return zFilenameMbcs;
}
@@ -32146,59 +33210,66 @@ SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
** is zero if the error message fits in the buffer, or non-zero
** otherwise (if the message was truncated).
*/
-static int getLastErrorMsg(int nBuf, char *zBuf){
+static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
/* FormatMessage returns 0 on failure. Otherwise it
** returns the number of TCHARs written to the output
** buffer, excluding the terminating null char.
*/
- DWORD error = GetLastError();
DWORD dwLen = 0;
char *zOut = 0;
if( isNT() ){
- WCHAR *zTempWide = NULL;
- dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- error,
- 0,
- (LPWSTR) &zTempWide,
- 0,
- 0);
+ LPWSTR zTempWide = NULL;
+ dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ lastErrno,
+ 0,
+ (LPWSTR) &zTempWide,
+ 0,
+ 0);
if( dwLen > 0 ){
/* allocate a buffer and convert to UTF8 */
+ sqlite3BeginBenignMalloc();
zOut = unicodeToUtf8(zTempWide);
+ sqlite3EndBenignMalloc();
/* free the system buffer allocated by FormatMessage */
- LocalFree(zTempWide);
+ osLocalFree(zTempWide);
}
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
-** Since the ASCII version of these Windows API do not exist for WINCE,
+** Since the ANSI version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
}else{
char *zTemp = NULL;
- dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- error,
- 0,
- (LPSTR) &zTemp,
- 0,
- 0);
+ dwLen = osFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ lastErrno,
+ 0,
+ (LPSTR) &zTemp,
+ 0,
+ 0);
if( dwLen > 0 ){
/* allocate a buffer and convert to UTF8 */
+ sqlite3BeginBenignMalloc();
zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
+ sqlite3EndBenignMalloc();
/* free the system buffer allocated by FormatMessage */
- LocalFree(zTemp);
+ osLocalFree(zTemp);
}
#endif
}
if( 0 == dwLen ){
- sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
+ sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", lastErrno, lastErrno);
}else{
/* copy a maximum of nBuf chars to output buffer */
sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
/* free the UTF8 buffer */
- free(zOut);
+ sqlite3_free(zOut);
}
return 0;
}
@@ -32218,26 +33289,26 @@ static int getLastErrorMsg(int nBuf, char *zBuf){
** The two subsequent arguments should be the name of the OS function that
** failed and the the associated file-system path, if any.
*/
-#define winLogError(a,b,c) winLogErrorAtLine(a,b,c,__LINE__)
+#define winLogError(a,b,c,d) winLogErrorAtLine(a,b,c,d,__LINE__)
static int winLogErrorAtLine(
int errcode, /* SQLite error code */
+ DWORD lastErrno, /* Win32 last error */
const char *zFunc, /* Name of OS function that failed */
const char *zPath, /* File path associated with error */
int iLine /* Source line number where error occurred */
){
char zMsg[500]; /* Human readable error text */
int i; /* Loop counter */
- DWORD iErrno = GetLastError(); /* Error code */
zMsg[0] = 0;
- getLastErrorMsg(sizeof(zMsg), zMsg);
+ getLastErrorMsg(lastErrno, sizeof(zMsg), zMsg);
assert( errcode!=SQLITE_OK );
if( zPath==0 ) zPath = "";
for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
zMsg[i] = 0;
sqlite3_log(errcode,
"os_win.c:%d: (%d) %s(%s) - %s",
- iLine, iErrno, zFunc, zPath, zMsg
+ iLine, lastErrno, zFunc, zPath, zMsg
);
return errcode;
@@ -32263,19 +33334,24 @@ static int win32IoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
** to see if it should be retried. Return TRUE to retry. Return FALSE
** to give up with an error.
*/
-static int retryIoerr(int *pnRetry){
- DWORD e;
+static int retryIoerr(int *pnRetry, DWORD *pError){
+ DWORD e = osGetLastError();
if( *pnRetry>=win32IoerrRetry ){
+ if( pError ){
+ *pError = e;
+ }
return 0;
}
- e = GetLastError();
if( e==ERROR_ACCESS_DENIED ||
e==ERROR_LOCK_VIOLATION ||
e==ERROR_SHARING_VIOLATION ){
- Sleep(win32IoerrRetryDelay*(1+*pnRetry));
+ osSleep(win32IoerrRetryDelay*(1+*pnRetry));
++*pnRetry;
return 1;
}
+ if( pError ){
+ *pError = e;
+ }
return 0;
}
@@ -32296,7 +33372,7 @@ static void logIoerr(int nRetry){
** This section contains code for WinCE only.
*/
/*
-** WindowsCE does not have a localtime() function. So create a
+** Windows CE does not have a localtime() function. So create a
** substitute.
*/
/* #include <time.h> */
@@ -32310,8 +33386,8 @@ struct tm *__cdecl localtime(const time_t *t)
t64 = (t64 + 11644473600)*10000000;
uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
uTm.dwHighDateTime= (DWORD)(t64 >> 32);
- FileTimeToLocalFileTime(&uTm,&lTm);
- FileTimeToSystemTime(&lTm,&pTm);
+ osFileTimeToLocalFileTime(&uTm,&lTm);
+ osFileTimeToSystemTime(&lTm,&pTm);
y.tm_year = pTm.wYear - 1900;
y.tm_mon = pTm.wMonth - 1;
y.tm_wday = pTm.wDayOfWeek;
@@ -32322,13 +33398,6 @@ struct tm *__cdecl localtime(const time_t *t)
return &y;
}
-/* This will never be called, but defined to make the code compile */
-#define GetTempPathA(a,b)
-
-#define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e)
-#define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e)
-#define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f)
-
#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
/*
@@ -32350,26 +33419,32 @@ static void winceMutexAcquire(HANDLE h){
** descriptor pFile
*/
static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
- WCHAR *zTok;
- WCHAR *zName = utf8ToUnicode(zFilename);
+ LPWSTR zTok;
+ LPWSTR zName;
BOOL bInit = TRUE;
+ zName = utf8ToUnicode(zFilename);
+ if( zName==0 ){
+ /* out of memory */
+ return FALSE;
+ }
+
/* Initialize the local lockdata */
- ZeroMemory(&pFile->local, sizeof(pFile->local));
+ memset(&pFile->local, 0, sizeof(pFile->local));
/* Replace the backslashes from the filename and lowercase it
** to derive a mutex name. */
- zTok = CharLowerW(zName);
+ zTok = osCharLowerW(zName);
for (;*zTok;zTok++){
if (*zTok == '\\') *zTok = '_';
}
/* Create/open the named mutex */
- pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
+ pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
if (!pFile->hMutex){
- pFile->lastErrno = GetLastError();
- winLogError(SQLITE_ERROR, "winceCreateLock1", zFilename);
- free(zName);
+ pFile->lastErrno = osGetLastError();
+ winLogError(SQLITE_ERROR, pFile->lastErrno, "winceCreateLock1", zFilename);
+ sqlite3_free(zName);
return FALSE;
}
@@ -32380,28 +33455,29 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
** case-sensitive, take advantage of that by uppercasing the mutex name
** and using that as the shared filemapping name.
*/
- CharUpperW(zName);
- pFile->hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
- PAGE_READWRITE, 0, sizeof(winceLock),
- zName);
+ osCharUpperW(zName);
+ pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
+ PAGE_READWRITE, 0, sizeof(winceLock),
+ zName);
/* Set a flag that indicates we're the first to create the memory so it
** must be zero-initialized */
- if (GetLastError() == ERROR_ALREADY_EXISTS){
+ if (osGetLastError() == ERROR_ALREADY_EXISTS){
bInit = FALSE;
}
- free(zName);
+ sqlite3_free(zName);
/* If we succeeded in making the shared memory handle, map it. */
if (pFile->hShared){
- pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared,
+ pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
/* If mapping failed, close the shared memory handle and erase it */
if (!pFile->shared){
- pFile->lastErrno = GetLastError();
- winLogError(SQLITE_ERROR, "winceCreateLock2", zFilename);
- CloseHandle(pFile->hShared);
+ pFile->lastErrno = osGetLastError();
+ winLogError(SQLITE_ERROR, pFile->lastErrno,
+ "winceCreateLock2", zFilename);
+ osCloseHandle(pFile->hShared);
pFile->hShared = NULL;
}
}
@@ -32409,14 +33485,14 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
/* If shared memory could not be created, then close the mutex and fail */
if (pFile->hShared == NULL){
winceMutexRelease(pFile->hMutex);
- CloseHandle(pFile->hMutex);
+ osCloseHandle(pFile->hMutex);
pFile->hMutex = NULL;
return FALSE;
}
/* Initialize the shared memory if we're supposed to */
if (bInit) {
- ZeroMemory(pFile->shared, sizeof(winceLock));
+ memset(pFile->shared, 0, sizeof(winceLock));
}
winceMutexRelease(pFile->hMutex);
@@ -32447,18 +33523,18 @@ static void winceDestroyLock(winFile *pFile){
}
/* De-reference and close our copy of the shared memory handle */
- UnmapViewOfFile(pFile->shared);
- CloseHandle(pFile->hShared);
+ osUnmapViewOfFile(pFile->shared);
+ osCloseHandle(pFile->hShared);
/* Done with the mutex */
winceMutexRelease(pFile->hMutex);
- CloseHandle(pFile->hMutex);
+ osCloseHandle(pFile->hMutex);
pFile->hMutex = NULL;
}
}
/*
-** An implementation of the LockFile() API of windows for wince
+** An implementation of the LockFile() API of Windows for CE
*/
static BOOL winceLockFile(
HANDLE *phFile,
@@ -32522,7 +33598,7 @@ static BOOL winceLockFile(
}
/*
-** An implementation of the UnlockFile API of windows for wince
+** An implementation of the UnlockFile API of Windows for CE
*/
static BOOL winceUnlockFile(
HANDLE *phFile,
@@ -32584,7 +33660,7 @@ static BOOL winceUnlockFile(
}
/*
-** An implementation of the LockFileEx() API of windows for wince
+** An implementation of the LockFileEx() API of Windows for CE
*/
static BOOL winceLockFileEx(
HANDLE *phFile,
@@ -32617,7 +33693,7 @@ static BOOL winceLockFileEx(
******************************************************************************/
/*
-** Some microsoft compilers lack this definition.
+** Some Microsoft compilers lack this definition.
*/
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
@@ -32632,6 +33708,7 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
LONG upperBits; /* Most sig. 32 bits of new offset */
LONG lowerBits; /* Least sig. 32 bits of new offset */
DWORD dwRet; /* Value returned by SetFilePointer() */
+ DWORD lastErrno; /* Value returned by GetLastError() */
upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
lowerBits = (LONG)(iOffset & 0xffffffff);
@@ -32643,10 +33720,13 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
** whether an error has actually occured, it is also necessary to call
** GetLastError().
*/
- dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
- if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){
- pFile->lastErrno = GetLastError();
- winLogError(SQLITE_IOERR_SEEK, "seekWinFile", pFile->zPath);
+ dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
+
+ if( (dwRet==INVALID_SET_FILE_POINTER
+ && ((lastErrno = osGetLastError())!=NO_ERROR)) ){
+ pFile->lastErrno = lastErrno;
+ winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
+ "seekWinFile", pFile->zPath);
return 1;
}
@@ -32657,7 +33737,7 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
** Close a file.
**
** It is reported that an attempt to close a handle might sometimes
-** fail. This is a very unreasonable result, but windows is notorious
+** fail. This is a very unreasonable result, but Windows is notorious
** for being unreasonable so I do not doubt that it might happen. If
** the close fails, we pause for 100 milliseconds and try again. As
** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
@@ -32672,28 +33752,32 @@ static int winClose(sqlite3_file *id){
assert( pFile->pShm==0 );
OSTRACE(("CLOSE %d\n", pFile->h));
do{
- rc = CloseHandle(pFile->h);
+ rc = osCloseHandle(pFile->h);
/* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
- }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
+ }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (osSleep(100), 1) );
#if SQLITE_OS_WINCE
#define WINCE_DELETION_ATTEMPTS 3
winceDestroyLock(pFile);
if( pFile->zDeleteOnClose ){
int cnt = 0;
while(
- DeleteFileW(pFile->zDeleteOnClose)==0
- && GetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
+ osDeleteFileW(pFile->zDeleteOnClose)==0
+ && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
&& cnt++ < WINCE_DELETION_ATTEMPTS
){
- Sleep(100); /* Wait a little before trying again */
+ osSleep(100); /* Wait a little before trying again */
}
- free(pFile->zDeleteOnClose);
+ sqlite3_free(pFile->zDeleteOnClose);
}
#endif
OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
+ if( rc ){
+ pFile->h = NULL;
+ }
OpenCounter(-1);
return rc ? SQLITE_OK
- : winLogError(SQLITE_IOERR_CLOSE, "winClose", pFile->zPath);
+ : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
+ "winClose", pFile->zPath);
}
/*
@@ -32707,6 +33791,9 @@ static int winRead(
int amt, /* Number of bytes to read */
sqlite3_int64 offset /* Begin reading at this offset */
){
+#if !SQLITE_OS_WINCE
+ OVERLAPPED overlapped; /* The offset for ReadFile. */
+#endif
winFile *pFile = (winFile*)id; /* file handle */
DWORD nRead; /* Number of bytes actually read from file */
int nRetry = 0; /* Number of retrys */
@@ -32715,13 +33802,23 @@ static int winRead(
SimulateIOError(return SQLITE_IOERR_READ);
OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
+#if SQLITE_OS_WINCE
if( seekWinFile(pFile, offset) ){
return SQLITE_FULL;
}
- while( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
- if( retryIoerr(&nRetry) ) continue;
- pFile->lastErrno = GetLastError();
- return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath);
+ while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
+#else
+ memset(&overlapped, 0, sizeof(OVERLAPPED));
+ overlapped.Offset = (LONG)(offset & 0xffffffff);
+ overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
+ while( !osReadFile(pFile->h, pBuf, amt, &nRead, &overlapped) &&
+ osGetLastError()!=ERROR_HANDLE_EOF ){
+#endif
+ DWORD lastErrno;
+ if( retryIoerr(&nRetry, &lastErrno) ) continue;
+ pFile->lastErrno = lastErrno;
+ return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
+ "winRead", pFile->zPath);
}
logIoerr(nRetry);
if( nRead<(DWORD)amt ){
@@ -32743,7 +33840,7 @@ static int winWrite(
int amt, /* Number of bytes to write */
sqlite3_int64 offset /* Offset into the file to begin writing at */
){
- int rc; /* True if error has occured, else false */
+ int rc = 0; /* True if error has occured, else false */
winFile *pFile = (winFile*)id; /* File handle */
int nRetry = 0; /* Number of retries */
@@ -32754,23 +33851,49 @@ static int winWrite(
OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
+#if SQLITE_OS_WINCE
rc = seekWinFile(pFile, offset);
if( rc==0 ){
+#else
+ {
+#endif
+#if !SQLITE_OS_WINCE
+ OVERLAPPED overlapped; /* The offset for WriteFile. */
+#endif
u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
int nRem = amt; /* Number of bytes yet to be written */
DWORD nWrite; /* Bytes written by each WriteFile() call */
+ DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
+
+#if !SQLITE_OS_WINCE
+ memset(&overlapped, 0, sizeof(OVERLAPPED));
+ overlapped.Offset = (LONG)(offset & 0xffffffff);
+ overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
+#endif
while( nRem>0 ){
- if( !WriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
- if( retryIoerr(&nRetry) ) continue;
+#if SQLITE_OS_WINCE
+ if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
+#else
+ if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
+#endif
+ if( retryIoerr(&nRetry, &lastErrno) ) continue;
break;
}
- if( nWrite<=0 ) break;
+ if( nWrite<=0 ){
+ lastErrno = osGetLastError();
+ break;
+ }
+#if !SQLITE_OS_WINCE
+ offset += nWrite;
+ overlapped.Offset = (LONG)(offset & 0xffffffff);
+ overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
+#endif
aRem += nWrite;
nRem -= nWrite;
}
if( nRem>0 ){
- pFile->lastErrno = GetLastError();
+ pFile->lastErrno = lastErrno;
rc = 1;
}
}
@@ -32780,7 +33903,8 @@ static int winWrite(
|| ( pFile->lastErrno==ERROR_DISK_FULL )){
return SQLITE_FULL;
}
- return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath);
+ return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
+ "winWrite", pFile->zPath);
}else{
logIoerr(nRetry);
}
@@ -32810,10 +33934,12 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
/* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
if( seekWinFile(pFile, nByte) ){
- rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate1", pFile->zPath);
- }else if( 0==SetEndOfFile(pFile->h) ){
- pFile->lastErrno = GetLastError();
- rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate2", pFile->zPath);
+ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
+ "winTruncate1", pFile->zPath);
+ }else if( 0==osSetEndOfFile(pFile->h) ){
+ pFile->lastErrno = osGetLastError();
+ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
+ "winTruncate2", pFile->zPath);
}
OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
@@ -32878,13 +34004,14 @@ static int winSync(sqlite3_file *id, int flags){
#ifdef SQLITE_NO_SYNC
return SQLITE_OK;
#else
- rc = FlushFileBuffers(pFile->h);
+ rc = osFlushFileBuffers(pFile->h);
SimulateIOError( rc=FALSE );
if( rc ){
return SQLITE_OK;
}else{
- pFile->lastErrno = GetLastError();
- return winLogError(SQLITE_IOERR_FSYNC, "winSync", pFile->zPath);
+ pFile->lastErrno = osGetLastError();
+ return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
+ "winSync", pFile->zPath);
}
#endif
}
@@ -32896,16 +34023,17 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
DWORD upperBits;
DWORD lowerBits;
winFile *pFile = (winFile*)id;
- DWORD error;
+ DWORD lastErrno;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_FSTAT);
- lowerBits = GetFileSize(pFile->h, &upperBits);
+ lowerBits = osGetFileSize(pFile->h, &upperBits);
if( (lowerBits == INVALID_FILE_SIZE)
- && ((error = GetLastError()) != NO_ERROR) )
+ && ((lastErrno = osGetLastError())!=NO_ERROR) )
{
- pFile->lastErrno = error;
- return winLogError(SQLITE_IOERR_FSTAT, "winFileSize", pFile->zPath);
+ pFile->lastErrno = lastErrno;
+ return winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
+ "winFileSize", pFile->zPath);
}
*pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
return SQLITE_OK;
@@ -32921,7 +34049,7 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
/*
** Acquire a reader lock.
** Different API routines are called depending on whether or not this
-** is Win95 or WinNT.
+** is Win9x or WinNT.
*/
static int getReadLock(winFile *pFile){
int res;
@@ -32930,8 +34058,8 @@ static int getReadLock(winFile *pFile){
ovlp.Offset = SHARED_FIRST;
ovlp.OffsetHigh = 0;
ovlp.hEvent = 0;
- res = LockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY,
- 0, SHARED_SIZE, 0, &ovlp);
+ res = osLockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY,
+ 0, SHARED_SIZE, 0, &ovlp);
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
*/
#if SQLITE_OS_WINCE==0
@@ -32939,11 +34067,11 @@ static int getReadLock(winFile *pFile){
int lk;
sqlite3_randomness(sizeof(lk), &lk);
pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
- res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
+ res = osLockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
#endif
}
if( res == 0 ){
- pFile->lastErrno = GetLastError();
+ pFile->lastErrno = osGetLastError();
/* No need to log a failure to lock */
}
return res;
@@ -32954,18 +34082,20 @@ static int getReadLock(winFile *pFile){
*/
static int unlockReadLock(winFile *pFile){
int res;
+ DWORD lastErrno;
if( isNT() ){
- res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
+ res = osUnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
*/
#if SQLITE_OS_WINCE==0
}else{
- res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
+ res = osUnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
#endif
}
- if( res==0 && GetLastError()!=ERROR_NOT_LOCKED ){
- pFile->lastErrno = GetLastError();
- winLogError(SQLITE_IOERR_UNLOCK, "unlockReadLock", pFile->zPath);
+ if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){
+ pFile->lastErrno = lastErrno;
+ winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
+ "unlockReadLock", pFile->zPath);
}
return res;
}
@@ -32998,11 +34128,11 @@ static int unlockReadLock(winFile *pFile){
*/
static int winLock(sqlite3_file *id, int locktype){
int rc = SQLITE_OK; /* Return code from subroutines */
- int res = 1; /* Result of a windows lock call */
+ int res = 1; /* Result of a Windows lock call */
int newLocktype; /* Set pFile->locktype to this value before exiting */
int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
winFile *pFile = (winFile*)id;
- DWORD error = NO_ERROR;
+ DWORD lastErrno = NO_ERROR;
assert( id!=0 );
OSTRACE(("LOCK %d %d was %d(%d)\n",
@@ -33032,16 +34162,19 @@ static int winLock(sqlite3_file *id, int locktype){
&& (pFile->locktype==RESERVED_LOCK))
){
int cnt = 3;
- while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){
- /* Try 3 times to get the pending lock. The pending lock might be
- ** held by another reader process who will release it momentarily.
+ while( cnt-->0 && (res = osLockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){
+ /* Try 3 times to get the pending lock. This is needed to work
+ ** around problems caused by indexing and/or anti-virus software on
+ ** Windows systems.
+ ** If you are using this code as a model for alternative VFSes, do not
+ ** copy this retry logic. It is a hack intended for Windows only.
*/
OSTRACE(("could not get a PENDING lock. cnt=%d\n", cnt));
- Sleep(1);
+ if( cnt ) osSleep(1);
}
gotPendingLock = res;
if( !res ){
- error = GetLastError();
+ lastErrno = osGetLastError();
}
}
@@ -33053,7 +34186,7 @@ static int winLock(sqlite3_file *id, int locktype){
if( res ){
newLocktype = SHARED_LOCK;
}else{
- error = GetLastError();
+ lastErrno = osGetLastError();
}
}
@@ -33061,11 +34194,11 @@ static int winLock(sqlite3_file *id, int locktype){
*/
if( locktype==RESERVED_LOCK && res ){
assert( pFile->locktype==SHARED_LOCK );
- res = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
+ res = osLockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
if( res ){
newLocktype = RESERVED_LOCK;
}else{
- error = GetLastError();
+ lastErrno = osGetLastError();
}
}
@@ -33082,12 +34215,12 @@ static int winLock(sqlite3_file *id, int locktype){
assert( pFile->locktype>=SHARED_LOCK );
res = unlockReadLock(pFile);
OSTRACE(("unreadlock = %d\n", res));
- res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
+ res = osLockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
- error = GetLastError();
- OSTRACE(("error-code = %d\n", error));
+ lastErrno = osGetLastError();
+ OSTRACE(("error-code = %d\n", lastErrno));
getReadLock(pFile);
}
}
@@ -33096,7 +34229,7 @@ static int winLock(sqlite3_file *id, int locktype){
** release it now.
*/
if( gotPendingLock && locktype==SHARED_LOCK ){
- UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
+ osUnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
}
/* Update the state of the lock has held in the file descriptor then
@@ -33107,7 +34240,7 @@ static int winLock(sqlite3_file *id, int locktype){
}else{
OSTRACE(("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
locktype, newLocktype));
- pFile->lastErrno = error;
+ pFile->lastErrno = lastErrno;
rc = SQLITE_BUSY;
}
pFile->locktype = (u8)newLocktype;
@@ -33130,9 +34263,9 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
rc = 1;
OSTRACE(("TEST WR-LOCK %d %d (local)\n", pFile->h, rc));
}else{
- rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
+ rc = osLockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
if( rc ){
- UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
+ osUnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
}
rc = !rc;
OSTRACE(("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc));
@@ -33162,27 +34295,44 @@ static int winUnlock(sqlite3_file *id, int locktype){
pFile->locktype, pFile->sharedLockByte));
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
- UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
+ osUnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
/* This should never happen. We should always be able to
** reacquire the read lock */
- rc = winLogError(SQLITE_IOERR_UNLOCK, "winUnlock", pFile->zPath);
+ rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(),
+ "winUnlock", pFile->zPath);
}
}
if( type>=RESERVED_LOCK ){
- UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
+ osUnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
}
if( locktype==NO_LOCK && type>=SHARED_LOCK ){
unlockReadLock(pFile);
}
if( type>=PENDING_LOCK ){
- UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
+ osUnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
}
pFile->locktype = (u8)locktype;
return rc;
}
/*
+** If *pArg is inititially negative then this is a query. Set *pArg to
+** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
+**
+** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
+*/
+static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
+ if( *pArg<0 ){
+ *pArg = (pFile->ctrlFlags & mask)!=0;
+ }else if( (*pArg)==0 ){
+ pFile->ctrlFlags &= ~mask;
+ }else{
+ pFile->ctrlFlags |= mask;
+ }
+}
+
+/*
** Control and query of the open file handle.
*/
static int winFileControl(sqlite3_file *id, int op, void *pArg){
@@ -33217,15 +34367,15 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
return SQLITE_OK;
}
case SQLITE_FCNTL_PERSIST_WAL: {
- int bPersist = *(int*)pArg;
- if( bPersist<0 ){
- *(int*)pArg = pFile->bPersistWal;
- }else{
- pFile->bPersistWal = bPersist!=0;
- }
+ winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg);
return SQLITE_OK;
}
- case SQLITE_FCNTL_SYNC_OMITTED: {
+ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
+ winModeBit(pFile, WINFILE_PSOW, (int*)pArg);
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_VFSNAME: {
+ *(char**)pArg = sqlite3_mprintf("win32");
return SQLITE_OK;
}
case SQLITE_FCNTL_WIN32_AV_RETRY: {
@@ -33257,16 +34407,17 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
** same for both.
*/
static int winSectorSize(sqlite3_file *id){
- assert( id!=0 );
- return (int)(((winFile*)id)->sectorSize);
+ (void)id;
+ return SQLITE_DEFAULT_SECTOR_SIZE;
}
/*
** Return a vector of device characteristics.
*/
static int winDeviceCharacteristics(sqlite3_file *id){
- UNUSED_PARAMETER(id);
- return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
+ winFile *p = (winFile*)id;
+ return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
+ ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
}
#ifndef SQLITE_OMIT_WAL
@@ -33413,15 +34564,15 @@ static int winShmSystemLock(
/* Release/Acquire the system-level lock */
if( lockType==_SHM_UNLCK ){
- rc = UnlockFileEx(pFile->hFile.h, 0, nByte, 0, &ovlp);
+ rc = osUnlockFileEx(pFile->hFile.h, 0, nByte, 0, &ovlp);
}else{
- rc = LockFileEx(pFile->hFile.h, dwFlags, 0, nByte, 0, &ovlp);
+ rc = osLockFileEx(pFile->hFile.h, dwFlags, 0, nByte, 0, &ovlp);
}
if( rc!= 0 ){
rc = SQLITE_OK;
}else{
- pFile->lastErrno = GetLastError();
+ pFile->lastErrno = osGetLastError();
rc = SQLITE_BUSY;
}
@@ -33455,13 +34606,13 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
int i;
if( p->mutex ) sqlite3_mutex_free(p->mutex);
for(i=0; i<p->nRegion; i++){
- bRc = UnmapViewOfFile(p->aRegion[i].pMap);
+ bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
- (int)GetCurrentProcessId(), i,
+ (int)osGetCurrentProcessId(), i,
bRc ? "ok" : "failed"));
- bRc = CloseHandle(p->aRegion[i].hMap);
+ bRc = osCloseHandle(p->aRegion[i].hMap);
OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n",
- (int)GetCurrentProcessId(), i,
+ (int)osGetCurrentProcessId(), i,
bRc ? "ok" : "failed"));
}
if( p->hFile.h != INVALID_HANDLE_VALUE ){
@@ -33471,7 +34622,9 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
}
if( deleteFlag ){
SimulateIOErrorBenign(1);
+ sqlite3BeginBenignMalloc();
winDelete(pVfs, p->zFilename, 0);
+ sqlite3EndBenignMalloc();
SimulateIOErrorBenign(0);
}
*pp = p->pNext;
@@ -33503,15 +34656,15 @@ static int winOpenSharedMemory(winFile *pDbFd){
** allocate space for a new winShmNode and filename.
*/
p = sqlite3_malloc( sizeof(*p) );
- if( p==0 ) return SQLITE_NOMEM;
+ if( p==0 ) return SQLITE_IOERR_NOMEM;
memset(p, 0, sizeof(*p));
nName = sqlite3Strlen30(pDbFd->zPath);
- pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 15 );
+ pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 17 );
if( pNew==0 ){
sqlite3_free(p);
- return SQLITE_NOMEM;
+ return SQLITE_IOERR_NOMEM;
}
- memset(pNew, 0, sizeof(*pNew));
+ memset(pNew, 0, sizeof(*pNew) + nName + 17);
pNew->zFilename = (char*)&pNew[1];
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
@@ -33537,7 +34690,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
if( pShmNode->mutex==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_IOERR_NOMEM;
goto shm_open_err;
}
@@ -33547,7 +34700,6 @@ static int winOpenSharedMemory(winFile *pDbFd){
SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
0);
if( SQLITE_OK!=rc ){
- rc = SQLITE_CANTOPEN_BKPT;
goto shm_open_err;
}
@@ -33557,7 +34709,8 @@ static int winOpenSharedMemory(winFile *pDbFd){
if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
if( rc!=SQLITE_OK ){
- rc = winLogError(SQLITE_IOERR_SHMOPEN, "winOpenShm", pDbFd->zPath);
+ rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
+ "winOpenShm", pDbFd->zPath);
}
}
if( rc==SQLITE_OK ){
@@ -33742,7 +34895,7 @@ static int winShmLock(
}
sqlite3_mutex_leave(pShmNode->mutex);
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n",
- p->id, (int)GetCurrentProcessId(), p->sharedMask, p->exclMask,
+ p->id, (int)osGetCurrentProcessId(), p->sharedMask, p->exclMask,
rc ? "failed" : "ok"));
return rc;
}
@@ -33816,7 +34969,8 @@ static int winShmMap(
*/
rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
if( rc!=SQLITE_OK ){
- rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap1", pDbFd->zPath);
+ rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
+ "winShmMap1", pDbFd->zPath);
goto shmpage_out;
}
@@ -33830,7 +34984,8 @@ static int winShmMap(
if( !isWrite ) goto shmpage_out;
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
if( rc!=SQLITE_OK ){
- rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap2", pDbFd->zPath);
+ rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
+ "winShmMap2", pDbFd->zPath);
goto shmpage_out;
}
}
@@ -33849,26 +35004,27 @@ static int winShmMap(
HANDLE hMap; /* file-mapping handle */
void *pMap = 0; /* Mapped memory region */
- hMap = CreateFileMapping(pShmNode->hFile.h,
+ hMap = osCreateFileMapping(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
);
OSTRACE(("SHM-MAP pid-%d create region=%d nbyte=%d %s\n",
- (int)GetCurrentProcessId(), pShmNode->nRegion, nByte,
+ (int)osGetCurrentProcessId(), pShmNode->nRegion, nByte,
hMap ? "ok" : "failed"));
if( hMap ){
int iOffset = pShmNode->nRegion*szRegion;
int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
- pMap = MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
+ pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
0, iOffset - iOffsetShift, szRegion + iOffsetShift
);
OSTRACE(("SHM-MAP pid-%d map region=%d offset=%d size=%d %s\n",
- (int)GetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion,
- pMap ? "ok" : "failed"));
+ (int)osGetCurrentProcessId(), pShmNode->nRegion, iOffset,
+ szRegion, pMap ? "ok" : "failed"));
}
if( !pMap ){
- pShmNode->lastErrno = GetLastError();
- rc = winLogError(SQLITE_IOERR_SHMMAP, "winShmMap3", pDbFd->zPath);
- if( hMap ) CloseHandle(hMap);
+ pShmNode->lastErrno = osGetLastError();
+ rc = winLogError(SQLITE_IOERR_SHMMAP, pShmNode->lastErrno,
+ "winShmMap3", pDbFd->zPath);
+ if( hMap ) osCloseHandle(hMap);
goto shmpage_out;
}
@@ -33966,7 +35122,7 @@ static int getTempname(int nBuf, char *zBuf){
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
size_t i, j;
- char zTempPath[MAX_PATH+1];
+ char zTempPath[MAX_PATH+2];
/* 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
@@ -33979,29 +35135,29 @@ static int getTempname(int nBuf, char *zBuf){
}else if( isNT() ){
char *zMulti;
WCHAR zWidePath[MAX_PATH];
- GetTempPathW(MAX_PATH-30, zWidePath);
+ osGetTempPathW(MAX_PATH-30, zWidePath);
zMulti = unicodeToUtf8(zWidePath);
if( zMulti ){
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
- free(zMulti);
+ sqlite3_free(zMulti);
}else{
- return SQLITE_NOMEM;
+ return SQLITE_IOERR_NOMEM;
}
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
-** Since the ASCII version of these Windows API do not exist for WINCE,
+** Since the ANSI version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
}else{
char *zUtf8;
char zMbcsPath[MAX_PATH];
- GetTempPathA(MAX_PATH-30, zMbcsPath);
+ osGetTempPathA(MAX_PATH-30, zMbcsPath);
zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
if( zUtf8 ){
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
- free(zUtf8);
+ sqlite3_free(zUtf8);
}else{
- return SQLITE_NOMEM;
+ return SQLITE_IOERR_NOMEM;
}
#endif
}
@@ -34009,14 +35165,14 @@ static int getTempname(int nBuf, char *zBuf){
/* Check that the output buffer is large enough for the temporary file
** name. If it is not, return SQLITE_ERROR.
*/
- if( (sqlite3Strlen30(zTempPath) + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 17) >= nBuf ){
+ if( (sqlite3Strlen30(zTempPath) + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){
return SQLITE_ERROR;
}
for(i=sqlite3Strlen30(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
zTempPath[i] = 0;
- sqlite3_snprintf(nBuf-17, zBuf,
+ sqlite3_snprintf(nBuf-18, zBuf,
"%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
j = sqlite3Strlen30(zBuf);
sqlite3_randomness(15, &zBuf[j]);
@@ -34024,12 +35180,42 @@ static int getTempname(int nBuf, char *zBuf){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
+ zBuf[j+1] = 0;
OSTRACE(("TEMP FILENAME: %s\n", zBuf));
return SQLITE_OK;
}
/*
+** Return TRUE if the named file is really a directory. Return false if
+** it is something other than a directory, or if there is any kind of memory
+** allocation failure.
+*/
+static int winIsDir(const void *zConverted){
+ DWORD attr;
+ int rc = 0;
+ DWORD lastErrno;
+
+ if( isNT() ){
+ int cnt = 0;
+ WIN32_FILE_ATTRIBUTE_DATA sAttrData;
+ memset(&sAttrData, 0, sizeof(sAttrData));
+ while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
+ GetFileExInfoStandard,
+ &sAttrData)) && retryIoerr(&cnt, &lastErrno) ){}
+ if( !rc ){
+ return 0; /* Invalid name? */
+ }
+ attr = sAttrData.dwFileAttributes;
+#if SQLITE_OS_WINCE==0
+ }else{
+ attr = osGetFileAttributesA((char*)zConverted);
+#endif
+ }
+ return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
+}
+
+/*
** Open a file.
*/
static int winOpen(
@@ -34040,6 +35226,7 @@ static int winOpen(
int *pOutFlags /* Status return flags */
){
HANDLE h;
+ DWORD lastErrno;
DWORD dwDesiredAccess;
DWORD dwShareMode;
DWORD dwCreationDisposition;
@@ -34055,7 +35242,7 @@ static int winOpen(
/* If argument zPath is a NULL pointer, this function is required to open
** a temporary file. Use this buffer to store the file name in.
*/
- char zTmpname[MAX_PATH+1]; /* Buffer used to create temp filename */
+ char zTmpname[MAX_PATH+2]; /* Buffer used to create temp filename */
int rc = SQLITE_OK; /* Function Return Code */
#if !defined(NDEBUG) || SQLITE_OS_WINCE
@@ -34114,17 +35301,29 @@ static int winOpen(
*/
if( !zUtf8Name ){
assert(isDelete && !isOpenJournal);
- rc = getTempname(MAX_PATH+1, zTmpname);
+ rc = getTempname(MAX_PATH+2, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
}
zUtf8Name = zTmpname;
}
+ /* Database filenames are double-zero terminated if they are not
+ ** URIs with parameters. Hence, they can always be passed into
+ ** sqlite3_uri_parameter().
+ */
+ assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) ||
+ zUtf8Name[strlen(zUtf8Name)+1]==0 );
+
/* Convert the filename to the system encoding. */
zConverted = convertUtf8Filename(zUtf8Name);
if( zConverted==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_IOERR_NOMEM;
+ }
+
+ if( winIsDir(zConverted) ){
+ sqlite3_free(zConverted);
+ return SQLITE_CANTOPEN_ISDIR;
}
if( isReadWrite ){
@@ -34170,26 +35369,26 @@ static int winOpen(
#endif
if( isNT() ){
- while( (h = CreateFileW((WCHAR*)zConverted,
- dwDesiredAccess,
- dwShareMode, NULL,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- NULL))==INVALID_HANDLE_VALUE &&
- retryIoerr(&cnt) ){}
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
-** Since the ASCII version of these Windows API do not exist for WINCE,
-** it's important to not reference them for WINCE builds.
-*/
+ while( (h = osCreateFileW((LPCWSTR)zConverted,
+ dwDesiredAccess,
+ dwShareMode, NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL))==INVALID_HANDLE_VALUE &&
+ retryIoerr(&cnt, &lastErrno) ){
+ /* Noop */
+ }
#if SQLITE_OS_WINCE==0
}else{
- while( (h = CreateFileA((char*)zConverted,
- dwDesiredAccess,
- dwShareMode, NULL,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- NULL))==INVALID_HANDLE_VALUE &&
- retryIoerr(&cnt) ){}
+ while( (h = osCreateFileA((LPCSTR)zConverted,
+ dwDesiredAccess,
+ dwShareMode, NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL))==INVALID_HANDLE_VALUE &&
+ retryIoerr(&cnt, &lastErrno) ){
+ /* Noop */
+ }
#endif
}
@@ -34200,9 +35399,9 @@ static int winOpen(
h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
if( h==INVALID_HANDLE_VALUE ){
- pFile->lastErrno = GetLastError();
- winLogError(SQLITE_CANTOPEN, "winOpen", zUtf8Name);
- free(zConverted);
+ pFile->lastErrno = lastErrno;
+ winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
+ sqlite3_free(zConverted);
if( isReadWrite && !isExclusive ){
return winOpen(pVfs, zName, id,
((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
@@ -34226,14 +35425,16 @@ static int winOpen(
pFile->pVfs = pVfs;
pFile->pShm = 0;
pFile->zPath = zName;
- pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
+ if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
+ pFile->ctrlFlags |= WINFILE_PSOW;
+ }
#if SQLITE_OS_WINCE
if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
&& !winceCreateLock(zName, pFile)
){
- CloseHandle(h);
- free(zConverted);
+ osCloseHandle(h);
+ sqlite3_free(zConverted);
return SQLITE_CANTOPEN_BKPT;
}
if( isTemp ){
@@ -34241,7 +35442,7 @@ static int winOpen(
}else
#endif
{
- free(zConverted);
+ sqlite3_free(zConverted);
}
OpenCounter(+1);
@@ -34251,7 +35452,7 @@ static int winOpen(
/*
** Delete the named file.
**
-** Note that windows does not allow a file to be deleted if some other
+** Note that Windows does not allow a file to be deleted if some other
** process has it open. Sometimes a virus scanner or indexing program
** will open a journal file shortly after it is created in order to do
** whatever it does. While this other process is holding the
@@ -34267,6 +35468,8 @@ static int winDelete(
){
int cnt = 0;
int rc;
+ DWORD attr;
+ DWORD lastErrno;
void *zConverted;
UNUSED_PARAMETER(pVfs);
UNUSED_PARAMETER(syncDir);
@@ -34274,31 +35477,62 @@ static int winDelete(
SimulateIOError(return SQLITE_IOERR_DELETE);
zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_IOERR_NOMEM;
}
if( isNT() ){
- rc = 1;
- while( GetFileAttributesW(zConverted)!=INVALID_FILE_ATTRIBUTES &&
- (rc = DeleteFileW(zConverted))==0 && retryIoerr(&cnt) ){}
- rc = rc ? SQLITE_OK : SQLITE_ERROR;
+ do {
+ attr = osGetFileAttributesW(zConverted);
+ if ( attr==INVALID_FILE_ATTRIBUTES ){
+ rc = SQLITE_OK; /* Already gone? */
+ break;
+ }
+ if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
+ rc = SQLITE_ERROR; /* Files only. */
+ break;
+ }
+ if ( osDeleteFileW(zConverted) ){
+ rc = SQLITE_OK; /* Deleted OK. */
+ break;
+ }
+ if ( !retryIoerr(&cnt, &lastErrno) ){
+ rc = SQLITE_ERROR; /* No more retries. */
+ break;
+ }
+ } while(1);
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
-** Since the ASCII version of these Windows API do not exist for WINCE,
+** Since the ANSI version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
}else{
- rc = 1;
- while( GetFileAttributesA(zConverted)!=INVALID_FILE_ATTRIBUTES &&
- (rc = DeleteFileA(zConverted))==0 && retryIoerr(&cnt) ){}
- rc = rc ? SQLITE_OK : SQLITE_ERROR;
+ do {
+ attr = osGetFileAttributesA(zConverted);
+ if ( attr==INVALID_FILE_ATTRIBUTES ){
+ rc = SQLITE_OK; /* Already gone? */
+ break;
+ }
+ if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
+ rc = SQLITE_ERROR; /* Files only. */
+ break;
+ }
+ if ( osDeleteFileA(zConverted) ){
+ rc = SQLITE_OK; /* Deleted OK. */
+ break;
+ }
+ if ( !retryIoerr(&cnt, &lastErrno) ){
+ rc = SQLITE_ERROR; /* No more retries. */
+ break;
+ }
+ } while(1);
#endif
}
if( rc ){
- rc = winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename);
+ rc = winLogError(SQLITE_IOERR_DELETE, lastErrno,
+ "winDelete", zFilename);
}else{
logIoerr(cnt);
}
- free(zConverted);
+ sqlite3_free(zConverted);
OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" )));
return rc;
}
@@ -34314,21 +35548,22 @@ static int winAccess(
){
DWORD attr;
int rc = 0;
+ DWORD lastErrno;
void *zConverted;
UNUSED_PARAMETER(pVfs);
SimulateIOError( return SQLITE_IOERR_ACCESS; );
zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_IOERR_NOMEM;
}
if( isNT() ){
int cnt = 0;
WIN32_FILE_ATTRIBUTE_DATA sAttrData;
memset(&sAttrData, 0, sizeof(sAttrData));
- while( !(rc = GetFileAttributesExW((WCHAR*)zConverted,
+ while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
GetFileExInfoStandard,
- &sAttrData)) && retryIoerr(&cnt) ){}
+ &sAttrData)) && retryIoerr(&cnt, &lastErrno) ){}
if( rc ){
/* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
** as if it does not exist.
@@ -34342,24 +35577,24 @@ static int winAccess(
}
}else{
logIoerr(cnt);
- if( GetLastError()!=ERROR_FILE_NOT_FOUND ){
- winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename);
- free(zConverted);
+ if( lastErrno!=ERROR_FILE_NOT_FOUND ){
+ winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", zFilename);
+ sqlite3_free(zConverted);
return SQLITE_IOERR_ACCESS;
}else{
attr = INVALID_FILE_ATTRIBUTES;
}
}
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
-** Since the ASCII version of these Windows API do not exist for WINCE,
+** Since the ANSI version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
}else{
- attr = GetFileAttributesA((char*)zConverted);
+ attr = osGetFileAttributesA((char*)zConverted);
#endif
}
- free(zConverted);
+ sqlite3_free(zConverted);
switch( flags ){
case SQLITE_ACCESS_READ:
case SQLITE_ACCESS_EXISTS:
@@ -34424,117 +35659,50 @@ static int winFullPathname(
SimulateIOError( return SQLITE_ERROR );
UNUSED_PARAMETER(nFull);
zConverted = convertUtf8Filename(zRelative);
+ if( zConverted==0 ){
+ return SQLITE_IOERR_NOMEM;
+ }
if( isNT() ){
- WCHAR *zTemp;
- nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3;
- zTemp = malloc( nByte*sizeof(zTemp[0]) );
+ LPWSTR zTemp;
+ nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0) + 3;
+ zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
- free(zConverted);
- return SQLITE_NOMEM;
+ sqlite3_free(zConverted);
+ return SQLITE_IOERR_NOMEM;
}
- GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0);
- free(zConverted);
+ osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
+ sqlite3_free(zConverted);
zOut = unicodeToUtf8(zTemp);
- free(zTemp);
+ sqlite3_free(zTemp);
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
-** Since the ASCII version of these Windows API do not exist for WINCE,
+** Since the ANSI version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
}else{
char *zTemp;
- nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
- zTemp = malloc( nByte*sizeof(zTemp[0]) );
+ nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
+ zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
- free(zConverted);
- return SQLITE_NOMEM;
+ sqlite3_free(zConverted);
+ return SQLITE_IOERR_NOMEM;
}
- GetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
- free(zConverted);
+ osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
+ sqlite3_free(zConverted);
zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
- free(zTemp);
+ sqlite3_free(zTemp);
#endif
}
if( zOut ){
sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zOut);
- free(zOut);
+ sqlite3_free(zOut);
return SQLITE_OK;
}else{
- return SQLITE_NOMEM;
+ return SQLITE_IOERR_NOMEM;
}
#endif
}
-/*
-** Get the sector size of the device used to store
-** file.
-*/
-static int getSectorSize(
- sqlite3_vfs *pVfs,
- const char *zRelative /* UTF-8 file name */
-){
- DWORD bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
- /* GetDiskFreeSpace is not supported under WINCE */
-#if SQLITE_OS_WINCE
- UNUSED_PARAMETER(pVfs);
- UNUSED_PARAMETER(zRelative);
-#else
- char zFullpath[MAX_PATH+1];
- int rc;
- DWORD dwRet = 0;
- DWORD dwDummy;
-
- /*
- ** We need to get the full path name of the file
- ** to get the drive letter to look up the sector
- ** size.
- */
- SimulateIOErrorBenign(1);
- rc = winFullPathname(pVfs, zRelative, MAX_PATH, zFullpath);
- SimulateIOErrorBenign(0);
- if( rc == SQLITE_OK )
- {
- void *zConverted = convertUtf8Filename(zFullpath);
- if( zConverted ){
- if( isNT() ){
- /* trim path to just drive reference */
- WCHAR *p = zConverted;
- for(;*p;p++){
- if( *p == '\\' ){
- *p = '\0';
- break;
- }
- }
- dwRet = GetDiskFreeSpaceW((WCHAR*)zConverted,
- &dwDummy,
- &bytesPerSector,
- &dwDummy,
- &dwDummy);
- }else{
- /* trim path to just drive reference */
- char *p = (char *)zConverted;
- for(;*p;p++){
- if( *p == '\\' ){
- *p = '\0';
- break;
- }
- }
- dwRet = GetDiskFreeSpaceA((char*)zConverted,
- &dwDummy,
- &bytesPerSector,
- &dwDummy,
- &dwDummy);
- }
- free(zConverted);
- }
- if( !dwRet ){
- bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
- }
- }
-#endif
- return (int) bytesPerSector;
-}
-
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Interfaces for opening a shared library, finding entry points
@@ -34552,37 +35720,30 @@ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
return 0;
}
if( isNT() ){
- h = LoadLibraryW((WCHAR*)zConverted);
+ h = osLoadLibraryW((LPCWSTR)zConverted);
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
-** Since the ASCII version of these Windows API do not exist for WINCE,
+** Since the ANSI version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
}else{
- h = LoadLibraryA((char*)zConverted);
+ h = osLoadLibraryA((char*)zConverted);
#endif
}
- free(zConverted);
+ sqlite3_free(zConverted);
return (void*)h;
}
static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
UNUSED_PARAMETER(pVfs);
- getLastErrorMsg(nBuf, zBufOut);
+ getLastErrorMsg(osGetLastError(), nBuf, zBufOut);
}
static void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
UNUSED_PARAMETER(pVfs);
-#if SQLITE_OS_WINCE
- /* The GetProcAddressA() routine is only available on wince. */
- return (void(*)(void))GetProcAddressA((HANDLE)pHandle, zSymbol);
-#else
- /* All other windows platforms expect GetProcAddress() to take
- ** an Ansi string regardless of the _UNICODE setting */
- return (void(*)(void))GetProcAddress((HANDLE)pHandle, zSymbol);
-#endif
+ return (void(*)(void))osGetProcAddressA((HANDLE)pHandle, zSymbol);
}
static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
UNUSED_PARAMETER(pVfs);
- FreeLibrary((HANDLE)pHandle);
+ osFreeLibrary((HANDLE)pHandle);
}
#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
#define winDlOpen 0
@@ -34604,23 +35765,23 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
#else
if( sizeof(SYSTEMTIME)<=nBuf-n ){
SYSTEMTIME x;
- GetSystemTime(&x);
+ osGetSystemTime(&x);
memcpy(&zBuf[n], &x, sizeof(x));
n += sizeof(x);
}
if( sizeof(DWORD)<=nBuf-n ){
- DWORD pid = GetCurrentProcessId();
+ DWORD pid = osGetCurrentProcessId();
memcpy(&zBuf[n], &pid, sizeof(pid));
n += sizeof(pid);
}
if( sizeof(DWORD)<=nBuf-n ){
- DWORD cnt = GetTickCount();
+ DWORD cnt = osGetTickCount();
memcpy(&zBuf[n], &cnt, sizeof(cnt));
n += sizeof(cnt);
}
if( sizeof(LARGE_INTEGER)<=nBuf-n ){
LARGE_INTEGER i;
- QueryPerformanceCounter(&i);
+ osQueryPerformanceCounter(&i);
memcpy(&zBuf[n], &i, sizeof(i));
n += sizeof(i);
}
@@ -34633,7 +35794,7 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
** Sleep for a little while. Return the amount of time slept.
*/
static int winSleep(sqlite3_vfs *pVfs, int microsec){
- Sleep((microsec+999)/1000);
+ osSleep((microsec+999)/1000);
UNUSED_PARAMETER(pVfs);
return ((microsec+999)/1000)*1000;
}
@@ -34672,13 +35833,13 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
#if SQLITE_OS_WINCE
SYSTEMTIME time;
- GetSystemTime(&time);
+ osGetSystemTime(&time);
/* if SystemTimeToFileTime() fails, it returns zero. */
- if (!SystemTimeToFileTime(&time,&ft)){
+ if (!osSystemTimeToFileTime(&time,&ft)){
return SQLITE_ERROR;
}
#else
- GetSystemTimeAsFileTime( &ft );
+ osGetSystemTimeAsFileTime( &ft );
#endif
*piNow = winFiletimeEpoch +
@@ -34711,8 +35872,8 @@ static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
/*
** The idea is that this function works like a combination of
-** GetLastError() and FormatMessage() on windows (or errno and
-** strerror_r() on unix). After an error is returned by an OS
+** GetLastError() and FormatMessage() on Windows (or errno and
+** strerror_r() on Unix). After an error is returned by an OS
** function, SQLite calls this function with zBuf pointing to
** a buffer of nBuf bytes. The OS layer should populate the
** buffer with a nul-terminated UTF-8 encoded error message
@@ -34741,11 +35902,9 @@ static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
*/
static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
UNUSED_PARAMETER(pVfs);
- return getLastErrorMsg(nBuf, zBuf);
+ return getLastErrorMsg(osGetLastError(), nBuf, zBuf);
}
-
-
/*
** Initialize and deinitialize the operating system interface.
*/
@@ -34770,21 +35929,26 @@ SQLITE_API int sqlite3_os_init(void){
winCurrentTime, /* xCurrentTime */
winGetLastError, /* xGetLastError */
winCurrentTimeInt64, /* xCurrentTimeInt64 */
- 0, /* xSetSystemCall */
- 0, /* xGetSystemCall */
- 0, /* xNextSystemCall */
+ winSetSystemCall, /* xSetSystemCall */
+ winGetSystemCall, /* xGetSystemCall */
+ winNextSystemCall, /* xNextSystemCall */
};
+ /* Double-check that the aSyscall[] array has been constructed
+ ** correctly. See ticket [bb3a86e890c8e96ab] */
+ assert( ArraySize(aSyscall)==60 );
+
#ifndef SQLITE_OMIT_WAL
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
- GetSystemInfo(&winSysInfo);
+ osGetSystemInfo(&winSysInfo);
assert(winSysInfo.dwAllocationGranularity > 0);
#endif
sqlite3_vfs_register(&winVfs, 1);
return SQLITE_OK;
}
+
SQLITE_API int sqlite3_os_end(void){
return SQLITE_OK;
}
@@ -35224,7 +36388,7 @@ struct PCache {
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
PgHdr *pSynced; /* Last synced page in dirty page list */
int nRef; /* Number of referenced pages */
- int nMax; /* Configured cache size */
+ int szCache; /* Configured cache size */
int szPage; /* Size of every page in this cache */
int szExtra; /* Size of extra space for each page */
int bPurgeable; /* True if pages are on backing store */
@@ -35335,7 +36499,7 @@ static void pcacheUnpin(PgHdr *p){
if( p->pgno==1 ){
pCache->pPage1 = 0;
}
- sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 0);
+ sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 0);
}
}
@@ -35345,18 +36509,18 @@ static void pcacheUnpin(PgHdr *p){
** functions are threadsafe.
*/
SQLITE_PRIVATE int sqlite3PcacheInitialize(void){
- if( sqlite3GlobalConfig.pcache.xInit==0 ){
+ if( sqlite3GlobalConfig.pcache2.xInit==0 ){
/* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the
** built-in default page cache is used instead of the application defined
** page cache. */
sqlite3PCacheSetDefault();
}
- return sqlite3GlobalConfig.pcache.xInit(sqlite3GlobalConfig.pcache.pArg);
+ return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg);
}
SQLITE_PRIVATE void sqlite3PcacheShutdown(void){
- if( sqlite3GlobalConfig.pcache.xShutdown ){
+ if( sqlite3GlobalConfig.pcache2.xShutdown ){
/* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
- sqlite3GlobalConfig.pcache.xShutdown(sqlite3GlobalConfig.pcache.pArg);
+ sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg);
}
}
@@ -35385,7 +36549,7 @@ SQLITE_PRIVATE void sqlite3PcacheOpen(
p->bPurgeable = bPurgeable;
p->xStress = xStress;
p->pStress = pStress;
- p->nMax = 100;
+ p->szCache = 100;
}
/*
@@ -35395,7 +36559,7 @@ SQLITE_PRIVATE void sqlite3PcacheOpen(
SQLITE_PRIVATE void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
assert( pCache->nRef==0 && pCache->pDirty==0 );
if( pCache->pCache ){
- sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
+ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
pCache->pCache = 0;
pCache->pPage1 = 0;
}
@@ -35403,6 +36567,17 @@ SQLITE_PRIVATE void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
}
/*
+** Compute the number of pages of cache requested.
+*/
+static int numberOfCachePages(PCache *p){
+ if( p->szCache>=0 ){
+ return p->szCache;
+ }else{
+ return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
+ }
+}
+
+/*
** Try to obtain a page from the cache.
*/
SQLITE_PRIVATE int sqlite3PcacheFetch(
@@ -35411,7 +36586,8 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
int createFlag, /* If true, create page if it does not exist already */
PgHdr **ppPage /* Write the page here */
){
- PgHdr *pPage = 0;
+ sqlite3_pcache_page *pPage = 0;
+ PgHdr *pPgHdr = 0;
int eCreate;
assert( pCache!=0 );
@@ -35423,19 +36599,19 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
*/
if( !pCache->pCache && createFlag ){
sqlite3_pcache *p;
- int nByte;
- nByte = pCache->szPage + pCache->szExtra + sizeof(PgHdr);
- p = sqlite3GlobalConfig.pcache.xCreate(nByte, pCache->bPurgeable);
+ p = sqlite3GlobalConfig.pcache2.xCreate(
+ pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
+ );
if( !p ){
return SQLITE_NOMEM;
}
- sqlite3GlobalConfig.pcache.xCachesize(p, pCache->nMax);
+ sqlite3GlobalConfig.pcache2.xCachesize(p, numberOfCachePages(pCache));
pCache->pCache = p;
}
eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty));
if( pCache->pCache ){
- pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, eCreate);
+ pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
}
if( !pPage && eCreate==1 ){
@@ -35462,7 +36638,7 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
"spill page %d making room for %d - cache used: %d/%d",
pPg->pgno, pgno,
sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
- pCache->nMax);
+ numberOfCachePages(pCache));
#endif
rc = pCache->xStress(pCache->pStress, pPg);
if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
@@ -35470,33 +36646,36 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
}
}
- pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, 2);
+ pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
}
if( pPage ){
- if( !pPage->pData ){
- memset(pPage, 0, sizeof(PgHdr));
- pPage->pData = (void *)&pPage[1];
- pPage->pExtra = (void*)&((char *)pPage->pData)[pCache->szPage];
- memset(pPage->pExtra, 0, pCache->szExtra);
- pPage->pCache = pCache;
- pPage->pgno = pgno;
- }
- assert( pPage->pCache==pCache );
- assert( pPage->pgno==pgno );
- assert( pPage->pData==(void *)&pPage[1] );
- assert( pPage->pExtra==(void *)&((char *)&pPage[1])[pCache->szPage] );
-
- if( 0==pPage->nRef ){
+ pPgHdr = (PgHdr *)pPage->pExtra;
+
+ if( !pPgHdr->pPage ){
+ memset(pPgHdr, 0, sizeof(PgHdr));
+ pPgHdr->pPage = pPage;
+ pPgHdr->pData = pPage->pBuf;
+ pPgHdr->pExtra = (void *)&pPgHdr[1];
+ memset(pPgHdr->pExtra, 0, pCache->szExtra);
+ pPgHdr->pCache = pCache;
+ pPgHdr->pgno = pgno;
+ }
+ assert( pPgHdr->pCache==pCache );
+ assert( pPgHdr->pgno==pgno );
+ assert( pPgHdr->pData==pPage->pBuf );
+ assert( pPgHdr->pExtra==(void *)&pPgHdr[1] );
+
+ if( 0==pPgHdr->nRef ){
pCache->nRef++;
}
- pPage->nRef++;
+ pPgHdr->nRef++;
if( pgno==1 ){
- pCache->pPage1 = pPage;
+ pCache->pPage1 = pPgHdr;
}
}
- *ppPage = pPage;
- return (pPage==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
+ *ppPage = pPgHdr;
+ return (pPgHdr==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
}
/*
@@ -35543,7 +36722,7 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
if( p->pgno==1 ){
pCache->pPage1 = 0;
}
- sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 1);
+ sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 1);
}
/*
@@ -35601,7 +36780,7 @@ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
assert( p->nRef>0 );
assert( newPgno>0 );
- sqlite3GlobalConfig.pcache.xRekey(pCache->pCache, p, p->pgno, newPgno);
+ sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
pcacheRemoveFromDirtyList(p);
@@ -35638,7 +36817,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
memset(pCache->pPage1->pData, 0, pCache->szPage);
pgno = 1;
}
- sqlite3GlobalConfig.pcache.xTruncate(pCache->pCache, pgno+1);
+ sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1);
}
}
@@ -35647,7 +36826,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
*/
SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
if( pCache->pCache ){
- sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
+ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
}
}
@@ -35759,7 +36938,7 @@ SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){
int nPage = 0;
if( pCache->pCache ){
- nPage = sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache);
+ nPage = sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache);
}
return nPage;
}
@@ -35769,7 +36948,7 @@ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){
** Get the suggested cache-size value.
*/
SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){
- return pCache->nMax;
+ return numberOfCachePages(pCache);
}
#endif
@@ -35777,9 +36956,19 @@ SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){
** Set the suggested cache-size value.
*/
SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
- pCache->nMax = mxPage;
+ pCache->szCache = mxPage;
if( pCache->pCache ){
- sqlite3GlobalConfig.pcache.xCachesize(pCache->pCache, mxPage);
+ sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
+ numberOfCachePages(pCache));
+ }
+}
+
+/*
+** Free up as much memory as possible from the page cache.
+*/
+SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){
+ if( pCache->pCache ){
+ sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
}
}
@@ -35824,7 +37013,6 @@ typedef struct PgHdr1 PgHdr1;
typedef struct PgFreeslot PgFreeslot;
typedef struct PGroup PGroup;
-
/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
** of one or more PCaches that are able to recycle each others unpinned
** pages when they are under memory pressure. A PGroup is an instance of
@@ -35841,7 +37029,7 @@ typedef struct PGroup PGroup;
** Mode 1 uses more memory (since PCache instances are not able to rob
** unused pages from other PCaches) but it also operates without a mutex,
** and is therefore often faster. Mode 2 requires a mutex in order to be
-** threadsafe, but is able recycle pages more efficient.
+** threadsafe, but recycles pages more efficiently.
**
** For mode (1), PGroup.mutex is NULL. For mode (2) there is only a single
** PGroup which is the pcache1.grp global variable and its mutex is
@@ -35849,10 +37037,10 @@ typedef struct PGroup PGroup;
*/
struct PGroup {
sqlite3_mutex *mutex; /* MUTEX_STATIC_LRU or NULL */
- int nMaxPage; /* Sum of nMax for purgeable caches */
- int nMinPage; /* Sum of nMin for purgeable caches */
- int mxPinned; /* nMaxpage + 10 - nMinPage */
- int nCurrentPage; /* Number of purgeable pages allocated */
+ unsigned int nMaxPage; /* Sum of nMax for purgeable caches */
+ unsigned int nMinPage; /* Sum of nMin for purgeable caches */
+ unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */
+ unsigned int nCurrentPage; /* Number of purgeable pages allocated */
PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */
};
@@ -35867,15 +37055,17 @@ struct PGroup {
struct PCache1 {
/* Cache configuration parameters. Page size (szPage) and the purgeable
** flag (bPurgeable) are set when the cache is created. nMax may be
- ** modified at any time by a call to the pcache1CacheSize() method.
+ ** modified at any time by a call to the pcache1Cachesize() method.
** The PGroup mutex must be held when accessing nMax.
*/
PGroup *pGroup; /* PGroup this cache belongs to */
int szPage; /* Size of allocated pages in bytes */
+ int szExtra; /* Size of extra space in bytes */
int bPurgeable; /* True if cache is purgeable */
unsigned int nMin; /* Minimum number of pages reserved */
unsigned int nMax; /* Configured "cache_size" value */
unsigned int n90pct; /* nMax*9/10 */
+ unsigned int iMaxKey; /* Largest key seen since xTruncate() */
/* Hash table of all pages. The following variables may only be accessed
** when the accessor is holding the PGroup mutex.
@@ -35884,17 +37074,16 @@ 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 */
-
- unsigned int iMaxKey; /* Largest key seen since xTruncate() */
};
/*
** Each cache entry is represented by an instance of the following
-** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
-** directly before this structure in memory (see the PGHDR1_TO_PAGE()
-** macro below).
+** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
+** PgHdr1.pCache->szPage bytes is allocated directly before this structure
+** in memory.
*/
struct PgHdr1 {
+ sqlite3_pcache_page page;
unsigned int iKey; /* Key value (page number) */
PgHdr1 *pNext; /* Next in hash table chain */
PCache1 *pCache; /* Cache that currently owns this page */
@@ -35928,8 +37117,8 @@ static SQLITE_WSD struct PCacheGlobal {
void *pStart, *pEnd; /* Bounds of pagecache malloc range */
/* Above requires no mutex. Use mutex below for variable that follow. */
sqlite3_mutex *mutex; /* Mutex for accessing the following: */
- int nFreeSlot; /* Number of unused pcache slots */
PgFreeslot *pFree; /* Free page blocks */
+ int nFreeSlot; /* Number of unused pcache slots */
/* The following value requires a mutex to change. We skip the mutex on
** reading because (1) most platforms read a 32-bit integer atomically and
** (2) even if an incorrect value is read, no great harm is done since this
@@ -35945,21 +37134,6 @@ static SQLITE_WSD struct PCacheGlobal {
#define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g))
/*
-** When a PgHdr1 structure is allocated, the associated PCache1.szPage
-** bytes of data are located directly before it in memory (i.e. the total
-** size of the allocation is sizeof(PgHdr1)+PCache1.szPage byte). The
-** PGHDR1_TO_PAGE() macro takes a pointer to a PgHdr1 structure as
-** an argument and returns a pointer to the associated block of szPage
-** bytes. The PAGE_TO_PGHDR1() macro does the opposite: its argument is
-** a pointer to a block of szPage bytes of data and the return value is
-** a pointer to the associated PgHdr1 structure.
-**
-** assert( PGHDR1_TO_PAGE(PAGE_TO_PGHDR1(pCache, X))==X );
-*/
-#define PGHDR1_TO_PAGE(p) (void*)(((char*)p) - p->pCache->szPage)
-#define PAGE_TO_PGHDR1(c, p) (PgHdr1*)(((char*)p) + c->szPage)
-
-/*
** Macros to enter and leave the PCache LRU mutex.
*/
#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
@@ -36041,8 +37215,9 @@ static void *pcache1Alloc(int nByte){
/*
** Free an allocated buffer obtained from pcache1Alloc().
*/
-static void pcache1Free(void *p){
- if( p==0 ) return;
+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);
@@ -36055,15 +37230,15 @@ static void pcache1Free(void *p){
assert( pcache1.nFreeSlot<=pcache1.nSlot );
sqlite3_mutex_leave(pcache1.mutex);
}else{
- int iSize;
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
- iSize = sqlite3MallocSize(p);
+ nFreed = sqlite3MallocSize(p);
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
+ sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -nFreed);
sqlite3_mutex_leave(pcache1.mutex);
sqlite3_free(p);
}
+ return nFreed;
}
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
@@ -36088,7 +37263,6 @@ static int pcache1MemSize(void *p){
** Allocate a new page object initially associated with cache pCache.
*/
static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
- int nByte = sizeof(PgHdr1) + pCache->szPage;
PgHdr1 *p = 0;
void *pPg;
@@ -36097,16 +37271,29 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
** this mutex is not held. */
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
pcache1LeaveMutex(pCache->pGroup);
- pPg = pcache1Alloc(nByte);
+#ifdef SQLITE_PCACHE_SEPARATE_HEADER
+ pPg = pcache1Alloc(pCache->szPage);
+ p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
+ if( !pPg || !p ){
+ pcache1Free(pPg);
+ sqlite3_free(p);
+ pPg = 0;
+ }
+#else
+ pPg = pcache1Alloc(sizeof(PgHdr1) + pCache->szPage + pCache->szExtra);
+ p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
+#endif
pcache1EnterMutex(pCache->pGroup);
if( pPg ){
- p = PAGE_TO_PGHDR1(pCache, pPg);
+ p->page.pBuf = pPg;
+ p->page.pExtra = &p[1];
if( pCache->bPurgeable ){
pCache->pGroup->nCurrentPage++;
}
+ return p;
}
- return p;
+ return 0;
}
/*
@@ -36120,7 +37307,10 @@ static void pcache1FreePage(PgHdr1 *p){
if( ALWAYS(p) ){
PCache1 *pCache = p->pCache;
assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
- pcache1Free(PGHDR1_TO_PAGE(p));
+ pcache1Free(p->page.pBuf);
+#ifdef SQLITE_PCACHE_SEPARATE_HEADER
+ sqlite3_free(p);
+#endif
if( pCache->bPurgeable ){
pCache->pGroup->nCurrentPage--;
}
@@ -36155,13 +37345,13 @@ SQLITE_PRIVATE void sqlite3PageFree(void *p){
** for all page cache needs and we should not need to spill the
** allocation onto the heap.
**
-** Or, the heap is used for all page cache memory put the heap is
+** Or, the heap is used for all page cache memory but the heap is
** under memory pressure, then again it is desirable to avoid
** allocating a new page cache entry in order to avoid stressing
** the heap even further.
*/
static int pcache1UnderMemoryPressure(PCache1 *pCache){
- if( pcache1.nSlot && pCache->szPage<=pcache1.szSlot ){
+ if( pcache1.nSlot && (pCache->szPage+pCache->szExtra)<=pcache1.szSlot ){
return pcache1.bUnderPressure;
}else{
return sqlite3HeapNearlyFull();
@@ -36352,7 +37542,7 @@ static void pcache1Shutdown(void *NotUsed){
**
** Allocate a new cache.
*/
-static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
+static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
PCache1 *pCache; /* The newly created page cache */
PGroup *pGroup; /* The group the new page cache will belong to */
int sz; /* Bytes of memory required to allocate the new cache */
@@ -36375,6 +37565,9 @@ static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
int separateCache = sqlite3GlobalConfig.bCoreMutex>0;
#endif
+ assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
+ assert( szExtra < 300 );
+
sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
pCache = (PCache1 *)sqlite3_malloc(sz);
if( pCache ){
@@ -36387,6 +37580,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
}
pCache->pGroup = pGroup;
pCache->szPage = szPage;
+ pCache->szExtra = szExtra;
pCache->bPurgeable = (bPurgeable ? 1 : 0);
if( bPurgeable ){
pCache->nMin = 10;
@@ -36419,6 +37613,25 @@ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
}
/*
+** Implementation of the sqlite3_pcache.xShrink method.
+**
+** Free up as much memory as possible.
+*/
+static void pcache1Shrink(sqlite3_pcache *p){
+ PCache1 *pCache = (PCache1*)p;
+ if( pCache->bPurgeable ){
+ PGroup *pGroup = pCache->pGroup;
+ int savedMaxPage;
+ pcache1EnterMutex(pGroup);
+ savedMaxPage = pGroup->nMaxPage;
+ pGroup->nMaxPage = 0;
+ pcache1EnforceMaxPage(pGroup);
+ pGroup->nMaxPage = savedMaxPage;
+ pcache1LeaveMutex(pGroup);
+ }
+}
+
+/*
** Implementation of the sqlite3_pcache.xPagecount method.
*/
static int pcache1Pagecount(sqlite3_pcache *p){
@@ -36443,7 +37656,7 @@ static int pcache1Pagecount(sqlite3_pcache *p){
** For a non-purgeable cache (a cache used as the storage for an in-memory
** database) there is really no difference between createFlag 1 and 2. So
** the calling function (pcache.c) will never have a createFlag of 1 on
-** a non-purgable cache.
+** a non-purgeable cache.
**
** There are three different approaches to obtaining space for a page,
** depending on the value of parameter createFlag (which may be 0, 1 or 2).
@@ -36484,8 +37697,12 @@ static int pcache1Pagecount(sqlite3_pcache *p){
**
** 5. Otherwise, allocate and return a new page buffer.
*/
-static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
- int nPinned;
+static sqlite3_pcache_page *pcache1Fetch(
+ sqlite3_pcache *p,
+ unsigned int iKey,
+ int createFlag
+){
+ unsigned int nPinned;
PCache1 *pCache = (PCache1 *)p;
PGroup *pGroup;
PgHdr1 *pPage = 0;
@@ -36519,15 +37736,14 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
pGroup = pCache->pGroup;
#endif
-
/* Step 3: Abort if createFlag is 1 but the cache is nearly full */
+ assert( pCache->nPage >= pCache->nRecyclable );
nPinned = pCache->nPage - pCache->nRecyclable;
- assert( nPinned>=0 );
assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
assert( pCache->n90pct == pCache->nMax*9/10 );
if( createFlag==1 && (
nPinned>=pGroup->mxPinned
- || nPinned>=(int)pCache->n90pct
+ || nPinned>=pCache->n90pct
|| pcache1UnderMemoryPressure(pCache)
)){
goto fetch_out;
@@ -36543,16 +37759,24 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
|| pGroup->nCurrentPage>=pGroup->nMaxPage
|| pcache1UnderMemoryPressure(pCache)
)){
- PCache1 *pOtherCache;
+ PCache1 *pOther;
pPage = pGroup->pLruTail;
pcache1RemoveFromHash(pPage);
pcache1PinPage(pPage);
- if( (pOtherCache = pPage->pCache)->szPage!=pCache->szPage ){
+ pOther = pPage->pCache;
+
+ /* We want to verify that szPage and szExtra are the same for pOther
+ ** and pCache. Assert that we can verify this by comparing sums. */
+ assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
+ assert( pCache->szExtra<512 );
+ assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
+ assert( pOther->szExtra<512 );
+
+ if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
pcache1FreePage(pPage);
pPage = 0;
}else{
- pGroup->nCurrentPage -=
- (pOtherCache->bPurgeable - pCache->bPurgeable);
+ pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
}
}
@@ -36573,7 +37797,7 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
pPage->pCache = pCache;
pPage->pLruPrev = 0;
pPage->pLruNext = 0;
- *(void **)(PGHDR1_TO_PAGE(pPage)) = 0;
+ *(void **)pPage->page.pExtra = 0;
pCache->apHash[h] = pPage;
}
@@ -36582,7 +37806,7 @@ fetch_out:
pCache->iMaxKey = iKey;
}
pcache1LeaveMutex(pGroup);
- return (pPage ? PGHDR1_TO_PAGE(pPage) : 0);
+ return &pPage->page;
}
@@ -36591,9 +37815,13 @@ fetch_out:
**
** Mark a page as unpinned (eligible for asynchronous recycling).
*/
-static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
+static void pcache1Unpin(
+ sqlite3_pcache *p,
+ sqlite3_pcache_page *pPg,
+ int reuseUnlikely
+){
PCache1 *pCache = (PCache1 *)p;
- PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
+ PgHdr1 *pPage = (PgHdr1 *)pPg;
PGroup *pGroup = pCache->pGroup;
assert( pPage->pCache==pCache );
@@ -36629,12 +37857,12 @@ static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
*/
static void pcache1Rekey(
sqlite3_pcache *p,
- void *pPg,
+ sqlite3_pcache_page *pPg,
unsigned int iOld,
unsigned int iNew
){
PCache1 *pCache = (PCache1 *)p;
- PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
+ PgHdr1 *pPage = (PgHdr1 *)pPg;
PgHdr1 **pp;
unsigned int h;
assert( pPage->iKey==iOld );
@@ -36688,7 +37916,9 @@ static void pcache1Destroy(sqlite3_pcache *p){
assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) );
pcache1EnterMutex(pGroup);
pcache1TruncateUnsafe(pCache, 0);
+ assert( pGroup->nMaxPage >= pCache->nMax );
pGroup->nMaxPage -= pCache->nMax;
+ assert( pGroup->nMinPage >= pCache->nMin );
pGroup->nMinPage -= pCache->nMin;
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
pcache1EnforceMaxPage(pGroup);
@@ -36703,7 +37933,8 @@ static void pcache1Destroy(sqlite3_pcache *p){
** already provided an alternative.
*/
SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
- static const sqlite3_pcache_methods defaultMethods = {
+ static const sqlite3_pcache_methods2 defaultMethods = {
+ 1, /* iVersion */
0, /* pArg */
pcache1Init, /* xInit */
pcache1Shutdown, /* xShutdown */
@@ -36714,9 +37945,10 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
pcache1Unpin, /* xUnpin */
pcache1Rekey, /* xRekey */
pcache1Truncate, /* xTruncate */
- pcache1Destroy /* xDestroy */
+ pcache1Destroy, /* xDestroy */
+ pcache1Shrink /* xShrink */
};
- sqlite3_config(SQLITE_CONFIG_PCACHE, &defaultMethods);
+ sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods);
}
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
@@ -36737,7 +37969,10 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
PgHdr1 *p;
pcache1EnterMutex(&pcache1.grp);
while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
- nFree += pcache1MemSize(PGHDR1_TO_PAGE(p));
+ nFree += pcache1MemSize(p->page.pBuf);
+#ifdef SQLITE_PCACHE_SEPARATE_HEADER
+ nFree += sqlite3MemSize(p);
+#endif
pcache1PinPage(p);
pcache1RemoveFromHash(p);
pcache1FreePage(p);
@@ -36765,8 +38000,8 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
nRecyclable++;
}
*pnCurrent = pcache1.grp.nCurrentPage;
- *pnMax = pcache1.grp.nMaxPage;
- *pnMin = pcache1.grp.nMinPage;
+ *pnMax = (int)pcache1.grp.nMaxPage;
+ *pnMin = (int)pcache1.grp.nMinPage;
*pnRecyclable = nRecyclable;
}
#endif
@@ -36850,6 +38085,11 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
/*
** Each entry in a RowSet is an instance of the following object.
+**
+** This same object is reused to store a linked list of trees of RowSetEntry
+** objects. In that alternative use, pRight points to the next entry
+** in the list, pLeft points to the tree, and v is unused. The
+** RowSet.pForest value points to the head of this forest list.
*/
struct RowSetEntry {
i64 v; /* ROWID value for this entry */
@@ -36879,13 +38119,19 @@ struct RowSet {
struct RowSetEntry *pEntry; /* List of entries using pRight */
struct RowSetEntry *pLast; /* Last entry on the pEntry list */
struct RowSetEntry *pFresh; /* Source of new entry objects */
- struct RowSetEntry *pTree; /* Binary tree of entries */
+ struct RowSetEntry *pForest; /* List of binary trees of entries */
u16 nFresh; /* Number of objects on pFresh */
- u8 isSorted; /* True if pEntry is sorted */
+ u8 rsFlags; /* Various flags */
u8 iBatch; /* Current insert batch */
};
/*
+** Allowed values for RowSet.rsFlags
+*/
+#define ROWSET_SORTED 0x01 /* True if RowSet.pEntry is sorted */
+#define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */
+
+/*
** Turn bulk memory into a RowSet object. N bytes of memory
** are available at pSpace. The db pointer is used as a memory context
** for any subsequent allocations that need to occur.
@@ -36905,10 +38151,10 @@ SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int
p->db = db;
p->pEntry = 0;
p->pLast = 0;
- p->pTree = 0;
+ p->pForest = 0;
p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
- p->isSorted = 1;
+ p->rsFlags = ROWSET_SORTED;
p->iBatch = 0;
return p;
}
@@ -36928,43 +38174,59 @@ SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){
p->nFresh = 0;
p->pEntry = 0;
p->pLast = 0;
- p->pTree = 0;
- p->isSorted = 1;
+ p->pForest = 0;
+ p->rsFlags = ROWSET_SORTED;
}
/*
-** Insert a new value into a RowSet.
+** Allocate a new RowSetEntry object that is associated with the
+** given RowSet. Return a pointer to the new and completely uninitialized
+** objected.
**
-** The mallocFailed flag of the database connection is set if a
-** memory allocation fails.
+** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
+** routine returns NULL.
*/
-SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
- struct RowSetEntry *pEntry; /* The new entry */
- struct RowSetEntry *pLast; /* The last prior entry */
+static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
assert( p!=0 );
if( p->nFresh==0 ){
struct RowSetChunk *pNew;
pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew));
if( pNew==0 ){
- return;
+ return 0;
}
pNew->pNextChunk = p->pChunk;
p->pChunk = pNew;
p->pFresh = pNew->aEntry;
p->nFresh = ROWSET_ENTRY_PER_CHUNK;
}
- pEntry = p->pFresh++;
p->nFresh--;
+ return p->pFresh++;
+}
+
+/*
+** Insert a new value into a RowSet.
+**
+** The mallocFailed flag of the database connection is set if a
+** memory allocation fails.
+*/
+SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
+ struct RowSetEntry *pEntry; /* The new entry */
+ struct RowSetEntry *pLast; /* The last prior entry */
+
+ /* This routine is never called after sqlite3RowSetNext() */
+ assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
+
+ pEntry = rowSetEntryAlloc(p);
+ if( pEntry==0 ) return;
pEntry->v = rowid;
pEntry->pRight = 0;
pLast = p->pLast;
if( pLast ){
- if( p->isSorted && rowid<=pLast->v ){
- p->isSorted = 0;
+ if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){
+ p->rsFlags &= ~ROWSET_SORTED;
}
pLast->pRight = pEntry;
}else{
- assert( p->pEntry==0 ); /* Fires if INSERT after SMALLEST */
p->pEntry = pEntry;
}
p->pLast = pEntry;
@@ -36976,7 +38238,7 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
** The input lists are connected via pRight pointers and are
** assumed to each already be in sorted order.
*/
-static struct RowSetEntry *rowSetMerge(
+static struct RowSetEntry *rowSetEntryMerge(
struct RowSetEntry *pA, /* First sorted list to be merged */
struct RowSetEntry *pB /* Second sorted list to be merged */
){
@@ -37010,32 +38272,29 @@ static struct RowSetEntry *rowSetMerge(
}
/*
-** Sort all elements on the pEntry list of the RowSet into ascending order.
+** Sort all elements on the list of RowSetEntry objects into order of
+** increasing v.
*/
-static void rowSetSort(RowSet *p){
+static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){
unsigned int i;
- struct RowSetEntry *pEntry;
- struct RowSetEntry *aBucket[40];
+ struct RowSetEntry *pNext, *aBucket[40];
- assert( p->isSorted==0 );
memset(aBucket, 0, sizeof(aBucket));
- while( p->pEntry ){
- pEntry = p->pEntry;
- p->pEntry = pEntry->pRight;
- pEntry->pRight = 0;
+ while( pIn ){
+ pNext = pIn->pRight;
+ pIn->pRight = 0;
for(i=0; aBucket[i]; i++){
- pEntry = rowSetMerge(aBucket[i], pEntry);
+ pIn = rowSetEntryMerge(aBucket[i], pIn);
aBucket[i] = 0;
}
- aBucket[i] = pEntry;
+ aBucket[i] = pIn;
+ pIn = pNext;
}
- pEntry = 0;
+ pIn = 0;
for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
- pEntry = rowSetMerge(pEntry, aBucket[i]);
+ pIn = rowSetEntryMerge(pIn, aBucket[i]);
}
- p->pEntry = pEntry;
- p->pLast = 0;
- p->isSorted = 1;
+ return pIn;
}
@@ -37129,20 +38388,37 @@ static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){
}
/*
-** Convert the list in p->pEntry into a sorted list if it is not
-** sorted already. If there is a binary tree on p->pTree, then
-** convert it into a list too and merge it into the p->pEntry list.
+** 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){
- if( !p->isSorted ){
- rowSetSort(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);
}
- if( p->pTree ){
- struct RowSetEntry *pHead, *pTail;
- rowSetTreeToList(p->pTree, &pHead, &pTail);
- p->pTree = 0;
- p->pEntry = rowSetMerge(p->pEntry, pHead);
+
+ /* 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 */
}
/*
@@ -37154,7 +38430,12 @@ static void rowSetToList(RowSet *p){
** routine may not be called again.
*/
SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
- rowSetToList(p);
+ assert( p!=0 );
+
+ /* Merge the forest into a single sorted list on first call */
+ if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p);
+
+ /* Return the next entry on the list */
if( p->pEntry ){
*pRowid = p->pEntry->v;
p->pEntry = p->pEntry->pRight;
@@ -37170,26 +38451,66 @@ SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
/*
** Check to see if element iRowid was inserted into the the rowset as
** part of any insert batch prior to iBatch. Return 1 or 0.
+**
+** If this is the first test of a new batch and if there exist entires
+** on pRowSet->pEntry, then sort those entires into the forest at
+** pRowSet->pForest so that they can be tested.
*/
SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){
- struct RowSetEntry *p;
+ struct RowSetEntry *p, *pTree;
+
+ /* This routine is never called after sqlite3RowSetNext() */
+ assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
+
+ /* Sort entries into the forest on the first test of a new batch
+ */
if( iBatch!=pRowSet->iBatch ){
- if( pRowSet->pEntry ){
- rowSetToList(pRowSet);
- pRowSet->pTree = rowSetListToTree(pRowSet->pEntry);
+ p = pRowSet->pEntry;
+ if( p ){
+ struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
+ if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){
+ p = rowSetEntrySort(p);
+ }
+ for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
+ ppPrevTree = &pTree->pRight;
+ if( pTree->pLeft==0 ){
+ pTree->pLeft = rowSetListToTree(p);
+ break;
+ }else{
+ struct RowSetEntry *pAux, *pTail;
+ rowSetTreeToList(pTree->pLeft, &pAux, &pTail);
+ pTree->pLeft = 0;
+ p = rowSetEntryMerge(pAux, p);
+ }
+ }
+ if( pTree==0 ){
+ *ppPrevTree = pTree = rowSetEntryAlloc(pRowSet);
+ if( pTree ){
+ pTree->v = 0;
+ pTree->pRight = 0;
+ pTree->pLeft = rowSetListToTree(p);
+ }
+ }
pRowSet->pEntry = 0;
pRowSet->pLast = 0;
+ pRowSet->rsFlags |= ROWSET_SORTED;
}
pRowSet->iBatch = iBatch;
}
- p = pRowSet->pTree;
- while( p ){
- if( p->v<iRowid ){
- p = p->pRight;
- }else if( p->v>iRowid ){
- p = p->pLeft;
- }else{
- return 1;
+
+ /* Test to see if the iRowid value appears anywhere in the forest.
+ ** Return 1 if it does and 0 if not.
+ */
+ for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
+ p = pTree->pLeft;
+ while( p ){
+ if( p->v<iRowid ){
+ p = p->pRight;
+ }else if( p->v>iRowid ){
+ p = p->pLeft;
+ }else{
+ return 1;
+ }
}
}
return 0;
@@ -37240,6 +38561,12 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
#define _WAL_H_
+/* Additional values that can be added to the sync_flags argument of
+** sqlite3WalFrames():
+*/
+#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */
+#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */
+
#ifdef SQLITE_OMIT_WAL
# define sqlite3WalOpen(x,y,z) 0
# define sqlite3WalLimit(x,y)
@@ -37258,6 +38585,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
# define sqlite3WalCallback(z) 0
# define sqlite3WalExclusiveMode(y,z) 0
# define sqlite3WalHeapMemory(z) 0
+# define sqlite3WalFramesize(z) 0
#else
#define WAL_SAVEPOINT_NDATA 4
@@ -37339,6 +38667,13 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op);
*/
SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
+#ifdef SQLITE_ENABLE_ZIPVFS
+/* If the WAL file is not empty, return the number of bytes of content
+** stored in each frame (i.e. the db page-size when the WAL was created).
+*/
+SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
+#endif
+
#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* _WAL_H_ */
@@ -37935,10 +39270,10 @@ struct Pager {
u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */
u8 journalMode; /* One of the PAGER_JOURNALMODE_* values */
u8 useJournal; /* Use a rollback journal on this file */
- u8 noReadlock; /* Do not bother to obtain readlocks */
u8 noSync; /* Do not sync the journal if true */
u8 fullSync; /* Do extra syncs of the journal for robustness */
u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */
+ u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */
u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */
u8 tempFile; /* zFilename is a temporary file */
u8 readOnly; /* True for a read-only database */
@@ -37993,9 +39328,9 @@ struct Pager {
char *zJournal; /* Name of the journal file */
int (*xBusyHandler)(void*); /* Function to call when busy */
void *pBusyHandlerArg; /* Context argument for xBusyHandler */
- int nHit, nMiss; /* Total cache hits and misses */
+ int aStat[3]; /* Total cache hits, misses and writes */
#ifdef SQLITE_TEST
- int nRead, nWrite; /* Database pages read/written */
+ int nRead; /* Database pages read */
#endif
void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
#ifdef SQLITE_HAS_CODEC
@@ -38013,6 +39348,15 @@ struct Pager {
};
/*
+** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains
+** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS
+** or CACHE_WRITE to sqlite3_db_status().
+*/
+#define PAGER_STAT_HIT 0
+#define PAGER_STAT_MISS 1
+#define PAGER_STAT_WRITE 2
+
+/*
** The following global variables hold counters used for
** testing purposes only. These variables do not exist in
** a non-testing build. These variables are not thread-safe.
@@ -38109,7 +39453,7 @@ static int pagerUseWal(Pager *pPager){
#else
# define pagerUseWal(x) 0
# define pagerRollbackWal(x) 0
-# define pagerWalFrames(v,w,x,y,z) 0
+# define pagerWalFrames(v,w,x,y) 0
# define pagerOpenWalIfPresent(z) SQLITE_OK
# define pagerBeginReadTransaction(z) SQLITE_OK
#endif
@@ -38182,7 +39526,7 @@ static int assert_pager_state(Pager *p){
case PAGER_READER:
assert( pPager->errCode==SQLITE_OK );
assert( p->eLock!=UNKNOWN_LOCK );
- assert( p->eLock>=SHARED_LOCK || p->noReadlock );
+ assert( p->eLock>=SHARED_LOCK );
break;
case PAGER_WRITER_LOCKED:
@@ -39808,10 +41152,9 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
if( rc==SQLITE_OK && currentSize!=newSize ){
if( currentSize>newSize ){
rc = sqlite3OsTruncate(pPager->fd, newSize);
- }else{
+ }else if( (currentSize+szPage)<=newSize ){
char *pTmp = pPager->pTmpSpace;
memset(pTmp, 0, szPage);
- testcase( (newSize-szPage) < currentSize );
testcase( (newSize-szPage) == currentSize );
testcase( (newSize-szPage) > currentSize );
rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage);
@@ -39837,23 +41180,36 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
** the value returned by the xSectorSize() method rounded up to 32 if
** it is less than 32, or rounded down to MAX_SECTOR_SIZE if it
** is greater than MAX_SECTOR_SIZE.
+**
+** If the file has the SQLITE_IOCAP_POWERSAFE_OVERWRITE property, then set
+** the effective sector size to its minimum value (512). The purpose of
+** pPager->sectorSize is to define the "blast radius" of bytes that
+** might change if a crash occurs while writing to a single byte in
+** that range. But with POWERSAFE_OVERWRITE, the blast radius is zero
+** (that is what POWERSAFE_OVERWRITE means), so we minimize the sector
+** size. For backwards compatibility of the rollback journal file format,
+** we cannot reduce the effective sector size below 512.
*/
static void setSectorSize(Pager *pPager){
assert( isOpen(pPager->fd) || pPager->tempFile );
- if( !pPager->tempFile ){
+ if( pPager->tempFile
+ || (sqlite3OsDeviceCharacteristics(pPager->fd) &
+ SQLITE_IOCAP_POWERSAFE_OVERWRITE)!=0
+ ){
/* Sector size doesn't matter for temporary files. Also, the file
** may not have been opened yet, in which case the OsSectorSize()
- ** call will segfault.
- */
- pPager->sectorSize = sqlite3OsSectorSize(pPager->fd);
- }
- if( pPager->sectorSize<32 ){
+ ** call will segfault. */
pPager->sectorSize = 512;
- }
- if( pPager->sectorSize>MAX_SECTOR_SIZE ){
- assert( MAX_SECTOR_SIZE>=512 );
- pPager->sectorSize = MAX_SECTOR_SIZE;
+ }else{
+ pPager->sectorSize = sqlite3OsSectorSize(pPager->fd);
+ if( pPager->sectorSize<32 ){
+ pPager->sectorSize = 512;
+ }
+ if( pPager->sectorSize>MAX_SECTOR_SIZE ){
+ assert( MAX_SECTOR_SIZE>=512 );
+ pPager->sectorSize = MAX_SECTOR_SIZE;
+ }
}
}
@@ -40056,10 +41412,11 @@ end_playback:
** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the
** assertion that the transaction counter was modified.
*/
- assert(
- pPager->fd->pMethods==0 ||
- sqlite3OsFileControl(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0)>=SQLITE_OK
- );
+#ifdef SQLITE_DEBUG
+ if( pPager->fd->pMethods ){
+ sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0);
+ }
+#endif
/* If this playback is happening automatically as a result of an IO or
** malloc error that occurred after the change-counter was updated but
@@ -40278,10 +41635,10 @@ static int pagerWalFrames(
Pager *pPager, /* Pager object */
PgHdr *pList, /* List of frames to log */
Pgno nTruncate, /* Database size after this commit */
- int isCommit, /* True if this is a commit */
- int syncFlags /* Flags to pass to OsSync() (or 0) */
+ int isCommit /* True if this is a commit */
){
int rc; /* Return code */
+ int nList; /* Number of pages in pList */
#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
PgHdr *p; /* For looping over pages */
#endif
@@ -40295,6 +41652,7 @@ static int pagerWalFrames(
}
#endif
+ assert( pList->pDirty==0 || isCommit );
if( isCommit ){
/* If a WAL transaction is being committed, there is no point in writing
** any pages with page numbers greater than nTruncate into the WAL file.
@@ -40302,15 +41660,22 @@ static int pagerWalFrames(
** list here. */
PgHdr *p;
PgHdr **ppNext = &pList;
- for(p=pList; (*ppNext = p); p=p->pDirty){
- if( p->pgno<=nTruncate ) ppNext = &p->pDirty;
+ nList = 0;
+ for(p=pList; (*ppNext = p)!=0; p=p->pDirty){
+ if( p->pgno<=nTruncate ){
+ ppNext = &p->pDirty;
+ nList++;
+ }
}
assert( pList );
+ }else{
+ nList = 1;
}
+ pPager->aStat[PAGER_STAT_WRITE] += nList;
if( pList->pgno==1 ) pager_write_changecounter(pList);
rc = sqlite3WalFrames(pPager->pWal,
- pPager->pageSize, pList, nTruncate, isCommit, syncFlags
+ pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags
);
if( rc==SQLITE_OK && pPager->pBackup ){
PgHdr *p;
@@ -40379,7 +41744,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
** contains no valid committed transactions.
*/
assert( pPager->eState==PAGER_OPEN );
- assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock );
+ assert( pPager->eLock>=SHARED_LOCK );
nPage = sqlite3WalDbsize(pPager->pWal);
/* If the database size was not available from the WAL sub-system,
@@ -40397,10 +41762,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
return rc;
}
}
- nPage = (Pgno)(n / pPager->pageSize);
- if( nPage==0 && n>0 ){
- nPage = 1;
- }
+ nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize);
}
/* If the current number of pages in the file is greater than the
@@ -40437,7 +41799,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
static int pagerOpenWalIfPresent(Pager *pPager){
int rc = SQLITE_OK;
assert( pPager->eState==PAGER_OPEN );
- assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock );
+ assert( pPager->eLock>=SHARED_LOCK );
if( !pPager->tempFile ){
int isWal; /* True if WAL file exists */
@@ -40590,13 +41952,13 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
*/
if( pSavepoint ){
u32 ii; /* Loop counter */
- i64 offset = pSavepoint->iSubRec*(4+pPager->pageSize);
+ i64 offset = (i64)pSavepoint->iSubRec*(4+pPager->pageSize);
if( pagerUseWal(pPager) ){
rc = sqlite3WalSavepointUndo(pPager->pWal, pSavepoint->aWalData);
}
for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && ii<pPager->nSubRec; ii++){
- assert( offset==ii*(4+pPager->pageSize) );
+ assert( offset==(i64)ii*(4+pPager->pageSize) );
rc = pager_playback_one_page(pPager, &offset, pDone, 0, 1);
}
assert( rc!=SQLITE_DONE );
@@ -40618,6 +41980,13 @@ SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
}
/*
+** Free as much memory as possible from the pager.
+*/
+SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
+ sqlite3PcacheShrink(pPager->pPCache);
+}
+
+/*
** Adjust the robustness of the database to damage due to OS crashes
** or power failures by changing the number of syncs()s when writing
** the rollback journal. There are three levels:
@@ -40683,6 +42052,10 @@ SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(
pPager->syncFlags = SQLITE_SYNC_NORMAL;
pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
}
+ pPager->walSyncFlags = pPager->syncFlags;
+ if( pPager->fullSync ){
+ pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
+ }
}
#endif
@@ -40820,7 +42193,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
if( rc==SQLITE_OK ){
pager_reset(pPager);
- pPager->dbSize = (Pgno)(nByte/pageSize);
+ pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
pPager->pageSize = pageSize;
sqlite3PageFree(pPager->pTmpSpace);
pPager->pTmpSpace = pNew;
@@ -41328,7 +42701,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
assert( rc!=SQLITE_OK || isOpen(pPager->fd) );
if( rc==SQLITE_OK && pPager->dbSize>pPager->dbHintSize ){
sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
- sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
+ sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
pPager->dbHintSize = pPager->dbSize;
}
@@ -41366,6 +42739,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno;
}
+ pPager->aStat[PAGER_STAT_WRITE]++;
/* Update any backup objects copying the contents of this pager. */
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)pList->pData);
@@ -41374,7 +42748,6 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
PAGERID(pPager), pgno, pager_pagehash(pList)));
IOTRACE(("PGOUT %p %d\n", pPager, pgno));
PAGER_INCR(sqlite3_pager_writedb_count);
- PAGER_INCR(pPager->nWrite);
}else{
PAGERTRACE(("NOSTORE %d page %d\n", PAGERID(pPager), pgno));
}
@@ -41437,7 +42810,7 @@ static int subjournalPage(PgHdr *pPg){
** write the journal record into the file. */
if( rc==SQLITE_OK ){
void *pData = pPg->pData;
- i64 offset = pPager->nSubRec*(4+pPager->pageSize);
+ i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
char *pData2;
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
@@ -41510,7 +42883,7 @@ static int pagerStress(void *p, PgHdr *pPg){
rc = subjournalPage(pPg);
}
if( rc==SQLITE_OK ){
- rc = pagerWalFrames(pPager, pPg, 0, 0, 0);
+ rc = pagerWalFrames(pPager, pPg, 0, 0);
}
}else{
@@ -41589,7 +42962,7 @@ static int pagerStress(void *p, PgHdr *pPg){
**
** The flags argument is used to specify properties that affect the
** operation of the pager. It should be passed some bitwise combination
-** of the PAGER_OMIT_JOURNAL and PAGER_NO_READLOCK flags.
+** of the PAGER_* flags.
**
** The vfsFlags parameter is a bitmask to pass to the flags parameter
** of the xOpen() method of the supplied VFS when opening files.
@@ -41620,7 +42993,6 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
char *zPathname = 0; /* Full path to database file */
int nPathname = 0; /* Number of bytes in zPathname */
int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */
- int noReadlock = (flags & PAGER_NO_READLOCK)!=0; /* True to omit read-lock */
int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */
u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */
const char *zUri = 0; /* URI args to copy */
@@ -41669,7 +43041,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
z += sqlite3Strlen30(z)+1;
z += sqlite3Strlen30(z)+1;
}
- nUri = &z[1] - zUri;
+ nUri = (int)(&z[1] - zUri);
+ assert( nUri>=0 );
if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
/* This branch is taken when the journal path required by
** the database being opened will be more than pVfs->mxPathname
@@ -41703,9 +43076,9 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
ROUND8(pVfs->szOsFile) + /* The main db file */
journalFileSize * 2 + /* The two journal files */
nPathname + 1 + nUri + /* zFilename */
- nPathname + 8 + 1 /* zJournal */
+ nPathname + 8 + 2 /* zJournal */
#ifndef SQLITE_OMIT_WAL
- + nPathname + 4 + 1 /* zWal */
+ + nPathname + 4 + 2 /* zWal */
#endif
);
assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
@@ -41728,12 +43101,12 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
memcpy(pPager->zFilename, zPathname, nPathname);
memcpy(&pPager->zFilename[nPathname+1], zUri, nUri);
memcpy(pPager->zJournal, zPathname, nPathname);
- memcpy(&pPager->zJournal[nPathname], "-journal", 8);
+ memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+1);
sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal);
#ifndef SQLITE_OMIT_WAL
pPager->zWal = &pPager->zJournal[nPathname+8+1];
memcpy(pPager->zWal, zPathname, nPathname);
- memcpy(&pPager->zWal[nPathname], "-wal", 4);
+ memcpy(&pPager->zWal[nPathname], "-wal\000", 4+1);
sqlite3FileSuffix3(pPager->zFilename, pPager->zWal);
#endif
sqlite3_free(zPathname);
@@ -41826,7 +43199,6 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename))
pPager->useJournal = (u8)useJournal;
- pPager->noReadlock = (noReadlock && readOnly) ?1:0;
/* pPager->stmtOpen = 0; */
/* pPager->stmtInUse = 0; */
/* pPager->nRef = 0; */
@@ -41849,9 +43221,17 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
pPager->readOnly = (u8)readOnly;
assert( useJournal || pPager->tempFile );
pPager->noSync = pPager->tempFile;
- pPager->fullSync = pPager->noSync ?0:1;
- pPager->syncFlags = pPager->noSync ? 0 : SQLITE_SYNC_NORMAL;
- pPager->ckptSyncFlags = pPager->syncFlags;
+ if( pPager->noSync ){
+ assert( pPager->fullSync==0 );
+ assert( pPager->syncFlags==0 );
+ assert( pPager->walSyncFlags==0 );
+ assert( pPager->ckptSyncFlags==0 );
+ }else{
+ pPager->fullSync = 1;
+ pPager->syncFlags = SQLITE_SYNC_NORMAL;
+ pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
+ pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
+ }
/* pPager->pFirst = 0; */
/* pPager->pFirstSynced = 0; */
/* pPager->pLast = 0; */
@@ -42040,14 +43420,11 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
int bHotJournal = 1; /* True if there exists a hot journal-file */
assert( !MEMDB );
- assert( pPager->noReadlock==0 || pPager->readOnly );
- if( pPager->noReadlock==0 ){
- rc = pager_wait_on_lock(pPager, SHARED_LOCK);
- if( rc!=SQLITE_OK ){
- assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
- goto failed;
- }
+ rc = pager_wait_on_lock(pPager, SHARED_LOCK);
+ if( rc!=SQLITE_OK ){
+ assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
+ goto failed;
}
/* If a journal file exists, and there is no RESERVED lock on the
@@ -42328,7 +43705,7 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
/* In this case the pcache already contains an initialized copy of
** the page. Return without further ado. */
assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
- pPager->nHit++;
+ pPager->aStat[PAGER_STAT_HIT]++;
return SQLITE_OK;
}else{
@@ -42370,7 +43747,7 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{
assert( pPg->pPager==pPager );
- pPager->nMiss++;
+ pPager->aStat[PAGER_STAT_MISS]++;
rc = readDbPage(pPg);
if( rc!=SQLITE_OK ){
goto pager_acquire_err;
@@ -42955,6 +44332,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
+ pPager->aStat[PAGER_STAT_WRITE]++;
}
if( rc==SQLITE_OK ){
pPager->changeCountDone = 1;
@@ -42984,7 +44362,10 @@ SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager){
rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
}else if( isOpen(pPager->fd) ){
assert( !MEMDB );
- sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC_OMITTED, (void *)&rc);
+ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC_OMITTED, 0);
+ if( rc==SQLITE_NOTFOUND ){
+ rc = SQLITE_OK;
+ }
}
return rc;
}
@@ -43081,9 +44462,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
}
assert( rc==SQLITE_OK );
if( ALWAYS(pList) ){
- rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1,
- (pPager->fullSync ? pPager->syncFlags : 0)
- );
+ rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1);
}
sqlite3PagerUnref(pPageOne);
if( rc==SQLITE_OK ){
@@ -43342,7 +44721,8 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
}
assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
- assert( rc==SQLITE_OK || rc==SQLITE_FULL || (rc&0xFF)==SQLITE_IOERR );
+ assert( rc==SQLITE_OK || rc==SQLITE_FULL
+ || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR );
/* If an error occurs during a ROLLBACK, we can no longer trust the pager
** cache. So call pager_error() on the way out to make any error persistent.
@@ -43396,11 +44776,11 @@ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){
a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize;
a[4] = pPager->eState;
a[5] = pPager->errCode;
- a[6] = pPager->nHit;
- a[7] = pPager->nMiss;
+ a[6] = pPager->aStat[PAGER_STAT_HIT];
+ a[7] = pPager->aStat[PAGER_STAT_MISS];
a[8] = 0; /* Used to be pPager->nOvfl */
a[9] = pPager->nRead;
- a[10] = pPager->nWrite;
+ a[10] = pPager->aStat[PAGER_STAT_WRITE];
return a;
}
#endif
@@ -43413,20 +44793,19 @@ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){
** returning.
*/
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
- int *piStat;
assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
|| eStat==SQLITE_DBSTATUS_CACHE_MISS
+ || eStat==SQLITE_DBSTATUS_CACHE_WRITE
);
- if( eStat==SQLITE_DBSTATUS_CACHE_HIT ){
- piStat = &pPager->nHit;
- }else{
- piStat = &pPager->nMiss;
- }
- *pnVal += *piStat;
+ assert( SQLITE_DBSTATUS_CACHE_HIT+1==SQLITE_DBSTATUS_CACHE_MISS );
+ assert( SQLITE_DBSTATUS_CACHE_HIT+2==SQLITE_DBSTATUS_CACHE_WRITE );
+ assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1 && PAGER_STAT_WRITE==2 );
+
+ *pnVal += pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT];
if( reset ){
- *piStat = 0;
+ pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT] = 0;
}
}
@@ -43983,6 +45362,15 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
return &pPager->pBackup;
}
+#ifndef SQLITE_OMIT_VACUUM
+/*
+** Unless this is an in-memory or temporary database, clear the pager cache.
+*/
+SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
+ if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
+}
+#endif
+
#ifndef SQLITE_OMIT_WAL
/*
** This function is called when the user invokes "PRAGMA wal_checkpoint",
@@ -44044,7 +45432,7 @@ static int pagerOpenWal(Pager *pPager){
int rc = SQLITE_OK;
assert( pPager->pWal==0 && pPager->tempFile==0 );
- assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK || pPager->noReadlock);
+ assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
/* If the pager is already in exclusive-mode, the WAL module will use
** heap-memory for the wal-index instead of the VFS shared-memory
@@ -44159,12 +45547,19 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
return rc;
}
+#ifdef SQLITE_ENABLE_ZIPVFS
/*
-** Unless this is an in-memory or temporary database, clear the pager cache.
+** A read-lock must be held on the pager when this function is called. If
+** the pager is in WAL mode and the WAL file currently contains one or more
+** frames, return the size in bytes of the page images stored within the
+** WAL frames. Otherwise, if this is not a WAL database or the WAL file
+** is empty, return 0.
*/
-SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
- if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
+SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
+ assert( pPager->eState==PAGER_READER );
+ return sqlite3WalFramesize(pPager->pWal);
}
+#endif
#ifdef SQLITE_HAS_CODEC
/*
@@ -44602,13 +45997,18 @@ struct Wal {
u32 iCallback; /* Value to pass to log callback (or 0) */
i64 mxWalSize; /* Truncate WAL to this size upon reset */
int nWiData; /* Size of array apWiData */
+ int szFirstBlock; /* Size of first block written to WAL file */
volatile u32 **apWiData; /* Pointer to wal-index content in memory */
u32 szPage; /* Database page size */
i16 readLock; /* Which read lock is being held. -1 for none */
+ u8 syncFlags; /* Flags to use to sync header writes */
u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */
u8 writeLock; /* True if in a write transaction */
u8 ckptLock; /* True if holding a checkpoint lock */
u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */
+ u8 truncateOnCommit; /* True to truncate WAL file on commit */
+ u8 syncHeader; /* Fsync the WAL header if true */
+ u8 padToSectorBoundary; /* Pad transactions out to the next sector */
WalIndexHdr hdr; /* Wal-index header for current transaction */
const char *zWalName; /* Name of WAL file */
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
@@ -45281,6 +46681,7 @@ static int walIndexRecover(Wal *pWal){
int szPage; /* Page size according to the log */
u32 magic; /* Magic value read from WAL header */
u32 version; /* Magic value read from WAL header */
+ int isValid; /* True if this frame is valid */
/* Read in the WAL header. */
rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
@@ -45339,14 +46740,14 @@ static int walIndexRecover(Wal *pWal){
for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
u32 pgno; /* Database page number for frame */
u32 nTruncate; /* dbsize field from frame header */
- int isValid; /* True if this frame is valid */
/* Read and decode the next log frame. */
+ iFrame++;
rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
if( rc!=SQLITE_OK ) break;
isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
if( !isValid ) break;
- rc = walIndexAppend(pWal, ++iFrame, pgno);
+ rc = walIndexAppend(pWal, iFrame, pgno);
if( rc!=SQLITE_OK ) break;
/* If nTruncate is non-zero, this is a commit record. */
@@ -45469,6 +46870,8 @@ SQLITE_PRIVATE int sqlite3WalOpen(
pRet->readLock = -1;
pRet->mxWalSize = mxWalSize;
pRet->zWalName = zWalName;
+ pRet->syncHeader = 1;
+ pRet->padToSectorBoundary = 1;
pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
/* Open file handle on the write-ahead log file. */
@@ -45483,6 +46886,11 @@ SQLITE_PRIVATE int sqlite3WalOpen(
sqlite3OsClose(pRet->pWalFd);
sqlite3_free(pRet);
}else{
+ int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
+ if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
+ if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
+ pRet->padToSectorBoundary = 0;
+ }
*ppWal = pRet;
WALTRACE(("WAL%d: opened\n", pRet));
}
@@ -45902,7 +47310,7 @@ static int walCheckpoint(
i64 nReq = ((i64)mxPage * szPage);
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
if( rc==SQLITE_OK && nSize<nReq ){
- sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
}
}
@@ -45970,6 +47378,24 @@ static int walCheckpoint(
}
/*
+** If the WAL file is currently larger than nMax bytes in size, truncate
+** it to exactly nMax bytes. If an error occurs while doing so, ignore it.
+*/
+static void walLimitSize(Wal *pWal, i64 nMax){
+ i64 sz;
+ int rx;
+ sqlite3BeginBenignMalloc();
+ rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
+ if( rx==SQLITE_OK && (sz > nMax ) ){
+ rx = sqlite3OsTruncate(pWal->pWalFd, nMax);
+ }
+ sqlite3EndBenignMalloc();
+ if( rx ){
+ sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
+ }
+}
+
+/*
** Close a connection to a log file.
*/
SQLITE_PRIVATE int sqlite3WalClose(
@@ -45992,23 +47418,40 @@ SQLITE_PRIVATE int sqlite3WalClose(
*/
rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
if( rc==SQLITE_OK ){
- int bPersistWal = -1;
if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
}
rc = sqlite3WalCheckpoint(
pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
);
- sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersistWal);
- if( rc==SQLITE_OK && bPersistWal!=1 ){
- isDelete = 1;
+ if( rc==SQLITE_OK ){
+ int bPersist = -1;
+ sqlite3OsFileControlHint(
+ pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist
+ );
+ if( bPersist!=1 ){
+ /* Try to delete the WAL file if the checkpoint completed and
+ ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
+ ** mode (!bPersist) */
+ isDelete = 1;
+ }else if( pWal->mxWalSize>=0 ){
+ /* Try to truncate the WAL file to zero bytes if the checkpoint
+ ** completed and fsynced (rc==SQLITE_OK) and we are in persistent
+ ** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a
+ ** non-negative value (pWal->mxWalSize>=0). Note that we truncate
+ ** to zero bytes as truncating to the journal_size_limit might
+ ** leave a corrupt WAL file on disk. */
+ walLimitSize(pWal, 0);
+ }
}
}
walIndexClose(pWal, isDelete);
sqlite3OsClose(pWal->pWalFd);
if( isDelete ){
+ sqlite3BeginBenignMalloc();
sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
+ sqlite3EndBenignMalloc();
}
WALTRACE(("WAL%p: closed\n", pWal));
sqlite3_free((void *)pWal->apWiData);
@@ -46498,7 +47941,7 @@ SQLITE_PRIVATE int sqlite3WalRead(
for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
u32 iFrame = aHash[iKey] + iZero;
if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
- assert( iFrame>iRead );
+ /* assert( iFrame>iRead ); -- not true if there is corruption */
iRead = iFrame;
}
if( (nCollide--)==0 ){
@@ -46537,7 +47980,7 @@ SQLITE_PRIVATE int sqlite3WalRead(
iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
*pInWal = 1;
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
- return sqlite3OsRead(pWal->pWalFd, pOut, nOut, iOffset);
+ return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
}
*pInWal = 0;
@@ -46610,6 +48053,7 @@ SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
if( pWal->writeLock ){
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
pWal->writeLock = 0;
+ pWal->truncateOnCommit = 0;
}
return SQLITE_OK;
}
@@ -46706,6 +48150,7 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
return rc;
}
+
/*
** This function is called just before writing a set of frames to the log
** file (see sqlite3WalFrames()). It checks to see if, instead of appending
@@ -46743,23 +48188,6 @@ static int walRestartLog(Wal *pWal){
int i; /* Loop counter */
u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
- /* Limit the size of WAL file if the journal_size_limit PRAGMA is
- ** set to a non-negative value. Log errors encountered
- ** during the truncation attempt. */
- if( pWal->mxWalSize>=0 ){
- i64 sz;
- int rx;
- sqlite3BeginBenignMalloc();
- rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
- if( rx==SQLITE_OK && (sz > pWal->mxWalSize) ){
- rx = sqlite3OsTruncate(pWal->pWalFd, pWal->mxWalSize);
- }
- sqlite3EndBenignMalloc();
- if( rx ){
- sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
- }
- }
-
pWal->nCkpt++;
pWal->hdr.mxFrame = 0;
sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
@@ -46788,6 +48216,74 @@ static int walRestartLog(Wal *pWal){
return rc;
}
+/*
+** Information about the current state of the WAL file and where
+** the next fsync should occur - passed from sqlite3WalFrames() into
+** walWriteToLog().
+*/
+typedef struct WalWriter {
+ Wal *pWal; /* The complete WAL information */
+ sqlite3_file *pFd; /* The WAL file to which we write */
+ sqlite3_int64 iSyncPoint; /* Fsync at this offset */
+ int syncFlags; /* Flags for the fsync */
+ int szPage; /* Size of one page */
+} WalWriter;
+
+/*
+** Write iAmt bytes of content into the WAL file beginning at iOffset.
+** Do a sync when crossing the p->iSyncPoint boundary.
+**
+** In other words, if iSyncPoint is in between iOffset and iOffset+iAmt,
+** first write the part before iSyncPoint, then sync, then write the
+** rest.
+*/
+static int walWriteToLog(
+ WalWriter *p, /* WAL to write to */
+ void *pContent, /* Content to be written */
+ int iAmt, /* Number of bytes to write */
+ sqlite3_int64 iOffset /* Start writing at this offset */
+){
+ int rc;
+ if( iOffset<p->iSyncPoint && iOffset+iAmt>=p->iSyncPoint ){
+ int iFirstAmt = (int)(p->iSyncPoint - iOffset);
+ rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset);
+ if( rc ) return rc;
+ iOffset += iFirstAmt;
+ iAmt -= iFirstAmt;
+ pContent = (void*)(iFirstAmt + (char*)pContent);
+ assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
+ rc = sqlite3OsSync(p->pFd, p->syncFlags);
+ if( iAmt==0 || rc ) return rc;
+ }
+ rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
+ return rc;
+}
+
+/*
+** Write out a single frame of the WAL
+*/
+static int walWriteOneFrame(
+ WalWriter *p, /* Where to write the frame */
+ PgHdr *pPage, /* The page of the frame to be written */
+ int nTruncate, /* The commit flag. Usually 0. >0 for commit */
+ sqlite3_int64 iOffset /* Byte offset at which to write */
+){
+ int rc; /* Result code from subfunctions */
+ void *pData; /* Data actually written */
+ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
+#if defined(SQLITE_HAS_CODEC)
+ if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
+#else
+ pData = pPage->pData;
+#endif
+ walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
+ rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
+ if( rc ) return rc;
+ /* Write the page data */
+ rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
+ return rc;
+}
+
/*
** Write a set of frames to the log. The caller must hold the write-lock
** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
@@ -46802,14 +48298,20 @@ SQLITE_PRIVATE int sqlite3WalFrames(
){
int rc; /* Used to catch return codes */
u32 iFrame; /* Next frame address */
- u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
PgHdr *p; /* Iterator to run through pList with. */
PgHdr *pLast = 0; /* Last frame in list */
- int nLast = 0; /* Number of extra copies of last page */
+ int nExtra = 0; /* Number of extra copies of last page */
+ int szFrame; /* The size of a single frame */
+ i64 iOffset; /* Next byte to write in WAL file */
+ WalWriter w; /* The writer */
assert( pList );
assert( pWal->writeLock );
+ /* If this frame set completes a transaction, then nTruncate>0. If
+ ** nTruncate==0 then this frame set does not complete the transaction. */
+ assert( (isCommit!=0)==(nTruncate!=0) );
+
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
{ int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
@@ -46837,7 +48339,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
sqlite3Put4byte(&aWalHdr[8], szPage);
sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
- sqlite3_randomness(8, pWal->hdr.aSalt);
+ if( pWal->nCkpt==0 ) sqlite3_randomness(8, pWal->hdr.aSalt);
memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
@@ -46847,77 +48349,89 @@ SQLITE_PRIVATE int sqlite3WalFrames(
pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
pWal->hdr.aFrameCksum[0] = aCksum[0];
pWal->hdr.aFrameCksum[1] = aCksum[1];
+ pWal->truncateOnCommit = 1;
rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok"));
if( rc!=SQLITE_OK ){
return rc;
}
+
+ /* Sync the header (unless SQLITE_IOCAP_SEQUENTIAL is true or unless
+ ** all syncing is turned off by PRAGMA synchronous=OFF). Otherwise
+ ** an out-of-order write following a WAL restart could result in
+ ** database corruption. See the ticket:
+ **
+ ** http://localhost:591/sqlite/info/ff5be73dee
+ */
+ if( pWal->syncHeader && sync_flags ){
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
+ if( rc ) return rc;
+ }
}
assert( (int)pWal->szPage==szPage );
- /* Write the log file. */
- for(p=pList; p; p=p->pDirty){
- u32 nDbsize; /* Db-size field for frame header */
- i64 iOffset; /* Write offset in log file */
- void *pData;
-
- iOffset = walFrameOffset(++iFrame, szPage);
- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
-
- /* Populate and write the frame header */
- nDbsize = (isCommit && p->pDirty==0) ? nTruncate : 0;
-#if defined(SQLITE_HAS_CODEC)
- if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
-#else
- pData = p->pData;
-#endif
- walEncodeFrame(pWal, p->pgno, nDbsize, pData, aFrame);
- rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
- if( rc!=SQLITE_OK ){
- return rc;
- }
+ /* Setup information needed to write frames into the WAL */
+ w.pWal = pWal;
+ w.pFd = pWal->pWalFd;
+ w.iSyncPoint = 0;
+ w.syncFlags = sync_flags;
+ w.szPage = szPage;
+ iOffset = walFrameOffset(iFrame+1, szPage);
+ szFrame = szPage + WAL_FRAME_HDRSIZE;
- /* Write the page data */
- rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset+sizeof(aFrame));
- if( rc!=SQLITE_OK ){
- return rc;
- }
+ /* Write all frames into the log file exactly once */
+ for(p=pList; p; p=p->pDirty){
+ int nDbSize; /* 0 normally. Positive == commit flag */
+ iFrame++;
+ assert( iOffset==walFrameOffset(iFrame, szPage) );
+ nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
+ rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
+ if( rc ) return rc;
pLast = p;
+ iOffset += szFrame;
}
- /* Sync the log file if the 'isSync' flag was specified. */
- if( sync_flags ){
- i64 iSegment = sqlite3OsSectorSize(pWal->pWalFd);
- i64 iOffset = walFrameOffset(iFrame+1, szPage);
-
- assert( isCommit );
- assert( iSegment>0 );
-
- iSegment = (((iOffset+iSegment-1)/iSegment) * iSegment);
- while( iOffset<iSegment ){
- void *pData;
-#if defined(SQLITE_HAS_CODEC)
- if( (pData = sqlite3PagerCodec(pLast))==0 ) return SQLITE_NOMEM;
-#else
- pData = pLast->pData;
-#endif
- walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
- rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- iOffset += WAL_FRAME_HDRSIZE;
- rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset);
- if( rc!=SQLITE_OK ){
- return rc;
+ /* If this is the end of a transaction, then we might need to pad
+ ** the transaction and/or sync the WAL file.
+ **
+ ** Padding and syncing only occur if this set of frames complete a
+ ** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL
+ ** or synchonous==OFF, then no padding or syncing are needed.
+ **
+ ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not
+ ** needed and only the sync is done. If padding is needed, then the
+ ** final frame is repeated (with its commit mark) until the next sector
+ ** boundary is crossed. Only the part of the WAL prior to the last
+ ** sector boundary is synced; the part of the last frame that extends
+ ** past the sector boundary is written after the sync.
+ */
+ if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
+ if( pWal->padToSectorBoundary ){
+ int sectorSize = sqlite3OsSectorSize(pWal->pWalFd);
+ w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
+ while( iOffset<w.iSyncPoint ){
+ rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
+ if( rc ) return rc;
+ iOffset += szFrame;
+ nExtra++;
}
- nLast++;
- iOffset += szPage;
+ }else{
+ rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
}
+ }
- rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+ /* If this frame set completes the first transaction in the WAL and
+ ** if PRAGMA journal_size_limit is set, then truncate the WAL to the
+ ** journal size limit, if possible.
+ */
+ if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){
+ i64 sz = pWal->mxWalSize;
+ if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){
+ sz = walFrameOffset(iFrame+nExtra+1, szPage);
+ }
+ walLimitSize(pWal, sz);
+ pWal->truncateOnCommit = 0;
}
/* Append data to the wal-index. It is not necessary to lock the
@@ -46930,9 +48444,9 @@ SQLITE_PRIVATE int sqlite3WalFrames(
iFrame++;
rc = walIndexAppend(pWal, iFrame, p->pgno);
}
- while( nLast>0 && rc==SQLITE_OK ){
+ while( rc==SQLITE_OK && nExtra>0 ){
iFrame++;
- nLast--;
+ nExtra--;
rc = walIndexAppend(pWal, iFrame, pLast->pgno);
}
@@ -47137,6 +48651,18 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
}
+#ifdef SQLITE_ENABLE_ZIPVFS
+/*
+** If the argument is not NULL, it points to a Wal object that holds a
+** read-lock. This function returns the database page-size if it is known,
+** or zero if it is not (or if pWal is NULL).
+*/
+SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
+ assert( pWal==0 || pWal->readLock>=0 );
+ return (pWal ? pWal->szPage : 0);
+}
+#endif
+
#endif /* #ifndef SQLITE_OMIT_WAL */
/************** End of wal.c *************************************************/
@@ -47438,18 +48964,20 @@ struct MemPage {
u8 hasData; /* True if this page stores data */
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
+ u8 max1bytePayload; /* min(maxLocal,127) */
u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
u16 cellOffset; /* Index in aData of first cell pointer */
u16 nFree; /* Number of free bytes on the page */
u16 nCell; /* Number of cells on this page, local and ovfl */
u16 maskPage; /* Mask for page offset */
- struct _OvflCell { /* Cells that will not fit on aData[] */
- u8 *pCell; /* Pointers to the body of the overflow cell */
- u16 idx; /* Insert this cell before idx-th non-overflow cell */
- } aOvfl[5];
+ u16 aiOvfl[5]; /* Insert the i-th overflow cell before the aiOvfl-th
+ ** non-overflow cell */
+ u8 *apOvfl[5]; /* Pointers to the body of overflow cells */
BtShared *pBt; /* Pointer to BtShared that this page is part of */
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 */
DbPage *pDbPage; /* Pager page handle */
Pgno pgno; /* Page number for this page */
};
@@ -47529,7 +49057,7 @@ struct Btree {
/*
** An instance of this object represents a single database file.
**
-** A single database file can be in use as the same time by two
+** A single database file can be in use at the same time by two
** or more database connections. When two or more connections are
** sharing the same database file, each connection has it own
** private Btree object for the file and each of those Btrees points
@@ -47566,17 +49094,14 @@ struct BtShared {
sqlite3 *db; /* Database connection currently using this Btree */
BtCursor *pCursor; /* A list of all open cursors */
MemPage *pPage1; /* First page of the database */
- u8 readOnly; /* True if the underlying file is readonly */
- u8 pageSizeFixed; /* True if the page size can no longer be changed */
- u8 secureDelete; /* True if secure_delete is enabled */
- u8 initiallyEmpty; /* Database is empty at start of transaction */
u8 openFlags; /* Flags to sqlite3BtreeOpen() */
#ifndef SQLITE_OMIT_AUTOVACUUM
u8 autoVacuum; /* True if auto-vacuum is enabled */
u8 incrVacuum; /* True if incr-vacuum is enabled */
#endif
u8 inTransaction; /* Transaction state */
- u8 doNotUseWAL; /* If true, do not open write-ahead-log file */
+ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
+ u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
@@ -47594,13 +49119,22 @@ struct BtShared {
BtShared *pNext; /* Next on a list of sharable BtShared structs */
BtLock *pLock; /* List of locks held on this shared-btree struct */
Btree *pWriter; /* Btree with currently open write transaction */
- u8 isExclusive; /* True if pWriter has an EXCLUSIVE lock on the db */
- u8 isPending; /* If waiting for read-locks to clear */
#endif
u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
};
/*
+** Allowed values for BtShared.btsFlags
+*/
+#define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */
+#define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */
+#define BTS_SECURE_DELETE 0x0004 /* PRAGMA secure_delete is enabled */
+#define BTS_INITIALLY_EMPTY 0x0008 /* Database was empty at trans start */
+#define BTS_NO_WAL 0x0010 /* Do not open write-ahead-log files */
+#define BTS_EXCLUSIVE 0x0020 /* pWriter has an exclusive lock */
+#define BTS_PENDING 0x0040 /* Waiting for read-locks to clear */
+
+/*
** An instance of the following structure is used to hold information
** about a cell. The parseCellPtr() function fills in this structure
** based on information extract from the raw disk page.
@@ -47635,7 +49169,7 @@ struct CellInfo {
** The entry is identified by its MemPage and the index in
** MemPage.aCell[] of the entry.
**
-** A single database file can shared by two more database connections,
+** A single database file can be shared by two more database connections,
** but cursors cannot be shared. Each cursor is associated with a
** particular database connection identified BtCursor.pBtree.db.
**
@@ -47647,6 +49181,9 @@ struct BtCursor {
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
+#ifndef SQLITE_OMIT_INCRBLOB
+ Pgno *aOverflow; /* Cache of overflow page locations */
+#endif
Pgno pgnoRoot; /* The root page of this tree */
sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */
CellInfo info; /* A parse of the cell we are pointing at */
@@ -47658,7 +49195,6 @@ struct BtCursor {
u8 validNKey; /* True if info.nKey is valid */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
#ifndef SQLITE_OMIT_INCRBLOB
- Pgno *aOverflow; /* Cache of overflow page locations */
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
#endif
i16 iPage; /* Index of current page in apPage */
@@ -47782,13 +49318,19 @@ struct BtCursor {
/*
** This structure is passed around through all the sanity checking routines
** in order to keep track of some global state information.
+**
+** The aRef[] array is allocated so that there is 1 bit for each page in
+** the database. As the integrity-check proceeds, for each page used in
+** the database the corresponding bit is set. This allows integrity-check to
+** detect pages that are used twice and orphaned pages (both of which
+** indicate corruption).
*/
typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk {
BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
+ u8 *aPgRef; /* 1 bit per page in the db (see above) */
Pgno nPage; /* Number of pages in the database */
- int *anRef; /* Number of times each page is referenced */
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
int mallocFailed; /* A memory allocation error has occurred */
@@ -47796,7 +49338,7 @@ struct IntegrityCk {
};
/*
-** Read or write a two- and four-byte big-endian integer values.
+** Routines to read or write a two- and four-byte big-endian integer values.
*/
#define get2byte(x) ((x)[0]<<8 | (x)[1])
#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
@@ -48321,7 +49863,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
/* If some other connection is holding an exclusive lock, the
** requested lock may not be obtained.
*/
- if( pBt->pWriter!=p && pBt->isExclusive ){
+ if( pBt->pWriter!=p && (pBt->btsFlags & BTS_EXCLUSIVE)!=0 ){
sqlite3ConnectionBlocked(p->db, pBt->pWriter->db);
return SQLITE_LOCKED_SHAREDCACHE;
}
@@ -48342,7 +49884,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
sqlite3ConnectionBlocked(p->db, pIter->pBtree->db);
if( eLock==WRITE_LOCK ){
assert( p==pBt->pWriter );
- pBt->isPending = 1;
+ pBt->btsFlags |= BTS_PENDING;
}
return SQLITE_LOCKED_SHAREDCACHE;
}
@@ -48430,7 +49972,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
** the setSharedCacheTableLock() procedure) held by Btree object p.
**
** This function assumes that Btree p has an open read or write
-** transaction. If it does not, then the BtShared.isPending variable
+** transaction. If it does not, then the BTS_PENDING flag
** may be incorrectly cleared.
*/
static void clearAllSharedCacheTableLocks(Btree *p){
@@ -48443,7 +49985,7 @@ static void clearAllSharedCacheTableLocks(Btree *p){
while( *ppIter ){
BtLock *pLock = *ppIter;
- assert( pBt->isExclusive==0 || pBt->pWriter==pLock->pBtree );
+ assert( (pBt->btsFlags & BTS_EXCLUSIVE)==0 || pBt->pWriter==pLock->pBtree );
assert( pLock->pBtree->inTrans>=pLock->eLock );
if( pLock->pBtree==p ){
*ppIter = pLock->pNext;
@@ -48456,22 +49998,21 @@ static void clearAllSharedCacheTableLocks(Btree *p){
}
}
- assert( pBt->isPending==0 || pBt->pWriter );
+ assert( (pBt->btsFlags & BTS_PENDING)==0 || pBt->pWriter );
if( pBt->pWriter==p ){
pBt->pWriter = 0;
- pBt->isExclusive = 0;
- pBt->isPending = 0;
+ pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING);
}else if( pBt->nTransaction==2 ){
/* This function is called when Btree p is concluding its
** transaction. If there currently exists a writer, and p is not
** that writer, then the number of locks held by connections other
** than the writer must be about to drop to zero. In this case
- ** set the isPending flag to 0.
+ ** set the BTS_PENDING flag to 0.
**
- ** If there is not currently a writer, then BtShared.isPending must
+ ** If there is not currently a writer, then BTS_PENDING must
** be zero already. So this next line is harmless in that case.
*/
- pBt->isPending = 0;
+ pBt->btsFlags &= ~BTS_PENDING;
}
}
@@ -48483,8 +50024,7 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){
if( pBt->pWriter==p ){
BtLock *pLock;
pBt->pWriter = 0;
- pBt->isExclusive = 0;
- pBt->isPending = 0;
+ pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING);
for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){
assert( pLock->eLock==READ_LOCK || pLock->pBtree==p );
pLock->eLock = READ_LOCK;
@@ -48937,7 +50477,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
** This routine works only for pages that do not contain overflow cells.
*/
#define findCell(P,I) \
- ((P)->aData + ((P)->maskPage & get2byte(&(P)->aData[(P)->cellOffset+2*(I)])))
+ ((P)->aData + ((P)->maskPage & get2byte(&(P)->aCellIdx[2*(I)])))
#define findCellv2(D,M,O,I) (D+(M&get2byte(D+(O+2*(I)))))
@@ -48950,12 +50490,10 @@ static u8 *findOverflowCell(MemPage *pPage, int iCell){
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
for(i=pPage->nOverflow-1; i>=0; i--){
int k;
- struct _OvflCell *pOvfl;
- pOvfl = &pPage->aOvfl[i];
- k = pOvfl->idx;
+ k = pPage->aiOvfl[i];
if( k<=iCell ){
if( k==iCell ){
- return pOvfl->pCell;
+ return pPage->apOvfl[i];
}
iCell--;
}
@@ -49342,7 +50880,7 @@ static int freeSpace(MemPage *pPage, int start, int size){
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( size>=0 ); /* Minimum cell size is 4 */
- if( pPage->pBt->secureDelete ){
+ if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){
/* Overwrite deleted information with zeros when the secure_delete
** option is enabled */
memset(&data[start], 0, size);
@@ -49445,6 +50983,7 @@ static int decodeFlags(MemPage *pPage, int flagByte){
}else{
return SQLITE_CORRUPT_BKPT;
}
+ pPage->max1bytePayload = pBt->max1bytePayload;
return SQLITE_OK;
}
@@ -49487,6 +51026,8 @@ static int btreeInitPage(MemPage *pPage){
pPage->nOverflow = 0;
usableSize = pBt->usableSize;
pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;
+ pPage->aDataEnd = &data[usableSize];
+ pPage->aCellIdx = &data[cellOffset];
top = get2byteNotZero(&data[hdr+5]);
pPage->nCell = get2byte(&data[hdr+3]);
if( pPage->nCell>MX_CELL(pBt) ){
@@ -49578,7 +51119,7 @@ static void zeroPage(MemPage *pPage, int flags){
assert( sqlite3PagerGetData(pPage->pDbPage) == data );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( sqlite3_mutex_held(pBt->mutex) );
- if( pBt->secureDelete ){
+ if( pBt->btsFlags & BTS_SECURE_DELETE ){
memset(&data[hdr], 0, pBt->usableSize - hdr);
}
data[hdr] = (char)flags;
@@ -49590,6 +51131,8 @@ static void zeroPage(MemPage *pPage, int flags){
decodeFlags(pPage, flags);
pPage->hdrOffset = hdr;
pPage->cellOffset = first;
+ pPage->aDataEnd = &data[pBt->usableSize];
+ pPage->aCellIdx = &data[first];
pPage->nOverflow = 0;
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
pPage->maskPage = (u16)(pBt->pageSize - 1);
@@ -49764,11 +51307,8 @@ static int btreeInvokeBusyHandler(void *pArg){
** If zFilename is ":memory:" then an in-memory database is created
** that is automatically destroyed when it is closed.
**
-** The "flags" parameter is a bitmask that might contain bits
-** BTREE_OMIT_JOURNAL and/or BTREE_NO_READLOCK. The BTREE_NO_READLOCK
-** bit is also set if the SQLITE_NoReadlock flags is set in db->flags.
-** These flags are passed through into sqlite3PagerOpen() and must
-** be the same values as PAGER_OMIT_JOURNAL and PAGER_NO_READLOCK.
+** The "flags" parameter is a bitmask that might contain bits like
+** BTREE_OMIT_JOURNAL and/or BTREE_MEMORY.
**
** If the database is already opened in the same database connection
** and we are in shared cache mode, then the open will fail with an
@@ -49815,9 +51355,6 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
/* A BTREE_SINGLE database is always a temporary and/or ephemeral */
assert( (flags & BTREE_SINGLE)==0 || isTempDb );
- if( db->flags & SQLITE_NoReadlock ){
- flags |= BTREE_NO_READLOCK;
- }
if( isMemdb ){
flags |= BTREE_MEMORY;
}
@@ -49850,7 +51387,12 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
sqlite3_free(p);
return SQLITE_NOMEM;
}
- sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname);
+ rc = sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname);
+ if( rc ){
+ sqlite3_free(zFullPathname);
+ sqlite3_free(p);
+ return rc;
+ }
#if SQLITE_THREADSAFE
mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN);
sqlite3_mutex_enter(mutexOpen);
@@ -49924,9 +51466,9 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
pBt->pCursor = 0;
pBt->pPage1 = 0;
- pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
+ if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY;
#ifdef SQLITE_SECURE_DELETE
- pBt->secureDelete = 1;
+ pBt->btsFlags |= BTS_SECURE_DELETE;
#endif
pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16);
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
@@ -49947,7 +51489,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
nReserve = 0;
}else{
nReserve = zDbHeader[20];
- pBt->pageSizeFixed = 1;
+ pBt->btsFlags |= BTS_PAGESIZE_FIXED;
#ifndef SQLITE_OMIT_AUTOVACUUM
pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0);
pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0);
@@ -50119,7 +51661,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
** The call to sqlite3BtreeRollback() drops any table-locks held by
** this handle.
*/
- sqlite3BtreeRollback(p);
+ sqlite3BtreeRollback(p, SQLITE_OK);
sqlite3BtreeLeave(p);
/* If there are still other outstanding references to the shared-btree
@@ -50235,7 +51777,7 @@ SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree *p){
** If parameter nReserve is less than zero, then the number of reserved
** bytes per page is left unchanged.
**
-** If the iFix!=0 then the pageSizeFixed flag is set so that the page size
+** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size
** and autovacuum mode can no longer be changed.
*/
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
@@ -50243,7 +51785,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve,
BtShared *pBt = p->pBt;
assert( nReserve>=-1 && nReserve<=255 );
sqlite3BtreeEnter(p);
- if( pBt->pageSizeFixed ){
+ if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
sqlite3BtreeLeave(p);
return SQLITE_READONLY;
}
@@ -50260,7 +51802,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve,
}
rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve);
pBt->usableSize = pBt->pageSize - (u16)nReserve;
- if( iFix ) pBt->pageSizeFixed = 1;
+ if( iFix ) pBt->btsFlags |= BTS_PAGESIZE_FIXED;
sqlite3BtreeLeave(p);
return rc;
}
@@ -50300,8 +51842,8 @@ SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
}
/*
-** Set the secureDelete flag if newFlag is 0 or 1. If newFlag is -1,
-** then make no changes. Always return the value of the secureDelete
+** Set the BTS_SECURE_DELETE flag if newFlag is 0 or 1. If newFlag is -1,
+** then make no changes. Always return the value of the BTS_SECURE_DELETE
** setting after the change.
*/
SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
@@ -50309,9 +51851,10 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
if( p==0 ) return 0;
sqlite3BtreeEnter(p);
if( newFlag>=0 ){
- p->pBt->secureDelete = (newFlag!=0) ? 1 : 0;
+ p->pBt->btsFlags &= ~BTS_SECURE_DELETE;
+ if( newFlag ) p->pBt->btsFlags |= BTS_SECURE_DELETE;
}
- b = p->pBt->secureDelete;
+ b = (p->pBt->btsFlags & BTS_SECURE_DELETE)!=0;
sqlite3BtreeLeave(p);
return b;
}
@@ -50332,7 +51875,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
u8 av = (u8)autoVacuum;
sqlite3BtreeEnter(p);
- if( pBt->pageSizeFixed && (av ?1:0)!=pBt->autoVacuum ){
+ if( (pBt->btsFlags & BTS_PAGESIZE_FIXED)!=0 && (av ?1:0)!=pBt->autoVacuum ){
rc = SQLITE_READONLY;
}else{
pBt->autoVacuum = av ?1:0;
@@ -50406,14 +51949,14 @@ static int lockBtree(BtShared *pBt){
#ifdef SQLITE_OMIT_WAL
if( page1[18]>1 ){
- pBt->readOnly = 1;
+ pBt->btsFlags |= BTS_READ_ONLY;
}
if( page1[19]>1 ){
goto page1_init_failed;
}
#else
if( page1[18]>2 ){
- pBt->readOnly = 1;
+ pBt->btsFlags |= BTS_READ_ONLY;
}
if( page1[19]>2 ){
goto page1_init_failed;
@@ -50427,7 +51970,7 @@ static int lockBtree(BtShared *pBt){
** may not be the latest version - there may be a newer one in the log
** file.
*/
- if( page1[19]==2 && pBt->doNotUseWAL==0 ){
+ if( page1[19]==2 && (pBt->btsFlags & BTS_NO_WAL)==0 ){
int isOpen = 0;
rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
if( rc!=SQLITE_OK ){
@@ -50504,6 +52047,11 @@ static int lockBtree(BtShared *pBt){
pBt->minLocal = (u16)((pBt->usableSize-12)*32/255 - 23);
pBt->maxLeaf = (u16)(pBt->usableSize - 35);
pBt->minLeaf = (u16)((pBt->usableSize-12)*32/255 - 23);
+ if( pBt->maxLocal>127 ){
+ pBt->max1bytePayload = 127;
+ }else{
+ pBt->max1bytePayload = (u8)pBt->maxLocal;
+ }
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
pBt->pPage1 = pPage1;
pBt->nPage = nPage;
@@ -50567,7 +52115,7 @@ static int newDatabase(BtShared *pBt){
data[23] = 32;
memset(&data[24], 0, 100-24);
zeroPage(pP1, PTF_INTKEY|PTF_LEAF|PTF_LEAFDATA );
- pBt->pageSizeFixed = 1;
+ pBt->btsFlags |= BTS_PAGESIZE_FIXED;
#ifndef SQLITE_OMIT_AUTOVACUUM
assert( pBt->autoVacuum==1 || pBt->autoVacuum==0 );
assert( pBt->incrVacuum==1 || pBt->incrVacuum==0 );
@@ -50631,7 +52179,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
/* Write transactions are not possible on a read-only database */
- if( pBt->readOnly && wrflag ){
+ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
rc = SQLITE_READONLY;
goto trans_begun;
}
@@ -50641,7 +52189,9 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
** on this shared-btree structure and a second write transaction is
** requested, return SQLITE_LOCKED.
*/
- if( (wrflag && pBt->inTransaction==TRANS_WRITE) || pBt->isPending ){
+ if( (wrflag && pBt->inTransaction==TRANS_WRITE)
+ || (pBt->btsFlags & BTS_PENDING)!=0
+ ){
pBlock = pBt->pWriter->db;
}else if( wrflag>1 ){
BtLock *pIter;
@@ -50665,7 +52215,8 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
if( SQLITE_OK!=rc ) goto trans_begun;
- pBt->initiallyEmpty = (u8)(pBt->nPage==0);
+ pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
+ if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
do {
/* Call lockBtree() until either pBt->pPage1 is populated or
** lockBtree() returns something other than SQLITE_OK. lockBtree()
@@ -50677,7 +52228,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
while( pBt->pPage1==0 && SQLITE_OK==(rc = lockBtree(pBt)) );
if( rc==SQLITE_OK && wrflag ){
- if( pBt->readOnly ){
+ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
rc = SQLITE_READONLY;
}else{
rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
@@ -50714,7 +52265,8 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
#ifndef SQLITE_OMIT_SHARED_CACHE
assert( !pBt->pWriter );
pBt->pWriter = p;
- pBt->isExclusive = (u8)(wrflag>1);
+ pBt->btsFlags &= ~BTS_EXCLUSIVE;
+ if( wrflag>1 ) pBt->btsFlags |= BTS_EXCLUSIVE;
#endif
/* If the db-size header field is incorrect (as it may be if an old
@@ -51347,6 +52899,7 @@ static int countWriteCursors(BtShared *pBt){
*/
SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
BtCursor *p;
+ if( pBtree==0 ) return;
sqlite3BtreeEnter(pBtree);
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
int i;
@@ -51370,25 +52923,20 @@ SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
-SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p){
+SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode){
int rc;
BtShared *pBt = p->pBt;
MemPage *pPage1;
sqlite3BtreeEnter(p);
- rc = saveAllCursors(pBt, 0, 0);
-#ifndef SQLITE_OMIT_SHARED_CACHE
- if( rc!=SQLITE_OK ){
- /* This is a horrible situation. An IO or malloc() error occurred whilst
- ** trying to save cursor positions. If this is an automatic rollback (as
- ** the result of a constraint, malloc() failure or IO error) then
- ** the cache may be internally inconsistent (not contain valid trees) so
- ** we cannot simply return the error to the caller. Instead, abort
- ** all queries that may be using any of the cursors that failed to save.
- */
- sqlite3BtreeTripAllCursors(p, rc);
+ if( tripCode==SQLITE_OK ){
+ rc = tripCode = saveAllCursors(pBt, 0, 0);
+ }else{
+ rc = SQLITE_OK;
+ }
+ if( tripCode ){
+ sqlite3BtreeTripAllCursors(p, tripCode);
}
-#endif
btreeIntegrity(p);
if( p->inTrans==TRANS_WRITE ){
@@ -51443,7 +52991,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p, int iStatement){
BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p);
assert( p->inTrans==TRANS_WRITE );
- assert( pBt->readOnly==0 );
+ assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( iStatement>0 );
assert( iStatement>p->db->nSavepoint );
assert( pBt->inTransaction==TRANS_WRITE );
@@ -51478,7 +53026,9 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
sqlite3BtreeEnter(p);
rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
if( rc==SQLITE_OK ){
- if( iSavepoint<0 && pBt->initiallyEmpty ) pBt->nPage = 0;
+ if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){
+ pBt->nPage = 0;
+ }
rc = newDatabase(pBt);
pBt->nPage = get4byte(28 + pBt->pPage1->aData);
@@ -51548,7 +53098,7 @@ static int btreeCursor(
assert( wrFlag==0 || p->inTrans==TRANS_WRITE );
assert( pBt->pPage1 && pBt->pPage1->aData );
- if( NEVER(wrFlag && pBt->readOnly) ){
+ if( NEVER(wrFlag && (pBt->btsFlags & BTS_READ_ONLY)!=0) ){
return SQLITE_READONLY;
}
if( iTable==1 && btreePagecount(pBt)==0 ){
@@ -52048,7 +53598,7 @@ static int accessPayload(
u8 aSave[4];
u8 *aWrite = &pBuf[-4];
memcpy(aSave, aWrite, 4);
- rc = sqlite3OsRead(fd, aWrite, a+4, pBt->pageSize * (nextPage-1));
+ rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
nextPage = get4byte(aWrite);
memcpy(aWrite, aSave, 4);
}else
@@ -52252,7 +53802,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
return SQLITE_OK;
}
-#ifndef NDEBUG
+#if 0
/*
** Page pParent is an internal (non-leaf) tree page. This function
** asserts that page number iChild is the left-child if the iIdx'th
@@ -52285,11 +53835,21 @@ static void moveToParent(BtCursor *pCur){
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
assert( pCur->apPage[pCur->iPage] );
+
+ /* UPDATE: It is actually possible for the condition tested by the assert
+ ** below to be untrue if the database file is corrupt. This can occur if
+ ** one cursor has modified page pParent while a reference to it is held
+ ** by a second cursor. Which can only happen if a single page is linked
+ ** into more than one b-tree structure in a corrupt database. */
+#if 0
assertParentIndex(
pCur->apPage[pCur->iPage-1],
pCur->aiIdx[pCur->iPage-1],
pCur->apPage[pCur->iPage]->pgno
);
+#endif
+ testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
+
releasePage(pCur->apPage[pCur->iPage]);
pCur->iPage--;
pCur->info.nSize = 0;
@@ -52628,16 +54188,21 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
** 2 bytes of the cell.
*/
int nCell = pCell[0];
- if( !(nCell & 0x80) && nCell<=pPage->maxLocal ){
+ if( nCell<=pPage->max1bytePayload
+ /* && (pCell+nCell)<pPage->aDataEnd */
+ ){
/* This branch runs if the record-size field of the cell is a
** single byte varint and the record fits entirely on the main
** b-tree page. */
+ testcase( pCell+nCell+1==pPage->aDataEnd );
c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
}else if( !(pCell[1] & 0x80)
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
+ /* && (pCell+nCell+2)<=pPage->aDataEnd */
){
/* The record-size field is a 2 byte varint and the record
** fits entirely on the main b-tree page. */
+ testcase( pCell+nCell+2==pPage->aDataEnd );
c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
}else{
/* The record flows over onto one or more overflow pages. In
@@ -52754,7 +54319,13 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
pPage = pCur->apPage[pCur->iPage];
idx = ++pCur->aiIdx[pCur->iPage];
assert( pPage->isInit );
- assert( idx<=pPage->nCell );
+
+ /* If the database file is corrupt, it is possible for the value of idx
+ ** to be invalid here. This can only occur if a second cursor modifies
+ ** the page while cursor pCur is holding a reference to it. Which can
+ ** only happen if the database is corrupt in such a way as to link the
+ ** page into more than one b-tree structure. */
+ testcase( idx>pPage->nCell );
pCur->info.nSize = 0;
pCur->validNKey = 0;
@@ -53179,7 +54750,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
nFree = get4byte(&pPage1->aData[36]);
put4byte(&pPage1->aData[36], nFree+1);
- if( pBt->secureDelete ){
+ if( pBt->btsFlags & BTS_SECURE_DELETE ){
/* If the secure_delete option is enabled, then
** always fully overwrite deleted information with zeros.
*/
@@ -53240,7 +54811,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
if( rc==SQLITE_OK ){
put4byte(&pTrunk->aData[4], nLeaf+1);
put4byte(&pTrunk->aData[8+nLeaf*4], iPage);
- if( pPage && !pBt->secureDelete ){
+ if( pPage && (pBt->btsFlags & BTS_SECURE_DELETE)==0 ){
sqlite3PagerDontWrite(pPage->pDbPage);
}
rc = btreeSetHasContent(pBt, iPage);
@@ -53532,7 +55103,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
data = pPage->aData;
- ptr = &data[pPage->cellOffset + 2*idx];
+ ptr = &pPage->aCellIdx[2*idx];
pc = get2byte(ptr);
hdr = pPage->hdrOffset;
testcase( pc==get2byte(&data[hdr+5]) );
@@ -53546,7 +55117,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
*pRC = rc;
return;
}
- endPtr = &data[pPage->cellOffset + 2*pPage->nCell - 2];
+ endPtr = &pPage->aCellIdx[2*pPage->nCell - 2];
assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 ); /* ptr is always 2-byte aligned */
while( ptr<endPtr ){
*(u16*)ptr = *(u16*)&ptr[2];
@@ -53564,7 +55135,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** If the cell content will fit on the page, then put it there. If it
** will not fit, then make a copy of the cell content into pTemp if
** pTemp is not null. Regardless of pTemp, allocate a new entry
-** in pPage->aOvfl[] and make it point to the cell content (either
+** in pPage->apOvfl[] and make it point to the cell content (either
** in pTemp or the original pCell) and also record its index.
** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
@@ -53598,7 +55169,8 @@ static void insertCell(
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=10921 );
- assert( pPage->nOverflow<=ArraySize(pPage->aOvfl) );
+ assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
+ assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
/* The cell should normally be sized correctly. However, when moving a
** malformed cell from a leaf page to an interior page, if the cell size
@@ -53615,9 +55187,9 @@ static void insertCell(
put4byte(pCell, iChild);
}
j = pPage->nOverflow++;
- assert( j<(int)(sizeof(pPage->aOvfl)/sizeof(pPage->aOvfl[0])) );
- pPage->aOvfl[j].pCell = pCell;
- pPage->aOvfl[j].idx = (u16)i;
+ assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) );
+ pPage->apOvfl[j] = pCell;
+ pPage->aiOvfl[j] = (u16)i;
}else{
int rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc!=SQLITE_OK ){
@@ -53688,7 +55260,7 @@ static void assemblePage(
assert( pPage->nCell==0 );
assert( get2byteNotZero(&data[hdr+5])==nUsable );
- pCellptr = &data[pPage->cellOffset + nCell*2];
+ pCellptr = &pPage->aCellIdx[nCell*2];
cellbody = nUsable;
for(i=nCell-1; i>=0; i--){
u16 sz = aSize[i];
@@ -53765,7 +55337,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
if( rc==SQLITE_OK ){
u8 *pOut = &pSpace[4];
- u8 *pCell = pPage->aOvfl[0].pCell;
+ u8 *pCell = pPage->apOvfl[0];
u16 szCell = cellSizePtr(pPage, pCell);
u8 *pStop;
@@ -53875,7 +55447,7 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
** map entries are also updated so that the parent page is page pTo.
**
** If pFrom is currently carrying any overflow cells (entries in the
-** MemPage.aOvfl[] array), they are not copied to pTo.
+** MemPage.apOvfl[] array), they are not copied to pTo.
**
** Before returning, page pTo is reinitialized using btreeInitPage().
**
@@ -54012,7 +55584,7 @@ static int balance_nonroot(
** is called (indirectly) from sqlite3BtreeDelete().
*/
assert( pParent->nOverflow==0 || pParent->nOverflow==1 );
- assert( pParent->nOverflow==0 || pParent->aOvfl[0].idx==iParentIdx );
+ assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx );
if( !aOvflSpace ){
return SQLITE_NOMEM;
@@ -54059,8 +55631,8 @@ static int balance_nonroot(
nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow;
if( (i--)==0 ) break;
- if( i+nxDiv==pParent->aOvfl[0].idx && pParent->nOverflow ){
- apDiv[i] = pParent->aOvfl[0].pCell;
+ if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){
+ apDiv[i] = pParent->apOvfl[0];
pgno = get4byte(apDiv[i]);
szNew[i] = cellSizePtr(pParent, apDiv[i]);
pParent->nOverflow = 0;
@@ -54081,7 +55653,7 @@ static int balance_nonroot(
** In this case, temporarily copy the cell into the aOvflSpace[]
** buffer. It will be copied out again as soon as the aSpace[] buffer
** is allocated. */
- if( pBt->secureDelete ){
+ if( pBt->btsFlags & BTS_SECURE_DELETE ){
int iOff;
iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
@@ -54266,8 +55838,14 @@ static int balance_nonroot(
/* Either we found one or more cells (cntnew[0])>0) or pPage is
** a virtual root page. A virtual root page is when the real root
** page is page 1 and we are the only child of that page.
+ **
+ ** UPDATE: The assert() below is not necessarily true if the database
+ ** file is corrupt. The corruption will be detected and reported later
+ ** in this procedure so there is no need to act upon it now.
*/
+#if 0
assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) );
+#endif
TRACE(("BALANCE: old: %d %d %d ",
apOld[0]->pgno,
@@ -54495,7 +56073,7 @@ static int balance_nonroot(
MemPage *pOld = apCopy[0];
int nOverflow = pOld->nOverflow;
int iNextOld = pOld->nCell + nOverflow;
- int iOverflow = (nOverflow ? pOld->aOvfl[0].idx : -1);
+ int iOverflow = (nOverflow ? pOld->aiOvfl[0] : -1);
j = 0; /* Current 'old' sibling page */
k = 0; /* Current 'new' sibling page */
for(i=0; i<nCell; i++){
@@ -54509,14 +56087,14 @@ static int balance_nonroot(
iNextOld = i + !leafData + pOld->nCell + pOld->nOverflow;
if( pOld->nOverflow ){
nOverflow = pOld->nOverflow;
- iOverflow = i + !leafData + pOld->aOvfl[0].idx;
+ iOverflow = i + !leafData + pOld->aiOvfl[0];
}
isDivider = !leafData;
}
assert(nOverflow>0 || iOverflow<i );
- assert(nOverflow<2 || pOld->aOvfl[0].idx==pOld->aOvfl[1].idx-1);
- assert(nOverflow<3 || pOld->aOvfl[1].idx==pOld->aOvfl[2].idx-1);
+ assert(nOverflow<2 || pOld->aiOvfl[0]==pOld->aiOvfl[1]-1);
+ assert(nOverflow<3 || pOld->aiOvfl[1]==pOld->aiOvfl[2]-1);
if( i==iOverflow ){
isDivider = 1;
if( (--nOverflow)>0 ){
@@ -54637,7 +56215,10 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));
/* Copy the overflow cells from pRoot to pChild */
- memcpy(pChild->aOvfl, pRoot->aOvfl, pRoot->nOverflow*sizeof(pRoot->aOvfl[0]));
+ memcpy(pChild->aiOvfl, pRoot->aiOvfl,
+ pRoot->nOverflow*sizeof(pRoot->aiOvfl[0]));
+ memcpy(pChild->apOvfl, pRoot->apOvfl,
+ pRoot->nOverflow*sizeof(pRoot->apOvfl[0]));
pChild->nOverflow = pRoot->nOverflow;
/* Zero the contents of pRoot. Then install pChild as the right-child. */
@@ -54700,7 +56281,7 @@ static int balance(BtCursor *pCur){
#ifndef SQLITE_OMIT_QUICKBALANCE
if( pPage->hasData
&& pPage->nOverflow==1
- && pPage->aOvfl[0].idx==pPage->nCell
+ && pPage->aiOvfl[0]==pPage->nCell
&& pParent->pgno!=1
&& pParent->nCell==iIdx
){
@@ -54817,7 +56398,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
}
assert( cursorHoldsMutex(pCur) );
- assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE && !pBt->readOnly );
+ assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE
+ && (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
/* Assert that the caller has been consistent. If this cursor was opened
@@ -54827,13 +56409,6 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
** blob of associated data. */
assert( (pKey==0)==(pCur->pKeyInfo==0) );
- /* If this is an insert into a table b-tree, invalidate any incrblob
- ** cursors open on the row being replaced (assuming this is a replace
- ** operation - if it is not, the following is a no-op). */
- if( pCur->pKeyInfo==0 ){
- invalidateIncrblobCursors(p, nKey, 0);
- }
-
/* Save the positions of any other cursors open on this table.
**
** In some cases, the call to btreeMoveto() below is a no-op. For
@@ -54847,6 +56422,14 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
*/
rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
if( rc ) return rc;
+
+ /* If this is an insert into a table b-tree, invalidate any incrblob
+ ** cursors open on the row being replaced (assuming this is a replace
+ ** operation - if it is not, the following is a no-op). */
+ if( pCur->pKeyInfo==0 ){
+ invalidateIncrblobCursors(p, nKey, 0);
+ }
+
if( !loc ){
rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc);
if( rc ) return rc;
@@ -54946,7 +56529,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( pBt->inTransaction==TRANS_WRITE );
- assert( !pBt->readOnly );
+ assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( pCur->wrFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
@@ -54957,12 +56540,6 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
return SQLITE_ERROR; /* Something has gone awry. */
}
- /* 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. */
- if( pCur->pKeyInfo==0 ){
- invalidateIncrblobCursors(p, pCur->info.nKey, 0);
- }
-
iCellDepth = pCur->iPage;
iCellIdx = pCur->aiIdx[iCellDepth];
pPage = pCur->apPage[iCellDepth];
@@ -54988,6 +56565,13 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
*/
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. */
+ if( pCur->pKeyInfo==0 ){
+ invalidateIncrblobCursors(p, pCur->info.nKey, 0);
+ }
+
rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
rc = clearCell(pPage, pCell);
@@ -55067,7 +56651,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
assert( sqlite3BtreeHoldsMutex(p) );
assert( pBt->inTransaction==TRANS_WRITE );
- assert( !pBt->readOnly );
+ assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
#ifdef SQLITE_OMIT_AUTOVACUUM
rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0);
@@ -55269,13 +56853,13 @@ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
sqlite3BtreeEnter(p);
assert( p->inTrans==TRANS_WRITE );
- /* Invalidate all incrblob cursors open on table iTable (assuming iTable
- ** is the root of a table b-tree - if it is not, the following call is
- ** a no-op). */
- invalidateIncrblobCursors(p, 0, 1);
-
rc = saveAllCursors(pBt, (Pgno)iTable, 0);
+
if( SQLITE_OK==rc ){
+ /* Invalidate all incrblob cursors open on table iTable (assuming iTable
+ ** is the root of a table b-tree - if it is not, the following call is
+ ** a no-op). */
+ invalidateIncrblobCursors(p, 0, 1);
rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
}
sqlite3BtreeLeave(p);
@@ -55441,7 +57025,9 @@ SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
/* If auto-vacuum is disabled in this build and this is an auto-vacuum
** database, mark the database as read-only. */
#ifdef SQLITE_OMIT_AUTOVACUUM
- if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ) pBt->readOnly = 1;
+ if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ){
+ pBt->btsFlags |= BTS_READ_ONLY;
+ }
#endif
sqlite3BtreeLeave(p);
@@ -55588,6 +57174,25 @@ static void checkAppendMsg(
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
+
+/*
+** Return non-zero if the bit in the IntegrityCk.aPgRef[] array that
+** corresponds to page iPg is already set.
+*/
+static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){
+ assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 );
+ return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07)));
+}
+
+/*
+** Set the bit in the IntegrityCk.aPgRef[] array that corresponds to page iPg.
+*/
+static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
+ assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 );
+ pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07));
+}
+
+
/*
** Add 1 to the reference count for page iPage. If this is the second
** reference to the page, add an error message to pCheck->zErrMsg.
@@ -55602,11 +57207,12 @@ static int checkRef(IntegrityCk *pCheck, Pgno iPage, char *zContext){
checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage);
return 1;
}
- if( pCheck->anRef[iPage]==1 ){
+ if( getPageReferenced(pCheck, iPage) ){
checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage);
return 1;
}
- return (pCheck->anRef[iPage]++)>1;
+ setPageReferenced(pCheck, iPage);
+ return 0;
}
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -55982,17 +57588,15 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
sqlite3BtreeLeave(p);
return 0;
}
- sCheck.anRef = sqlite3Malloc( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
- if( !sCheck.anRef ){
+
+ sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
+ if( !sCheck.aPgRef ){
*pnErr = 1;
sqlite3BtreeLeave(p);
return 0;
}
- for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; }
i = PENDING_BYTE_PAGE(pBt);
- if( i<=sCheck.nPage ){
- sCheck.anRef[i] = 1;
- }
+ if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), 20000);
sCheck.errMsg.useMalloc = 2;
@@ -56017,18 +57621,18 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
*/
for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
- if( sCheck.anRef[i]==0 ){
+ if( getPageReferenced(&sCheck, i)==0 ){
checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
}
#else
/* If the database supports auto-vacuum, make sure no tables contain
** references to pointer-map pages.
*/
- if( sCheck.anRef[i]==0 &&
+ if( getPageReferenced(&sCheck, i)==0 &&
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
}
- if( sCheck.anRef[i]!=0 &&
+ if( getPageReferenced(&sCheck, i)!=0 &&
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
}
@@ -56049,7 +57653,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
/* Clean up and report errors.
*/
sqlite3BtreeLeave(p);
- sqlite3_free(sCheck.anRef);
+ sqlite3_free(sCheck.aPgRef);
if( sCheck.mallocFailed ){
sqlite3StrAccumReset(&sCheck.errMsg);
*pnErr = sCheck.nErr+1;
@@ -56241,7 +57845,8 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
if( !pCsr->wrFlag ){
return SQLITE_READONLY;
}
- assert( !pCsr->pBt->readOnly && pCsr->pBt->inTransaction==TRANS_WRITE );
+ assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0
+ && pCsr->pBt->inTransaction==TRANS_WRITE );
assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) );
assert( pCsr->apPage[pCsr->iPage]->intKey );
@@ -56281,7 +57886,8 @@ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
/* If setting the version fields to 1, do not automatically open the
** WAL connection, even if the version fields are currently set to 2.
*/
- pBt->doNotUseWAL = (u8)(iVersion==1);
+ pBt->btsFlags &= ~BTS_NO_WAL;
+ if( iVersion==1 ) pBt->btsFlags |= BTS_NO_WAL;
rc = sqlite3BtreeBeginTrans(pBtree, 0);
if( rc==SQLITE_OK ){
@@ -56298,7 +57904,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
}
}
- pBt->doNotUseWAL = 0;
+ pBt->btsFlags &= ~BTS_NO_WAL;
return rc;
}
@@ -56872,7 +58478,7 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
}
/* If a transaction is still open on the Btree, roll it back. */
- sqlite3BtreeRollback(p->pDest);
+ sqlite3BtreeRollback(p->pDest, SQLITE_OK);
/* Set the error code of the destination database handle. */
rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
@@ -56982,7 +58588,9 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
pFd = sqlite3PagerFile(sqlite3BtreePager(pTo));
if( pFd->pMethods ){
i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom);
- sqlite3OsFileControl(pFd, SQLITE_FCNTL_OVERWRITE, &nByte);
+ rc = sqlite3OsFileControl(pFd, SQLITE_FCNTL_OVERWRITE, &nByte);
+ if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
+ if( rc ) goto copy_finished;
}
/* Set up an sqlite3_backup object. sqlite3_backup.pDestDb must be set
@@ -57007,12 +58615,13 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
assert( b.rc!=SQLITE_OK );
rc = sqlite3_backup_finish(&b);
if( rc==SQLITE_OK ){
- pTo->pBt->pageSizeFixed = 0;
+ pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
}else{
sqlite3PagerClearCache(sqlite3BtreePager(b.pDest));
}
assert( sqlite3BtreeIsInTrans(pTo)==0 );
+copy_finished:
sqlite3BtreeLeave(pFrom);
sqlite3BtreeLeave(pTo);
return rc;
@@ -57040,12 +58649,6 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
*/
/*
-** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*)
-** P if required.
-*/
-#define expandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0)
-
-/*
** If pMem is an object with a valid string representation, this routine
** ensures the internal encoding for the string representation is
** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE.
@@ -57086,10 +58689,10 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
** Make sure pMem->z points to a writable allocation of at least
** n bytes.
**
-** If the memory cell currently contains string or blob data
-** and the third argument passed to this function is true, the
-** current content of the cell is preserved. Otherwise, it may
-** be discarded.
+** If the third argument passed to this function is true, then memory
+** cell pMem must contain a string or blob. In this case the content is
+** preserved. Otherwise, if the third parameter to this function is false,
+** any current string or blob value may be discarded.
**
** This function sets the MEM_Dyn flag and clears any xDel callback.
** It also clears MEM_Ephem and MEM_Static. If the preserve flag is
@@ -57104,6 +58707,10 @@ SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
);
assert( (pMem->flags&MEM_RowSet)==0 );
+ /* If the preserve flag is set to true, then the memory cell must already
+ ** contain a valid string or blob value. */
+ assert( preserve==0 || pMem->flags&(MEM_Blob|MEM_Str) );
+
if( n<32 ) n = 32;
if( sqlite3DbMallocSize(pMem->db, pMem->zMalloc)<n ){
if( preserve && pMem->z==pMem->zMalloc ){
@@ -57119,6 +58726,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( pMem->flags&MEM_Dyn && pMem->xDel ){
+ assert( pMem->xDel!=SQLITE_DYNAMIC );
pMem->xDel((void *)(pMem->z));
}
@@ -57144,7 +58752,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
int f;
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( (pMem->flags&MEM_RowSet)==0 );
- expandBlob(pMem);
+ ExpandBlob(pMem);
f = pMem->flags;
if( (f&(MEM_Str|MEM_Blob)) && pMem->z!=pMem->zMalloc ){
if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
@@ -57298,6 +58906,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p){
sqlite3VdbeMemRelease(p);
}else if( p->flags&MEM_Dyn && p->xDel ){
assert( (p->flags&MEM_RowSet)==0 );
+ assert( p->xDel!=SQLITE_DYNAMIC );
p->xDel((void *)p->z);
p->xDel = 0;
}else if( p->flags&MEM_RowSet ){
@@ -57313,7 +58922,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p){
** (Mem.type==SQLITE_TEXT).
*/
SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){
- MemReleaseExt(p);
+ VdbeMemRelease(p);
sqlite3DbFree(p->db, p->zMalloc);
p->z = 0;
p->zMalloc = 0;
@@ -57440,8 +59049,14 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
** true and could be omitted. But we leave it in because other
** architectures might behave differently.
*/
- if( pMem->r==(double)pMem->u.i && pMem->u.i>SMALLEST_INT64
- && ALWAYS(pMem->u.i<LARGEST_INT64) ){
+ if( pMem->r==(double)pMem->u.i
+ && pMem->u.i>SMALLEST_INT64
+#if defined(__i486__) || defined(__x86_64__)
+ && ALWAYS(pMem->u.i<LARGEST_INT64)
+#else
+ && pMem->u.i<LARGEST_INT64
+#endif
+ ){
pMem->flags |= MEM_Int;
}
}
@@ -57609,7 +59224,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
** This is used for testing and debugging only - to make sure shallow
** copies are not misused.
*/
-SQLITE_PRIVATE void sqlite3VdbeMemPrepareToChange(Vdbe *pVdbe, Mem *pMem){
+SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
int i;
Mem *pX;
for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
@@ -57635,7 +59250,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrepareToChange(Vdbe *pVdbe, Mem *pMem){
*/
SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
assert( (pFrom->flags & MEM_RowSet)==0 );
- MemReleaseExt(pTo);
+ VdbeMemRelease(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->xDel = 0;
if( (pFrom->flags&MEM_Static)==0 ){
@@ -57653,7 +59268,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
int rc = SQLITE_OK;
assert( (pFrom->flags & MEM_RowSet)==0 );
- MemReleaseExt(pTo);
+ VdbeMemRelease(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->flags &= ~MEM_Dyn;
@@ -57981,7 +59596,7 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
}
assert( (MEM_Blob>>3) == MEM_Str );
pVal->flags |= (pVal->flags & MEM_Blob)>>3;
- expandBlob(pVal);
+ ExpandBlob(pVal);
if( pVal->flags&MEM_Str ){
sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&SQLITE_PTR_TO_INT(pVal->z)) ){
@@ -57990,7 +59605,7 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
return 0;
}
}
- sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-59893-45467 */
+ sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-31275-44060 */
}else{
assert( (pVal->flags&MEM_Blob)==0 );
sqlite3VdbeMemStringify(pVal, enc);
@@ -58371,7 +59986,8 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4(
/*
** Add an OP_ParseSchema opcode. This routine is broken out from
-** sqlite3VdbeAddOp4() since it needs to also local all btrees.
+** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees
+** as having been used.
**
** The zWhere string must have been obtained from sqlite3_malloc().
** This routine will take ownership of the allocated memory.
@@ -58414,14 +60030,11 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(
** Zero is returned if a malloc() fails.
*/
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *p){
- int i;
- i = p->nLabel++;
+ int i = p->nLabel++;
assert( p->magic==VDBE_MAGIC_INIT );
- if( i>=p->nLabelAlloc ){
- int n = p->nLabelAlloc*2 + 5;
- p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel,
- n*sizeof(p->aLabel[0]));
- p->nLabelAlloc = sqlite3DbMallocSize(p->db, p->aLabel)/sizeof(p->aLabel[0]);
+ if( (i & (i-1))==0 ){
+ p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel,
+ (i*2+1)*sizeof(p->aLabel[0]));
}
if( p->aLabel ){
p->aLabel[i] = -1;
@@ -59088,13 +60701,14 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
}
case P4_MEM: {
Mem *pMem = pOp->p4.pMem;
- assert( (pMem->flags & MEM_Null)==0 );
if( pMem->flags & MEM_Str ){
zP4 = pMem->z;
}else if( pMem->flags & MEM_Int ){
sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i);
}else if( pMem->flags & MEM_Real ){
sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->r);
+ }else if( pMem->flags & MEM_Null ){
+ sqlite3_snprintf(nTemp, zTemp, "NULL");
}else{
assert( pMem->flags & MEM_Blob );
zP4 = "(blob)";
@@ -59137,8 +60751,9 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
**
** The prepared statements need to know in advance the complete set of
-** attached databases that they will be using. A mask of these databases
-** is maintained in p->btreeMask and is used for locking and other purposes.
+** attached databases that will be use. A mask of these databases
+** is maintained in p->btreeMask. The p->lockMask value is the subset of
+** p->btreeMask of databases that will require a lock.
*/
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
assert( i>=0 && i<p->db->nDb && i<(int)sizeof(yDbMask)*8 );
@@ -59269,7 +60884,7 @@ static void releaseMemArray(Mem *p, int N){
p->zMalloc = 0;
}
- p->flags = MEM_Null;
+ p->flags = MEM_Invalid;
}
db->mallocFailed = malloc_failed;
}
@@ -59414,7 +61029,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
for(j=0; j<nSub; j++){
if( apSub[j]==pOp->p4.pProgram ) break;
}
- if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, 1) ){
+ if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, nSub!=0) ){
apSub = (SubProgram **)pSub->z;
apSub[nSub++] = pOp->p4.pProgram;
pSub->flags |= MEM_Blob;
@@ -59644,6 +61259,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
int nMem; /* Number of VM memory registers */
int nCursor; /* Number of cursors required */
int nArg; /* Number of arguments in subprograms */
+ int nOnce; /* Number of OP_Once instructions */
int n; /* Loop counter */
u8 *zCsr; /* Memory available for allocation */
u8 *zEnd; /* First byte past allocated memory */
@@ -59659,6 +61275,8 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
nMem = pParse->nMem;
nCursor = pParse->nTab;
nArg = pParse->nMaxArg;
+ nOnce = pParse->nOnce;
+ if( nOnce==0 ) nOnce = 1; /* Ensure at least one byte in p->aOnceFlag[] */
/* For each cursor required, also allocate a memory cell. Memory
** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
@@ -59705,6 +61323,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
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);
if( nByte ){
p->pFree = sqlite3DbMallocZero(db, nByte);
}
@@ -59713,6 +61332,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
}while( nByte && !db->mallocFailed );
p->nCursor = (u16)nCursor;
+ p->nOnceFlag = nOnce;
if( p->aVar ){
p->nVar = (ynVar)nVar;
for(n=0; n<nVar; n++){
@@ -59729,7 +61349,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
p->aMem--; /* aMem[] goes from 1..nMem */
p->nMem = nMem; /* not from 0..nMem-1 */
for(n=1; n<=nMem; n++){
- p->aMem[n].flags = MEM_Null;
+ p->aMem[n].flags = MEM_Invalid;
p->aMem[n].db = db;
}
}
@@ -59771,6 +61391,8 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
*/
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
Vdbe *v = pFrame->v;
+ v->aOnceFlag = pFrame->aOnceFlag;
+ v->nOnceFlag = pFrame->nOnceFlag;
v->aOp = pFrame->aOp;
v->nOp = pFrame->nOp;
v->aMem = pFrame->aMem;
@@ -59833,8 +61455,10 @@ static void Cleanup(Vdbe *p){
/* Execute assert() statements to ensure that the Vdbe.apCsr[] and
** Vdbe.aMem[] arrays have already been cleaned up. */
int i;
- for(i=0; i<p->nCursor; i++) assert( p->apCsr==0 || p->apCsr[i]==0 );
- for(i=1; i<=p->nMem; i++) assert( p->aMem==0 || p->aMem[i].flags==MEM_Null );
+ if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
+ if( p->aMem ){
+ for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Invalid );
+ }
#endif
sqlite3DbFree(db, p->zErrMsg);
@@ -59999,16 +61623,31 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
sqlite3_file *pMaster = 0;
i64 offset = 0;
int res;
+ int retryCount = 0;
+ int nMainFile;
/* Select a master journal file name */
+ nMainFile = sqlite3Strlen30(zMainFile);
+ zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile);
+ if( zMaster==0 ) return SQLITE_NOMEM;
do {
u32 iRandom;
- sqlite3DbFree(db, zMaster);
- sqlite3_randomness(sizeof(iRandom), &iRandom);
- zMaster = sqlite3MPrintf(db, "%s-mj%08X", zMainFile, iRandom&0x7fffffff);
- if( !zMaster ){
- return SQLITE_NOMEM;
+ if( retryCount ){
+ if( retryCount>100 ){
+ sqlite3_log(SQLITE_FULL, "MJ delete: %s", zMaster);
+ sqlite3OsDelete(pVfs, zMaster, 0);
+ break;
+ }else if( retryCount==1 ){
+ sqlite3_log(SQLITE_FULL, "MJ collide: %s", zMaster);
+ }
}
+ retryCount++;
+ sqlite3_randomness(sizeof(iRandom), &iRandom);
+ sqlite3_snprintf(13, &zMaster[nMainFile], "-mj%06X9%02X",
+ (iRandom>>8)&0xffffff, iRandom&0xff);
+ /* The antipenultimate character of the master journal name must
+ ** be "9" to avoid name collisions when using 8+3 filenames. */
+ assert( zMaster[sqlite3Strlen30(zMaster)-3]=='9' );
sqlite3FileSuffix3(zMainFile, zMaster);
rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
}while( rc==SQLITE_OK && res );
@@ -60154,32 +61793,6 @@ static void checkActiveVdbeCnt(sqlite3 *db){
#endif
/*
-** For every Btree that in database connection db which
-** has been modified, "trip" or invalidate each cursor in
-** that Btree might have been modified so that the cursor
-** can never be used again. This happens when a rollback
-*** occurs. We have to trip all the other cursors, even
-** cursor from other VMs in different database connections,
-** so that none of them try to use the data at which they
-** were pointing and which now may have been changed due
-** to the rollback.
-**
-** Remember that a rollback can delete tables complete and
-** reorder rootpages. So it is not sufficient just to save
-** the state of the cursor. We have to invalidate the cursor
-** so that it is never used again.
-*/
-static void invalidateCursorsOnModifiedBtrees(sqlite3 *db){
- int i;
- for(i=0; i<db->nDb; i++){
- Btree *p = db->aDb[i].pBt;
- if( p && sqlite3BtreeIsInTrans(p) ){
- sqlite3BtreeTripAllCursors(p, SQLITE_ABORT);
- }
- }
-}
-
-/*
** If the Vdbe passed as the first argument opened a statement-transaction,
** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or
** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement
@@ -60302,6 +61915,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
if( p->db->mallocFailed ){
p->rc = SQLITE_NOMEM;
}
+ if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag);
closeAllCursors(p);
if( p->magic!=VDBE_MAGIC_RUN ){
return SQLITE_OK;
@@ -60342,8 +61956,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
/* We are forced to roll back the active transaction. Before doing
** so, abort any other statements this handle currently has active.
*/
- invalidateCursorsOnModifiedBtrees(db);
- sqlite3RollbackAll(db);
+ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
}
@@ -60385,13 +61998,13 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
return SQLITE_BUSY;
}else if( rc!=SQLITE_OK ){
p->rc = rc;
- sqlite3RollbackAll(db);
+ sqlite3RollbackAll(db, SQLITE_OK);
}else{
db->nDeferredCons = 0;
sqlite3CommitInternalChanges(db);
}
}else{
- sqlite3RollbackAll(db);
+ sqlite3RollbackAll(db, SQLITE_OK);
}
db->nStatement = 0;
}else if( eStatementOp==0 ){
@@ -60400,8 +62013,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}else if( p->errorAction==OE_Abort ){
eStatementOp = SAVEPOINT_ROLLBACK;
}else{
- invalidateCursorsOnModifiedBtrees(db);
- sqlite3RollbackAll(db);
+ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
}
@@ -60421,8 +62033,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
- invalidateCursorsOnModifiedBtrees(db);
- sqlite3RollbackAll(db);
+ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
}
@@ -60439,12 +62050,6 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}
p->nChange = 0;
}
-
- /* Rollback or commit any schema changes that occurred. */
- if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){
- sqlite3ResetInternalSchema(db, -1);
- db->flags = (db->flags | SQLITE_InternChanges);
- }
/* Release the locks */
sqlite3VdbeLeave(p);
@@ -60639,6 +62244,10 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
sqlite3DbFree(db, p->pFree);
+#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
+ sqlite3DbFree(db, p->zExplain);
+ sqlite3DbFree(db, p->pExplain);
+#endif
sqlite3DbFree(db, p);
}
@@ -61118,15 +62727,6 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
** Or if the UNPACKED_MATCH_PREFIX flag is set and the prefixes are
** equal, then the keys are considered to be equal and
** the parts beyond the common prefix are ignored.
-**
-** If the UNPACKED_IGNORE_ROWID flag is set, then the last byte of
-** the header of pKey1 is ignored. It is assumed that pKey1 is
-** an index key, and thus ends with a rowid value. The last byte
-** of the header will therefore be the serial type of the rowid:
-** one of 1, 2, 3, 4, 5, 6, 8, or 9 - the integer serial types.
-** The serial type of the final rowid will always be a single byte.
-** By ignoring this last byte of the header, we force the comparison
-** to ignore the rowid at the end of key1.
*/
SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
int nKey1, const void *pKey1, /* Left key */
@@ -61159,9 +62759,6 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
- if( pPKey2->flags & UNPACKED_IGNORE_ROWID ){
- szHdr1--;
- }
nField = pKeyInfo->nField;
while( idx1<szHdr1 && i<pPKey2->nField ){
u32 serial_type1;
@@ -61341,7 +62938,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
if( rc ){
return rc;
}
- assert( pUnpacked->flags & UNPACKED_IGNORE_ROWID );
+ assert( pUnpacked->flags & UNPACKED_PREFIX_MATCH );
*res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked);
sqlite3VdbeMemRelease(&m);
return SQLITE_OK;
@@ -61784,7 +63381,7 @@ static int sqlite3Step(Vdbe *p){
**
** Nevertheless, some published applications that were originally written
** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
- ** returns, and the so were broken by the automatic-reset change. As a
+ ** returns, and those were broken by the automatic-reset change. As a
** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
** legacy behavior of returning SQLITE_MISUSE for cases where the
** previous sqlite3_step() returned something other than a SQLITE_LOCKED
@@ -62130,13 +63727,13 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
/* If the value passed as the second argument is out of range, return
** a pointer to the following static Mem object which contains the
** value SQL NULL. Even though the Mem structure contains an element
- ** of type i64, on certain architecture (x86) with certain compiler
+ ** of type i64, on certain architectures (x86) with certain compiler
** switches (-Os), gcc may align this Mem object on a 4-byte boundary
** instead of an 8-byte one. This all works fine, except that when
** running with SQLITE_DEBUG defined the SQLite code sometimes assert()s
** that a Mem structure is located on an 8-byte boundary. To prevent
- ** this assert() from failing, when building with SQLITE_DEBUG defined
- ** using gcc, force nullMem to be 8-byte aligned using the magical
+ ** these assert()s from failing, when building with SQLITE_DEBUG defined
+ ** using gcc, we force nullMem to be 8-byte aligned using the magical
** __attribute__((aligned(8))) macro. */
static const Mem nullMem
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
@@ -62708,6 +64305,14 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
}
/*
+** Return true if the prepared statement is in need of being reset.
+*/
+SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
+ Vdbe *v = (Vdbe*)pStmt;
+ return v!=0 && v->pc>0 && v->magic==VDBE_MAGIC_RUN;
+}
+
+/*
** Return a pointer to the next prepared statement after pStmt associated
** with database connection pDb. If pStmt is NULL, return the first
** prepared statement for the database connection. Return NULL if there
@@ -62751,6 +64356,8 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
**
** This file contains code used to insert the values of host parameters
** (aka "wildcards") into the SQL text output by sqlite3_trace().
+**
+** The Vdbe parse-tree explainer is also found here.
*/
#ifndef SQLITE_OMIT_TRACE
@@ -62890,6 +64497,122 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
#endif /* #ifndef SQLITE_OMIT_TRACE */
+/*****************************************************************************
+** The following code implements the data-structure explaining logic
+** for the Vdbe.
+*/
+
+#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
+
+/*
+** Allocate a new Explain object
+*/
+SQLITE_PRIVATE void sqlite3ExplainBegin(Vdbe *pVdbe){
+ if( pVdbe ){
+ Explain *p;
+ sqlite3BeginBenignMalloc();
+ p = sqlite3_malloc( sizeof(Explain) );
+ if( p ){
+ memset(p, 0, sizeof(*p));
+ p->pVdbe = pVdbe;
+ sqlite3_free(pVdbe->pExplain);
+ pVdbe->pExplain = p;
+ sqlite3StrAccumInit(&p->str, p->zBase, sizeof(p->zBase),
+ SQLITE_MAX_LENGTH);
+ p->str.useMalloc = 2;
+ }else{
+ sqlite3EndBenignMalloc();
+ }
+ }
+}
+
+/*
+** Return true if the Explain ends with a new-line.
+*/
+static int endsWithNL(Explain *p){
+ return p && p->str.zText && p->str.nChar
+ && p->str.zText[p->str.nChar-1]=='\n';
+}
+
+/*
+** Append text to the indentation
+*/
+SQLITE_PRIVATE void sqlite3ExplainPrintf(Vdbe *pVdbe, const char *zFormat, ...){
+ Explain *p;
+ if( pVdbe && (p = pVdbe->pExplain)!=0 ){
+ va_list ap;
+ if( p->nIndent && endsWithNL(p) ){
+ int n = p->nIndent;
+ if( n>ArraySize(p->aIndent) ) n = ArraySize(p->aIndent);
+ sqlite3AppendSpace(&p->str, p->aIndent[n-1]);
+ }
+ va_start(ap, zFormat);
+ sqlite3VXPrintf(&p->str, 1, zFormat, ap);
+ va_end(ap);
+ }
+}
+
+/*
+** Append a '\n' if there is not already one.
+*/
+SQLITE_PRIVATE void sqlite3ExplainNL(Vdbe *pVdbe){
+ Explain *p;
+ if( pVdbe && (p = pVdbe->pExplain)!=0 && !endsWithNL(p) ){
+ sqlite3StrAccumAppend(&p->str, "\n", 1);
+ }
+}
+
+/*
+** Push a new indentation level. Subsequent lines will be indented
+** so that they begin at the current cursor position.
+*/
+SQLITE_PRIVATE void sqlite3ExplainPush(Vdbe *pVdbe){
+ Explain *p;
+ if( pVdbe && (p = pVdbe->pExplain)!=0 ){
+ if( p->str.zText && p->nIndent<ArraySize(p->aIndent) ){
+ const char *z = p->str.zText;
+ int i = p->str.nChar-1;
+ int x;
+ while( i>=0 && z[i]!='\n' ){ i--; }
+ x = (p->str.nChar - 1) - i;
+ if( p->nIndent && x<p->aIndent[p->nIndent-1] ){
+ x = p->aIndent[p->nIndent-1];
+ }
+ p->aIndent[p->nIndent] = x;
+ }
+ p->nIndent++;
+ }
+}
+
+/*
+** Pop the indentation stack by one level.
+*/
+SQLITE_PRIVATE void sqlite3ExplainPop(Vdbe *p){
+ if( p && p->pExplain ) p->pExplain->nIndent--;
+}
+
+/*
+** Free the indentation structure
+*/
+SQLITE_PRIVATE void sqlite3ExplainFinish(Vdbe *pVdbe){
+ if( pVdbe && pVdbe->pExplain ){
+ sqlite3_free(pVdbe->zExplain);
+ sqlite3ExplainNL(pVdbe);
+ pVdbe->zExplain = sqlite3StrAccumFinish(&pVdbe->pExplain->str);
+ sqlite3_free(pVdbe->pExplain);
+ pVdbe->pExplain = 0;
+ sqlite3EndBenignMalloc();
+ }
+}
+
+/*
+** Return the explanation of a virtual machine.
+*/
+SQLITE_PRIVATE const char *sqlite3VdbeExplanation(Vdbe *pVdbe){
+ return (pVdbe && pVdbe->zExplain) ? pVdbe->zExplain : 0;
+}
+#endif /* defined(SQLITE_DEBUG) */
+
/************** End of vdbetrace.c *******************************************/
/************** Begin file vdbe.c ********************************************/
/*
@@ -62944,7 +64667,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
** not misused.
*/
#ifdef SQLITE_DEBUG
-# define memAboutToChange(P,M) sqlite3VdbeMemPrepareToChange(P,M)
+# define memAboutToChange(P,M) sqlite3VdbeMemAboutToChange(P,M)
#else
# define memAboutToChange(P,M)
#endif
@@ -62962,8 +64685,8 @@ SQLITE_API int sqlite3_search_count = 0;
/*
** When this global variable is positive, it gets decremented once before
-** each instruction in the VDBE. When reaches zero, the u1.isInterrupted
-** field of the sqlite3 structure is set in order to simulate and interrupt.
+** each instruction in the VDBE. When it reaches zero, the u1.isInterrupted
+** field of the sqlite3 structure is set in order to simulate an interrupt.
**
** This facility is used for testing purposes only. It does not function
** in an ordinary build.
@@ -63043,12 +64766,6 @@ SQLITE_API int sqlite3_found_count = 0;
if( ((P)->flags&MEM_Ephem)!=0 \
&& sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
-/*
-** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*)
-** P if required.
-*/
-#define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0)
-
/* Return true if the cursor was opened using the OP_OpenSorter opcode. */
#ifdef SQLITE_OMIT_MERGE_SORT
# define isSorter(x) 0
@@ -63088,7 +64805,7 @@ static VdbeCursor *allocateCursor(
Vdbe *p, /* The virtual machine */
int iCur, /* Index of the new VdbeCursor */
int nField, /* Number of fields in the table or index */
- int iDb, /* When database the cursor belongs to, or -1 */
+ int iDb, /* Database the cursor belongs to, or -1 */
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
@@ -63459,7 +65176,7 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
**
** This macro added to every instruction that does a jump in order to
** implement a loop. This test used to be on every single instruction,
-** but that meant we more testing that we needed. By only testing the
+** but that meant we more testing than we needed. By only testing the
** flag on jump instructions, we get a (small) speed improvement.
*/
#define CHECK_FOR_INTERRUPT \
@@ -63569,48 +65286,51 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
struct OP_Yield_stack_vars {
int pcDest;
} aa;
+ struct OP_Null_stack_vars {
+ int cnt;
+ } ab;
struct OP_Variable_stack_vars {
Mem *pVar; /* Value being transferred */
- } ab;
+ } ac;
struct OP_Move_stack_vars {
char *zMalloc; /* Holding variable for allocated memory */
int n; /* Number of registers left to copy */
int p1; /* Register to copy from */
int p2; /* Register to copy to */
- } ac;
+ } ad;
struct OP_ResultRow_stack_vars {
Mem *pMem;
int i;
- } ad;
+ } ae;
struct OP_Concat_stack_vars {
i64 nByte;
- } ae;
+ } af;
struct OP_Remainder_stack_vars {
int flags; /* Combined MEM_* flags from both inputs */
i64 iA; /* Integer value of left operand */
i64 iB; /* Integer value of right operand */
double rA; /* Real value of left operand */
double rB; /* Real value of right operand */
- } af;
+ } ag;
struct OP_Function_stack_vars {
int i;
Mem *pArg;
sqlite3_context ctx;
sqlite3_value **apVal;
int n;
- } ag;
+ } ah;
struct OP_ShiftRight_stack_vars {
i64 iA;
u64 uA;
i64 iB;
u8 op;
- } ah;
+ } ai;
struct OP_Ge_stack_vars {
int res; /* Result of the comparison of pIn1 against pIn3 */
char affinity; /* Affinity to use for comparison */
u16 flags1; /* Copy of initial value of pIn1->flags */
u16 flags3; /* Copy of initial value of pIn3->flags */
- } ai;
+ } aj;
struct OP_Compare_stack_vars {
int n;
int i;
@@ -63620,14 +65340,14 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int idx;
CollSeq *pColl; /* Collating sequence to use on this term */
int bRev; /* True for DESCENDING sort order */
- } aj;
+ } ak;
struct OP_Or_stack_vars {
int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
- } ak;
+ } al;
struct OP_IfNot_stack_vars {
int c;
- } al;
+ } am;
struct OP_Column_stack_vars {
u32 payloadSize; /* Number of bytes in the record */
i64 payloadSize64; /* Number of bytes in the record */
@@ -63652,11 +65372,11 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int avail; /* Number of bytes of available data */
u32 t; /* A type code from the record header */
Mem *pReg; /* PseudoTable input register */
- } am;
+ } an;
struct OP_Affinity_stack_vars {
const char *zAffinity; /* The affinity to be applied */
char cAff; /* A single character of affinity */
- } an;
+ } ao;
struct OP_MakeRecord_stack_vars {
u8 *zNewRecord; /* A buffer to hold the data for the new record */
Mem *pRec; /* The new record */
@@ -63673,11 +65393,11 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int file_format; /* File format to use for encoding */
int i; /* Space used in zNewRecord[] */
int len; /* Length of a field */
- } ao;
+ } ap;
struct OP_Count_stack_vars {
i64 nEntry;
BtCursor *pCrsr;
- } ap;
+ } aq;
struct OP_Savepoint_stack_vars {
int p1; /* Value of P1 operand */
char *zName; /* Name of savepoint */
@@ -63687,28 +65407,28 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Savepoint *pTmp;
int iSavepoint;
int ii;
- } aq;
+ } ar;
struct OP_AutoCommit_stack_vars {
int desiredAutoCommit;
int iRollback;
int turnOnAC;
- } ar;
+ } as;
struct OP_Transaction_stack_vars {
Btree *pBt;
- } as;
+ } at;
struct OP_ReadCookie_stack_vars {
int iMeta;
int iDb;
int iCookie;
- } at;
+ } au;
struct OP_SetCookie_stack_vars {
Db *pDb;
- } au;
+ } av;
struct OP_VerifyCookie_stack_vars {
int iMeta;
int iGen;
Btree *pBt;
- } av;
+ } aw;
struct OP_OpenWrite_stack_vars {
int nField;
KeyInfo *pKeyInfo;
@@ -63718,16 +65438,16 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Btree *pX;
VdbeCursor *pCur;
Db *pDb;
- } aw;
+ } ax;
struct OP_OpenEphemeral_stack_vars {
VdbeCursor *pCx;
- } ax;
+ } ay;
struct OP_SorterOpen_stack_vars {
VdbeCursor *pCx;
- } ay;
+ } az;
struct OP_OpenPseudo_stack_vars {
VdbeCursor *pCx;
- } az;
+ } ba;
struct OP_SeekGt_stack_vars {
int res;
int oc;
@@ -63735,10 +65455,10 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
UnpackedRecord r;
int nField;
i64 iKey; /* The rowid we are to seek to */
- } ba;
+ } bb;
struct OP_Seek_stack_vars {
VdbeCursor *pC;
- } bb;
+ } bc;
struct OP_Found_stack_vars {
int alreadyExists;
VdbeCursor *pC;
@@ -63747,7 +65467,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
UnpackedRecord *pIdxKey;
UnpackedRecord r;
char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7];
- } bc;
+ } bd;
struct OP_IsUnique_stack_vars {
u16 ii;
VdbeCursor *pCx;
@@ -63756,13 +65476,13 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Mem *aMx;
UnpackedRecord r; /* B-Tree index search key */
i64 R; /* Rowid stored in register P3 */
- } bd;
+ } be;
struct OP_NotExists_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
u64 iKey;
- } be;
+ } bf;
struct OP_NewRowid_stack_vars {
i64 v; /* The new rowid */
VdbeCursor *pC; /* Cursor of table to get the new rowid */
@@ -63770,7 +65490,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int cnt; /* Counter to limit the number of searches */
Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */
VdbeFrame *pFrame; /* Root frame of VDBE */
- } bf;
+ } bg;
struct OP_InsertInt_stack_vars {
Mem *pData; /* MEM cell holding data for the record to be inserted */
Mem *pKey; /* MEM cell holding key for the record */
@@ -63781,89 +65501,89 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
const char *zDb; /* database name - used by the update hook */
const char *zTbl; /* Table name - used by the opdate hook */
int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
- } bg;
+ } bh;
struct OP_Delete_stack_vars {
i64 iKey;
VdbeCursor *pC;
- } bh;
+ } bi;
struct OP_SorterCompare_stack_vars {
VdbeCursor *pC;
int res;
- } bi;
+ } bj;
struct OP_SorterData_stack_vars {
VdbeCursor *pC;
- } bj;
+ } bk;
struct OP_RowData_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
u32 n;
i64 n64;
- } bk;
+ } bl;
struct OP_Rowid_stack_vars {
VdbeCursor *pC;
i64 v;
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
- } bl;
+ } bm;
struct OP_NullRow_stack_vars {
VdbeCursor *pC;
- } bm;
+ } bn;
struct OP_Last_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
- } bn;
+ } bo;
struct OP_Rewind_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
- } bo;
+ } bp;
struct OP_Next_stack_vars {
VdbeCursor *pC;
int res;
- } bp;
+ } bq;
struct OP_IdxInsert_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int nKey;
const char *zKey;
- } bq;
+ } br;
struct OP_IdxDelete_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
UnpackedRecord r;
- } br;
+ } bs;
struct OP_IdxRowid_stack_vars {
BtCursor *pCrsr;
VdbeCursor *pC;
i64 rowid;
- } bs;
+ } bt;
struct OP_IdxGE_stack_vars {
VdbeCursor *pC;
int res;
UnpackedRecord r;
- } bt;
+ } bu;
struct OP_Destroy_stack_vars {
int iMoved;
int iCnt;
Vdbe *pVdbe;
int iDb;
- } bu;
+ } bv;
struct OP_Clear_stack_vars {
int nChange;
- } bv;
+ } bw;
struct OP_CreateTable_stack_vars {
int pgno;
int flags;
Db *pDb;
- } bw;
+ } bx;
struct OP_ParseSchema_stack_vars {
int iDb;
const char *zMaster;
char *zSql;
InitData initData;
- } bx;
+ } by;
struct OP_IntegrityCk_stack_vars {
int nRoot; /* Number of tables to check. (Number of root pages.) */
int *aRoot; /* Array of rootpage numbers for tables to be checked */
@@ -63871,14 +65591,14 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int nErr; /* Number of errors reported */
char *z; /* Text of the error report */
Mem *pnErr; /* Register keeping track of errors remaining */
- } by;
+ } bz;
struct OP_RowSetRead_stack_vars {
i64 val;
- } bz;
+ } ca;
struct OP_RowSetTest_stack_vars {
int iSet;
int exists;
- } ca;
+ } cb;
struct OP_Program_stack_vars {
int nMem; /* Number of memory registers for sub-program */
int nByte; /* Bytes of runtime space required for sub-program */
@@ -63888,15 +65608,15 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
VdbeFrame *pFrame; /* New vdbe frame to execute in */
SubProgram *pProgram; /* Sub-program to execute */
void *t; /* Token identifying trigger */
- } cb;
+ } cc;
struct OP_Param_stack_vars {
VdbeFrame *pFrame;
Mem *pIn;
- } cc;
+ } cd;
struct OP_MemMax_stack_vars {
Mem *pIn1;
VdbeFrame *pFrame;
- } cd;
+ } ce;
struct OP_AggStep_stack_vars {
int n;
int i;
@@ -63904,34 +65624,34 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Mem *pRec;
sqlite3_context ctx;
sqlite3_value **apVal;
- } ce;
+ } cf;
struct OP_AggFinal_stack_vars {
Mem *pMem;
- } cf;
+ } cg;
struct OP_Checkpoint_stack_vars {
int i; /* Loop counter */
int aRes[3]; /* Results */
Mem *pMem; /* Write results here */
- } cg;
+ } ch;
struct OP_JournalMode_stack_vars {
Btree *pBt; /* Btree to change journal mode of */
Pager *pPager; /* Pager associated with pBt */
int eNew; /* New journal mode */
int eOld; /* The old journal mode */
const char *zFilename; /* Name of database file for pPager */
- } ch;
+ } ci;
struct OP_IncrVacuum_stack_vars {
Btree *pBt;
- } ci;
+ } cj;
struct OP_VBegin_stack_vars {
VTable *pVTab;
- } cj;
+ } ck;
struct OP_VOpen_stack_vars {
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
- } ck;
+ } cl;
struct OP_VFilter_stack_vars {
int nArg;
int iQuery;
@@ -63944,23 +65664,23 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int res;
int i;
Mem **apArg;
- } cl;
+ } cm;
struct OP_VColumn_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
- } cm;
+ } cn;
struct OP_VNext_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
VdbeCursor *pCur;
- } cn;
+ } co;
struct OP_VRename_stack_vars {
sqlite3_vtab *pVtab;
Mem *pName;
- } co;
+ } cp;
struct OP_VUpdate_stack_vars {
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
@@ -63969,11 +65689,11 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
sqlite_int64 rowid;
Mem **apArg;
Mem *pX;
- } cp;
+ } cq;
struct OP_Trace_stack_vars {
char *zTrace;
char *z;
- } cq;
+ } cr;
} u;
/* End automatically generated code
********************************************************************/
@@ -64073,7 +65793,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
assert( pOp->p2<=p->nMem );
pOut = &aMem[pOp->p2];
memAboutToChange(p, pOut);
- MemReleaseExt(pOut);
+ VdbeMemRelease(pOut);
pOut->flags = MEM_Int;
}
@@ -64164,7 +65884,8 @@ case OP_Goto: { /* jump */
** Write the current address onto register P1
** and then jump to address P2.
*/
-case OP_Gosub: { /* jump, in1 */
+case OP_Gosub: { /* jump */
+ assert( pOp->p1>0 && pOp->p1<=p->nMem );
pIn1 = &aMem[pOp->p1];
assert( (pIn1->flags & MEM_Dyn)==0 );
memAboutToChange(p, pIn1);
@@ -64363,12 +66084,27 @@ case OP_String: { /* out2-prerelease */
break;
}
-/* Opcode: Null * P2 * * *
+/* Opcode: Null * P2 P3 * *
**
-** Write a NULL into register P2.
+** Write a NULL into registers P2. If P3 greater than P2, then also write
+** NULL into register P3 and ever register in between P2 and P3. If P3
+** is less than P2 (typically P3 is zero) then only register P2 is
+** set to NULL
*/
case OP_Null: { /* out2-prerelease */
+#if 0 /* local variables moved into u.ab */
+ int cnt;
+#endif /* local variables moved into u.ab */
+ u.ab.cnt = pOp->p3-pOp->p2;
+ assert( pOp->p3<=p->nMem );
pOut->flags = MEM_Null;
+ while( u.ab.cnt>0 ){
+ pOut++;
+ memAboutToChange(p, pOut);
+ VdbeMemRelease(pOut);
+ pOut->flags = MEM_Null;
+ u.ab.cnt--;
+ }
break;
}
@@ -64394,17 +66130,17 @@ case OP_Blob: { /* out2-prerelease */
** The P4 value is used by sqlite3_bind_parameter_name().
*/
case OP_Variable: { /* out2-prerelease */
-#if 0 /* local variables moved into u.ab */
+#if 0 /* local variables moved into u.ac */
Mem *pVar; /* Value being transferred */
-#endif /* local variables moved into u.ab */
+#endif /* local variables moved into u.ac */
assert( pOp->p1>0 && pOp->p1<=p->nVar );
assert( pOp->p4.z==0 || pOp->p4.z==p->azVar[pOp->p1-1] );
- u.ab.pVar = &p->aVar[pOp->p1 - 1];
- if( sqlite3VdbeMemTooBig(u.ab.pVar) ){
+ u.ac.pVar = &p->aVar[pOp->p1 - 1];
+ if( sqlite3VdbeMemTooBig(u.ac.pVar) ){
goto too_big;
}
- sqlite3VdbeMemShallowCopy(pOut, u.ab.pVar, MEM_Static);
+ sqlite3VdbeMemShallowCopy(pOut, u.ac.pVar, MEM_Static);
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -64417,36 +66153,36 @@ case OP_Variable: { /* out2-prerelease */
** P1..P1+P3-1 and P2..P2+P3-1 to overlap.
*/
case OP_Move: {
-#if 0 /* local variables moved into u.ac */
+#if 0 /* local variables moved into u.ad */
char *zMalloc; /* Holding variable for allocated memory */
int n; /* Number of registers left to copy */
int p1; /* Register to copy from */
int p2; /* Register to copy to */
-#endif /* local variables moved into u.ac */
+#endif /* local variables moved into u.ad */
- u.ac.n = pOp->p3;
- u.ac.p1 = pOp->p1;
- u.ac.p2 = pOp->p2;
- assert( u.ac.n>0 && u.ac.p1>0 && u.ac.p2>0 );
- assert( u.ac.p1+u.ac.n<=u.ac.p2 || u.ac.p2+u.ac.n<=u.ac.p1 );
+ u.ad.n = pOp->p3;
+ u.ad.p1 = pOp->p1;
+ u.ad.p2 = pOp->p2;
+ assert( u.ad.n>0 && u.ad.p1>0 && u.ad.p2>0 );
+ assert( u.ad.p1+u.ad.n<=u.ad.p2 || u.ad.p2+u.ad.n<=u.ad.p1 );
- pIn1 = &aMem[u.ac.p1];
- pOut = &aMem[u.ac.p2];
- while( u.ac.n-- ){
+ pIn1 = &aMem[u.ad.p1];
+ pOut = &aMem[u.ad.p2];
+ while( u.ad.n-- ){
assert( pOut<=&aMem[p->nMem] );
assert( pIn1<=&aMem[p->nMem] );
assert( memIsValid(pIn1) );
memAboutToChange(p, pOut);
- u.ac.zMalloc = pOut->zMalloc;
+ u.ad.zMalloc = pOut->zMalloc;
pOut->zMalloc = 0;
sqlite3VdbeMemMove(pOut, pIn1);
#ifdef SQLITE_DEBUG
- if( pOut->pScopyFrom>=&aMem[u.ac.p1] && pOut->pScopyFrom<&aMem[u.ac.p1+pOp->p3] ){
- pOut->pScopyFrom += u.ac.p1 - pOp->p2;
+ if( pOut->pScopyFrom>=&aMem[u.ad.p1] && pOut->pScopyFrom<&aMem[u.ad.p1+pOp->p3] ){
+ pOut->pScopyFrom += u.ad.p1 - pOp->p2;
}
#endif
- pIn1->zMalloc = u.ac.zMalloc;
- REGISTER_TRACE(u.ac.p2++, pOut);
+ pIn1->zMalloc = u.ad.zMalloc;
+ REGISTER_TRACE(u.ad.p2++, pOut);
pIn1++;
pOut++;
}
@@ -64503,10 +66239,10 @@ case OP_SCopy: { /* in1, out2 */
** row.
*/
case OP_ResultRow: {
-#if 0 /* local variables moved into u.ad */
+#if 0 /* local variables moved into u.ae */
Mem *pMem;
int i;
-#endif /* local variables moved into u.ad */
+#endif /* local variables moved into u.ae */
assert( p->nResColumn==pOp->p2 );
assert( pOp->p1>0 );
assert( pOp->p1+pOp->p2<=p->nMem+1 );
@@ -64546,17 +66282,17 @@ case OP_ResultRow: {
/* Make sure the results of the current row are \000 terminated
** and have an assigned type. The results are de-ephemeralized as
- ** as side effect.
- */
- u.ad.pMem = p->pResultSet = &aMem[pOp->p1];
- for(u.ad.i=0; u.ad.i<pOp->p2; u.ad.i++){
- assert( memIsValid(&u.ad.pMem[u.ad.i]) );
- Deephemeralize(&u.ad.pMem[u.ad.i]);
- assert( (u.ad.pMem[u.ad.i].flags & MEM_Ephem)==0
- || (u.ad.pMem[u.ad.i].flags & (MEM_Str|MEM_Blob))==0 );
- sqlite3VdbeMemNulTerminate(&u.ad.pMem[u.ad.i]);
- sqlite3VdbeMemStoreType(&u.ad.pMem[u.ad.i]);
- REGISTER_TRACE(pOp->p1+u.ad.i, &u.ad.pMem[u.ad.i]);
+ ** a side effect.
+ */
+ u.ae.pMem = p->pResultSet = &aMem[pOp->p1];
+ for(u.ae.i=0; u.ae.i<pOp->p2; u.ae.i++){
+ assert( memIsValid(&u.ae.pMem[u.ae.i]) );
+ Deephemeralize(&u.ae.pMem[u.ae.i]);
+ assert( (u.ae.pMem[u.ae.i].flags & MEM_Ephem)==0
+ || (u.ae.pMem[u.ae.i].flags & (MEM_Str|MEM_Blob))==0 );
+ sqlite3VdbeMemNulTerminate(&u.ae.pMem[u.ae.i]);
+ sqlite3VdbeMemStoreType(&u.ae.pMem[u.ae.i]);
+ REGISTER_TRACE(pOp->p1+u.ae.i, &u.ae.pMem[u.ae.i]);
}
if( db->mallocFailed ) goto no_mem;
@@ -64580,9 +66316,9 @@ case OP_ResultRow: {
** to avoid a memcpy().
*/
case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
-#if 0 /* local variables moved into u.ae */
+#if 0 /* local variables moved into u.af */
i64 nByte;
-#endif /* local variables moved into u.ae */
+#endif /* local variables moved into u.af */
pIn1 = &aMem[pOp->p1];
pIn2 = &aMem[pOp->p2];
@@ -64595,22 +66331,22 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
if( ExpandBlob(pIn1) || ExpandBlob(pIn2) ) goto no_mem;
Stringify(pIn1, encoding);
Stringify(pIn2, encoding);
- u.ae.nByte = pIn1->n + pIn2->n;
- if( u.ae.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ u.af.nByte = pIn1->n + pIn2->n;
+ if( u.af.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
MemSetTypeFlag(pOut, MEM_Str);
- if( sqlite3VdbeMemGrow(pOut, (int)u.ae.nByte+2, pOut==pIn2) ){
+ if( sqlite3VdbeMemGrow(pOut, (int)u.af.nByte+2, pOut==pIn2) ){
goto no_mem;
}
if( pOut!=pIn2 ){
memcpy(pOut->z, pIn2->z, pIn2->n);
}
memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n);
- pOut->z[u.ae.nByte] = 0;
- pOut->z[u.ae.nByte+1] = 0;
+ pOut->z[u.af.nByte] = 0;
+ pOut->z[u.af.nByte+1] = 0;
pOut->flags |= MEM_Term;
- pOut->n = (int)u.ae.nByte;
+ pOut->n = (int)u.af.nByte;
pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut);
break;
@@ -64654,76 +66390,76 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
-#if 0 /* local variables moved into u.af */
+#if 0 /* local variables moved into u.ag */
int flags; /* Combined MEM_* flags from both inputs */
i64 iA; /* Integer value of left operand */
i64 iB; /* Integer value of right operand */
double rA; /* Real value of left operand */
double rB; /* Real value of right operand */
-#endif /* local variables moved into u.af */
+#endif /* local variables moved into u.ag */
pIn1 = &aMem[pOp->p1];
applyNumericAffinity(pIn1);
pIn2 = &aMem[pOp->p2];
applyNumericAffinity(pIn2);
pOut = &aMem[pOp->p3];
- u.af.flags = pIn1->flags | pIn2->flags;
- if( (u.af.flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
+ u.ag.flags = pIn1->flags | pIn2->flags;
+ if( (u.ag.flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){
- u.af.iA = pIn1->u.i;
- u.af.iB = pIn2->u.i;
+ u.ag.iA = pIn1->u.i;
+ u.ag.iB = pIn2->u.i;
switch( pOp->opcode ){
- case OP_Add: if( sqlite3AddInt64(&u.af.iB,u.af.iA) ) goto fp_math; break;
- case OP_Subtract: if( sqlite3SubInt64(&u.af.iB,u.af.iA) ) goto fp_math; break;
- case OP_Multiply: if( sqlite3MulInt64(&u.af.iB,u.af.iA) ) goto fp_math; break;
+ case OP_Add: if( sqlite3AddInt64(&u.ag.iB,u.ag.iA) ) goto fp_math; break;
+ case OP_Subtract: if( sqlite3SubInt64(&u.ag.iB,u.ag.iA) ) goto fp_math; break;
+ case OP_Multiply: if( sqlite3MulInt64(&u.ag.iB,u.ag.iA) ) goto fp_math; break;
case OP_Divide: {
- if( u.af.iA==0 ) goto arithmetic_result_is_null;
- if( u.af.iA==-1 && u.af.iB==SMALLEST_INT64 ) goto fp_math;
- u.af.iB /= u.af.iA;
+ if( u.ag.iA==0 ) goto arithmetic_result_is_null;
+ if( u.ag.iA==-1 && u.ag.iB==SMALLEST_INT64 ) goto fp_math;
+ u.ag.iB /= u.ag.iA;
break;
}
default: {
- if( u.af.iA==0 ) goto arithmetic_result_is_null;
- if( u.af.iA==-1 ) u.af.iA = 1;
- u.af.iB %= u.af.iA;
+ if( u.ag.iA==0 ) goto arithmetic_result_is_null;
+ if( u.ag.iA==-1 ) u.ag.iA = 1;
+ u.ag.iB %= u.ag.iA;
break;
}
}
- pOut->u.i = u.af.iB;
+ pOut->u.i = u.ag.iB;
MemSetTypeFlag(pOut, MEM_Int);
}else{
fp_math:
- u.af.rA = sqlite3VdbeRealValue(pIn1);
- u.af.rB = sqlite3VdbeRealValue(pIn2);
+ u.ag.rA = sqlite3VdbeRealValue(pIn1);
+ u.ag.rB = sqlite3VdbeRealValue(pIn2);
switch( pOp->opcode ){
- case OP_Add: u.af.rB += u.af.rA; break;
- case OP_Subtract: u.af.rB -= u.af.rA; break;
- case OP_Multiply: u.af.rB *= u.af.rA; break;
+ case OP_Add: u.ag.rB += u.ag.rA; break;
+ case OP_Subtract: u.ag.rB -= u.ag.rA; break;
+ case OP_Multiply: u.ag.rB *= u.ag.rA; break;
case OP_Divide: {
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
- if( u.af.rA==(double)0 ) goto arithmetic_result_is_null;
- u.af.rB /= u.af.rA;
+ if( u.ag.rA==(double)0 ) goto arithmetic_result_is_null;
+ u.ag.rB /= u.ag.rA;
break;
}
default: {
- u.af.iA = (i64)u.af.rA;
- u.af.iB = (i64)u.af.rB;
- if( u.af.iA==0 ) goto arithmetic_result_is_null;
- if( u.af.iA==-1 ) u.af.iA = 1;
- u.af.rB = (double)(u.af.iB % u.af.iA);
+ u.ag.iA = (i64)u.ag.rA;
+ u.ag.iB = (i64)u.ag.rB;
+ if( u.ag.iA==0 ) goto arithmetic_result_is_null;
+ if( u.ag.iA==-1 ) u.ag.iA = 1;
+ u.ag.rB = (double)(u.ag.iB % u.ag.iA);
break;
}
}
#ifdef SQLITE_OMIT_FLOATING_POINT
- pOut->u.i = u.af.rB;
+ pOut->u.i = u.ag.rB;
MemSetTypeFlag(pOut, MEM_Int);
#else
- if( sqlite3IsNaN(u.af.rB) ){
+ if( sqlite3IsNaN(u.ag.rB) ){
goto arithmetic_result_is_null;
}
- pOut->r = u.af.rB;
+ pOut->r = u.ag.rB;
MemSetTypeFlag(pOut, MEM_Real);
- if( (u.af.flags & MEM_Real)==0 ){
+ if( (u.ag.flags & MEM_Real)==0 ){
sqlite3VdbeIntegerAffinity(pOut);
}
#endif
@@ -64735,19 +66471,26 @@ arithmetic_result_is_null:
break;
}
-/* Opcode: CollSeq * * P4
+/* Opcode: CollSeq P1 * * P4
**
** P4 is a pointer to a CollSeq struct. If the next call to a user function
** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
** be returned. This is used by the built-in min(), max() and nullif()
** functions.
**
+** If P1 is not zero, then it is a register that a subsequent min() or
+** max() aggregate will set to 1 if the current row is not the minimum or
+** maximum. The P1 register is initialized to 0 by this instruction.
+**
** The interface used by the implementation of the aforementioned functions
** to retrieve the collation sequence set by this opcode is not available
** publicly, only to user functions defined in func.c.
*/
case OP_CollSeq: {
assert( pOp->p4type==P4_COLLSEQ );
+ if( pOp->p1 ){
+ sqlite3VdbeMemSetInt64(&aMem[pOp->p1], 0);
+ }
break;
}
@@ -64768,70 +66511,70 @@ case OP_CollSeq: {
** See also: AggStep and AggFinal
*/
case OP_Function: {
-#if 0 /* local variables moved into u.ag */
+#if 0 /* local variables moved into u.ah */
int i;
Mem *pArg;
sqlite3_context ctx;
sqlite3_value **apVal;
int n;
-#endif /* local variables moved into u.ag */
+#endif /* local variables moved into u.ah */
- u.ag.n = pOp->p5;
- u.ag.apVal = p->apArg;
- assert( u.ag.apVal || u.ag.n==0 );
+ u.ah.n = pOp->p5;
+ u.ah.apVal = p->apArg;
+ assert( u.ah.apVal || u.ah.n==0 );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
pOut = &aMem[pOp->p3];
memAboutToChange(p, pOut);
- assert( u.ag.n==0 || (pOp->p2>0 && pOp->p2+u.ag.n<=p->nMem+1) );
- assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+u.ag.n );
- u.ag.pArg = &aMem[pOp->p2];
- for(u.ag.i=0; u.ag.i<u.ag.n; u.ag.i++, u.ag.pArg++){
- assert( memIsValid(u.ag.pArg) );
- u.ag.apVal[u.ag.i] = u.ag.pArg;
- Deephemeralize(u.ag.pArg);
- sqlite3VdbeMemStoreType(u.ag.pArg);
- REGISTER_TRACE(pOp->p2+u.ag.i, u.ag.pArg);
+ assert( u.ah.n==0 || (pOp->p2>0 && pOp->p2+u.ah.n<=p->nMem+1) );
+ assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+u.ah.n );
+ u.ah.pArg = &aMem[pOp->p2];
+ for(u.ah.i=0; u.ah.i<u.ah.n; u.ah.i++, u.ah.pArg++){
+ assert( memIsValid(u.ah.pArg) );
+ u.ah.apVal[u.ah.i] = u.ah.pArg;
+ Deephemeralize(u.ah.pArg);
+ sqlite3VdbeMemStoreType(u.ah.pArg);
+ REGISTER_TRACE(pOp->p2+u.ah.i, u.ah.pArg);
}
assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
if( pOp->p4type==P4_FUNCDEF ){
- u.ag.ctx.pFunc = pOp->p4.pFunc;
- u.ag.ctx.pVdbeFunc = 0;
+ u.ah.ctx.pFunc = pOp->p4.pFunc;
+ u.ah.ctx.pVdbeFunc = 0;
}else{
- u.ag.ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc;
- u.ag.ctx.pFunc = u.ag.ctx.pVdbeFunc->pFunc;
+ u.ah.ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc;
+ u.ah.ctx.pFunc = u.ah.ctx.pVdbeFunc->pFunc;
}
- u.ag.ctx.s.flags = MEM_Null;
- u.ag.ctx.s.db = db;
- u.ag.ctx.s.xDel = 0;
- u.ag.ctx.s.zMalloc = 0;
+ u.ah.ctx.s.flags = MEM_Null;
+ u.ah.ctx.s.db = db;
+ u.ah.ctx.s.xDel = 0;
+ u.ah.ctx.s.zMalloc = 0;
/* The output cell may already have a buffer allocated. Move
- ** the pointer to u.ag.ctx.s so in case the user-function can use
+ ** the pointer to u.ah.ctx.s so in case the user-function can use
** the already allocated buffer instead of allocating a new one.
*/
- sqlite3VdbeMemMove(&u.ag.ctx.s, pOut);
- MemSetTypeFlag(&u.ag.ctx.s, MEM_Null);
+ sqlite3VdbeMemMove(&u.ah.ctx.s, pOut);
+ MemSetTypeFlag(&u.ah.ctx.s, MEM_Null);
- u.ag.ctx.isError = 0;
- if( u.ag.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
+ u.ah.ctx.isError = 0;
+ if( u.ah.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
assert( pOp>aOp );
assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
- u.ag.ctx.pColl = pOp[-1].p4.pColl;
+ u.ah.ctx.pColl = pOp[-1].p4.pColl;
}
db->lastRowid = lastRowid;
- (*u.ag.ctx.pFunc->xFunc)(&u.ag.ctx, u.ag.n, u.ag.apVal); /* IMP: R-24505-23230 */
+ (*u.ah.ctx.pFunc->xFunc)(&u.ah.ctx, u.ah.n, u.ah.apVal); /* IMP: R-24505-23230 */
lastRowid = db->lastRowid;
/* If any auxiliary data functions have been called by this user function,
** immediately call the destructor for any non-static values.
*/
- if( u.ag.ctx.pVdbeFunc ){
- sqlite3VdbeDeleteAuxData(u.ag.ctx.pVdbeFunc, pOp->p1);
- pOp->p4.pVdbeFunc = u.ag.ctx.pVdbeFunc;
+ if( u.ah.ctx.pVdbeFunc ){
+ sqlite3VdbeDeleteAuxData(u.ah.ctx.pVdbeFunc, pOp->p1);
+ pOp->p4.pVdbeFunc = u.ah.ctx.pVdbeFunc;
pOp->p4type = P4_VDBEFUNC;
}
@@ -64841,19 +66584,19 @@ case OP_Function: {
** to return a value. The following call releases any resources
** associated with such a value.
*/
- sqlite3VdbeMemRelease(&u.ag.ctx.s);
+ sqlite3VdbeMemRelease(&u.ah.ctx.s);
goto no_mem;
}
/* If the function returned an error, throw an exception */
- if( u.ag.ctx.isError ){
- sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.ag.ctx.s));
- rc = u.ag.ctx.isError;
+ if( u.ah.ctx.isError ){
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.ah.ctx.s));
+ rc = u.ah.ctx.isError;
}
/* Copy the result of the function into register P3 */
- sqlite3VdbeChangeEncoding(&u.ag.ctx.s, encoding);
- sqlite3VdbeMemMove(pOut, &u.ag.ctx.s);
+ sqlite3VdbeChangeEncoding(&u.ah.ctx.s, encoding);
+ sqlite3VdbeMemMove(pOut, &u.ah.ctx.s);
if( sqlite3VdbeMemTooBig(pOut) ){
goto too_big;
}
@@ -64901,12 +66644,12 @@ case OP_BitAnd: /* same as TK_BITAND, in1, in2, out3 */
case OP_BitOr: /* same as TK_BITOR, in1, in2, out3 */
case OP_ShiftLeft: /* same as TK_LSHIFT, in1, in2, out3 */
case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
-#if 0 /* local variables moved into u.ah */
+#if 0 /* local variables moved into u.ai */
i64 iA;
u64 uA;
i64 iB;
u8 op;
-#endif /* local variables moved into u.ah */
+#endif /* local variables moved into u.ai */
pIn1 = &aMem[pOp->p1];
pIn2 = &aMem[pOp->p2];
@@ -64915,38 +66658,38 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
sqlite3VdbeMemSetNull(pOut);
break;
}
- u.ah.iA = sqlite3VdbeIntValue(pIn2);
- u.ah.iB = sqlite3VdbeIntValue(pIn1);
- u.ah.op = pOp->opcode;
- if( u.ah.op==OP_BitAnd ){
- u.ah.iA &= u.ah.iB;
- }else if( u.ah.op==OP_BitOr ){
- u.ah.iA |= u.ah.iB;
- }else if( u.ah.iB!=0 ){
- assert( u.ah.op==OP_ShiftRight || u.ah.op==OP_ShiftLeft );
+ u.ai.iA = sqlite3VdbeIntValue(pIn2);
+ u.ai.iB = sqlite3VdbeIntValue(pIn1);
+ u.ai.op = pOp->opcode;
+ if( u.ai.op==OP_BitAnd ){
+ u.ai.iA &= u.ai.iB;
+ }else if( u.ai.op==OP_BitOr ){
+ u.ai.iA |= u.ai.iB;
+ }else if( u.ai.iB!=0 ){
+ assert( u.ai.op==OP_ShiftRight || u.ai.op==OP_ShiftLeft );
/* If shifting by a negative amount, shift in the other direction */
- if( u.ah.iB<0 ){
+ if( u.ai.iB<0 ){
assert( OP_ShiftRight==OP_ShiftLeft+1 );
- u.ah.op = 2*OP_ShiftLeft + 1 - u.ah.op;
- u.ah.iB = u.ah.iB>(-64) ? -u.ah.iB : 64;
+ u.ai.op = 2*OP_ShiftLeft + 1 - u.ai.op;
+ u.ai.iB = u.ai.iB>(-64) ? -u.ai.iB : 64;
}
- if( u.ah.iB>=64 ){
- u.ah.iA = (u.ah.iA>=0 || u.ah.op==OP_ShiftLeft) ? 0 : -1;
+ if( u.ai.iB>=64 ){
+ u.ai.iA = (u.ai.iA>=0 || u.ai.op==OP_ShiftLeft) ? 0 : -1;
}else{
- memcpy(&u.ah.uA, &u.ah.iA, sizeof(u.ah.uA));
- if( u.ah.op==OP_ShiftLeft ){
- u.ah.uA <<= u.ah.iB;
+ memcpy(&u.ai.uA, &u.ai.iA, sizeof(u.ai.uA));
+ if( u.ai.op==OP_ShiftLeft ){
+ u.ai.uA <<= u.ai.iB;
}else{
- u.ah.uA >>= u.ah.iB;
+ u.ai.uA >>= u.ai.iB;
/* Sign-extend on a right shift of a negative number */
- if( u.ah.iA<0 ) u.ah.uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-u.ah.iB);
+ if( u.ai.iA<0 ) u.ai.uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-u.ai.iB);
}
- memcpy(&u.ah.iA, &u.ah.uA, sizeof(u.ah.iA));
+ memcpy(&u.ai.iA, &u.ai.uA, sizeof(u.ai.iA));
}
}
- pOut->u.i = u.ah.iA;
+ pOut->u.i = u.ai.iA;
MemSetTypeFlag(pOut, MEM_Int);
break;
}
@@ -65187,18 +66930,18 @@ case OP_Lt: /* same as TK_LT, jump, in1, in3 */
case OP_Le: /* same as TK_LE, jump, in1, in3 */
case OP_Gt: /* same as TK_GT, jump, in1, in3 */
case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
-#if 0 /* local variables moved into u.ai */
+#if 0 /* local variables moved into u.aj */
int res; /* Result of the comparison of pIn1 against pIn3 */
char affinity; /* Affinity to use for comparison */
u16 flags1; /* Copy of initial value of pIn1->flags */
u16 flags3; /* Copy of initial value of pIn3->flags */
-#endif /* local variables moved into u.ai */
+#endif /* local variables moved into u.aj */
pIn1 = &aMem[pOp->p1];
pIn3 = &aMem[pOp->p3];
- u.ai.flags1 = pIn1->flags;
- u.ai.flags3 = pIn3->flags;
- if( (u.ai.flags1 | u.ai.flags3)&MEM_Null ){
+ u.aj.flags1 = pIn1->flags;
+ u.aj.flags3 = pIn3->flags;
+ if( (u.aj.flags1 | u.aj.flags3)&MEM_Null ){
/* One or both operands are NULL */
if( pOp->p5 & SQLITE_NULLEQ ){
/* If SQLITE_NULLEQ is set (which will only happen if the operator is
@@ -65206,7 +66949,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** or not both operands are null.
*/
assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
- u.ai.res = (u.ai.flags1 & u.ai.flags3 & MEM_Null)==0;
+ u.aj.res = (u.aj.flags1 & u.aj.flags3 & MEM_Null)==0;
}else{
/* SQLITE_NULLEQ is clear and at least one operand is NULL,
** then the result is always NULL.
@@ -65223,40 +66966,40 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
}
}else{
/* Neither operand is NULL. Do a comparison. */
- u.ai.affinity = pOp->p5 & SQLITE_AFF_MASK;
- if( u.ai.affinity ){
- applyAffinity(pIn1, u.ai.affinity, encoding);
- applyAffinity(pIn3, u.ai.affinity, encoding);
+ u.aj.affinity = pOp->p5 & SQLITE_AFF_MASK;
+ if( u.aj.affinity ){
+ applyAffinity(pIn1, u.aj.affinity, encoding);
+ applyAffinity(pIn3, u.aj.affinity, encoding);
if( db->mallocFailed ) goto no_mem;
}
assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
ExpandBlob(pIn1);
ExpandBlob(pIn3);
- u.ai.res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
+ u.aj.res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
}
switch( pOp->opcode ){
- case OP_Eq: u.ai.res = u.ai.res==0; break;
- case OP_Ne: u.ai.res = u.ai.res!=0; break;
- case OP_Lt: u.ai.res = u.ai.res<0; break;
- case OP_Le: u.ai.res = u.ai.res<=0; break;
- case OP_Gt: u.ai.res = u.ai.res>0; break;
- default: u.ai.res = u.ai.res>=0; break;
+ case OP_Eq: u.aj.res = u.aj.res==0; break;
+ case OP_Ne: u.aj.res = u.aj.res!=0; break;
+ case OP_Lt: u.aj.res = u.aj.res<0; break;
+ case OP_Le: u.aj.res = u.aj.res<=0; break;
+ case OP_Gt: u.aj.res = u.aj.res>0; break;
+ default: u.aj.res = u.aj.res>=0; break;
}
if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
memAboutToChange(p, pOut);
MemSetTypeFlag(pOut, MEM_Int);
- pOut->u.i = u.ai.res;
+ pOut->u.i = u.aj.res;
REGISTER_TRACE(pOp->p2, pOut);
- }else if( u.ai.res ){
+ }else if( u.aj.res ){
pc = pOp->p2-1;
}
/* Undo any changes made by applyAffinity() to the input registers. */
- pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (u.ai.flags1&MEM_TypeMask);
- pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (u.ai.flags3&MEM_TypeMask);
+ pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (u.aj.flags1&MEM_TypeMask);
+ pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (u.aj.flags3&MEM_TypeMask);
break;
}
@@ -65291,7 +67034,7 @@ case OP_Permutation: {
** and strings are less than blobs.
*/
case OP_Compare: {
-#if 0 /* local variables moved into u.aj */
+#if 0 /* local variables moved into u.ak */
int n;
int i;
int p1;
@@ -65300,37 +67043,37 @@ case OP_Compare: {
int idx;
CollSeq *pColl; /* Collating sequence to use on this term */
int bRev; /* True for DESCENDING sort order */
-#endif /* local variables moved into u.aj */
+#endif /* local variables moved into u.ak */
- u.aj.n = pOp->p3;
- u.aj.pKeyInfo = pOp->p4.pKeyInfo;
- assert( u.aj.n>0 );
- assert( u.aj.pKeyInfo!=0 );
- u.aj.p1 = pOp->p1;
- u.aj.p2 = pOp->p2;
+ u.ak.n = pOp->p3;
+ u.ak.pKeyInfo = pOp->p4.pKeyInfo;
+ assert( u.ak.n>0 );
+ assert( u.ak.pKeyInfo!=0 );
+ u.ak.p1 = pOp->p1;
+ u.ak.p2 = pOp->p2;
#if SQLITE_DEBUG
if( aPermute ){
int k, mx = 0;
- for(k=0; k<u.aj.n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
- assert( u.aj.p1>0 && u.aj.p1+mx<=p->nMem+1 );
- assert( u.aj.p2>0 && u.aj.p2+mx<=p->nMem+1 );
+ for(k=0; k<u.ak.n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
+ assert( u.ak.p1>0 && u.ak.p1+mx<=p->nMem+1 );
+ assert( u.ak.p2>0 && u.ak.p2+mx<=p->nMem+1 );
}else{
- assert( u.aj.p1>0 && u.aj.p1+u.aj.n<=p->nMem+1 );
- assert( u.aj.p2>0 && u.aj.p2+u.aj.n<=p->nMem+1 );
+ assert( u.ak.p1>0 && u.ak.p1+u.ak.n<=p->nMem+1 );
+ assert( u.ak.p2>0 && u.ak.p2+u.ak.n<=p->nMem+1 );
}
#endif /* SQLITE_DEBUG */
- for(u.aj.i=0; u.aj.i<u.aj.n; u.aj.i++){
- u.aj.idx = aPermute ? aPermute[u.aj.i] : u.aj.i;
- assert( memIsValid(&aMem[u.aj.p1+u.aj.idx]) );
- assert( memIsValid(&aMem[u.aj.p2+u.aj.idx]) );
- REGISTER_TRACE(u.aj.p1+u.aj.idx, &aMem[u.aj.p1+u.aj.idx]);
- REGISTER_TRACE(u.aj.p2+u.aj.idx, &aMem[u.aj.p2+u.aj.idx]);
- assert( u.aj.i<u.aj.pKeyInfo->nField );
- u.aj.pColl = u.aj.pKeyInfo->aColl[u.aj.i];
- u.aj.bRev = u.aj.pKeyInfo->aSortOrder[u.aj.i];
- iCompare = sqlite3MemCompare(&aMem[u.aj.p1+u.aj.idx], &aMem[u.aj.p2+u.aj.idx], u.aj.pColl);
+ for(u.ak.i=0; u.ak.i<u.ak.n; u.ak.i++){
+ u.ak.idx = aPermute ? aPermute[u.ak.i] : u.ak.i;
+ assert( memIsValid(&aMem[u.ak.p1+u.ak.idx]) );
+ assert( memIsValid(&aMem[u.ak.p2+u.ak.idx]) );
+ REGISTER_TRACE(u.ak.p1+u.ak.idx, &aMem[u.ak.p1+u.ak.idx]);
+ REGISTER_TRACE(u.ak.p2+u.ak.idx, &aMem[u.ak.p2+u.ak.idx]);
+ assert( u.ak.i<u.ak.pKeyInfo->nField );
+ u.ak.pColl = u.ak.pKeyInfo->aColl[u.ak.i];
+ u.ak.bRev = u.ak.pKeyInfo->aSortOrder[u.ak.i];
+ iCompare = sqlite3MemCompare(&aMem[u.ak.p1+u.ak.idx], &aMem[u.ak.p2+u.ak.idx], u.ak.pColl);
if( iCompare ){
- if( u.aj.bRev ) iCompare = -iCompare;
+ if( u.ak.bRev ) iCompare = -iCompare;
break;
}
}
@@ -65375,35 +67118,35 @@ case OP_Jump: { /* jump */
*/
case OP_And: /* same as TK_AND, in1, in2, out3 */
case OP_Or: { /* same as TK_OR, in1, in2, out3 */
-#if 0 /* local variables moved into u.ak */
+#if 0 /* local variables moved into u.al */
int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
-#endif /* local variables moved into u.ak */
+#endif /* local variables moved into u.al */
pIn1 = &aMem[pOp->p1];
if( pIn1->flags & MEM_Null ){
- u.ak.v1 = 2;
+ u.al.v1 = 2;
}else{
- u.ak.v1 = sqlite3VdbeIntValue(pIn1)!=0;
+ u.al.v1 = sqlite3VdbeIntValue(pIn1)!=0;
}
pIn2 = &aMem[pOp->p2];
if( pIn2->flags & MEM_Null ){
- u.ak.v2 = 2;
+ u.al.v2 = 2;
}else{
- u.ak.v2 = sqlite3VdbeIntValue(pIn2)!=0;
+ u.al.v2 = sqlite3VdbeIntValue(pIn2)!=0;
}
if( pOp->opcode==OP_And ){
static const unsigned char and_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 };
- u.ak.v1 = and_logic[u.ak.v1*3+u.ak.v2];
+ u.al.v1 = and_logic[u.al.v1*3+u.al.v2];
}else{
static const unsigned char or_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 };
- u.ak.v1 = or_logic[u.ak.v1*3+u.ak.v2];
+ u.al.v1 = or_logic[u.al.v1*3+u.al.v2];
}
pOut = &aMem[pOp->p3];
- if( u.ak.v1==2 ){
+ if( u.al.v1==2 ){
MemSetTypeFlag(pOut, MEM_Null);
}else{
- pOut->u.i = u.ak.v1;
+ pOut->u.i = u.al.v1;
MemSetTypeFlag(pOut, MEM_Int);
}
break;
@@ -65445,51 +67188,51 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
/* Opcode: Once P1 P2 * * *
**
-** Jump to P2 if the value in register P1 is a not null or zero. If
-** the value is NULL or zero, fall through and change the P1 register
-** to an integer 1.
+** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
+** set the flag and fall through to the next instruction.
**
-** When P1 is not used otherwise in a program, this opcode falls through
-** once and jumps on all subsequent invocations. It is the equivalent
-** of "OP_If P1 P2", followed by "OP_Integer 1 P1".
+** See also: JumpOnce
*/
+case OP_Once: { /* jump */
+ assert( pOp->p1<p->nOnceFlag );
+ if( p->aOnceFlag[pOp->p1] ){
+ pc = pOp->p2-1;
+ }else{
+ p->aOnceFlag[pOp->p1] = 1;
+ }
+ break;
+}
+
/* Opcode: If P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is true. The value
** is considered true if it is numeric and non-zero. If the value
-** in P1 is NULL then take the jump if P3 is true.
+** in P1 is NULL then take the jump if P3 is non-zero.
*/
/* Opcode: IfNot P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is False. The value
-** is considered true if it has a numeric value of zero. If the value
-** in P1 is NULL then take the jump if P3 is true.
+** is considered false if it has a numeric value of zero. If the value
+** in P1 is NULL then take the jump if P3 is zero.
*/
-case OP_Once: /* jump, in1 */
case OP_If: /* jump, in1 */
case OP_IfNot: { /* jump, in1 */
-#if 0 /* local variables moved into u.al */
+#if 0 /* local variables moved into u.am */
int c;
-#endif /* local variables moved into u.al */
+#endif /* local variables moved into u.am */
pIn1 = &aMem[pOp->p1];
if( pIn1->flags & MEM_Null ){
- u.al.c = pOp->p3;
+ u.am.c = pOp->p3;
}else{
#ifdef SQLITE_OMIT_FLOATING_POINT
- u.al.c = sqlite3VdbeIntValue(pIn1)!=0;
+ u.am.c = sqlite3VdbeIntValue(pIn1)!=0;
#else
- u.al.c = sqlite3VdbeRealValue(pIn1)!=0.0;
+ u.am.c = sqlite3VdbeRealValue(pIn1)!=0.0;
#endif
- if( pOp->opcode==OP_IfNot ) u.al.c = !u.al.c;
+ if( pOp->opcode==OP_IfNot ) u.am.c = !u.am.c;
}
- if( u.al.c ){
+ if( u.am.c ){
pc = pOp->p2-1;
- }else if( pOp->opcode==OP_Once ){
- assert( (pIn1->flags & (MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))==0 );
- memAboutToChange(p, pIn1);
- pIn1->flags = MEM_Int;
- pIn1->u.i = 1;
- REGISTER_TRACE(pOp->p1, pIn1);
}
break;
}
@@ -65536,9 +67279,14 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
** then the cache of the cursor is reset prior to extracting the column.
** The first OP_Column against a pseudo-table after the value of the content
** register has changed should have this bit set.
+**
+** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when
+** the result is guaranteed to only be used as the argument of a length()
+** or typeof() function, respectively. The loading of large blobs can be
+** skipped for length() and all content loading can be skipped for typeof().
*/
case OP_Column: {
-#if 0 /* local variables moved into u.am */
+#if 0 /* local variables moved into u.an */
u32 payloadSize; /* Number of bytes in the record */
i64 payloadSize64; /* Number of bytes in the record */
int p1; /* P1 value of the opcode */
@@ -65562,126 +67310,126 @@ case OP_Column: {
int avail; /* Number of bytes of available data */
u32 t; /* A type code from the record header */
Mem *pReg; /* PseudoTable input register */
-#endif /* local variables moved into u.am */
+#endif /* local variables moved into u.an */
- u.am.p1 = pOp->p1;
- u.am.p2 = pOp->p2;
- u.am.pC = 0;
- memset(&u.am.sMem, 0, sizeof(u.am.sMem));
- assert( u.am.p1<p->nCursor );
+ u.an.p1 = pOp->p1;
+ u.an.p2 = pOp->p2;
+ u.an.pC = 0;
+ memset(&u.an.sMem, 0, sizeof(u.an.sMem));
+ assert( u.an.p1<p->nCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- u.am.pDest = &aMem[pOp->p3];
- memAboutToChange(p, u.am.pDest);
- u.am.zRec = 0;
+ u.an.pDest = &aMem[pOp->p3];
+ memAboutToChange(p, u.an.pDest);
+ u.an.zRec = 0;
- /* This block sets the variable u.am.payloadSize to be the total number of
+ /* This block sets the variable u.an.payloadSize to be the total number of
** bytes in the record.
**
- ** u.am.zRec is set to be the complete text of the record if it is available.
+ ** u.an.zRec is set to be the complete text of the record if it is available.
** The complete record text is always available for pseudo-tables
** If the record is stored in a cursor, the complete record text
- ** might be available in the u.am.pC->aRow cache. Or it might not be.
- ** If the data is unavailable, u.am.zRec is set to NULL.
+ ** might be available in the u.an.pC->aRow cache. Or it might not be.
+ ** If the data is unavailable, u.an.zRec is set to NULL.
**
** We also compute the number of columns in the record. For cursors,
** the number of columns is stored in the VdbeCursor.nField element.
*/
- u.am.pC = p->apCsr[u.am.p1];
- assert( u.am.pC!=0 );
+ u.an.pC = p->apCsr[u.an.p1];
+ assert( u.an.pC!=0 );
#ifndef SQLITE_OMIT_VIRTUALTABLE
- assert( u.am.pC->pVtabCursor==0 );
+ assert( u.an.pC->pVtabCursor==0 );
#endif
- u.am.pCrsr = u.am.pC->pCursor;
- if( u.am.pCrsr!=0 ){
+ u.an.pCrsr = u.an.pC->pCursor;
+ if( u.an.pCrsr!=0 ){
/* The record is stored in a B-Tree */
- rc = sqlite3VdbeCursorMoveto(u.am.pC);
+ rc = sqlite3VdbeCursorMoveto(u.an.pC);
if( rc ) goto abort_due_to_error;
- if( u.am.pC->nullRow ){
- u.am.payloadSize = 0;
- }else if( u.am.pC->cacheStatus==p->cacheCtr ){
- u.am.payloadSize = u.am.pC->payloadSize;
- u.am.zRec = (char*)u.am.pC->aRow;
- }else if( u.am.pC->isIndex ){
- assert( sqlite3BtreeCursorIsValid(u.am.pCrsr) );
- VVA_ONLY(rc =) sqlite3BtreeKeySize(u.am.pCrsr, &u.am.payloadSize64);
+ if( u.an.pC->nullRow ){
+ u.an.payloadSize = 0;
+ }else if( u.an.pC->cacheStatus==p->cacheCtr ){
+ u.an.payloadSize = u.an.pC->payloadSize;
+ u.an.zRec = (char*)u.an.pC->aRow;
+ }else if( u.an.pC->isIndex ){
+ assert( sqlite3BtreeCursorIsValid(u.an.pCrsr) );
+ VVA_ONLY(rc =) sqlite3BtreeKeySize(u.an.pCrsr, &u.an.payloadSize64);
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
/* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
- ** payload size, so it is impossible for u.am.payloadSize64 to be
+ ** payload size, so it is impossible for u.an.payloadSize64 to be
** larger than 32 bits. */
- assert( (u.am.payloadSize64 & SQLITE_MAX_U32)==(u64)u.am.payloadSize64 );
- u.am.payloadSize = (u32)u.am.payloadSize64;
+ assert( (u.an.payloadSize64 & SQLITE_MAX_U32)==(u64)u.an.payloadSize64 );
+ u.an.payloadSize = (u32)u.an.payloadSize64;
}else{
- assert( sqlite3BtreeCursorIsValid(u.am.pCrsr) );
- VVA_ONLY(rc =) sqlite3BtreeDataSize(u.am.pCrsr, &u.am.payloadSize);
+ assert( sqlite3BtreeCursorIsValid(u.an.pCrsr) );
+ VVA_ONLY(rc =) sqlite3BtreeDataSize(u.an.pCrsr, &u.an.payloadSize);
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
}
- }else if( ALWAYS(u.am.pC->pseudoTableReg>0) ){
- u.am.pReg = &aMem[u.am.pC->pseudoTableReg];
- assert( u.am.pReg->flags & MEM_Blob );
- assert( memIsValid(u.am.pReg) );
- u.am.payloadSize = u.am.pReg->n;
- u.am.zRec = u.am.pReg->z;
- u.am.pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
- assert( u.am.payloadSize==0 || u.am.zRec!=0 );
+ }else if( ALWAYS(u.an.pC->pseudoTableReg>0) ){
+ u.an.pReg = &aMem[u.an.pC->pseudoTableReg];
+ assert( u.an.pReg->flags & MEM_Blob );
+ assert( memIsValid(u.an.pReg) );
+ u.an.payloadSize = u.an.pReg->n;
+ u.an.zRec = u.an.pReg->z;
+ u.an.pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
+ assert( u.an.payloadSize==0 || u.an.zRec!=0 );
}else{
/* Consider the row to be NULL */
- u.am.payloadSize = 0;
+ u.an.payloadSize = 0;
}
- /* If u.am.payloadSize is 0, then just store a NULL. This can happen because of
+ /* If u.an.payloadSize is 0, then just store a NULL. This can happen because of
** nullRow or because of a corrupt database. */
- if( u.am.payloadSize==0 ){
- MemSetTypeFlag(u.am.pDest, MEM_Null);
+ if( u.an.payloadSize==0 ){
+ MemSetTypeFlag(u.an.pDest, MEM_Null);
goto op_column_out;
}
assert( db->aLimit[SQLITE_LIMIT_LENGTH]>=0 );
- if( u.am.payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ if( u.an.payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
- u.am.nField = u.am.pC->nField;
- assert( u.am.p2<u.am.nField );
+ u.an.nField = u.an.pC->nField;
+ assert( u.an.p2<u.an.nField );
/* Read and parse the table header. Store the results of the parse
** into the record header cache fields of the cursor.
*/
- u.am.aType = u.am.pC->aType;
- if( u.am.pC->cacheStatus==p->cacheCtr ){
- u.am.aOffset = u.am.pC->aOffset;
+ u.an.aType = u.an.pC->aType;
+ if( u.an.pC->cacheStatus==p->cacheCtr ){
+ u.an.aOffset = u.an.pC->aOffset;
}else{
- assert(u.am.aType);
- u.am.avail = 0;
- u.am.pC->aOffset = u.am.aOffset = &u.am.aType[u.am.nField];
- u.am.pC->payloadSize = u.am.payloadSize;
- u.am.pC->cacheStatus = p->cacheCtr;
+ assert(u.an.aType);
+ u.an.avail = 0;
+ u.an.pC->aOffset = u.an.aOffset = &u.an.aType[u.an.nField];
+ u.an.pC->payloadSize = u.an.payloadSize;
+ u.an.pC->cacheStatus = p->cacheCtr;
/* Figure out how many bytes are in the header */
- if( u.am.zRec ){
- u.am.zData = u.am.zRec;
+ if( u.an.zRec ){
+ u.an.zData = u.an.zRec;
}else{
- if( u.am.pC->isIndex ){
- u.am.zData = (char*)sqlite3BtreeKeyFetch(u.am.pCrsr, &u.am.avail);
+ if( u.an.pC->isIndex ){
+ u.an.zData = (char*)sqlite3BtreeKeyFetch(u.an.pCrsr, &u.an.avail);
}else{
- u.am.zData = (char*)sqlite3BtreeDataFetch(u.am.pCrsr, &u.am.avail);
+ u.an.zData = (char*)sqlite3BtreeDataFetch(u.an.pCrsr, &u.an.avail);
}
/* If KeyFetch()/DataFetch() managed to get the entire payload,
- ** save the payload in the u.am.pC->aRow cache. That will save us from
+ ** save the payload in the u.an.pC->aRow cache. That will save us from
** having to make additional calls to fetch the content portion of
** the record.
*/
- assert( u.am.avail>=0 );
- if( u.am.payloadSize <= (u32)u.am.avail ){
- u.am.zRec = u.am.zData;
- u.am.pC->aRow = (u8*)u.am.zData;
+ assert( u.an.avail>=0 );
+ if( u.an.payloadSize <= (u32)u.an.avail ){
+ u.an.zRec = u.an.zData;
+ u.an.pC->aRow = (u8*)u.an.zData;
}else{
- u.am.pC->aRow = 0;
+ u.an.pC->aRow = 0;
}
}
- /* The following assert is true in all cases accept when
+ /* The following assert is true in all cases except when
** the database file has been corrupted externally.
- ** assert( u.am.zRec!=0 || u.am.avail>=u.am.payloadSize || u.am.avail>=9 ); */
- u.am.szHdr = getVarint32((u8*)u.am.zData, u.am.offset);
+ ** assert( u.an.zRec!=0 || u.an.avail>=u.an.payloadSize || u.an.avail>=9 ); */
+ u.an.szHdr = getVarint32((u8*)u.an.zData, u.an.offset);
/* Make sure a corrupt database has not given us an oversize header.
** Do this now to avoid an oversize memory allocation.
@@ -65692,26 +67440,26 @@ case OP_Column: {
** 3-byte type for each of the maximum of 32768 columns plus three
** extra bytes for the header length itself. 32768*3 + 3 = 98307.
*/
- if( u.am.offset > 98307 ){
+ if( u.an.offset > 98307 ){
rc = SQLITE_CORRUPT_BKPT;
goto op_column_out;
}
- /* Compute in u.am.len the number of bytes of data we need to read in order
- ** to get u.am.nField type values. u.am.offset is an upper bound on this. But
- ** u.am.nField might be significantly less than the true number of columns
- ** in the table, and in that case, 5*u.am.nField+3 might be smaller than u.am.offset.
- ** We want to minimize u.am.len in order to limit the size of the memory
- ** allocation, especially if a corrupt database file has caused u.am.offset
+ /* Compute in u.an.len the number of bytes of data we need to read in order
+ ** to get u.an.nField type values. u.an.offset is an upper bound on this. But
+ ** u.an.nField might be significantly less than the true number of columns
+ ** in the table, and in that case, 5*u.an.nField+3 might be smaller than u.an.offset.
+ ** We want to minimize u.an.len in order to limit the size of the memory
+ ** allocation, especially if a corrupt database file has caused u.an.offset
** to be oversized. Offset is limited to 98307 above. But 98307 might
** still exceed Robson memory allocation limits on some configurations.
- ** On systems that cannot tolerate large memory allocations, u.am.nField*5+3
- ** will likely be much smaller since u.am.nField will likely be less than
+ ** On systems that cannot tolerate large memory allocations, u.an.nField*5+3
+ ** will likely be much smaller since u.an.nField will likely be less than
** 20 or so. This insures that Robson memory allocation limits are
** not exceeded even for corrupt database files.
*/
- u.am.len = u.am.nField*5 + 3;
- if( u.am.len > (int)u.am.offset ) u.am.len = (int)u.am.offset;
+ u.an.len = u.an.nField*5 + 3;
+ if( u.an.len > (int)u.an.offset ) u.an.len = (int)u.an.offset;
/* The KeyFetch() or DataFetch() above are fast and will get the entire
** record header in most cases. But they will fail to get the complete
@@ -65719,51 +67467,51 @@ case OP_Column: {
** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to
** acquire the complete header text.
*/
- if( !u.am.zRec && u.am.avail<u.am.len ){
- u.am.sMem.flags = 0;
- u.am.sMem.db = 0;
- rc = sqlite3VdbeMemFromBtree(u.am.pCrsr, 0, u.am.len, u.am.pC->isIndex, &u.am.sMem);
+ if( !u.an.zRec && u.an.avail<u.an.len ){
+ u.an.sMem.flags = 0;
+ u.an.sMem.db = 0;
+ rc = sqlite3VdbeMemFromBtree(u.an.pCrsr, 0, u.an.len, u.an.pC->isIndex, &u.an.sMem);
if( rc!=SQLITE_OK ){
goto op_column_out;
}
- u.am.zData = u.am.sMem.z;
+ u.an.zData = u.an.sMem.z;
}
- u.am.zEndHdr = (u8 *)&u.am.zData[u.am.len];
- u.am.zIdx = (u8 *)&u.am.zData[u.am.szHdr];
+ u.an.zEndHdr = (u8 *)&u.an.zData[u.an.len];
+ u.an.zIdx = (u8 *)&u.an.zData[u.an.szHdr];
- /* Scan the header and use it to fill in the u.am.aType[] and u.am.aOffset[]
- ** arrays. u.am.aType[u.am.i] will contain the type integer for the u.am.i-th
- ** column and u.am.aOffset[u.am.i] will contain the u.am.offset from the beginning
- ** of the record to the start of the data for the u.am.i-th column
+ /* Scan the header and use it to fill in the u.an.aType[] and u.an.aOffset[]
+ ** arrays. u.an.aType[u.an.i] will contain the type integer for the u.an.i-th
+ ** column and u.an.aOffset[u.an.i] will contain the u.an.offset from the beginning
+ ** of the record to the start of the data for the u.an.i-th column
*/
- for(u.am.i=0; u.am.i<u.am.nField; u.am.i++){
- if( u.am.zIdx<u.am.zEndHdr ){
- u.am.aOffset[u.am.i] = u.am.offset;
- if( u.am.zIdx[0]<0x80 ){
- u.am.t = u.am.zIdx[0];
- u.am.zIdx++;
+ for(u.an.i=0; u.an.i<u.an.nField; u.an.i++){
+ if( u.an.zIdx<u.an.zEndHdr ){
+ u.an.aOffset[u.an.i] = u.an.offset;
+ if( u.an.zIdx[0]<0x80 ){
+ u.an.t = u.an.zIdx[0];
+ u.an.zIdx++;
}else{
- u.am.zIdx += sqlite3GetVarint32(u.am.zIdx, &u.am.t);
+ u.an.zIdx += sqlite3GetVarint32(u.an.zIdx, &u.an.t);
}
- u.am.aType[u.am.i] = u.am.t;
- u.am.szField = sqlite3VdbeSerialTypeLen(u.am.t);
- u.am.offset += u.am.szField;
- if( u.am.offset<u.am.szField ){ /* True if u.am.offset overflows */
- u.am.zIdx = &u.am.zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
+ u.an.aType[u.an.i] = u.an.t;
+ u.an.szField = sqlite3VdbeSerialTypeLen(u.an.t);
+ u.an.offset += u.an.szField;
+ if( u.an.offset<u.an.szField ){ /* True if u.an.offset overflows */
+ u.an.zIdx = &u.an.zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
break;
}
}else{
- /* If u.am.i is less that u.am.nField, then there are less fields in this
+ /* If u.an.i is less that u.an.nField, then there are fewer fields in this
** record than SetNumColumns indicated there are columns in the
- ** table. Set the u.am.offset for any extra columns not present in
- ** the record to 0. This tells code below to store a NULL
- ** instead of deserializing a value from the record.
+ ** table. Set the u.an.offset for any extra columns not present in
+ ** the record to 0. This tells code below to store the default value
+ ** for the column instead of deserializing a value from the record.
*/
- u.am.aOffset[u.am.i] = 0;
+ u.an.aOffset[u.an.i] = 0;
}
}
- sqlite3VdbeMemRelease(&u.am.sMem);
- u.am.sMem.flags = MEM_Null;
+ sqlite3VdbeMemRelease(&u.an.sMem);
+ u.an.sMem.flags = MEM_Null;
/* If we have read more header data than was contained in the header,
** or if the end of the last field appears to be past the end of the
@@ -65771,63 +67519,78 @@ case OP_Column: {
** of the record (when all fields present), then we must be dealing
** with a corrupt database.
*/
- if( (u.am.zIdx > u.am.zEndHdr) || (u.am.offset > u.am.payloadSize)
- || (u.am.zIdx==u.am.zEndHdr && u.am.offset!=u.am.payloadSize) ){
+ if( (u.an.zIdx > u.an.zEndHdr) || (u.an.offset > u.an.payloadSize)
+ || (u.an.zIdx==u.an.zEndHdr && u.an.offset!=u.an.payloadSize) ){
rc = SQLITE_CORRUPT_BKPT;
goto op_column_out;
}
}
- /* Get the column information. If u.am.aOffset[u.am.p2] is non-zero, then
- ** deserialize the value from the record. If u.am.aOffset[u.am.p2] is zero,
+ /* Get the column information. If u.an.aOffset[u.an.p2] is non-zero, then
+ ** deserialize the value from the record. If u.an.aOffset[u.an.p2] is zero,
** then there are not enough fields in the record to satisfy the
** request. In this case, set the value NULL or to P4 if P4 is
** a pointer to a Mem object.
*/
- if( u.am.aOffset[u.am.p2] ){
+ if( u.an.aOffset[u.an.p2] ){
assert( rc==SQLITE_OK );
- if( u.am.zRec ){
- MemReleaseExt(u.am.pDest);
- sqlite3VdbeSerialGet((u8 *)&u.am.zRec[u.am.aOffset[u.am.p2]], u.am.aType[u.am.p2], u.am.pDest);
+ if( u.an.zRec ){
+ /* This is the common case where the whole row fits on a single page */
+ VdbeMemRelease(u.an.pDest);
+ sqlite3VdbeSerialGet((u8 *)&u.an.zRec[u.an.aOffset[u.an.p2]], u.an.aType[u.an.p2], u.an.pDest);
}else{
- u.am.len = sqlite3VdbeSerialTypeLen(u.am.aType[u.am.p2]);
- sqlite3VdbeMemMove(&u.am.sMem, u.am.pDest);
- rc = sqlite3VdbeMemFromBtree(u.am.pCrsr, u.am.aOffset[u.am.p2], u.am.len, u.am.pC->isIndex, &u.am.sMem);
- if( rc!=SQLITE_OK ){
- goto op_column_out;
+ /* This branch happens only when the row overflows onto multiple pages */
+ u.an.t = u.an.aType[u.an.p2];
+ if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
+ && ((u.an.t>=12 && (u.an.t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)
+ ){
+ /* Content is irrelevant for the typeof() function and for
+ ** the length(X) function if X is a blob. So we might as well use
+ ** bogus content rather than reading content from disk. NULL works
+ ** for text and blob and whatever is in the u.an.payloadSize64 variable
+ ** will work for everything else. */
+ u.an.zData = u.an.t<12 ? (char*)&u.an.payloadSize64 : 0;
+ }else{
+ u.an.len = sqlite3VdbeSerialTypeLen(u.an.t);
+ sqlite3VdbeMemMove(&u.an.sMem, u.an.pDest);
+ rc = sqlite3VdbeMemFromBtree(u.an.pCrsr, u.an.aOffset[u.an.p2], u.an.len, u.an.pC->isIndex,
+ &u.an.sMem);
+ if( rc!=SQLITE_OK ){
+ goto op_column_out;
+ }
+ u.an.zData = u.an.sMem.z;
}
- u.am.zData = u.am.sMem.z;
- sqlite3VdbeSerialGet((u8*)u.am.zData, u.am.aType[u.am.p2], u.am.pDest);
+ sqlite3VdbeSerialGet((u8*)u.an.zData, u.an.t, u.an.pDest);
}
- u.am.pDest->enc = encoding;
+ u.an.pDest->enc = encoding;
}else{
if( pOp->p4type==P4_MEM ){
- sqlite3VdbeMemShallowCopy(u.am.pDest, pOp->p4.pMem, MEM_Static);
+ sqlite3VdbeMemShallowCopy(u.an.pDest, pOp->p4.pMem, MEM_Static);
}else{
- MemSetTypeFlag(u.am.pDest, MEM_Null);
+ MemSetTypeFlag(u.an.pDest, MEM_Null);
}
}
/* If we dynamically allocated space to hold the data (in the
** sqlite3VdbeMemFromBtree() call above) then transfer control of that
- ** dynamically allocated space over to the u.am.pDest structure.
+ ** dynamically allocated space over to the u.an.pDest structure.
** This prevents a memory copy.
*/
- if( u.am.sMem.zMalloc ){
- assert( u.am.sMem.z==u.am.sMem.zMalloc );
- assert( !(u.am.pDest->flags & MEM_Dyn) );
- assert( !(u.am.pDest->flags & (MEM_Blob|MEM_Str)) || u.am.pDest->z==u.am.sMem.z );
- u.am.pDest->flags &= ~(MEM_Ephem|MEM_Static);
- u.am.pDest->flags |= MEM_Term;
- u.am.pDest->z = u.am.sMem.z;
- u.am.pDest->zMalloc = u.am.sMem.zMalloc;
+ if( u.an.sMem.zMalloc ){
+ assert( u.an.sMem.z==u.an.sMem.zMalloc );
+ assert( !(u.an.pDest->flags & MEM_Dyn) );
+ assert( !(u.an.pDest->flags & (MEM_Blob|MEM_Str)) || u.an.pDest->z==u.an.sMem.z );
+ u.an.pDest->flags &= ~(MEM_Ephem|MEM_Static);
+ u.an.pDest->flags |= MEM_Term;
+ u.an.pDest->z = u.an.sMem.z;
+ u.an.pDest->zMalloc = u.an.sMem.zMalloc;
}
- rc = sqlite3VdbeMemMakeWriteable(u.am.pDest);
+ rc = sqlite3VdbeMemMakeWriteable(u.an.pDest);
op_column_out:
- UPDATE_MAX_BLOBSIZE(u.am.pDest);
- REGISTER_TRACE(pOp->p3, u.am.pDest);
+ UPDATE_MAX_BLOBSIZE(u.an.pDest);
+ REGISTER_TRACE(pOp->p3, u.an.pDest);
break;
}
@@ -65840,20 +67603,20 @@ op_column_out:
** memory cell in the range.
*/
case OP_Affinity: {
-#if 0 /* local variables moved into u.an */
+#if 0 /* local variables moved into u.ao */
const char *zAffinity; /* The affinity to be applied */
char cAff; /* A single character of affinity */
-#endif /* local variables moved into u.an */
+#endif /* local variables moved into u.ao */
- u.an.zAffinity = pOp->p4.z;
- assert( u.an.zAffinity!=0 );
- assert( u.an.zAffinity[pOp->p2]==0 );
+ u.ao.zAffinity = pOp->p4.z;
+ assert( u.ao.zAffinity!=0 );
+ assert( u.ao.zAffinity[pOp->p2]==0 );
pIn1 = &aMem[pOp->p1];
- while( (u.an.cAff = *(u.an.zAffinity++))!=0 ){
+ while( (u.ao.cAff = *(u.ao.zAffinity++))!=0 ){
assert( pIn1 <= &p->aMem[p->nMem] );
assert( memIsValid(pIn1) );
ExpandBlob(pIn1);
- applyAffinity(pIn1, u.an.cAff, encoding);
+ applyAffinity(pIn1, u.ao.cAff, encoding);
pIn1++;
}
break;
@@ -65875,7 +67638,7 @@ case OP_Affinity: {
** If P4 is NULL then all index fields have the affinity NONE.
*/
case OP_MakeRecord: {
-#if 0 /* local variables moved into u.ao */
+#if 0 /* local variables moved into u.ap */
u8 *zNewRecord; /* A buffer to hold the data for the new record */
Mem *pRec; /* The new record */
u64 nData; /* Number of bytes of data space */
@@ -65891,7 +67654,7 @@ case OP_MakeRecord: {
int file_format; /* File format to use for encoding */
int i; /* Space used in zNewRecord[] */
int len; /* Length of a field */
-#endif /* local variables moved into u.ao */
+#endif /* local variables moved into u.ap */
/* Assuming the record contains N fields, the record format looks
** like this:
@@ -65908,16 +67671,16 @@ case OP_MakeRecord: {
** hdr-size field is also a varint which is the offset from the beginning
** of the record to data0.
*/
- u.ao.nData = 0; /* Number of bytes of data space */
- u.ao.nHdr = 0; /* Number of bytes of header space */
- u.ao.nZero = 0; /* Number of zero bytes at the end of the record */
- u.ao.nField = pOp->p1;
- u.ao.zAffinity = pOp->p4.z;
- assert( u.ao.nField>0 && pOp->p2>0 && pOp->p2+u.ao.nField<=p->nMem+1 );
- u.ao.pData0 = &aMem[u.ao.nField];
- u.ao.nField = pOp->p2;
- u.ao.pLast = &u.ao.pData0[u.ao.nField-1];
- u.ao.file_format = p->minWriteFileFormat;
+ u.ap.nData = 0; /* Number of bytes of data space */
+ u.ap.nHdr = 0; /* Number of bytes of header space */
+ u.ap.nZero = 0; /* Number of zero bytes at the end of the record */
+ u.ap.nField = pOp->p1;
+ u.ap.zAffinity = pOp->p4.z;
+ assert( u.ap.nField>0 && pOp->p2>0 && pOp->p2+u.ap.nField<=p->nMem+1 );
+ u.ap.pData0 = &aMem[u.ap.nField];
+ u.ap.nField = pOp->p2;
+ u.ap.pLast = &u.ap.pData0[u.ap.nField-1];
+ u.ap.file_format = p->minWriteFileFormat;
/* Identify the output register */
assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
@@ -65927,34 +67690,34 @@ case OP_MakeRecord: {
/* Loop through the elements that will make up the record to figure
** out how much space is required for the new record.
*/
- for(u.ao.pRec=u.ao.pData0; u.ao.pRec<=u.ao.pLast; u.ao.pRec++){
- assert( memIsValid(u.ao.pRec) );
- if( u.ao.zAffinity ){
- applyAffinity(u.ao.pRec, u.ao.zAffinity[u.ao.pRec-u.ao.pData0], encoding);
+ for(u.ap.pRec=u.ap.pData0; u.ap.pRec<=u.ap.pLast; u.ap.pRec++){
+ assert( memIsValid(u.ap.pRec) );
+ if( u.ap.zAffinity ){
+ applyAffinity(u.ap.pRec, u.ap.zAffinity[u.ap.pRec-u.ap.pData0], encoding);
}
- if( u.ao.pRec->flags&MEM_Zero && u.ao.pRec->n>0 ){
- sqlite3VdbeMemExpandBlob(u.ao.pRec);
+ if( u.ap.pRec->flags&MEM_Zero && u.ap.pRec->n>0 ){
+ sqlite3VdbeMemExpandBlob(u.ap.pRec);
}
- u.ao.serial_type = sqlite3VdbeSerialType(u.ao.pRec, u.ao.file_format);
- u.ao.len = sqlite3VdbeSerialTypeLen(u.ao.serial_type);
- u.ao.nData += u.ao.len;
- u.ao.nHdr += sqlite3VarintLen(u.ao.serial_type);
- if( u.ao.pRec->flags & MEM_Zero ){
+ u.ap.serial_type = sqlite3VdbeSerialType(u.ap.pRec, u.ap.file_format);
+ u.ap.len = sqlite3VdbeSerialTypeLen(u.ap.serial_type);
+ u.ap.nData += u.ap.len;
+ u.ap.nHdr += sqlite3VarintLen(u.ap.serial_type);
+ if( u.ap.pRec->flags & MEM_Zero ){
/* Only pure zero-filled BLOBs can be input to this Opcode.
** We do not allow blobs with a prefix and a zero-filled tail. */
- u.ao.nZero += u.ao.pRec->u.nZero;
- }else if( u.ao.len ){
- u.ao.nZero = 0;
+ u.ap.nZero += u.ap.pRec->u.nZero;
+ }else if( u.ap.len ){
+ u.ap.nZero = 0;
}
}
/* Add the initial header varint and total the size */
- u.ao.nHdr += u.ao.nVarint = sqlite3VarintLen(u.ao.nHdr);
- if( u.ao.nVarint<sqlite3VarintLen(u.ao.nHdr) ){
- u.ao.nHdr++;
+ u.ap.nHdr += u.ap.nVarint = sqlite3VarintLen(u.ap.nHdr);
+ if( u.ap.nVarint<sqlite3VarintLen(u.ap.nHdr) ){
+ u.ap.nHdr++;
}
- u.ao.nByte = u.ao.nHdr+u.ao.nData-u.ao.nZero;
- if( u.ao.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ u.ap.nByte = u.ap.nHdr+u.ap.nData-u.ap.nZero;
+ if( u.ap.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
@@ -65963,28 +67726,28 @@ case OP_MakeRecord: {
** be one of the input registers (because the following call to
** sqlite3VdbeMemGrow() could clobber the value before it is used).
*/
- if( sqlite3VdbeMemGrow(pOut, (int)u.ao.nByte, 0) ){
+ if( sqlite3VdbeMemGrow(pOut, (int)u.ap.nByte, 0) ){
goto no_mem;
}
- u.ao.zNewRecord = (u8 *)pOut->z;
+ u.ap.zNewRecord = (u8 *)pOut->z;
/* Write the record */
- u.ao.i = putVarint32(u.ao.zNewRecord, u.ao.nHdr);
- for(u.ao.pRec=u.ao.pData0; u.ao.pRec<=u.ao.pLast; u.ao.pRec++){
- u.ao.serial_type = sqlite3VdbeSerialType(u.ao.pRec, u.ao.file_format);
- u.ao.i += putVarint32(&u.ao.zNewRecord[u.ao.i], u.ao.serial_type); /* serial type */
+ u.ap.i = putVarint32(u.ap.zNewRecord, u.ap.nHdr);
+ for(u.ap.pRec=u.ap.pData0; u.ap.pRec<=u.ap.pLast; u.ap.pRec++){
+ u.ap.serial_type = sqlite3VdbeSerialType(u.ap.pRec, u.ap.file_format);
+ u.ap.i += putVarint32(&u.ap.zNewRecord[u.ap.i], u.ap.serial_type); /* serial type */
}
- for(u.ao.pRec=u.ao.pData0; u.ao.pRec<=u.ao.pLast; u.ao.pRec++){ /* serial data */
- u.ao.i += sqlite3VdbeSerialPut(&u.ao.zNewRecord[u.ao.i], (int)(u.ao.nByte-u.ao.i), u.ao.pRec,u.ao.file_format);
+ for(u.ap.pRec=u.ap.pData0; u.ap.pRec<=u.ap.pLast; u.ap.pRec++){ /* serial data */
+ u.ap.i += sqlite3VdbeSerialPut(&u.ap.zNewRecord[u.ap.i], (int)(u.ap.nByte-u.ap.i), u.ap.pRec,u.ap.file_format);
}
- assert( u.ao.i==u.ao.nByte );
+ assert( u.ap.i==u.ap.nByte );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- pOut->n = (int)u.ao.nByte;
+ pOut->n = (int)u.ap.nByte;
pOut->flags = MEM_Blob | MEM_Dyn;
pOut->xDel = 0;
- if( u.ao.nZero ){
- pOut->u.nZero = u.ao.nZero;
+ if( u.ap.nZero ){
+ pOut->u.nZero = u.ap.nZero;
pOut->flags |= MEM_Zero;
}
pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
@@ -66000,18 +67763,18 @@ case OP_MakeRecord: {
*/
#ifndef SQLITE_OMIT_BTREECOUNT
case OP_Count: { /* out2-prerelease */
-#if 0 /* local variables moved into u.ap */
+#if 0 /* local variables moved into u.aq */
i64 nEntry;
BtCursor *pCrsr;
-#endif /* local variables moved into u.ap */
+#endif /* local variables moved into u.aq */
- u.ap.pCrsr = p->apCsr[pOp->p1]->pCursor;
- if( ALWAYS(u.ap.pCrsr) ){
- rc = sqlite3BtreeCount(u.ap.pCrsr, &u.ap.nEntry);
+ u.aq.pCrsr = p->apCsr[pOp->p1]->pCursor;
+ if( ALWAYS(u.aq.pCrsr) ){
+ rc = sqlite3BtreeCount(u.aq.pCrsr, &u.aq.nEntry);
}else{
- u.ap.nEntry = 0;
+ u.aq.nEntry = 0;
}
- pOut->u.i = u.ap.nEntry;
+ pOut->u.i = u.aq.nEntry;
break;
}
#endif
@@ -66023,7 +67786,7 @@ case OP_Count: { /* out2-prerelease */
** existing savepoint, P1==1, or to rollback an existing savepoint P1==2.
*/
case OP_Savepoint: {
-#if 0 /* local variables moved into u.aq */
+#if 0 /* local variables moved into u.ar */
int p1; /* Value of P1 operand */
char *zName; /* Name of savepoint */
int nName;
@@ -66032,20 +67795,20 @@ case OP_Savepoint: {
Savepoint *pTmp;
int iSavepoint;
int ii;
-#endif /* local variables moved into u.aq */
+#endif /* local variables moved into u.ar */
- u.aq.p1 = pOp->p1;
- u.aq.zName = pOp->p4.z;
+ u.ar.p1 = pOp->p1;
+ u.ar.zName = pOp->p4.z;
- /* Assert that the u.aq.p1 parameter is valid. Also that if there is no open
+ /* Assert that the u.ar.p1 parameter is valid. Also that if there is no open
** transaction, then there cannot be any savepoints.
*/
assert( db->pSavepoint==0 || db->autoCommit==0 );
- assert( u.aq.p1==SAVEPOINT_BEGIN||u.aq.p1==SAVEPOINT_RELEASE||u.aq.p1==SAVEPOINT_ROLLBACK );
+ assert( u.ar.p1==SAVEPOINT_BEGIN||u.ar.p1==SAVEPOINT_RELEASE||u.ar.p1==SAVEPOINT_ROLLBACK );
assert( db->pSavepoint || db->isTransactionSavepoint==0 );
assert( checkSavepointCount(db) );
- if( u.aq.p1==SAVEPOINT_BEGIN ){
+ if( u.ar.p1==SAVEPOINT_BEGIN ){
if( db->writeVdbeCnt>0 ){
/* A new savepoint cannot be created if there are active write
** statements (i.e. open read/write incremental blob handles).
@@ -66054,7 +67817,7 @@ case OP_Savepoint: {
"SQL statements in progress");
rc = SQLITE_BUSY;
}else{
- u.aq.nName = sqlite3Strlen30(u.aq.zName);
+ u.ar.nName = sqlite3Strlen30(u.ar.zName);
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* This call is Ok even if this savepoint is actually a transaction
@@ -66068,10 +67831,10 @@ case OP_Savepoint: {
#endif
/* Create a new savepoint structure. */
- u.aq.pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+u.aq.nName+1);
- if( u.aq.pNew ){
- u.aq.pNew->zName = (char *)&u.aq.pNew[1];
- memcpy(u.aq.pNew->zName, u.aq.zName, u.aq.nName+1);
+ u.ar.pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+u.ar.nName+1);
+ if( u.ar.pNew ){
+ u.ar.pNew->zName = (char *)&u.ar.pNew[1];
+ memcpy(u.ar.pNew->zName, u.ar.zName, u.ar.nName+1);
/* If there is no open transaction, then mark this as a special
** "transaction savepoint". */
@@ -66083,36 +67846,32 @@ case OP_Savepoint: {
}
/* Link the new savepoint into the database handle's list. */
- u.aq.pNew->pNext = db->pSavepoint;
- db->pSavepoint = u.aq.pNew;
- u.aq.pNew->nDeferredCons = db->nDeferredCons;
+ u.ar.pNew->pNext = db->pSavepoint;
+ db->pSavepoint = u.ar.pNew;
+ u.ar.pNew->nDeferredCons = db->nDeferredCons;
}
}
}else{
- u.aq.iSavepoint = 0;
+ u.ar.iSavepoint = 0;
/* Find the named savepoint. If there is no such savepoint, then an
** an error is returned to the user. */
for(
- u.aq.pSavepoint = db->pSavepoint;
- u.aq.pSavepoint && sqlite3StrICmp(u.aq.pSavepoint->zName, u.aq.zName);
- u.aq.pSavepoint = u.aq.pSavepoint->pNext
+ u.ar.pSavepoint = db->pSavepoint;
+ u.ar.pSavepoint && sqlite3StrICmp(u.ar.pSavepoint->zName, u.ar.zName);
+ u.ar.pSavepoint = u.ar.pSavepoint->pNext
){
- u.aq.iSavepoint++;
+ u.ar.iSavepoint++;
}
- if( !u.aq.pSavepoint ){
- sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", u.aq.zName);
+ if( !u.ar.pSavepoint ){
+ sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", u.ar.zName);
rc = SQLITE_ERROR;
- }else if(
- db->writeVdbeCnt>0 || (u.aq.p1==SAVEPOINT_ROLLBACK && db->activeVdbeCnt>1)
- ){
+ }else if( db->writeVdbeCnt>0 && u.ar.p1==SAVEPOINT_RELEASE ){
/* It is not possible to release (commit) a savepoint if there are
- ** active write statements. It is not possible to rollback a savepoint
- ** if there are any active statements at all.
+ ** active write statements.
*/
sqlite3SetString(&p->zErrMsg, db,
- "cannot %s savepoint - SQL statements in progress",
- (u.aq.p1==SAVEPOINT_ROLLBACK ? "rollback": "release")
+ "cannot release savepoint - SQL statements in progress"
);
rc = SQLITE_BUSY;
}else{
@@ -66121,8 +67880,8 @@ case OP_Savepoint: {
** and this is a RELEASE command, then the current transaction
** is committed.
*/
- int isTransaction = u.aq.pSavepoint->pNext==0 && db->isTransactionSavepoint;
- if( isTransaction && u.aq.p1==SAVEPOINT_RELEASE ){
+ int isTransaction = u.ar.pSavepoint->pNext==0 && db->isTransactionSavepoint;
+ if( isTransaction && u.ar.p1==SAVEPOINT_RELEASE ){
if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
goto vdbe_return;
}
@@ -66136,14 +67895,19 @@ case OP_Savepoint: {
db->isTransactionSavepoint = 0;
rc = p->rc;
}else{
- u.aq.iSavepoint = db->nSavepoint - u.aq.iSavepoint - 1;
- for(u.aq.ii=0; u.aq.ii<db->nDb; u.aq.ii++){
- rc = sqlite3BtreeSavepoint(db->aDb[u.aq.ii].pBt, u.aq.p1, u.aq.iSavepoint);
+ u.ar.iSavepoint = db->nSavepoint - u.ar.iSavepoint - 1;
+ if( u.ar.p1==SAVEPOINT_ROLLBACK ){
+ for(u.ar.ii=0; u.ar.ii<db->nDb; u.ar.ii++){
+ sqlite3BtreeTripAllCursors(db->aDb[u.ar.ii].pBt, SQLITE_ABORT);
+ }
+ }
+ for(u.ar.ii=0; u.ar.ii<db->nDb; u.ar.ii++){
+ rc = sqlite3BtreeSavepoint(db->aDb[u.ar.ii].pBt, u.ar.p1, u.ar.iSavepoint);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
}
- if( u.aq.p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
+ if( u.ar.p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetInternalSchema(db, -1);
db->flags = (db->flags | SQLITE_InternChanges);
@@ -66152,10 +67916,10 @@ case OP_Savepoint: {
/* Regardless of whether this is a RELEASE or ROLLBACK, destroy all
** savepoints nested inside of the savepoint being operated on. */
- while( db->pSavepoint!=u.aq.pSavepoint ){
- u.aq.pTmp = db->pSavepoint;
- db->pSavepoint = u.aq.pTmp->pNext;
- sqlite3DbFree(db, u.aq.pTmp);
+ while( db->pSavepoint!=u.ar.pSavepoint ){
+ u.ar.pTmp = db->pSavepoint;
+ db->pSavepoint = u.ar.pTmp->pNext;
+ sqlite3DbFree(db, u.ar.pTmp);
db->nSavepoint--;
}
@@ -66163,19 +67927,19 @@ case OP_Savepoint: {
** too. If it is a ROLLBACK TO, then set the number of deferred
** constraint violations present in the database to the value stored
** when the savepoint was created. */
- if( u.aq.p1==SAVEPOINT_RELEASE ){
- assert( u.aq.pSavepoint==db->pSavepoint );
- db->pSavepoint = u.aq.pSavepoint->pNext;
- sqlite3DbFree(db, u.aq.pSavepoint);
+ if( u.ar.p1==SAVEPOINT_RELEASE ){
+ assert( u.ar.pSavepoint==db->pSavepoint );
+ db->pSavepoint = u.ar.pSavepoint->pNext;
+ sqlite3DbFree(db, u.ar.pSavepoint);
if( !isTransaction ){
db->nSavepoint--;
}
}else{
- db->nDeferredCons = u.aq.pSavepoint->nDeferredCons;
+ db->nDeferredCons = u.ar.pSavepoint->nDeferredCons;
}
if( !isTransaction ){
- rc = sqlite3VtabSavepoint(db, u.aq.p1, u.aq.iSavepoint);
+ rc = sqlite3VtabSavepoint(db, u.ar.p1, u.ar.iSavepoint);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}
@@ -66194,20 +67958,21 @@ case OP_Savepoint: {
** This instruction causes the VM to halt.
*/
case OP_AutoCommit: {
-#if 0 /* local variables moved into u.ar */
+#if 0 /* local variables moved into u.as */
int desiredAutoCommit;
int iRollback;
int turnOnAC;
-#endif /* local variables moved into u.ar */
+#endif /* local variables moved into u.as */
- u.ar.desiredAutoCommit = pOp->p1;
- u.ar.iRollback = pOp->p2;
- u.ar.turnOnAC = u.ar.desiredAutoCommit && !db->autoCommit;
- assert( u.ar.desiredAutoCommit==1 || u.ar.desiredAutoCommit==0 );
- assert( u.ar.desiredAutoCommit==1 || u.ar.iRollback==0 );
+ u.as.desiredAutoCommit = pOp->p1;
+ u.as.iRollback = pOp->p2;
+ u.as.turnOnAC = u.as.desiredAutoCommit && !db->autoCommit;
+ assert( u.as.desiredAutoCommit==1 || u.as.desiredAutoCommit==0 );
+ assert( u.as.desiredAutoCommit==1 || u.as.iRollback==0 );
assert( db->activeVdbeCnt>0 ); /* At least this one VM is active */
- if( u.ar.turnOnAC && u.ar.iRollback && db->activeVdbeCnt>1 ){
+#if 0
+ if( u.as.turnOnAC && u.as.iRollback && db->activeVdbeCnt>1 ){
/* If this instruction implements a ROLLBACK and other VMs are
** still running, and a transaction is active, return an error indicating
** that the other VMs must complete first.
@@ -66215,25 +67980,27 @@ case OP_AutoCommit: {
sqlite3SetString(&p->zErrMsg, db, "cannot rollback transaction - "
"SQL statements in progress");
rc = SQLITE_BUSY;
- }else if( u.ar.turnOnAC && !u.ar.iRollback && db->writeVdbeCnt>0 ){
+ }else
+#endif
+ if( u.as.turnOnAC && !u.as.iRollback && db->writeVdbeCnt>0 ){
/* If this instruction implements a COMMIT and other VMs are writing
** return an error indicating that the other VMs must complete first.
*/
sqlite3SetString(&p->zErrMsg, db, "cannot commit transaction - "
"SQL statements in progress");
rc = SQLITE_BUSY;
- }else if( u.ar.desiredAutoCommit!=db->autoCommit ){
- if( u.ar.iRollback ){
- assert( u.ar.desiredAutoCommit==1 );
- sqlite3RollbackAll(db);
+ }else if( u.as.desiredAutoCommit!=db->autoCommit ){
+ if( u.as.iRollback ){
+ assert( u.as.desiredAutoCommit==1 );
+ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
db->autoCommit = 1;
}else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
goto vdbe_return;
}else{
- db->autoCommit = (u8)u.ar.desiredAutoCommit;
+ db->autoCommit = (u8)u.as.desiredAutoCommit;
if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
p->pc = pc;
- db->autoCommit = (u8)(1-u.ar.desiredAutoCommit);
+ db->autoCommit = (u8)(1-u.as.desiredAutoCommit);
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
@@ -66248,8 +68015,8 @@ case OP_AutoCommit: {
goto vdbe_return;
}else{
sqlite3SetString(&p->zErrMsg, db,
- (!u.ar.desiredAutoCommit)?"cannot start a transaction within a transaction":(
- (u.ar.iRollback)?"cannot rollback - no transaction is active":
+ (!u.as.desiredAutoCommit)?"cannot start a transaction within a transaction":(
+ (u.as.iRollback)?"cannot rollback - no transaction is active":
"cannot commit - no transaction is active"));
rc = SQLITE_ERROR;
@@ -66281,7 +68048,7 @@ case OP_AutoCommit: {
** throw an ABORT exception), a statement transaction may also be opened.
** More specifically, a statement transaction is opened iff the database
** connection is currently not in autocommit mode, or if there are other
-** active statements. A statement transaction allows the affects of this
+** active statements. A statement transaction allows the changes made by this
** VDBE to be rolled back after an error without having to roll back the
** entire transaction. If no error is encountered, the statement transaction
** will automatically commit when the VDBE halts.
@@ -66289,16 +68056,16 @@ case OP_AutoCommit: {
** If P2 is zero, then a read-lock is obtained on the database file.
*/
case OP_Transaction: {
-#if 0 /* local variables moved into u.as */
+#if 0 /* local variables moved into u.at */
Btree *pBt;
-#endif /* local variables moved into u.as */
+#endif /* local variables moved into u.at */
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
- u.as.pBt = db->aDb[pOp->p1].pBt;
+ u.at.pBt = db->aDb[pOp->p1].pBt;
- if( u.as.pBt ){
- rc = sqlite3BtreeBeginTrans(u.as.pBt, pOp->p2);
+ if( u.at.pBt ){
+ rc = sqlite3BtreeBeginTrans(u.at.pBt, pOp->p2);
if( rc==SQLITE_BUSY ){
p->pc = pc;
p->rc = rc = SQLITE_BUSY;
@@ -66311,7 +68078,7 @@ case OP_Transaction: {
if( pOp->p2 && p->usesStmtJournal
&& (db->autoCommit==0 || db->activeVdbeCnt>1)
){
- assert( sqlite3BtreeIsInTrans(u.as.pBt) );
+ assert( sqlite3BtreeIsInTrans(u.at.pBt) );
if( p->iStatement==0 ){
assert( db->nStatement>=0 && db->nSavepoint>=0 );
db->nStatement++;
@@ -66320,7 +68087,7 @@ case OP_Transaction: {
rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement-1);
if( rc==SQLITE_OK ){
- rc = sqlite3BtreeBeginStmt(u.as.pBt, p->iStatement);
+ rc = sqlite3BtreeBeginStmt(u.at.pBt, p->iStatement);
}
/* Store the current value of the database handles deferred constraint
@@ -66345,21 +68112,21 @@ case OP_Transaction: {
** executing this instruction.
*/
case OP_ReadCookie: { /* out2-prerelease */
-#if 0 /* local variables moved into u.at */
+#if 0 /* local variables moved into u.au */
int iMeta;
int iDb;
int iCookie;
-#endif /* local variables moved into u.at */
+#endif /* local variables moved into u.au */
- u.at.iDb = pOp->p1;
- u.at.iCookie = pOp->p3;
+ u.au.iDb = pOp->p1;
+ u.au.iCookie = pOp->p3;
assert( pOp->p3<SQLITE_N_BTREE_META );
- assert( u.at.iDb>=0 && u.at.iDb<db->nDb );
- assert( db->aDb[u.at.iDb].pBt!=0 );
- assert( (p->btreeMask & (((yDbMask)1)<<u.at.iDb))!=0 );
+ assert( u.au.iDb>=0 && u.au.iDb<db->nDb );
+ assert( db->aDb[u.au.iDb].pBt!=0 );
+ assert( (p->btreeMask & (((yDbMask)1)<<u.au.iDb))!=0 );
- sqlite3BtreeGetMeta(db->aDb[u.at.iDb].pBt, u.at.iCookie, (u32 *)&u.at.iMeta);
- pOut->u.i = u.at.iMeta;
+ sqlite3BtreeGetMeta(db->aDb[u.au.iDb].pBt, u.au.iCookie, (u32 *)&u.au.iMeta);
+ pOut->u.i = u.au.iMeta;
break;
}
@@ -66374,26 +68141,26 @@ case OP_ReadCookie: { /* out2-prerelease */
** A transaction must be started before executing this opcode.
*/
case OP_SetCookie: { /* in3 */
-#if 0 /* local variables moved into u.au */
+#if 0 /* local variables moved into u.av */
Db *pDb;
-#endif /* local variables moved into u.au */
+#endif /* local variables moved into u.av */
assert( pOp->p2<SQLITE_N_BTREE_META );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
- u.au.pDb = &db->aDb[pOp->p1];
- assert( u.au.pDb->pBt!=0 );
+ u.av.pDb = &db->aDb[pOp->p1];
+ assert( u.av.pDb->pBt!=0 );
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
pIn3 = &aMem[pOp->p3];
sqlite3VdbeMemIntegerify(pIn3);
/* See note about index shifting on OP_ReadCookie */
- rc = sqlite3BtreeUpdateMeta(u.au.pDb->pBt, pOp->p2, (int)pIn3->u.i);
+ rc = sqlite3BtreeUpdateMeta(u.av.pDb->pBt, pOp->p2, (int)pIn3->u.i);
if( pOp->p2==BTREE_SCHEMA_VERSION ){
/* When the schema cookie changes, record the new cookie internally */
- u.au.pDb->pSchema->schema_cookie = (int)pIn3->u.i;
+ u.av.pDb->pSchema->schema_cookie = (int)pIn3->u.i;
db->flags |= SQLITE_InternChanges;
}else if( pOp->p2==BTREE_FILE_FORMAT ){
/* Record changes in the file format */
- u.au.pDb->pSchema->file_format = (u8)pIn3->u.i;
+ u.av.pDb->pSchema->file_format = (u8)pIn3->u.i;
}
if( pOp->p1==1 ){
/* Invalidate all prepared statements whenever the TEMP database
@@ -66423,23 +68190,23 @@ case OP_SetCookie: { /* in3 */
** invoked.
*/
case OP_VerifyCookie: {
-#if 0 /* local variables moved into u.av */
+#if 0 /* local variables moved into u.aw */
int iMeta;
int iGen;
Btree *pBt;
-#endif /* local variables moved into u.av */
+#endif /* local variables moved into u.aw */
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
- u.av.pBt = db->aDb[pOp->p1].pBt;
- if( u.av.pBt ){
- sqlite3BtreeGetMeta(u.av.pBt, BTREE_SCHEMA_VERSION, (u32 *)&u.av.iMeta);
- u.av.iGen = db->aDb[pOp->p1].pSchema->iGeneration;
+ u.aw.pBt = db->aDb[pOp->p1].pBt;
+ if( u.aw.pBt ){
+ sqlite3BtreeGetMeta(u.aw.pBt, BTREE_SCHEMA_VERSION, (u32 *)&u.aw.iMeta);
+ u.aw.iGen = db->aDb[pOp->p1].pSchema->iGeneration;
}else{
- u.av.iGen = u.av.iMeta = 0;
+ u.aw.iGen = u.aw.iMeta = 0;
}
- if( u.av.iMeta!=pOp->p2 || u.av.iGen!=pOp->p3 ){
+ if( u.aw.iMeta!=pOp->p2 || u.aw.iGen!=pOp->p3 ){
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
/* If the schema-cookie from the database file matches the cookie
@@ -66455,7 +68222,7 @@ case OP_VerifyCookie: {
** to be invalidated whenever sqlite3_step() is called from within
** a v-table method.
*/
- if( db->aDb[pOp->p1].pSchema->schema_cookie!=u.av.iMeta ){
+ if( db->aDb[pOp->p1].pSchema->schema_cookie!=u.aw.iMeta ){
sqlite3ResetInternalSchema(db, pOp->p1);
}
@@ -66516,7 +68283,7 @@ case OP_VerifyCookie: {
*/
case OP_OpenRead:
case OP_OpenWrite: {
-#if 0 /* local variables moved into u.aw */
+#if 0 /* local variables moved into u.ax */
int nField;
KeyInfo *pKeyInfo;
int p2;
@@ -66525,62 +68292,62 @@ case OP_OpenWrite: {
Btree *pX;
VdbeCursor *pCur;
Db *pDb;
-#endif /* local variables moved into u.aw */
+#endif /* local variables moved into u.ax */
if( p->expired ){
rc = SQLITE_ABORT;
break;
}
- u.aw.nField = 0;
- u.aw.pKeyInfo = 0;
- u.aw.p2 = pOp->p2;
- u.aw.iDb = pOp->p3;
- assert( u.aw.iDb>=0 && u.aw.iDb<db->nDb );
- assert( (p->btreeMask & (((yDbMask)1)<<u.aw.iDb))!=0 );
- u.aw.pDb = &db->aDb[u.aw.iDb];
- u.aw.pX = u.aw.pDb->pBt;
- assert( u.aw.pX!=0 );
+ u.ax.nField = 0;
+ u.ax.pKeyInfo = 0;
+ u.ax.p2 = pOp->p2;
+ u.ax.iDb = pOp->p3;
+ assert( u.ax.iDb>=0 && u.ax.iDb<db->nDb );
+ assert( (p->btreeMask & (((yDbMask)1)<<u.ax.iDb))!=0 );
+ u.ax.pDb = &db->aDb[u.ax.iDb];
+ u.ax.pX = u.ax.pDb->pBt;
+ assert( u.ax.pX!=0 );
if( pOp->opcode==OP_OpenWrite ){
- u.aw.wrFlag = 1;
- assert( sqlite3SchemaMutexHeld(db, u.aw.iDb, 0) );
- if( u.aw.pDb->pSchema->file_format < p->minWriteFileFormat ){
- p->minWriteFileFormat = u.aw.pDb->pSchema->file_format;
+ u.ax.wrFlag = 1;
+ assert( sqlite3SchemaMutexHeld(db, u.ax.iDb, 0) );
+ if( u.ax.pDb->pSchema->file_format < p->minWriteFileFormat ){
+ p->minWriteFileFormat = u.ax.pDb->pSchema->file_format;
}
}else{
- u.aw.wrFlag = 0;
+ u.ax.wrFlag = 0;
}
if( pOp->p5 ){
- assert( u.aw.p2>0 );
- assert( u.aw.p2<=p->nMem );
- pIn2 = &aMem[u.aw.p2];
+ assert( u.ax.p2>0 );
+ assert( u.ax.p2<=p->nMem );
+ pIn2 = &aMem[u.ax.p2];
assert( memIsValid(pIn2) );
assert( (pIn2->flags & MEM_Int)!=0 );
sqlite3VdbeMemIntegerify(pIn2);
- u.aw.p2 = (int)pIn2->u.i;
- /* The u.aw.p2 value always comes from a prior OP_CreateTable opcode and
- ** that opcode will always set the u.aw.p2 value to 2 or more or else fail.
+ u.ax.p2 = (int)pIn2->u.i;
+ /* The u.ax.p2 value always comes from a prior OP_CreateTable opcode and
+ ** that opcode will always set the u.ax.p2 value to 2 or more or else fail.
** If there were a failure, the prepared statement would have halted
** before reaching this instruction. */
- if( NEVER(u.aw.p2<2) ) {
+ if( NEVER(u.ax.p2<2) ) {
rc = SQLITE_CORRUPT_BKPT;
goto abort_due_to_error;
}
}
if( pOp->p4type==P4_KEYINFO ){
- u.aw.pKeyInfo = pOp->p4.pKeyInfo;
- u.aw.pKeyInfo->enc = ENC(p->db);
- u.aw.nField = u.aw.pKeyInfo->nField+1;
+ u.ax.pKeyInfo = pOp->p4.pKeyInfo;
+ u.ax.pKeyInfo->enc = ENC(p->db);
+ u.ax.nField = u.ax.pKeyInfo->nField+1;
}else if( pOp->p4type==P4_INT32 ){
- u.aw.nField = pOp->p4.i;
+ u.ax.nField = pOp->p4.i;
}
assert( pOp->p1>=0 );
- u.aw.pCur = allocateCursor(p, pOp->p1, u.aw.nField, u.aw.iDb, 1);
- if( u.aw.pCur==0 ) goto no_mem;
- u.aw.pCur->nullRow = 1;
- u.aw.pCur->isOrdered = 1;
- rc = sqlite3BtreeCursor(u.aw.pX, u.aw.p2, u.aw.wrFlag, u.aw.pKeyInfo, u.aw.pCur->pCursor);
- u.aw.pCur->pKeyInfo = u.aw.pKeyInfo;
+ u.ax.pCur = allocateCursor(p, pOp->p1, u.ax.nField, u.ax.iDb, 1);
+ if( u.ax.pCur==0 ) goto no_mem;
+ u.ax.pCur->nullRow = 1;
+ u.ax.pCur->isOrdered = 1;
+ rc = sqlite3BtreeCursor(u.ax.pX, u.ax.p2, u.ax.wrFlag, u.ax.pKeyInfo, u.ax.pCur->pCursor);
+ u.ax.pCur->pKeyInfo = u.ax.pKeyInfo;
/* Since it performs no memory allocation or IO, the only value that
** sqlite3BtreeCursor() may return is SQLITE_OK. */
@@ -66590,8 +68357,8 @@ case OP_OpenWrite: {
** SQLite used to check if the root-page flags were sane at this point
** and report database corruption if they were not, but this check has
** since moved into the btree layer. */
- u.aw.pCur->isTable = pOp->p4type!=P4_KEYINFO;
- u.aw.pCur->isIndex = !u.aw.pCur->isTable;
+ u.ax.pCur->isTable = pOp->p4type!=P4_KEYINFO;
+ u.ax.pCur->isIndex = !u.ax.pCur->isTable;
break;
}
@@ -66627,9 +68394,9 @@ case OP_OpenWrite: {
*/
case OP_OpenAutoindex:
case OP_OpenEphemeral: {
-#if 0 /* local variables moved into u.ax */
+#if 0 /* local variables moved into u.ay */
VdbeCursor *pCx;
-#endif /* local variables moved into u.ax */
+#endif /* local variables moved into u.ay */
static const int vfsFlags =
SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE |
@@ -66638,13 +68405,13 @@ case OP_OpenEphemeral: {
SQLITE_OPEN_TRANSIENT_DB;
assert( pOp->p1>=0 );
- u.ax.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
- if( u.ax.pCx==0 ) goto no_mem;
- u.ax.pCx->nullRow = 1;
- rc = sqlite3BtreeOpen(db->pVfs, 0, db, &u.ax.pCx->pBt,
+ u.ay.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
+ if( u.ay.pCx==0 ) goto no_mem;
+ u.ay.pCx->nullRow = 1;
+ rc = sqlite3BtreeOpen(db->pVfs, 0, db, &u.ay.pCx->pBt,
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
if( rc==SQLITE_OK ){
- rc = sqlite3BtreeBeginTrans(u.ax.pCx->pBt, 1);
+ rc = sqlite3BtreeBeginTrans(u.ay.pCx->pBt, 1);
}
if( rc==SQLITE_OK ){
/* If a transient index is required, create it by calling
@@ -66655,22 +68422,22 @@ case OP_OpenEphemeral: {
if( pOp->p4.pKeyInfo ){
int pgno;
assert( pOp->p4type==P4_KEYINFO );
- rc = sqlite3BtreeCreateTable(u.ax.pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5);
+ rc = sqlite3BtreeCreateTable(u.ay.pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5);
if( rc==SQLITE_OK ){
assert( pgno==MASTER_ROOT+1 );
- rc = sqlite3BtreeCursor(u.ax.pCx->pBt, pgno, 1,
- (KeyInfo*)pOp->p4.z, u.ax.pCx->pCursor);
- u.ax.pCx->pKeyInfo = pOp->p4.pKeyInfo;
- u.ax.pCx->pKeyInfo->enc = ENC(p->db);
+ rc = sqlite3BtreeCursor(u.ay.pCx->pBt, pgno, 1,
+ (KeyInfo*)pOp->p4.z, u.ay.pCx->pCursor);
+ u.ay.pCx->pKeyInfo = pOp->p4.pKeyInfo;
+ u.ay.pCx->pKeyInfo->enc = ENC(p->db);
}
- u.ax.pCx->isTable = 0;
+ u.ay.pCx->isTable = 0;
}else{
- rc = sqlite3BtreeCursor(u.ax.pCx->pBt, MASTER_ROOT, 1, 0, u.ax.pCx->pCursor);
- u.ax.pCx->isTable = 1;
+ rc = sqlite3BtreeCursor(u.ay.pCx->pBt, MASTER_ROOT, 1, 0, u.ay.pCx->pCursor);
+ u.ay.pCx->isTable = 1;
}
}
- u.ax.pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
- u.ax.pCx->isIndex = !u.ax.pCx->isTable;
+ u.ay.pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
+ u.ay.pCx->isIndex = !u.ay.pCx->isTable;
break;
}
@@ -66681,16 +68448,16 @@ case OP_OpenEphemeral: {
** tables using an external merge-sort algorithm.
*/
case OP_SorterOpen: {
-#if 0 /* local variables moved into u.ay */
+#if 0 /* local variables moved into u.az */
VdbeCursor *pCx;
-#endif /* local variables moved into u.ay */
+#endif /* local variables moved into u.az */
#ifndef SQLITE_OMIT_MERGE_SORT
- u.ay.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
- if( u.ay.pCx==0 ) goto no_mem;
- u.ay.pCx->pKeyInfo = pOp->p4.pKeyInfo;
- u.ay.pCx->pKeyInfo->enc = ENC(p->db);
- u.ay.pCx->isSorter = 1;
- rc = sqlite3VdbeSorterInit(db, u.ay.pCx);
+ u.az.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
+ if( u.az.pCx==0 ) goto no_mem;
+ u.az.pCx->pKeyInfo = pOp->p4.pKeyInfo;
+ u.az.pCx->pKeyInfo->enc = ENC(p->db);
+ u.az.pCx->isSorter = 1;
+ rc = sqlite3VdbeSorterInit(db, u.az.pCx);
#else
pOp->opcode = OP_OpenEphemeral;
pc--;
@@ -66714,17 +68481,17 @@ case OP_SorterOpen: {
** the pseudo-table.
*/
case OP_OpenPseudo: {
-#if 0 /* local variables moved into u.az */
+#if 0 /* local variables moved into u.ba */
VdbeCursor *pCx;
-#endif /* local variables moved into u.az */
+#endif /* local variables moved into u.ba */
assert( pOp->p1>=0 );
- u.az.pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
- if( u.az.pCx==0 ) goto no_mem;
- u.az.pCx->nullRow = 1;
- u.az.pCx->pseudoTableReg = pOp->p2;
- u.az.pCx->isTable = 1;
- u.az.pCx->isIndex = 0;
+ u.ba.pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
+ if( u.ba.pCx==0 ) goto no_mem;
+ u.ba.pCx->nullRow = 1;
+ u.ba.pCx->pseudoTableReg = pOp->p2;
+ u.ba.pCx->isTable = 1;
+ u.ba.pCx->isIndex = 0;
break;
}
@@ -66796,35 +68563,35 @@ case OP_SeekLt: /* jump, in3 */
case OP_SeekLe: /* jump, in3 */
case OP_SeekGe: /* jump, in3 */
case OP_SeekGt: { /* jump, in3 */
-#if 0 /* local variables moved into u.ba */
+#if 0 /* local variables moved into u.bb */
int res;
int oc;
VdbeCursor *pC;
UnpackedRecord r;
int nField;
i64 iKey; /* The rowid we are to seek to */
-#endif /* local variables moved into u.ba */
+#endif /* local variables moved into u.bb */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p2!=0 );
- u.ba.pC = p->apCsr[pOp->p1];
- assert( u.ba.pC!=0 );
- assert( u.ba.pC->pseudoTableReg==0 );
+ u.bb.pC = p->apCsr[pOp->p1];
+ assert( u.bb.pC!=0 );
+ assert( u.bb.pC->pseudoTableReg==0 );
assert( OP_SeekLe == OP_SeekLt+1 );
assert( OP_SeekGe == OP_SeekLt+2 );
assert( OP_SeekGt == OP_SeekLt+3 );
- assert( u.ba.pC->isOrdered );
- if( ALWAYS(u.ba.pC->pCursor!=0) ){
- u.ba.oc = pOp->opcode;
- u.ba.pC->nullRow = 0;
- if( u.ba.pC->isTable ){
+ assert( u.bb.pC->isOrdered );
+ if( ALWAYS(u.bb.pC->pCursor!=0) ){
+ u.bb.oc = pOp->opcode;
+ u.bb.pC->nullRow = 0;
+ if( u.bb.pC->isTable ){
/* The input value in P3 might be of any type: integer, real, string,
** blob, or NULL. But it needs to be an integer before we can do
** the seek, so covert it. */
pIn3 = &aMem[pOp->p3];
applyNumericAffinity(pIn3);
- u.ba.iKey = sqlite3VdbeIntValue(pIn3);
- u.ba.pC->rowidIsValid = 0;
+ u.bb.iKey = sqlite3VdbeIntValue(pIn3);
+ u.bb.pC->rowidIsValid = 0;
/* If the P3 value could not be converted into an integer without
** loss of information, then special processing is required... */
@@ -66839,101 +68606,101 @@ case OP_SeekGt: { /* jump, in3 */
** point number. */
assert( (pIn3->flags & MEM_Real)!=0 );
- if( u.ba.iKey==SMALLEST_INT64 && (pIn3->r<(double)u.ba.iKey || pIn3->r>0) ){
+ if( u.bb.iKey==SMALLEST_INT64 && (pIn3->r<(double)u.bb.iKey || pIn3->r>0) ){
/* The P3 value is too large in magnitude to be expressed as an
** integer. */
- u.ba.res = 1;
+ u.bb.res = 1;
if( pIn3->r<0 ){
- if( u.ba.oc>=OP_SeekGe ){ assert( u.ba.oc==OP_SeekGe || u.ba.oc==OP_SeekGt );
- rc = sqlite3BtreeFirst(u.ba.pC->pCursor, &u.ba.res);
+ if( u.bb.oc>=OP_SeekGe ){ assert( u.bb.oc==OP_SeekGe || u.bb.oc==OP_SeekGt );
+ rc = sqlite3BtreeFirst(u.bb.pC->pCursor, &u.bb.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}else{
- if( u.ba.oc<=OP_SeekLe ){ assert( u.ba.oc==OP_SeekLt || u.ba.oc==OP_SeekLe );
- rc = sqlite3BtreeLast(u.ba.pC->pCursor, &u.ba.res);
+ if( u.bb.oc<=OP_SeekLe ){ assert( u.bb.oc==OP_SeekLt || u.bb.oc==OP_SeekLe );
+ rc = sqlite3BtreeLast(u.bb.pC->pCursor, &u.bb.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}
- if( u.ba.res ){
+ if( u.bb.res ){
pc = pOp->p2 - 1;
}
break;
- }else if( u.ba.oc==OP_SeekLt || u.ba.oc==OP_SeekGe ){
+ }else if( u.bb.oc==OP_SeekLt || u.bb.oc==OP_SeekGe ){
/* Use the ceiling() function to convert real->int */
- if( pIn3->r > (double)u.ba.iKey ) u.ba.iKey++;
+ if( pIn3->r > (double)u.bb.iKey ) u.bb.iKey++;
}else{
/* Use the floor() function to convert real->int */
- assert( u.ba.oc==OP_SeekLe || u.ba.oc==OP_SeekGt );
- if( pIn3->r < (double)u.ba.iKey ) u.ba.iKey--;
+ assert( u.bb.oc==OP_SeekLe || u.bb.oc==OP_SeekGt );
+ if( pIn3->r < (double)u.bb.iKey ) u.bb.iKey--;
}
}
- rc = sqlite3BtreeMovetoUnpacked(u.ba.pC->pCursor, 0, (u64)u.ba.iKey, 0, &u.ba.res);
+ rc = sqlite3BtreeMovetoUnpacked(u.bb.pC->pCursor, 0, (u64)u.bb.iKey, 0, &u.bb.res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- if( u.ba.res==0 ){
- u.ba.pC->rowidIsValid = 1;
- u.ba.pC->lastRowid = u.ba.iKey;
+ if( u.bb.res==0 ){
+ u.bb.pC->rowidIsValid = 1;
+ u.bb.pC->lastRowid = u.bb.iKey;
}
}else{
- u.ba.nField = pOp->p4.i;
+ u.bb.nField = pOp->p4.i;
assert( pOp->p4type==P4_INT32 );
- assert( u.ba.nField>0 );
- u.ba.r.pKeyInfo = u.ba.pC->pKeyInfo;
- u.ba.r.nField = (u16)u.ba.nField;
+ assert( u.bb.nField>0 );
+ u.bb.r.pKeyInfo = u.bb.pC->pKeyInfo;
+ u.bb.r.nField = (u16)u.bb.nField;
/* The next line of code computes as follows, only faster:
- ** if( u.ba.oc==OP_SeekGt || u.ba.oc==OP_SeekLe ){
- ** u.ba.r.flags = UNPACKED_INCRKEY;
+ ** if( u.bb.oc==OP_SeekGt || u.bb.oc==OP_SeekLe ){
+ ** u.bb.r.flags = UNPACKED_INCRKEY;
** }else{
- ** u.ba.r.flags = 0;
+ ** u.bb.r.flags = 0;
** }
*/
- u.ba.r.flags = (u16)(UNPACKED_INCRKEY * (1 & (u.ba.oc - OP_SeekLt)));
- assert( u.ba.oc!=OP_SeekGt || u.ba.r.flags==UNPACKED_INCRKEY );
- assert( u.ba.oc!=OP_SeekLe || u.ba.r.flags==UNPACKED_INCRKEY );
- assert( u.ba.oc!=OP_SeekGe || u.ba.r.flags==0 );
- assert( u.ba.oc!=OP_SeekLt || u.ba.r.flags==0 );
+ u.bb.r.flags = (u16)(UNPACKED_INCRKEY * (1 & (u.bb.oc - OP_SeekLt)));
+ assert( u.bb.oc!=OP_SeekGt || u.bb.r.flags==UNPACKED_INCRKEY );
+ assert( u.bb.oc!=OP_SeekLe || u.bb.r.flags==UNPACKED_INCRKEY );
+ assert( u.bb.oc!=OP_SeekGe || u.bb.r.flags==0 );
+ assert( u.bb.oc!=OP_SeekLt || u.bb.r.flags==0 );
- u.ba.r.aMem = &aMem[pOp->p3];
+ u.bb.r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<u.ba.r.nField; i++) assert( memIsValid(&u.ba.r.aMem[i]) ); }
+ { int i; for(i=0; i<u.bb.r.nField; i++) assert( memIsValid(&u.bb.r.aMem[i]) ); }
#endif
- ExpandBlob(u.ba.r.aMem);
- rc = sqlite3BtreeMovetoUnpacked(u.ba.pC->pCursor, &u.ba.r, 0, 0, &u.ba.res);
+ ExpandBlob(u.bb.r.aMem);
+ rc = sqlite3BtreeMovetoUnpacked(u.bb.pC->pCursor, &u.bb.r, 0, 0, &u.bb.res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- u.ba.pC->rowidIsValid = 0;
+ u.bb.pC->rowidIsValid = 0;
}
- u.ba.pC->deferredMoveto = 0;
- u.ba.pC->cacheStatus = CACHE_STALE;
+ u.bb.pC->deferredMoveto = 0;
+ u.bb.pC->cacheStatus = CACHE_STALE;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
- if( u.ba.oc>=OP_SeekGe ){ assert( u.ba.oc==OP_SeekGe || u.ba.oc==OP_SeekGt );
- if( u.ba.res<0 || (u.ba.res==0 && u.ba.oc==OP_SeekGt) ){
- rc = sqlite3BtreeNext(u.ba.pC->pCursor, &u.ba.res);
+ if( u.bb.oc>=OP_SeekGe ){ assert( u.bb.oc==OP_SeekGe || u.bb.oc==OP_SeekGt );
+ if( u.bb.res<0 || (u.bb.res==0 && u.bb.oc==OP_SeekGt) ){
+ rc = sqlite3BtreeNext(u.bb.pC->pCursor, &u.bb.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
- u.ba.pC->rowidIsValid = 0;
+ u.bb.pC->rowidIsValid = 0;
}else{
- u.ba.res = 0;
+ u.bb.res = 0;
}
}else{
- assert( u.ba.oc==OP_SeekLt || u.ba.oc==OP_SeekLe );
- if( u.ba.res>0 || (u.ba.res==0 && u.ba.oc==OP_SeekLt) ){
- rc = sqlite3BtreePrevious(u.ba.pC->pCursor, &u.ba.res);
+ assert( u.bb.oc==OP_SeekLt || u.bb.oc==OP_SeekLe );
+ if( u.bb.res>0 || (u.bb.res==0 && u.bb.oc==OP_SeekLt) ){
+ rc = sqlite3BtreePrevious(u.bb.pC->pCursor, &u.bb.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
- u.ba.pC->rowidIsValid = 0;
+ u.bb.pC->rowidIsValid = 0;
}else{
- /* u.ba.res might be negative because the table is empty. Check to
+ /* u.bb.res might be negative because the table is empty. Check to
** see if this is the case.
*/
- u.ba.res = sqlite3BtreeEof(u.ba.pC->pCursor);
+ u.bb.res = sqlite3BtreeEof(u.bb.pC->pCursor);
}
}
assert( pOp->p2>0 );
- if( u.ba.res ){
+ if( u.bb.res ){
pc = pOp->p2 - 1;
}
}else{
@@ -66956,20 +68723,20 @@ case OP_SeekGt: { /* jump, in3 */
** occur, no unnecessary I/O happens.
*/
case OP_Seek: { /* in2 */
-#if 0 /* local variables moved into u.bb */
+#if 0 /* local variables moved into u.bc */
VdbeCursor *pC;
-#endif /* local variables moved into u.bb */
+#endif /* local variables moved into u.bc */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bb.pC = p->apCsr[pOp->p1];
- assert( u.bb.pC!=0 );
- if( ALWAYS(u.bb.pC->pCursor!=0) ){
- assert( u.bb.pC->isTable );
- u.bb.pC->nullRow = 0;
+ u.bc.pC = p->apCsr[pOp->p1];
+ assert( u.bc.pC!=0 );
+ if( ALWAYS(u.bc.pC->pCursor!=0) ){
+ assert( u.bc.pC->isTable );
+ u.bc.pC->nullRow = 0;
pIn2 = &aMem[pOp->p2];
- u.bb.pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
- u.bb.pC->rowidIsValid = 0;
- u.bb.pC->deferredMoveto = 1;
+ u.bc.pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
+ u.bc.pC->rowidIsValid = 0;
+ u.bc.pC->deferredMoveto = 1;
}
break;
}
@@ -67001,7 +68768,7 @@ case OP_Seek: { /* in2 */
*/
case OP_NotFound: /* jump, in3 */
case OP_Found: { /* jump, in3 */
-#if 0 /* local variables moved into u.bc */
+#if 0 /* local variables moved into u.bd */
int alreadyExists;
VdbeCursor *pC;
int res;
@@ -67009,55 +68776,55 @@ case OP_Found: { /* jump, in3 */
UnpackedRecord *pIdxKey;
UnpackedRecord r;
char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7];
-#endif /* local variables moved into u.bc */
+#endif /* local variables moved into u.bd */
#ifdef SQLITE_TEST
sqlite3_found_count++;
#endif
- u.bc.alreadyExists = 0;
+ u.bd.alreadyExists = 0;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p4type==P4_INT32 );
- u.bc.pC = p->apCsr[pOp->p1];
- assert( u.bc.pC!=0 );
+ u.bd.pC = p->apCsr[pOp->p1];
+ assert( u.bd.pC!=0 );
pIn3 = &aMem[pOp->p3];
- if( ALWAYS(u.bc.pC->pCursor!=0) ){
+ if( ALWAYS(u.bd.pC->pCursor!=0) ){
- assert( u.bc.pC->isTable==0 );
+ assert( u.bd.pC->isTable==0 );
if( pOp->p4.i>0 ){
- u.bc.r.pKeyInfo = u.bc.pC->pKeyInfo;
- u.bc.r.nField = (u16)pOp->p4.i;
- u.bc.r.aMem = pIn3;
+ u.bd.r.pKeyInfo = u.bd.pC->pKeyInfo;
+ u.bd.r.nField = (u16)pOp->p4.i;
+ u.bd.r.aMem = pIn3;
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<u.bc.r.nField; i++) assert( memIsValid(&u.bc.r.aMem[i]) ); }
+ { int i; for(i=0; i<u.bd.r.nField; i++) assert( memIsValid(&u.bd.r.aMem[i]) ); }
#endif
- u.bc.r.flags = UNPACKED_PREFIX_MATCH;
- u.bc.pIdxKey = &u.bc.r;
+ u.bd.r.flags = UNPACKED_PREFIX_MATCH;
+ u.bd.pIdxKey = &u.bd.r;
}else{
- u.bc.pIdxKey = sqlite3VdbeAllocUnpackedRecord(
- u.bc.pC->pKeyInfo, u.bc.aTempRec, sizeof(u.bc.aTempRec), &u.bc.pFree
+ u.bd.pIdxKey = sqlite3VdbeAllocUnpackedRecord(
+ u.bd.pC->pKeyInfo, u.bd.aTempRec, sizeof(u.bd.aTempRec), &u.bd.pFree
);
- if( u.bc.pIdxKey==0 ) goto no_mem;
+ if( u.bd.pIdxKey==0 ) goto no_mem;
assert( pIn3->flags & MEM_Blob );
assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */
- sqlite3VdbeRecordUnpack(u.bc.pC->pKeyInfo, pIn3->n, pIn3->z, u.bc.pIdxKey);
- u.bc.pIdxKey->flags |= UNPACKED_PREFIX_MATCH;
+ sqlite3VdbeRecordUnpack(u.bd.pC->pKeyInfo, pIn3->n, pIn3->z, u.bd.pIdxKey);
+ u.bd.pIdxKey->flags |= UNPACKED_PREFIX_MATCH;
}
- rc = sqlite3BtreeMovetoUnpacked(u.bc.pC->pCursor, u.bc.pIdxKey, 0, 0, &u.bc.res);
+ rc = sqlite3BtreeMovetoUnpacked(u.bd.pC->pCursor, u.bd.pIdxKey, 0, 0, &u.bd.res);
if( pOp->p4.i==0 ){
- sqlite3DbFree(db, u.bc.pFree);
+ sqlite3DbFree(db, u.bd.pFree);
}
if( rc!=SQLITE_OK ){
break;
}
- u.bc.alreadyExists = (u.bc.res==0);
- u.bc.pC->deferredMoveto = 0;
- u.bc.pC->cacheStatus = CACHE_STALE;
+ u.bd.alreadyExists = (u.bd.res==0);
+ u.bd.pC->deferredMoveto = 0;
+ u.bd.pC->cacheStatus = CACHE_STALE;
}
if( pOp->opcode==OP_Found ){
- if( u.bc.alreadyExists ) pc = pOp->p2 - 1;
+ if( u.bd.alreadyExists ) pc = pOp->p2 - 1;
}else{
- if( !u.bc.alreadyExists ) pc = pOp->p2 - 1;
+ if( !u.bd.alreadyExists ) pc = pOp->p2 - 1;
}
break;
}
@@ -67089,7 +68856,7 @@ case OP_Found: { /* jump, in3 */
** See also: NotFound, NotExists, Found
*/
case OP_IsUnique: { /* jump, in3 */
-#if 0 /* local variables moved into u.bd */
+#if 0 /* local variables moved into u.be */
u16 ii;
VdbeCursor *pCx;
BtCursor *pCrsr;
@@ -67097,55 +68864,55 @@ case OP_IsUnique: { /* jump, in3 */
Mem *aMx;
UnpackedRecord r; /* B-Tree index search key */
i64 R; /* Rowid stored in register P3 */
-#endif /* local variables moved into u.bd */
+#endif /* local variables moved into u.be */
pIn3 = &aMem[pOp->p3];
- u.bd.aMx = &aMem[pOp->p4.i];
+ u.be.aMx = &aMem[pOp->p4.i];
/* Assert that the values of parameters P1 and P4 are in range. */
assert( pOp->p4type==P4_INT32 );
assert( pOp->p4.i>0 && pOp->p4.i<=p->nMem );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
/* Find the index cursor. */
- u.bd.pCx = p->apCsr[pOp->p1];
- assert( u.bd.pCx->deferredMoveto==0 );
- u.bd.pCx->seekResult = 0;
- u.bd.pCx->cacheStatus = CACHE_STALE;
- u.bd.pCrsr = u.bd.pCx->pCursor;
+ u.be.pCx = p->apCsr[pOp->p1];
+ assert( u.be.pCx->deferredMoveto==0 );
+ u.be.pCx->seekResult = 0;
+ u.be.pCx->cacheStatus = CACHE_STALE;
+ u.be.pCrsr = u.be.pCx->pCursor;
/* If any of the values are NULL, take the jump. */
- u.bd.nField = u.bd.pCx->pKeyInfo->nField;
- for(u.bd.ii=0; u.bd.ii<u.bd.nField; u.bd.ii++){
- if( u.bd.aMx[u.bd.ii].flags & MEM_Null ){
+ u.be.nField = u.be.pCx->pKeyInfo->nField;
+ for(u.be.ii=0; u.be.ii<u.be.nField; u.be.ii++){
+ if( u.be.aMx[u.be.ii].flags & MEM_Null ){
pc = pOp->p2 - 1;
- u.bd.pCrsr = 0;
+ u.be.pCrsr = 0;
break;
}
}
- assert( (u.bd.aMx[u.bd.nField].flags & MEM_Null)==0 );
+ assert( (u.be.aMx[u.be.nField].flags & MEM_Null)==0 );
- if( u.bd.pCrsr!=0 ){
+ if( u.be.pCrsr!=0 ){
/* Populate the index search key. */
- u.bd.r.pKeyInfo = u.bd.pCx->pKeyInfo;
- u.bd.r.nField = u.bd.nField + 1;
- u.bd.r.flags = UNPACKED_PREFIX_SEARCH;
- u.bd.r.aMem = u.bd.aMx;
+ u.be.r.pKeyInfo = u.be.pCx->pKeyInfo;
+ u.be.r.nField = u.be.nField + 1;
+ u.be.r.flags = UNPACKED_PREFIX_SEARCH;
+ u.be.r.aMem = u.be.aMx;
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<u.bd.r.nField; i++) assert( memIsValid(&u.bd.r.aMem[i]) ); }
+ { int i; for(i=0; i<u.be.r.nField; i++) assert( memIsValid(&u.be.r.aMem[i]) ); }
#endif
- /* Extract the value of u.bd.R from register P3. */
+ /* Extract the value of u.be.R from register P3. */
sqlite3VdbeMemIntegerify(pIn3);
- u.bd.R = pIn3->u.i;
+ u.be.R = pIn3->u.i;
/* Search the B-Tree index. If no conflicting record is found, jump
** to P2. Otherwise, copy the rowid of the conflicting record to
** register P3 and fall through to the next instruction. */
- rc = sqlite3BtreeMovetoUnpacked(u.bd.pCrsr, &u.bd.r, 0, 0, &u.bd.pCx->seekResult);
- if( (u.bd.r.flags & UNPACKED_PREFIX_SEARCH) || u.bd.r.rowid==u.bd.R ){
+ rc = sqlite3BtreeMovetoUnpacked(u.be.pCrsr, &u.be.r, 0, 0, &u.be.pCx->seekResult);
+ if( (u.be.r.flags & UNPACKED_PREFIX_SEARCH) || u.be.r.rowid==u.be.R ){
pc = pOp->p2 - 1;
}else{
- pIn3->u.i = u.bd.r.rowid;
+ pIn3->u.i = u.be.r.rowid;
}
}
break;
@@ -67166,42 +68933,42 @@ case OP_IsUnique: { /* jump, in3 */
** See also: Found, NotFound, IsUnique
*/
case OP_NotExists: { /* jump, in3 */
-#if 0 /* local variables moved into u.be */
+#if 0 /* local variables moved into u.bf */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
u64 iKey;
-#endif /* local variables moved into u.be */
+#endif /* local variables moved into u.bf */
pIn3 = &aMem[pOp->p3];
assert( pIn3->flags & MEM_Int );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.be.pC = p->apCsr[pOp->p1];
- assert( u.be.pC!=0 );
- assert( u.be.pC->isTable );
- assert( u.be.pC->pseudoTableReg==0 );
- u.be.pCrsr = u.be.pC->pCursor;
- if( ALWAYS(u.be.pCrsr!=0) ){
- u.be.res = 0;
- u.be.iKey = pIn3->u.i;
- rc = sqlite3BtreeMovetoUnpacked(u.be.pCrsr, 0, u.be.iKey, 0, &u.be.res);
- u.be.pC->lastRowid = pIn3->u.i;
- u.be.pC->rowidIsValid = u.be.res==0 ?1:0;
- u.be.pC->nullRow = 0;
- u.be.pC->cacheStatus = CACHE_STALE;
- u.be.pC->deferredMoveto = 0;
- if( u.be.res!=0 ){
+ u.bf.pC = p->apCsr[pOp->p1];
+ assert( u.bf.pC!=0 );
+ assert( u.bf.pC->isTable );
+ assert( u.bf.pC->pseudoTableReg==0 );
+ u.bf.pCrsr = u.bf.pC->pCursor;
+ if( ALWAYS(u.bf.pCrsr!=0) ){
+ u.bf.res = 0;
+ u.bf.iKey = pIn3->u.i;
+ rc = sqlite3BtreeMovetoUnpacked(u.bf.pCrsr, 0, u.bf.iKey, 0, &u.bf.res);
+ u.bf.pC->lastRowid = pIn3->u.i;
+ u.bf.pC->rowidIsValid = u.bf.res==0 ?1:0;
+ u.bf.pC->nullRow = 0;
+ u.bf.pC->cacheStatus = CACHE_STALE;
+ u.bf.pC->deferredMoveto = 0;
+ if( u.bf.res!=0 ){
pc = pOp->p2 - 1;
- assert( u.be.pC->rowidIsValid==0 );
+ assert( u.bf.pC->rowidIsValid==0 );
}
- u.be.pC->seekResult = u.be.res;
+ u.bf.pC->seekResult = u.bf.res;
}else{
/* This happens when an attempt to open a read cursor on the
** sqlite_master table returns SQLITE_EMPTY.
*/
pc = pOp->p2 - 1;
- assert( u.be.pC->rowidIsValid==0 );
- u.be.pC->seekResult = 0;
+ assert( u.bf.pC->rowidIsValid==0 );
+ u.bf.pC->seekResult = 0;
}
break;
}
@@ -67236,21 +69003,21 @@ case OP_Sequence: { /* out2-prerelease */
** AUTOINCREMENT feature.
*/
case OP_NewRowid: { /* out2-prerelease */
-#if 0 /* local variables moved into u.bf */
+#if 0 /* local variables moved into u.bg */
i64 v; /* The new rowid */
VdbeCursor *pC; /* Cursor of table to get the new rowid */
int res; /* Result of an sqlite3BtreeLast() */
int cnt; /* Counter to limit the number of searches */
Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */
VdbeFrame *pFrame; /* Root frame of VDBE */
-#endif /* local variables moved into u.bf */
+#endif /* local variables moved into u.bg */
- u.bf.v = 0;
- u.bf.res = 0;
+ u.bg.v = 0;
+ u.bg.res = 0;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bf.pC = p->apCsr[pOp->p1];
- assert( u.bf.pC!=0 );
- if( NEVER(u.bf.pC->pCursor==0) ){
+ u.bg.pC = p->apCsr[pOp->p1];
+ assert( u.bg.pC!=0 );
+ if( NEVER(u.bg.pC->pCursor==0) ){
/* The zero initialization above is all that is needed */
}else{
/* The next rowid or record number (different terms for the same
@@ -67266,7 +69033,7 @@ case OP_NewRowid: { /* out2-prerelease */
** succeeded. If the random rowid does exist, we select a new one
** and try again, up to 100 times.
*/
- assert( u.bf.pC->isTable );
+ assert( u.bg.pC->isTable );
#ifdef SQLITE_32BIT_ROWID
# define MAX_ROWID 0x7fffffff
@@ -67278,23 +69045,23 @@ case OP_NewRowid: { /* out2-prerelease */
# define MAX_ROWID (i64)( (((u64)0x7fffffff)<<32) | (u64)0xffffffff )
#endif
- if( !u.bf.pC->useRandomRowid ){
- u.bf.v = sqlite3BtreeGetCachedRowid(u.bf.pC->pCursor);
- if( u.bf.v==0 ){
- rc = sqlite3BtreeLast(u.bf.pC->pCursor, &u.bf.res);
+ if( !u.bg.pC->useRandomRowid ){
+ u.bg.v = sqlite3BtreeGetCachedRowid(u.bg.pC->pCursor);
+ if( u.bg.v==0 ){
+ rc = sqlite3BtreeLast(u.bg.pC->pCursor, &u.bg.res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- if( u.bf.res ){
- u.bf.v = 1; /* IMP: R-61914-48074 */
+ if( u.bg.res ){
+ u.bg.v = 1; /* IMP: R-61914-48074 */
}else{
- assert( sqlite3BtreeCursorIsValid(u.bf.pC->pCursor) );
- rc = sqlite3BtreeKeySize(u.bf.pC->pCursor, &u.bf.v);
+ assert( sqlite3BtreeCursorIsValid(u.bg.pC->pCursor) );
+ rc = sqlite3BtreeKeySize(u.bg.pC->pCursor, &u.bg.v);
assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */
- if( u.bf.v==MAX_ROWID ){
- u.bf.pC->useRandomRowid = 1;
+ if( u.bg.v>=MAX_ROWID ){
+ u.bg.pC->useRandomRowid = 1;
}else{
- u.bf.v++; /* IMP: R-29538-34987 */
+ u.bg.v++; /* IMP: R-29538-34987 */
}
}
}
@@ -67304,35 +69071,35 @@ case OP_NewRowid: { /* out2-prerelease */
/* Assert that P3 is a valid memory cell. */
assert( pOp->p3>0 );
if( p->pFrame ){
- for(u.bf.pFrame=p->pFrame; u.bf.pFrame->pParent; u.bf.pFrame=u.bf.pFrame->pParent);
+ for(u.bg.pFrame=p->pFrame; u.bg.pFrame->pParent; u.bg.pFrame=u.bg.pFrame->pParent);
/* Assert that P3 is a valid memory cell. */
- assert( pOp->p3<=u.bf.pFrame->nMem );
- u.bf.pMem = &u.bf.pFrame->aMem[pOp->p3];
+ assert( pOp->p3<=u.bg.pFrame->nMem );
+ u.bg.pMem = &u.bg.pFrame->aMem[pOp->p3];
}else{
/* Assert that P3 is a valid memory cell. */
assert( pOp->p3<=p->nMem );
- u.bf.pMem = &aMem[pOp->p3];
- memAboutToChange(p, u.bf.pMem);
+ u.bg.pMem = &aMem[pOp->p3];
+ memAboutToChange(p, u.bg.pMem);
}
- assert( memIsValid(u.bf.pMem) );
+ assert( memIsValid(u.bg.pMem) );
- REGISTER_TRACE(pOp->p3, u.bf.pMem);
- sqlite3VdbeMemIntegerify(u.bf.pMem);
- assert( (u.bf.pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */
- if( u.bf.pMem->u.i==MAX_ROWID || u.bf.pC->useRandomRowid ){
+ REGISTER_TRACE(pOp->p3, u.bg.pMem);
+ sqlite3VdbeMemIntegerify(u.bg.pMem);
+ assert( (u.bg.pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */
+ if( u.bg.pMem->u.i==MAX_ROWID || u.bg.pC->useRandomRowid ){
rc = SQLITE_FULL; /* IMP: R-12275-61338 */
goto abort_due_to_error;
}
- if( u.bf.v<u.bf.pMem->u.i+1 ){
- u.bf.v = u.bf.pMem->u.i + 1;
+ if( u.bg.v<u.bg.pMem->u.i+1 ){
+ u.bg.v = u.bg.pMem->u.i + 1;
}
- u.bf.pMem->u.i = u.bf.v;
+ u.bg.pMem->u.i = u.bg.v;
}
#endif
- sqlite3BtreeSetCachedRowid(u.bf.pC->pCursor, u.bf.v<MAX_ROWID ? u.bf.v+1 : 0);
+ sqlite3BtreeSetCachedRowid(u.bg.pC->pCursor, u.bg.v<MAX_ROWID ? u.bg.v+1 : 0);
}
- if( u.bf.pC->useRandomRowid ){
+ if( u.bg.pC->useRandomRowid ){
/* IMPLEMENTATION-OF: R-07677-41881 If the largest ROWID is equal to the
** largest possible integer (9223372036854775807) then the database
** engine starts picking positive candidate ROWIDs at random until
@@ -67340,35 +69107,35 @@ case OP_NewRowid: { /* out2-prerelease */
assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is
** an AUTOINCREMENT table. */
/* on the first attempt, simply do one more than previous */
- u.bf.v = lastRowid;
- u.bf.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
- u.bf.v++; /* ensure non-zero */
- u.bf.cnt = 0;
- while( ((rc = sqlite3BtreeMovetoUnpacked(u.bf.pC->pCursor, 0, (u64)u.bf.v,
- 0, &u.bf.res))==SQLITE_OK)
- && (u.bf.res==0)
- && (++u.bf.cnt<100)){
+ u.bg.v = lastRowid;
+ u.bg.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
+ u.bg.v++; /* ensure non-zero */
+ u.bg.cnt = 0;
+ while( ((rc = sqlite3BtreeMovetoUnpacked(u.bg.pC->pCursor, 0, (u64)u.bg.v,
+ 0, &u.bg.res))==SQLITE_OK)
+ && (u.bg.res==0)
+ && (++u.bg.cnt<100)){
/* collision - try another random rowid */
- sqlite3_randomness(sizeof(u.bf.v), &u.bf.v);
- if( u.bf.cnt<5 ){
+ sqlite3_randomness(sizeof(u.bg.v), &u.bg.v);
+ if( u.bg.cnt<5 ){
/* try "small" random rowids for the initial attempts */
- u.bf.v &= 0xffffff;
+ u.bg.v &= 0xffffff;
}else{
- u.bf.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
+ u.bg.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
}
- u.bf.v++; /* ensure non-zero */
+ u.bg.v++; /* ensure non-zero */
}
- if( rc==SQLITE_OK && u.bf.res==0 ){
+ if( rc==SQLITE_OK && u.bg.res==0 ){
rc = SQLITE_FULL; /* IMP: R-38219-53002 */
goto abort_due_to_error;
}
- assert( u.bf.v>0 ); /* EV: R-40812-03570 */
+ assert( u.bg.v>0 ); /* EV: R-40812-03570 */
}
- u.bf.pC->rowidIsValid = 0;
- u.bf.pC->deferredMoveto = 0;
- u.bf.pC->cacheStatus = CACHE_STALE;
+ u.bg.pC->rowidIsValid = 0;
+ u.bg.pC->deferredMoveto = 0;
+ u.bg.pC->cacheStatus = CACHE_STALE;
}
- pOut->u.i = u.bf.v;
+ pOut->u.i = u.bg.v;
break;
}
@@ -67418,7 +69185,7 @@ case OP_NewRowid: { /* out2-prerelease */
*/
case OP_Insert:
case OP_InsertInt: {
-#if 0 /* local variables moved into u.bg */
+#if 0 /* local variables moved into u.bh */
Mem *pData; /* MEM cell holding data for the record to be inserted */
Mem *pKey; /* MEM cell holding key for the record */
i64 iKey; /* The integer ROWID or key for the record to be inserted */
@@ -67428,60 +69195,60 @@ case OP_InsertInt: {
const char *zDb; /* database name - used by the update hook */
const char *zTbl; /* Table name - used by the opdate hook */
int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
-#endif /* local variables moved into u.bg */
+#endif /* local variables moved into u.bh */
- u.bg.pData = &aMem[pOp->p2];
+ u.bh.pData = &aMem[pOp->p2];
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( memIsValid(u.bg.pData) );
- u.bg.pC = p->apCsr[pOp->p1];
- assert( u.bg.pC!=0 );
- assert( u.bg.pC->pCursor!=0 );
- assert( u.bg.pC->pseudoTableReg==0 );
- assert( u.bg.pC->isTable );
- REGISTER_TRACE(pOp->p2, u.bg.pData);
+ assert( memIsValid(u.bh.pData) );
+ u.bh.pC = p->apCsr[pOp->p1];
+ assert( u.bh.pC!=0 );
+ assert( u.bh.pC->pCursor!=0 );
+ assert( u.bh.pC->pseudoTableReg==0 );
+ assert( u.bh.pC->isTable );
+ REGISTER_TRACE(pOp->p2, u.bh.pData);
if( pOp->opcode==OP_Insert ){
- u.bg.pKey = &aMem[pOp->p3];
- assert( u.bg.pKey->flags & MEM_Int );
- assert( memIsValid(u.bg.pKey) );
- REGISTER_TRACE(pOp->p3, u.bg.pKey);
- u.bg.iKey = u.bg.pKey->u.i;
+ u.bh.pKey = &aMem[pOp->p3];
+ assert( u.bh.pKey->flags & MEM_Int );
+ assert( memIsValid(u.bh.pKey) );
+ REGISTER_TRACE(pOp->p3, u.bh.pKey);
+ u.bh.iKey = u.bh.pKey->u.i;
}else{
assert( pOp->opcode==OP_InsertInt );
- u.bg.iKey = pOp->p3;
+ u.bh.iKey = pOp->p3;
}
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
- if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = u.bg.iKey;
- if( u.bg.pData->flags & MEM_Null ){
- u.bg.pData->z = 0;
- u.bg.pData->n = 0;
+ if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = u.bh.iKey;
+ if( u.bh.pData->flags & MEM_Null ){
+ u.bh.pData->z = 0;
+ u.bh.pData->n = 0;
}else{
- assert( u.bg.pData->flags & (MEM_Blob|MEM_Str) );
+ assert( u.bh.pData->flags & (MEM_Blob|MEM_Str) );
}
- u.bg.seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.bg.pC->seekResult : 0);
- if( u.bg.pData->flags & MEM_Zero ){
- u.bg.nZero = u.bg.pData->u.nZero;
+ u.bh.seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.bh.pC->seekResult : 0);
+ if( u.bh.pData->flags & MEM_Zero ){
+ u.bh.nZero = u.bh.pData->u.nZero;
}else{
- u.bg.nZero = 0;
+ u.bh.nZero = 0;
}
- sqlite3BtreeSetCachedRowid(u.bg.pC->pCursor, 0);
- rc = sqlite3BtreeInsert(u.bg.pC->pCursor, 0, u.bg.iKey,
- u.bg.pData->z, u.bg.pData->n, u.bg.nZero,
- pOp->p5 & OPFLAG_APPEND, u.bg.seekResult
+ sqlite3BtreeSetCachedRowid(u.bh.pC->pCursor, 0);
+ rc = sqlite3BtreeInsert(u.bh.pC->pCursor, 0, u.bh.iKey,
+ u.bh.pData->z, u.bh.pData->n, u.bh.nZero,
+ pOp->p5 & OPFLAG_APPEND, u.bh.seekResult
);
- u.bg.pC->rowidIsValid = 0;
- u.bg.pC->deferredMoveto = 0;
- u.bg.pC->cacheStatus = CACHE_STALE;
+ u.bh.pC->rowidIsValid = 0;
+ u.bh.pC->deferredMoveto = 0;
+ u.bh.pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
- u.bg.zDb = db->aDb[u.bg.pC->iDb].zName;
- u.bg.zTbl = pOp->p4.z;
- u.bg.op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
- assert( u.bg.pC->isTable );
- db->xUpdateCallback(db->pUpdateArg, u.bg.op, u.bg.zDb, u.bg.zTbl, u.bg.iKey);
- assert( u.bg.pC->iDb>=0 );
+ u.bh.zDb = db->aDb[u.bh.pC->iDb].zName;
+ u.bh.zTbl = pOp->p4.z;
+ u.bh.op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
+ assert( u.bh.pC->isTable );
+ db->xUpdateCallback(db->pUpdateArg, u.bh.op, u.bh.zDb, u.bh.zTbl, u.bh.iKey);
+ assert( u.bh.pC->iDb>=0 );
}
break;
}
@@ -67507,47 +69274,47 @@ case OP_InsertInt: {
** using OP_NotFound prior to invoking this opcode.
*/
case OP_Delete: {
-#if 0 /* local variables moved into u.bh */
+#if 0 /* local variables moved into u.bi */
i64 iKey;
VdbeCursor *pC;
-#endif /* local variables moved into u.bh */
+#endif /* local variables moved into u.bi */
- u.bh.iKey = 0;
+ u.bi.iKey = 0;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bh.pC = p->apCsr[pOp->p1];
- assert( u.bh.pC!=0 );
- assert( u.bh.pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */
+ u.bi.pC = p->apCsr[pOp->p1];
+ assert( u.bi.pC!=0 );
+ assert( u.bi.pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */
- /* If the update-hook will be invoked, set u.bh.iKey to the rowid of the
+ /* If the update-hook will be invoked, set u.bi.iKey to the rowid of the
** row being deleted.
*/
if( db->xUpdateCallback && pOp->p4.z ){
- assert( u.bh.pC->isTable );
- assert( u.bh.pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */
- u.bh.iKey = u.bh.pC->lastRowid;
+ assert( u.bi.pC->isTable );
+ assert( u.bi.pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */
+ u.bi.iKey = u.bi.pC->lastRowid;
}
/* The OP_Delete opcode always follows an OP_NotExists or OP_Last or
** OP_Column on the same table without any intervening operations that
- ** might move or invalidate the cursor. Hence cursor u.bh.pC is always pointing
+ ** might move or invalidate the cursor. Hence cursor u.bi.pC is always pointing
** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation
** below is always a no-op and cannot fail. We will run it anyhow, though,
** to guard against future changes to the code generator.
**/
- assert( u.bh.pC->deferredMoveto==0 );
- rc = sqlite3VdbeCursorMoveto(u.bh.pC);
+ assert( u.bi.pC->deferredMoveto==0 );
+ rc = sqlite3VdbeCursorMoveto(u.bi.pC);
if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
- sqlite3BtreeSetCachedRowid(u.bh.pC->pCursor, 0);
- rc = sqlite3BtreeDelete(u.bh.pC->pCursor);
- u.bh.pC->cacheStatus = CACHE_STALE;
+ sqlite3BtreeSetCachedRowid(u.bi.pC->pCursor, 0);
+ rc = sqlite3BtreeDelete(u.bi.pC->pCursor);
+ u.bi.pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
- const char *zDb = db->aDb[u.bh.pC->iDb].zName;
+ const char *zDb = db->aDb[u.bi.pC->iDb].zName;
const char *zTbl = pOp->p4.z;
- db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, u.bh.iKey);
- assert( u.bh.pC->iDb>=0 );
+ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, u.bi.iKey);
+ assert( u.bi.pC->iDb>=0 );
}
if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
break;
@@ -67573,16 +69340,16 @@ case OP_ResetCount: {
** fall through to the next instruction. Otherwise, jump to instruction P2.
*/
case OP_SorterCompare: {
-#if 0 /* local variables moved into u.bi */
+#if 0 /* local variables moved into u.bj */
VdbeCursor *pC;
int res;
-#endif /* local variables moved into u.bi */
+#endif /* local variables moved into u.bj */
- u.bi.pC = p->apCsr[pOp->p1];
- assert( isSorter(u.bi.pC) );
+ u.bj.pC = p->apCsr[pOp->p1];
+ assert( isSorter(u.bj.pC) );
pIn3 = &aMem[pOp->p3];
- rc = sqlite3VdbeSorterCompare(u.bi.pC, pIn3, &u.bi.res);
- if( u.bi.res ){
+ rc = sqlite3VdbeSorterCompare(u.bj.pC, pIn3, &u.bj.res);
+ if( u.bj.res ){
pc = pOp->p2-1;
}
break;
@@ -67593,14 +69360,14 @@ case OP_SorterCompare: {
** Write into register P2 the current sorter data for sorter cursor P1.
*/
case OP_SorterData: {
-#if 0 /* local variables moved into u.bj */
+#if 0 /* local variables moved into u.bk */
VdbeCursor *pC;
-#endif /* local variables moved into u.bj */
+#endif /* local variables moved into u.bk */
#ifndef SQLITE_OMIT_MERGE_SORT
pOut = &aMem[pOp->p2];
- u.bj.pC = p->apCsr[pOp->p1];
- assert( u.bj.pC->isSorter );
- rc = sqlite3VdbeSorterRowkey(u.bj.pC, pOut);
+ u.bk.pC = p->apCsr[pOp->p1];
+ assert( u.bk.pC->isSorter );
+ rc = sqlite3VdbeSorterRowkey(u.bk.pC, pOut);
#else
pOp->opcode = OP_RowKey;
pc--;
@@ -67630,63 +69397,63 @@ case OP_SorterData: {
*/
case OP_RowKey:
case OP_RowData: {
-#if 0 /* local variables moved into u.bk */
+#if 0 /* local variables moved into u.bl */
VdbeCursor *pC;
BtCursor *pCrsr;
u32 n;
i64 n64;
-#endif /* local variables moved into u.bk */
+#endif /* local variables moved into u.bl */
pOut = &aMem[pOp->p2];
memAboutToChange(p, pOut);
/* Note that RowKey and RowData are really exactly the same instruction */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bk.pC = p->apCsr[pOp->p1];
- assert( u.bk.pC->isSorter==0 );
- assert( u.bk.pC->isTable || pOp->opcode!=OP_RowData );
- assert( u.bk.pC->isIndex || pOp->opcode==OP_RowData );
- assert( u.bk.pC!=0 );
- assert( u.bk.pC->nullRow==0 );
- assert( u.bk.pC->pseudoTableReg==0 );
- assert( !u.bk.pC->isSorter );
- assert( u.bk.pC->pCursor!=0 );
- u.bk.pCrsr = u.bk.pC->pCursor;
- assert( sqlite3BtreeCursorIsValid(u.bk.pCrsr) );
+ u.bl.pC = p->apCsr[pOp->p1];
+ assert( u.bl.pC->isSorter==0 );
+ assert( u.bl.pC->isTable || pOp->opcode!=OP_RowData );
+ assert( u.bl.pC->isIndex || pOp->opcode==OP_RowData );
+ assert( u.bl.pC!=0 );
+ assert( u.bl.pC->nullRow==0 );
+ assert( u.bl.pC->pseudoTableReg==0 );
+ assert( !u.bl.pC->isSorter );
+ assert( u.bl.pC->pCursor!=0 );
+ u.bl.pCrsr = u.bl.pC->pCursor;
+ assert( sqlite3BtreeCursorIsValid(u.bl.pCrsr) );
/* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
** OP_Rewind/Op_Next with no intervening instructions that might invalidate
** the cursor. Hence the following sqlite3VdbeCursorMoveto() call is always
** a no-op and can never fail. But we leave it in place as a safety.
*/
- assert( u.bk.pC->deferredMoveto==0 );
- rc = sqlite3VdbeCursorMoveto(u.bk.pC);
+ assert( u.bl.pC->deferredMoveto==0 );
+ rc = sqlite3VdbeCursorMoveto(u.bl.pC);
if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
- if( u.bk.pC->isIndex ){
- assert( !u.bk.pC->isTable );
- VVA_ONLY(rc =) sqlite3BtreeKeySize(u.bk.pCrsr, &u.bk.n64);
+ if( u.bl.pC->isIndex ){
+ assert( !u.bl.pC->isTable );
+ VVA_ONLY(rc =) sqlite3BtreeKeySize(u.bl.pCrsr, &u.bl.n64);
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
- if( u.bk.n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ if( u.bl.n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
- u.bk.n = (u32)u.bk.n64;
+ u.bl.n = (u32)u.bl.n64;
}else{
- VVA_ONLY(rc =) sqlite3BtreeDataSize(u.bk.pCrsr, &u.bk.n);
+ VVA_ONLY(rc =) sqlite3BtreeDataSize(u.bl.pCrsr, &u.bl.n);
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
- if( u.bk.n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ if( u.bl.n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
}
- if( sqlite3VdbeMemGrow(pOut, u.bk.n, 0) ){
+ if( sqlite3VdbeMemGrow(pOut, u.bl.n, 0) ){
goto no_mem;
}
- pOut->n = u.bk.n;
+ pOut->n = u.bl.n;
MemSetTypeFlag(pOut, MEM_Blob);
- if( u.bk.pC->isIndex ){
- rc = sqlite3BtreeKey(u.bk.pCrsr, 0, u.bk.n, pOut->z);
+ if( u.bl.pC->isIndex ){
+ rc = sqlite3BtreeKey(u.bl.pCrsr, 0, u.bl.n, pOut->z);
}else{
- rc = sqlite3BtreeData(u.bk.pCrsr, 0, u.bk.n, pOut->z);
+ rc = sqlite3BtreeData(u.bl.pCrsr, 0, u.bl.n, pOut->z);
}
pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
UPDATE_MAX_BLOBSIZE(pOut);
@@ -67703,42 +69470,42 @@ case OP_RowData: {
** one opcode now works for both table types.
*/
case OP_Rowid: { /* out2-prerelease */
-#if 0 /* local variables moved into u.bl */
+#if 0 /* local variables moved into u.bm */
VdbeCursor *pC;
i64 v;
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
-#endif /* local variables moved into u.bl */
+#endif /* local variables moved into u.bm */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bl.pC = p->apCsr[pOp->p1];
- assert( u.bl.pC!=0 );
- assert( u.bl.pC->pseudoTableReg==0 );
- if( u.bl.pC->nullRow ){
+ u.bm.pC = p->apCsr[pOp->p1];
+ assert( u.bm.pC!=0 );
+ assert( u.bm.pC->pseudoTableReg==0 );
+ if( u.bm.pC->nullRow ){
pOut->flags = MEM_Null;
break;
- }else if( u.bl.pC->deferredMoveto ){
- u.bl.v = u.bl.pC->movetoTarget;
+ }else if( u.bm.pC->deferredMoveto ){
+ u.bm.v = u.bm.pC->movetoTarget;
#ifndef SQLITE_OMIT_VIRTUALTABLE
- }else if( u.bl.pC->pVtabCursor ){
- u.bl.pVtab = u.bl.pC->pVtabCursor->pVtab;
- u.bl.pModule = u.bl.pVtab->pModule;
- assert( u.bl.pModule->xRowid );
- rc = u.bl.pModule->xRowid(u.bl.pC->pVtabCursor, &u.bl.v);
- importVtabErrMsg(p, u.bl.pVtab);
+ }else if( u.bm.pC->pVtabCursor ){
+ u.bm.pVtab = u.bm.pC->pVtabCursor->pVtab;
+ u.bm.pModule = u.bm.pVtab->pModule;
+ assert( u.bm.pModule->xRowid );
+ rc = u.bm.pModule->xRowid(u.bm.pC->pVtabCursor, &u.bm.v);
+ importVtabErrMsg(p, u.bm.pVtab);
#endif /* SQLITE_OMIT_VIRTUALTABLE */
}else{
- assert( u.bl.pC->pCursor!=0 );
- rc = sqlite3VdbeCursorMoveto(u.bl.pC);
+ assert( u.bm.pC->pCursor!=0 );
+ rc = sqlite3VdbeCursorMoveto(u.bm.pC);
if( rc ) goto abort_due_to_error;
- if( u.bl.pC->rowidIsValid ){
- u.bl.v = u.bl.pC->lastRowid;
+ if( u.bm.pC->rowidIsValid ){
+ u.bm.v = u.bm.pC->lastRowid;
}else{
- rc = sqlite3BtreeKeySize(u.bl.pC->pCursor, &u.bl.v);
+ rc = sqlite3BtreeKeySize(u.bm.pC->pCursor, &u.bm.v);
assert( rc==SQLITE_OK ); /* Always so because of CursorMoveto() above */
}
}
- pOut->u.i = u.bl.v;
+ pOut->u.i = u.bm.v;
break;
}
@@ -67749,18 +69516,18 @@ case OP_Rowid: { /* out2-prerelease */
** write a NULL.
*/
case OP_NullRow: {
-#if 0 /* local variables moved into u.bm */
+#if 0 /* local variables moved into u.bn */
VdbeCursor *pC;
-#endif /* local variables moved into u.bm */
+#endif /* local variables moved into u.bn */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bm.pC = p->apCsr[pOp->p1];
- assert( u.bm.pC!=0 );
- u.bm.pC->nullRow = 1;
- u.bm.pC->rowidIsValid = 0;
- assert( u.bm.pC->pCursor || u.bm.pC->pVtabCursor );
- if( u.bm.pC->pCursor ){
- sqlite3BtreeClearCursor(u.bm.pC->pCursor);
+ u.bn.pC = p->apCsr[pOp->p1];
+ assert( u.bn.pC!=0 );
+ u.bn.pC->nullRow = 1;
+ u.bn.pC->rowidIsValid = 0;
+ assert( u.bn.pC->pCursor || u.bn.pC->pVtabCursor );
+ if( u.bn.pC->pCursor ){
+ sqlite3BtreeClearCursor(u.bn.pC->pCursor);
}
break;
}
@@ -67774,25 +69541,25 @@ case OP_NullRow: {
** to the following instruction.
*/
case OP_Last: { /* jump */
-#if 0 /* local variables moved into u.bn */
+#if 0 /* local variables moved into u.bo */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
-#endif /* local variables moved into u.bn */
+#endif /* local variables moved into u.bo */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bn.pC = p->apCsr[pOp->p1];
- assert( u.bn.pC!=0 );
- u.bn.pCrsr = u.bn.pC->pCursor;
- u.bn.res = 0;
- if( ALWAYS(u.bn.pCrsr!=0) ){
- rc = sqlite3BtreeLast(u.bn.pCrsr, &u.bn.res);
+ u.bo.pC = p->apCsr[pOp->p1];
+ assert( u.bo.pC!=0 );
+ u.bo.pCrsr = u.bo.pC->pCursor;
+ u.bo.res = 0;
+ if( ALWAYS(u.bo.pCrsr!=0) ){
+ rc = sqlite3BtreeLast(u.bo.pCrsr, &u.bo.res);
}
- u.bn.pC->nullRow = (u8)u.bn.res;
- u.bn.pC->deferredMoveto = 0;
- u.bn.pC->rowidIsValid = 0;
- u.bn.pC->cacheStatus = CACHE_STALE;
- if( pOp->p2>0 && u.bn.res ){
+ u.bo.pC->nullRow = (u8)u.bo.res;
+ u.bo.pC->deferredMoveto = 0;
+ u.bo.pC->rowidIsValid = 0;
+ u.bo.pC->cacheStatus = CACHE_STALE;
+ if( pOp->p2>0 && u.bo.res ){
pc = pOp->p2 - 1;
}
break;
@@ -67832,31 +69599,31 @@ case OP_Sort: { /* jump */
** to the following instruction.
*/
case OP_Rewind: { /* jump */
-#if 0 /* local variables moved into u.bo */
+#if 0 /* local variables moved into u.bp */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
-#endif /* local variables moved into u.bo */
+#endif /* local variables moved into u.bp */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bo.pC = p->apCsr[pOp->p1];
- assert( u.bo.pC!=0 );
- assert( u.bo.pC->isSorter==(pOp->opcode==OP_SorterSort) );
- u.bo.res = 1;
- if( isSorter(u.bo.pC) ){
- rc = sqlite3VdbeSorterRewind(db, u.bo.pC, &u.bo.res);
- }else{
- u.bo.pCrsr = u.bo.pC->pCursor;
- assert( u.bo.pCrsr );
- rc = sqlite3BtreeFirst(u.bo.pCrsr, &u.bo.res);
- u.bo.pC->atFirst = u.bo.res==0 ?1:0;
- u.bo.pC->deferredMoveto = 0;
- u.bo.pC->cacheStatus = CACHE_STALE;
- u.bo.pC->rowidIsValid = 0;
+ u.bp.pC = p->apCsr[pOp->p1];
+ assert( u.bp.pC!=0 );
+ assert( u.bp.pC->isSorter==(pOp->opcode==OP_SorterSort) );
+ u.bp.res = 1;
+ if( isSorter(u.bp.pC) ){
+ rc = sqlite3VdbeSorterRewind(db, u.bp.pC, &u.bp.res);
+ }else{
+ u.bp.pCrsr = u.bp.pC->pCursor;
+ assert( u.bp.pCrsr );
+ rc = sqlite3BtreeFirst(u.bp.pCrsr, &u.bp.res);
+ u.bp.pC->atFirst = u.bp.res==0 ?1:0;
+ u.bp.pC->deferredMoveto = 0;
+ u.bp.pC->cacheStatus = CACHE_STALE;
+ u.bp.pC->rowidIsValid = 0;
}
- u.bo.pC->nullRow = (u8)u.bo.res;
+ u.bp.pC->nullRow = (u8)u.bp.res;
assert( pOp->p2>0 && pOp->p2<p->nOp );
- if( u.bo.res ){
+ if( u.bp.res ){
pc = pOp->p2 - 1;
}
break;
@@ -67900,40 +69667,40 @@ case OP_SorterNext: /* jump */
#endif
case OP_Prev: /* jump */
case OP_Next: { /* jump */
-#if 0 /* local variables moved into u.bp */
+#if 0 /* local variables moved into u.bq */
VdbeCursor *pC;
int res;
-#endif /* local variables moved into u.bp */
+#endif /* local variables moved into u.bq */
CHECK_FOR_INTERRUPT;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5<=ArraySize(p->aCounter) );
- u.bp.pC = p->apCsr[pOp->p1];
- if( u.bp.pC==0 ){
+ u.bq.pC = p->apCsr[pOp->p1];
+ if( u.bq.pC==0 ){
break; /* See ticket #2273 */
}
- assert( u.bp.pC->isSorter==(pOp->opcode==OP_SorterNext) );
- if( isSorter(u.bp.pC) ){
+ assert( u.bq.pC->isSorter==(pOp->opcode==OP_SorterNext) );
+ if( isSorter(u.bq.pC) ){
assert( pOp->opcode==OP_SorterNext );
- rc = sqlite3VdbeSorterNext(db, u.bp.pC, &u.bp.res);
+ rc = sqlite3VdbeSorterNext(db, u.bq.pC, &u.bq.res);
}else{
- u.bp.res = 1;
- assert( u.bp.pC->deferredMoveto==0 );
- assert( u.bp.pC->pCursor );
+ u.bq.res = 1;
+ assert( u.bq.pC->deferredMoveto==0 );
+ assert( u.bq.pC->pCursor );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
- rc = pOp->p4.xAdvance(u.bp.pC->pCursor, &u.bp.res);
+ rc = pOp->p4.xAdvance(u.bq.pC->pCursor, &u.bq.res);
}
- u.bp.pC->nullRow = (u8)u.bp.res;
- u.bp.pC->cacheStatus = CACHE_STALE;
- if( u.bp.res==0 ){
+ u.bq.pC->nullRow = (u8)u.bq.res;
+ u.bq.pC->cacheStatus = CACHE_STALE;
+ if( u.bq.res==0 ){
pc = pOp->p2 - 1;
if( pOp->p5 ) p->aCounter[pOp->p5-1]++;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
}
- u.bp.pC->rowidIsValid = 0;
+ u.bq.pC->rowidIsValid = 0;
break;
}
@@ -67954,34 +69721,34 @@ case OP_SorterInsert: /* in2 */
pOp->opcode = OP_IdxInsert;
#endif
case OP_IdxInsert: { /* in2 */
-#if 0 /* local variables moved into u.bq */
+#if 0 /* local variables moved into u.br */
VdbeCursor *pC;
BtCursor *pCrsr;
int nKey;
const char *zKey;
-#endif /* local variables moved into u.bq */
+#endif /* local variables moved into u.br */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bq.pC = p->apCsr[pOp->p1];
- assert( u.bq.pC!=0 );
- assert( u.bq.pC->isSorter==(pOp->opcode==OP_SorterInsert) );
+ u.br.pC = p->apCsr[pOp->p1];
+ assert( u.br.pC!=0 );
+ assert( u.br.pC->isSorter==(pOp->opcode==OP_SorterInsert) );
pIn2 = &aMem[pOp->p2];
assert( pIn2->flags & MEM_Blob );
- u.bq.pCrsr = u.bq.pC->pCursor;
- if( ALWAYS(u.bq.pCrsr!=0) ){
- assert( u.bq.pC->isTable==0 );
+ u.br.pCrsr = u.br.pC->pCursor;
+ if( ALWAYS(u.br.pCrsr!=0) ){
+ assert( u.br.pC->isTable==0 );
rc = ExpandBlob(pIn2);
if( rc==SQLITE_OK ){
- if( isSorter(u.bq.pC) ){
- rc = sqlite3VdbeSorterWrite(db, u.bq.pC, pIn2);
+ if( isSorter(u.br.pC) ){
+ rc = sqlite3VdbeSorterWrite(db, u.br.pC, pIn2);
}else{
- u.bq.nKey = pIn2->n;
- u.bq.zKey = pIn2->z;
- rc = sqlite3BtreeInsert(u.bq.pCrsr, u.bq.zKey, u.bq.nKey, "", 0, 0, pOp->p3,
- ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.bq.pC->seekResult : 0)
+ u.br.nKey = pIn2->n;
+ u.br.zKey = pIn2->z;
+ rc = sqlite3BtreeInsert(u.br.pCrsr, u.br.zKey, u.br.nKey, "", 0, 0, pOp->p3,
+ ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.br.pC->seekResult : 0)
);
- assert( u.bq.pC->deferredMoveto==0 );
- u.bq.pC->cacheStatus = CACHE_STALE;
+ assert( u.br.pC->deferredMoveto==0 );
+ u.br.pC->cacheStatus = CACHE_STALE;
}
}
}
@@ -67995,33 +69762,33 @@ case OP_IdxInsert: { /* in2 */
** index opened by cursor P1.
*/
case OP_IdxDelete: {
-#if 0 /* local variables moved into u.br */
+#if 0 /* local variables moved into u.bs */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
UnpackedRecord r;
-#endif /* local variables moved into u.br */
+#endif /* local variables moved into u.bs */
assert( pOp->p3>0 );
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem+1 );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.br.pC = p->apCsr[pOp->p1];
- assert( u.br.pC!=0 );
- u.br.pCrsr = u.br.pC->pCursor;
- if( ALWAYS(u.br.pCrsr!=0) ){
- u.br.r.pKeyInfo = u.br.pC->pKeyInfo;
- u.br.r.nField = (u16)pOp->p3;
- u.br.r.flags = 0;
- u.br.r.aMem = &aMem[pOp->p2];
+ u.bs.pC = p->apCsr[pOp->p1];
+ assert( u.bs.pC!=0 );
+ u.bs.pCrsr = u.bs.pC->pCursor;
+ if( ALWAYS(u.bs.pCrsr!=0) ){
+ u.bs.r.pKeyInfo = u.bs.pC->pKeyInfo;
+ u.bs.r.nField = (u16)pOp->p3;
+ u.bs.r.flags = 0;
+ u.bs.r.aMem = &aMem[pOp->p2];
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<u.br.r.nField; i++) assert( memIsValid(&u.br.r.aMem[i]) ); }
+ { int i; for(i=0; i<u.bs.r.nField; i++) assert( memIsValid(&u.bs.r.aMem[i]) ); }
#endif
- rc = sqlite3BtreeMovetoUnpacked(u.br.pCrsr, &u.br.r, 0, 0, &u.br.res);
- if( rc==SQLITE_OK && u.br.res==0 ){
- rc = sqlite3BtreeDelete(u.br.pCrsr);
+ rc = sqlite3BtreeMovetoUnpacked(u.bs.pCrsr, &u.bs.r, 0, 0, &u.bs.res);
+ if( rc==SQLITE_OK && u.bs.res==0 ){
+ rc = sqlite3BtreeDelete(u.bs.pCrsr);
}
- assert( u.br.pC->deferredMoveto==0 );
- u.br.pC->cacheStatus = CACHE_STALE;
+ assert( u.bs.pC->deferredMoveto==0 );
+ u.bs.pC->cacheStatus = CACHE_STALE;
}
break;
}
@@ -68035,28 +69802,28 @@ case OP_IdxDelete: {
** See also: Rowid, MakeRecord.
*/
case OP_IdxRowid: { /* out2-prerelease */
-#if 0 /* local variables moved into u.bs */
+#if 0 /* local variables moved into u.bt */
BtCursor *pCrsr;
VdbeCursor *pC;
i64 rowid;
-#endif /* local variables moved into u.bs */
+#endif /* local variables moved into u.bt */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bs.pC = p->apCsr[pOp->p1];
- assert( u.bs.pC!=0 );
- u.bs.pCrsr = u.bs.pC->pCursor;
+ u.bt.pC = p->apCsr[pOp->p1];
+ assert( u.bt.pC!=0 );
+ u.bt.pCrsr = u.bt.pC->pCursor;
pOut->flags = MEM_Null;
- if( ALWAYS(u.bs.pCrsr!=0) ){
- rc = sqlite3VdbeCursorMoveto(u.bs.pC);
+ if( ALWAYS(u.bt.pCrsr!=0) ){
+ rc = sqlite3VdbeCursorMoveto(u.bt.pC);
if( NEVER(rc) ) goto abort_due_to_error;
- assert( u.bs.pC->deferredMoveto==0 );
- assert( u.bs.pC->isTable==0 );
- if( !u.bs.pC->nullRow ){
- rc = sqlite3VdbeIdxRowid(db, u.bs.pCrsr, &u.bs.rowid);
+ assert( u.bt.pC->deferredMoveto==0 );
+ assert( u.bt.pC->isTable==0 );
+ if( !u.bt.pC->nullRow ){
+ rc = sqlite3VdbeIdxRowid(db, u.bt.pCrsr, &u.bt.rowid);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- pOut->u.i = u.bs.rowid;
+ pOut->u.i = u.bt.rowid;
pOut->flags = MEM_Int;
}
}
@@ -68091,39 +69858,39 @@ case OP_IdxRowid: { /* out2-prerelease */
*/
case OP_IdxLT: /* jump */
case OP_IdxGE: { /* jump */
-#if 0 /* local variables moved into u.bt */
+#if 0 /* local variables moved into u.bu */
VdbeCursor *pC;
int res;
UnpackedRecord r;
-#endif /* local variables moved into u.bt */
+#endif /* local variables moved into u.bu */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bt.pC = p->apCsr[pOp->p1];
- assert( u.bt.pC!=0 );
- assert( u.bt.pC->isOrdered );
- if( ALWAYS(u.bt.pC->pCursor!=0) ){
- assert( u.bt.pC->deferredMoveto==0 );
+ u.bu.pC = p->apCsr[pOp->p1];
+ assert( u.bu.pC!=0 );
+ assert( u.bu.pC->isOrdered );
+ if( ALWAYS(u.bu.pC->pCursor!=0) ){
+ assert( u.bu.pC->deferredMoveto==0 );
assert( pOp->p5==0 || pOp->p5==1 );
assert( pOp->p4type==P4_INT32 );
- u.bt.r.pKeyInfo = u.bt.pC->pKeyInfo;
- u.bt.r.nField = (u16)pOp->p4.i;
+ u.bu.r.pKeyInfo = u.bu.pC->pKeyInfo;
+ u.bu.r.nField = (u16)pOp->p4.i;
if( pOp->p5 ){
- u.bt.r.flags = UNPACKED_INCRKEY | UNPACKED_IGNORE_ROWID;
+ u.bu.r.flags = UNPACKED_INCRKEY | UNPACKED_PREFIX_MATCH;
}else{
- u.bt.r.flags = UNPACKED_IGNORE_ROWID;
+ u.bu.r.flags = UNPACKED_PREFIX_MATCH;
}
- u.bt.r.aMem = &aMem[pOp->p3];
+ u.bu.r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<u.bt.r.nField; i++) assert( memIsValid(&u.bt.r.aMem[i]) ); }
+ { int i; for(i=0; i<u.bu.r.nField; i++) assert( memIsValid(&u.bu.r.aMem[i]) ); }
#endif
- rc = sqlite3VdbeIdxKeyCompare(u.bt.pC, &u.bt.r, &u.bt.res);
+ rc = sqlite3VdbeIdxKeyCompare(u.bu.pC, &u.bu.r, &u.bu.res);
if( pOp->opcode==OP_IdxLT ){
- u.bt.res = -u.bt.res;
+ u.bu.res = -u.bu.res;
}else{
assert( pOp->opcode==OP_IdxGE );
- u.bt.res++;
+ u.bu.res++;
}
- if( u.bt.res>0 ){
+ if( u.bu.res>0 ){
pc = pOp->p2 - 1 ;
}
}
@@ -68151,39 +69918,39 @@ case OP_IdxGE: { /* jump */
** See also: Clear
*/
case OP_Destroy: { /* out2-prerelease */
-#if 0 /* local variables moved into u.bu */
+#if 0 /* local variables moved into u.bv */
int iMoved;
int iCnt;
Vdbe *pVdbe;
int iDb;
-#endif /* local variables moved into u.bu */
+#endif /* local variables moved into u.bv */
#ifndef SQLITE_OMIT_VIRTUALTABLE
- u.bu.iCnt = 0;
- for(u.bu.pVdbe=db->pVdbe; u.bu.pVdbe; u.bu.pVdbe = u.bu.pVdbe->pNext){
- if( u.bu.pVdbe->magic==VDBE_MAGIC_RUN && u.bu.pVdbe->inVtabMethod<2 && u.bu.pVdbe->pc>=0 ){
- u.bu.iCnt++;
+ u.bv.iCnt = 0;
+ for(u.bv.pVdbe=db->pVdbe; u.bv.pVdbe; u.bv.pVdbe = u.bv.pVdbe->pNext){
+ if( u.bv.pVdbe->magic==VDBE_MAGIC_RUN && u.bv.pVdbe->inVtabMethod<2 && u.bv.pVdbe->pc>=0 ){
+ u.bv.iCnt++;
}
}
#else
- u.bu.iCnt = db->activeVdbeCnt;
+ u.bv.iCnt = db->activeVdbeCnt;
#endif
pOut->flags = MEM_Null;
- if( u.bu.iCnt>1 ){
+ if( u.bv.iCnt>1 ){
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
}else{
- u.bu.iDb = pOp->p3;
- assert( u.bu.iCnt==1 );
- assert( (p->btreeMask & (((yDbMask)1)<<u.bu.iDb))!=0 );
- rc = sqlite3BtreeDropTable(db->aDb[u.bu.iDb].pBt, pOp->p1, &u.bu.iMoved);
+ u.bv.iDb = pOp->p3;
+ assert( u.bv.iCnt==1 );
+ assert( (p->btreeMask & (((yDbMask)1)<<u.bv.iDb))!=0 );
+ rc = sqlite3BtreeDropTable(db->aDb[u.bv.iDb].pBt, pOp->p1, &u.bv.iMoved);
pOut->flags = MEM_Int;
- pOut->u.i = u.bu.iMoved;
+ pOut->u.i = u.bv.iMoved;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( rc==SQLITE_OK && u.bu.iMoved!=0 ){
- sqlite3RootPageMoved(db, u.bu.iDb, u.bu.iMoved, pOp->p1);
+ if( rc==SQLITE_OK && u.bv.iMoved!=0 ){
+ sqlite3RootPageMoved(db, u.bv.iDb, u.bv.iMoved, pOp->p1);
/* All OP_Destroy operations occur on the same btree */
- assert( resetSchemaOnFault==0 || resetSchemaOnFault==u.bu.iDb+1 );
- resetSchemaOnFault = u.bu.iDb+1;
+ assert( resetSchemaOnFault==0 || resetSchemaOnFault==u.bv.iDb+1 );
+ resetSchemaOnFault = u.bv.iDb+1;
}
#endif
}
@@ -68209,21 +69976,21 @@ case OP_Destroy: { /* out2-prerelease */
** See also: Destroy
*/
case OP_Clear: {
-#if 0 /* local variables moved into u.bv */
+#if 0 /* local variables moved into u.bw */
int nChange;
-#endif /* local variables moved into u.bv */
+#endif /* local variables moved into u.bw */
- u.bv.nChange = 0;
+ u.bw.nChange = 0;
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p2))!=0 );
rc = sqlite3BtreeClearTable(
- db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &u.bv.nChange : 0)
+ db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &u.bw.nChange : 0)
);
if( pOp->p3 ){
- p->nChange += u.bv.nChange;
+ p->nChange += u.bw.nChange;
if( pOp->p3>0 ){
assert( memIsValid(&aMem[pOp->p3]) );
memAboutToChange(p, &aMem[pOp->p3]);
- aMem[pOp->p3].u.i += u.bv.nChange;
+ aMem[pOp->p3].u.i += u.bw.nChange;
}
}
break;
@@ -68253,25 +70020,25 @@ case OP_Clear: {
*/
case OP_CreateIndex: /* out2-prerelease */
case OP_CreateTable: { /* out2-prerelease */
-#if 0 /* local variables moved into u.bw */
+#if 0 /* local variables moved into u.bx */
int pgno;
int flags;
Db *pDb;
-#endif /* local variables moved into u.bw */
+#endif /* local variables moved into u.bx */
- u.bw.pgno = 0;
+ u.bx.pgno = 0;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
- u.bw.pDb = &db->aDb[pOp->p1];
- assert( u.bw.pDb->pBt!=0 );
+ u.bx.pDb = &db->aDb[pOp->p1];
+ assert( u.bx.pDb->pBt!=0 );
if( pOp->opcode==OP_CreateTable ){
- /* u.bw.flags = BTREE_INTKEY; */
- u.bw.flags = BTREE_INTKEY;
+ /* u.bx.flags = BTREE_INTKEY; */
+ u.bx.flags = BTREE_INTKEY;
}else{
- u.bw.flags = BTREE_BLOBKEY;
+ u.bx.flags = BTREE_BLOBKEY;
}
- rc = sqlite3BtreeCreateTable(u.bw.pDb->pBt, &u.bw.pgno, u.bw.flags);
- pOut->u.i = u.bw.pgno;
+ rc = sqlite3BtreeCreateTable(u.bx.pDb->pBt, &u.bx.pgno, u.bx.flags);
+ pOut->u.i = u.bx.pgno;
break;
}
@@ -68284,47 +70051,48 @@ case OP_CreateTable: { /* out2-prerelease */
** then runs the new virtual machine. It is thus a re-entrant opcode.
*/
case OP_ParseSchema: {
-#if 0 /* local variables moved into u.bx */
+#if 0 /* local variables moved into u.by */
int iDb;
const char *zMaster;
char *zSql;
InitData initData;
-#endif /* local variables moved into u.bx */
+#endif /* local variables moved into u.by */
/* Any prepared statement that invokes this opcode will hold mutexes
** on every btree. This is a prerequisite for invoking
** sqlite3InitCallback().
*/
#ifdef SQLITE_DEBUG
- for(u.bx.iDb=0; u.bx.iDb<db->nDb; u.bx.iDb++){
- assert( u.bx.iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[u.bx.iDb].pBt) );
+ for(u.by.iDb=0; u.by.iDb<db->nDb; u.by.iDb++){
+ assert( u.by.iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[u.by.iDb].pBt) );
}
#endif
- u.bx.iDb = pOp->p1;
- assert( u.bx.iDb>=0 && u.bx.iDb<db->nDb );
- assert( DbHasProperty(db, u.bx.iDb, DB_SchemaLoaded) );
+ u.by.iDb = pOp->p1;
+ assert( u.by.iDb>=0 && u.by.iDb<db->nDb );
+ assert( DbHasProperty(db, u.by.iDb, DB_SchemaLoaded) );
/* Used to be a conditional */ {
- u.bx.zMaster = SCHEMA_TABLE(u.bx.iDb);
- u.bx.initData.db = db;
- u.bx.initData.iDb = pOp->p1;
- u.bx.initData.pzErrMsg = &p->zErrMsg;
- u.bx.zSql = sqlite3MPrintf(db,
+ u.by.zMaster = SCHEMA_TABLE(u.by.iDb);
+ u.by.initData.db = db;
+ u.by.initData.iDb = pOp->p1;
+ u.by.initData.pzErrMsg = &p->zErrMsg;
+ u.by.zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
- db->aDb[u.bx.iDb].zName, u.bx.zMaster, pOp->p4.z);
- if( u.bx.zSql==0 ){
+ db->aDb[u.by.iDb].zName, u.by.zMaster, pOp->p4.z);
+ if( u.by.zSql==0 ){
rc = SQLITE_NOMEM;
}else{
assert( db->init.busy==0 );
db->init.busy = 1;
- u.bx.initData.rc = SQLITE_OK;
+ u.by.initData.rc = SQLITE_OK;
assert( !db->mallocFailed );
- rc = sqlite3_exec(db, u.bx.zSql, sqlite3InitCallback, &u.bx.initData, 0);
- if( rc==SQLITE_OK ) rc = u.bx.initData.rc;
- sqlite3DbFree(db, u.bx.zSql);
+ rc = sqlite3_exec(db, u.by.zSql, sqlite3InitCallback, &u.by.initData, 0);
+ if( rc==SQLITE_OK ) rc = u.by.initData.rc;
+ sqlite3DbFree(db, u.by.zSql);
db->init.busy = 0;
}
}
+ if( rc ) sqlite3ResetInternalSchema(db, -1);
if( rc==SQLITE_NOMEM ){
goto no_mem;
}
@@ -68404,41 +70172,41 @@ case OP_DropTrigger: {
** This opcode is used to implement the integrity_check pragma.
*/
case OP_IntegrityCk: {
-#if 0 /* local variables moved into u.by */
+#if 0 /* local variables moved into u.bz */
int nRoot; /* Number of tables to check. (Number of root pages.) */
int *aRoot; /* Array of rootpage numbers for tables to be checked */
int j; /* Loop counter */
int nErr; /* Number of errors reported */
char *z; /* Text of the error report */
Mem *pnErr; /* Register keeping track of errors remaining */
-#endif /* local variables moved into u.by */
+#endif /* local variables moved into u.bz */
- u.by.nRoot = pOp->p2;
- assert( u.by.nRoot>0 );
- u.by.aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(u.by.nRoot+1) );
- if( u.by.aRoot==0 ) goto no_mem;
+ u.bz.nRoot = pOp->p2;
+ assert( u.bz.nRoot>0 );
+ u.bz.aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(u.bz.nRoot+1) );
+ if( u.bz.aRoot==0 ) goto no_mem;
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- u.by.pnErr = &aMem[pOp->p3];
- assert( (u.by.pnErr->flags & MEM_Int)!=0 );
- assert( (u.by.pnErr->flags & (MEM_Str|MEM_Blob))==0 );
+ u.bz.pnErr = &aMem[pOp->p3];
+ assert( (u.bz.pnErr->flags & MEM_Int)!=0 );
+ assert( (u.bz.pnErr->flags & (MEM_Str|MEM_Blob))==0 );
pIn1 = &aMem[pOp->p1];
- for(u.by.j=0; u.by.j<u.by.nRoot; u.by.j++){
- u.by.aRoot[u.by.j] = (int)sqlite3VdbeIntValue(&pIn1[u.by.j]);
+ for(u.bz.j=0; u.bz.j<u.bz.nRoot; u.bz.j++){
+ u.bz.aRoot[u.bz.j] = (int)sqlite3VdbeIntValue(&pIn1[u.bz.j]);
}
- u.by.aRoot[u.by.j] = 0;
+ u.bz.aRoot[u.bz.j] = 0;
assert( pOp->p5<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p5))!=0 );
- u.by.z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, u.by.aRoot, u.by.nRoot,
- (int)u.by.pnErr->u.i, &u.by.nErr);
- sqlite3DbFree(db, u.by.aRoot);
- u.by.pnErr->u.i -= u.by.nErr;
+ u.bz.z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, u.bz.aRoot, u.bz.nRoot,
+ (int)u.bz.pnErr->u.i, &u.bz.nErr);
+ sqlite3DbFree(db, u.bz.aRoot);
+ u.bz.pnErr->u.i -= u.bz.nErr;
sqlite3VdbeMemSetNull(pIn1);
- if( u.by.nErr==0 ){
- assert( u.by.z==0 );
- }else if( u.by.z==0 ){
+ if( u.bz.nErr==0 ){
+ assert( u.bz.z==0 );
+ }else if( u.bz.z==0 ){
goto no_mem;
}else{
- sqlite3VdbeMemSetStr(pIn1, u.by.z, -1, SQLITE_UTF8, sqlite3_free);
+ sqlite3VdbeMemSetStr(pIn1, u.bz.z, -1, SQLITE_UTF8, sqlite3_free);
}
UPDATE_MAX_BLOBSIZE(pIn1);
sqlite3VdbeChangeEncoding(pIn1, encoding);
@@ -68472,20 +70240,20 @@ case OP_RowSetAdd: { /* in1, in2 */
** unchanged and jump to instruction P2.
*/
case OP_RowSetRead: { /* jump, in1, out3 */
-#if 0 /* local variables moved into u.bz */
+#if 0 /* local variables moved into u.ca */
i64 val;
-#endif /* local variables moved into u.bz */
+#endif /* local variables moved into u.ca */
CHECK_FOR_INTERRUPT;
pIn1 = &aMem[pOp->p1];
if( (pIn1->flags & MEM_RowSet)==0
- || sqlite3RowSetNext(pIn1->u.pRowSet, &u.bz.val)==0
+ || sqlite3RowSetNext(pIn1->u.pRowSet, &u.ca.val)==0
){
/* The boolean index is empty */
sqlite3VdbeMemSetNull(pIn1);
pc = pOp->p2 - 1;
}else{
/* A value was pulled from the index */
- sqlite3VdbeMemSetInt64(&aMem[pOp->p3], u.bz.val);
+ sqlite3VdbeMemSetInt64(&aMem[pOp->p3], u.ca.val);
}
break;
}
@@ -68514,14 +70282,14 @@ case OP_RowSetRead: { /* jump, in1, out3 */
** inserted as part of some other set).
*/
case OP_RowSetTest: { /* jump, in1, in3 */
-#if 0 /* local variables moved into u.ca */
+#if 0 /* local variables moved into u.cb */
int iSet;
int exists;
-#endif /* local variables moved into u.ca */
+#endif /* local variables moved into u.cb */
pIn1 = &aMem[pOp->p1];
pIn3 = &aMem[pOp->p3];
- u.ca.iSet = pOp->p4.i;
+ u.cb.iSet = pOp->p4.i;
assert( pIn3->flags&MEM_Int );
/* If there is anything other than a rowset object in memory cell P1,
@@ -68533,17 +70301,17 @@ case OP_RowSetTest: { /* jump, in1, in3 */
}
assert( pOp->p4type==P4_INT32 );
- assert( u.ca.iSet==-1 || u.ca.iSet>=0 );
- if( u.ca.iSet ){
- u.ca.exists = sqlite3RowSetTest(pIn1->u.pRowSet,
- (u8)(u.ca.iSet>=0 ? u.ca.iSet & 0xf : 0xff),
+ assert( u.cb.iSet==-1 || u.cb.iSet>=0 );
+ if( u.cb.iSet ){
+ u.cb.exists = sqlite3RowSetTest(pIn1->u.pRowSet,
+ (u8)(u.cb.iSet>=0 ? u.cb.iSet & 0xf : 0xff),
pIn3->u.i);
- if( u.ca.exists ){
+ if( u.cb.exists ){
pc = pOp->p2 - 1;
break;
}
}
- if( u.ca.iSet>=0 ){
+ if( u.cb.iSet>=0 ){
sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i);
}
break;
@@ -68566,7 +70334,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
** P4 is a pointer to the VM containing the trigger program.
*/
case OP_Program: { /* jump */
-#if 0 /* local variables moved into u.cb */
+#if 0 /* local variables moved into u.cc */
int nMem; /* Number of memory registers for sub-program */
int nByte; /* Bytes of runtime space required for sub-program */
Mem *pRt; /* Register to allocate runtime space */
@@ -68575,12 +70343,11 @@ case OP_Program: { /* jump */
VdbeFrame *pFrame; /* New vdbe frame to execute in */
SubProgram *pProgram; /* Sub-program to execute */
void *t; /* Token identifying trigger */
-#endif /* local variables moved into u.cb */
+#endif /* local variables moved into u.cc */
- u.cb.pProgram = pOp->p4.pProgram;
- u.cb.pRt = &aMem[pOp->p3];
- assert( memIsValid(u.cb.pRt) );
- assert( u.cb.pProgram->nOp>0 );
+ u.cc.pProgram = pOp->p4.pProgram;
+ u.cc.pRt = &aMem[pOp->p3];
+ assert( u.cc.pProgram->nOp>0 );
/* If the p5 flag is clear, then recursive invocation of triggers is
** disabled for backwards compatibility (p5 is set if this sub-program
@@ -68594,9 +70361,9 @@ case OP_Program: { /* jump */
** single trigger all have the same value for the SubProgram.token
** variable. */
if( pOp->p5 ){
- u.cb.t = u.cb.pProgram->token;
- for(u.cb.pFrame=p->pFrame; u.cb.pFrame && u.cb.pFrame->token!=u.cb.t; u.cb.pFrame=u.cb.pFrame->pParent);
- if( u.cb.pFrame ) break;
+ u.cc.t = u.cc.pProgram->token;
+ for(u.cc.pFrame=p->pFrame; u.cc.pFrame && u.cc.pFrame->token!=u.cc.t; u.cc.pFrame=u.cc.pFrame->pParent);
+ if( u.cc.pFrame ) break;
}
if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){
@@ -68605,65 +70372,71 @@ case OP_Program: { /* jump */
break;
}
- /* Register u.cb.pRt is used to store the memory required to save the state
+ /* Register u.cc.pRt is used to store the memory required to save the state
** of the current program, and the memory required at runtime to execute
- ** the trigger program. If this trigger has been fired before, then u.cb.pRt
+ ** the trigger program. If this trigger has been fired before, then u.cc.pRt
** is already allocated. Otherwise, it must be initialized. */
- if( (u.cb.pRt->flags&MEM_Frame)==0 ){
+ if( (u.cc.pRt->flags&MEM_Frame)==0 ){
/* SubProgram.nMem is set to the number of memory cells used by the
** program stored in SubProgram.aOp. As well as these, one memory
** cell is required for each cursor used by the program. Set local
- ** variable u.cb.nMem (and later, VdbeFrame.nChildMem) to this value.
+ ** variable u.cc.nMem (and later, VdbeFrame.nChildMem) to this value.
*/
- u.cb.nMem = u.cb.pProgram->nMem + u.cb.pProgram->nCsr;
- u.cb.nByte = ROUND8(sizeof(VdbeFrame))
- + u.cb.nMem * sizeof(Mem)
- + u.cb.pProgram->nCsr * sizeof(VdbeCursor *);
- u.cb.pFrame = sqlite3DbMallocZero(db, u.cb.nByte);
- if( !u.cb.pFrame ){
+ u.cc.nMem = u.cc.pProgram->nMem + u.cc.pProgram->nCsr;
+ u.cc.nByte = ROUND8(sizeof(VdbeFrame))
+ + u.cc.nMem * sizeof(Mem)
+ + u.cc.pProgram->nCsr * sizeof(VdbeCursor *)
+ + u.cc.pProgram->nOnce * sizeof(u8);
+ u.cc.pFrame = sqlite3DbMallocZero(db, u.cc.nByte);
+ if( !u.cc.pFrame ){
goto no_mem;
}
- sqlite3VdbeMemRelease(u.cb.pRt);
- u.cb.pRt->flags = MEM_Frame;
- u.cb.pRt->u.pFrame = u.cb.pFrame;
-
- u.cb.pFrame->v = p;
- u.cb.pFrame->nChildMem = u.cb.nMem;
- u.cb.pFrame->nChildCsr = u.cb.pProgram->nCsr;
- u.cb.pFrame->pc = pc;
- u.cb.pFrame->aMem = p->aMem;
- u.cb.pFrame->nMem = p->nMem;
- u.cb.pFrame->apCsr = p->apCsr;
- u.cb.pFrame->nCursor = p->nCursor;
- u.cb.pFrame->aOp = p->aOp;
- u.cb.pFrame->nOp = p->nOp;
- u.cb.pFrame->token = u.cb.pProgram->token;
-
- u.cb.pEnd = &VdbeFrameMem(u.cb.pFrame)[u.cb.pFrame->nChildMem];
- for(u.cb.pMem=VdbeFrameMem(u.cb.pFrame); u.cb.pMem!=u.cb.pEnd; u.cb.pMem++){
- u.cb.pMem->flags = MEM_Null;
- u.cb.pMem->db = db;
+ sqlite3VdbeMemRelease(u.cc.pRt);
+ u.cc.pRt->flags = MEM_Frame;
+ u.cc.pRt->u.pFrame = u.cc.pFrame;
+
+ u.cc.pFrame->v = p;
+ u.cc.pFrame->nChildMem = u.cc.nMem;
+ u.cc.pFrame->nChildCsr = u.cc.pProgram->nCsr;
+ u.cc.pFrame->pc = pc;
+ u.cc.pFrame->aMem = p->aMem;
+ u.cc.pFrame->nMem = p->nMem;
+ u.cc.pFrame->apCsr = p->apCsr;
+ u.cc.pFrame->nCursor = p->nCursor;
+ u.cc.pFrame->aOp = p->aOp;
+ u.cc.pFrame->nOp = p->nOp;
+ u.cc.pFrame->token = u.cc.pProgram->token;
+ u.cc.pFrame->aOnceFlag = p->aOnceFlag;
+ u.cc.pFrame->nOnceFlag = p->nOnceFlag;
+
+ u.cc.pEnd = &VdbeFrameMem(u.cc.pFrame)[u.cc.pFrame->nChildMem];
+ for(u.cc.pMem=VdbeFrameMem(u.cc.pFrame); u.cc.pMem!=u.cc.pEnd; u.cc.pMem++){
+ u.cc.pMem->flags = MEM_Invalid;
+ u.cc.pMem->db = db;
}
}else{
- u.cb.pFrame = u.cb.pRt->u.pFrame;
- assert( u.cb.pProgram->nMem+u.cb.pProgram->nCsr==u.cb.pFrame->nChildMem );
- assert( u.cb.pProgram->nCsr==u.cb.pFrame->nChildCsr );
- assert( pc==u.cb.pFrame->pc );
+ u.cc.pFrame = u.cc.pRt->u.pFrame;
+ assert( u.cc.pProgram->nMem+u.cc.pProgram->nCsr==u.cc.pFrame->nChildMem );
+ assert( u.cc.pProgram->nCsr==u.cc.pFrame->nChildCsr );
+ assert( pc==u.cc.pFrame->pc );
}
p->nFrame++;
- u.cb.pFrame->pParent = p->pFrame;
- u.cb.pFrame->lastRowid = lastRowid;
- u.cb.pFrame->nChange = p->nChange;
+ u.cc.pFrame->pParent = p->pFrame;
+ u.cc.pFrame->lastRowid = lastRowid;
+ u.cc.pFrame->nChange = p->nChange;
p->nChange = 0;
- p->pFrame = u.cb.pFrame;
- p->aMem = aMem = &VdbeFrameMem(u.cb.pFrame)[-1];
- p->nMem = u.cb.pFrame->nChildMem;
- p->nCursor = (u16)u.cb.pFrame->nChildCsr;
+ p->pFrame = u.cc.pFrame;
+ p->aMem = aMem = &VdbeFrameMem(u.cc.pFrame)[-1];
+ p->nMem = u.cc.pFrame->nChildMem;
+ p->nCursor = (u16)u.cc.pFrame->nChildCsr;
p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
- p->aOp = aOp = u.cb.pProgram->aOp;
- p->nOp = u.cb.pProgram->nOp;
+ p->aOp = aOp = u.cc.pProgram->aOp;
+ p->nOp = u.cc.pProgram->nOp;
+ p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
+ p->nOnceFlag = u.cc.pProgram->nOnce;
pc = -1;
+ memset(p->aOnceFlag, 0, p->nOnceFlag);
break;
}
@@ -68681,13 +70454,13 @@ case OP_Program: { /* jump */
** calling OP_Program instruction.
*/
case OP_Param: { /* out2-prerelease */
-#if 0 /* local variables moved into u.cc */
+#if 0 /* local variables moved into u.cd */
VdbeFrame *pFrame;
Mem *pIn;
-#endif /* local variables moved into u.cc */
- u.cc.pFrame = p->pFrame;
- u.cc.pIn = &u.cc.pFrame->aMem[pOp->p1 + u.cc.pFrame->aOp[u.cc.pFrame->pc].p1];
- sqlite3VdbeMemShallowCopy(pOut, u.cc.pIn, MEM_Ephem);
+#endif /* local variables moved into u.cd */
+ u.cd.pFrame = p->pFrame;
+ u.cd.pIn = &u.cd.pFrame->aMem[pOp->p1 + u.cd.pFrame->aOp[u.cd.pFrame->pc].p1];
+ sqlite3VdbeMemShallowCopy(pOut, u.cd.pIn, MEM_Ephem);
break;
}
@@ -68743,22 +70516,22 @@ case OP_FkIfZero: { /* jump */
** an integer.
*/
case OP_MemMax: { /* in2 */
-#if 0 /* local variables moved into u.cd */
+#if 0 /* local variables moved into u.ce */
Mem *pIn1;
VdbeFrame *pFrame;
-#endif /* local variables moved into u.cd */
+#endif /* local variables moved into u.ce */
if( p->pFrame ){
- for(u.cd.pFrame=p->pFrame; u.cd.pFrame->pParent; u.cd.pFrame=u.cd.pFrame->pParent);
- u.cd.pIn1 = &u.cd.pFrame->aMem[pOp->p1];
+ for(u.ce.pFrame=p->pFrame; u.ce.pFrame->pParent; u.ce.pFrame=u.ce.pFrame->pParent);
+ u.ce.pIn1 = &u.ce.pFrame->aMem[pOp->p1];
}else{
- u.cd.pIn1 = &aMem[pOp->p1];
+ u.ce.pIn1 = &aMem[pOp->p1];
}
- assert( memIsValid(u.cd.pIn1) );
- sqlite3VdbeMemIntegerify(u.cd.pIn1);
+ assert( memIsValid(u.ce.pIn1) );
+ sqlite3VdbeMemIntegerify(u.ce.pIn1);
pIn2 = &aMem[pOp->p2];
sqlite3VdbeMemIntegerify(pIn2);
- if( u.cd.pIn1->u.i<pIn2->u.i){
- u.cd.pIn1->u.i = pIn2->u.i;
+ if( u.ce.pIn1->u.i<pIn2->u.i){
+ u.ce.pIn1->u.i = pIn2->u.i;
}
break;
}
@@ -68825,50 +70598,56 @@ case OP_IfZero: { /* jump, in1 */
** successors.
*/
case OP_AggStep: {
-#if 0 /* local variables moved into u.ce */
+#if 0 /* local variables moved into u.cf */
int n;
int i;
Mem *pMem;
Mem *pRec;
sqlite3_context ctx;
sqlite3_value **apVal;
-#endif /* local variables moved into u.ce */
+#endif /* local variables moved into u.cf */
- u.ce.n = pOp->p5;
- assert( u.ce.n>=0 );
- u.ce.pRec = &aMem[pOp->p2];
- u.ce.apVal = p->apArg;
- assert( u.ce.apVal || u.ce.n==0 );
- for(u.ce.i=0; u.ce.i<u.ce.n; u.ce.i++, u.ce.pRec++){
- assert( memIsValid(u.ce.pRec) );
- u.ce.apVal[u.ce.i] = u.ce.pRec;
- memAboutToChange(p, u.ce.pRec);
- sqlite3VdbeMemStoreType(u.ce.pRec);
- }
- u.ce.ctx.pFunc = pOp->p4.pFunc;
+ u.cf.n = pOp->p5;
+ assert( u.cf.n>=0 );
+ u.cf.pRec = &aMem[pOp->p2];
+ u.cf.apVal = p->apArg;
+ assert( u.cf.apVal || u.cf.n==0 );
+ for(u.cf.i=0; u.cf.i<u.cf.n; u.cf.i++, u.cf.pRec++){
+ assert( memIsValid(u.cf.pRec) );
+ u.cf.apVal[u.cf.i] = u.cf.pRec;
+ memAboutToChange(p, u.cf.pRec);
+ sqlite3VdbeMemStoreType(u.cf.pRec);
+ }
+ u.cf.ctx.pFunc = pOp->p4.pFunc;
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- u.ce.ctx.pMem = u.ce.pMem = &aMem[pOp->p3];
- u.ce.pMem->n++;
- u.ce.ctx.s.flags = MEM_Null;
- u.ce.ctx.s.z = 0;
- u.ce.ctx.s.zMalloc = 0;
- u.ce.ctx.s.xDel = 0;
- u.ce.ctx.s.db = db;
- u.ce.ctx.isError = 0;
- u.ce.ctx.pColl = 0;
- if( u.ce.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
+ u.cf.ctx.pMem = u.cf.pMem = &aMem[pOp->p3];
+ u.cf.pMem->n++;
+ u.cf.ctx.s.flags = MEM_Null;
+ u.cf.ctx.s.z = 0;
+ u.cf.ctx.s.zMalloc = 0;
+ u.cf.ctx.s.xDel = 0;
+ u.cf.ctx.s.db = db;
+ u.cf.ctx.isError = 0;
+ u.cf.ctx.pColl = 0;
+ u.cf.ctx.skipFlag = 0;
+ if( u.cf.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
assert( pOp>p->aOp );
assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
- u.ce.ctx.pColl = pOp[-1].p4.pColl;
+ u.cf.ctx.pColl = pOp[-1].p4.pColl;
+ }
+ (u.cf.ctx.pFunc->xStep)(&u.cf.ctx, u.cf.n, u.cf.apVal); /* IMP: R-24505-23230 */
+ if( u.cf.ctx.isError ){
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.cf.ctx.s));
+ rc = u.cf.ctx.isError;
}
- (u.ce.ctx.pFunc->xStep)(&u.ce.ctx, u.ce.n, u.ce.apVal); /* IMP: R-24505-23230 */
- if( u.ce.ctx.isError ){
- sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.ce.ctx.s));
- rc = u.ce.ctx.isError;
+ if( u.cf.ctx.skipFlag ){
+ assert( pOp[-1].opcode==OP_CollSeq );
+ u.cf.i = pOp[-1].p1;
+ if( u.cf.i ) sqlite3VdbeMemSetInt64(&aMem[u.cf.i], 1);
}
- sqlite3VdbeMemRelease(&u.ce.ctx.s);
+ sqlite3VdbeMemRelease(&u.cf.ctx.s);
break;
}
@@ -68886,19 +70665,19 @@ case OP_AggStep: {
** the step function was not previously called.
*/
case OP_AggFinal: {
-#if 0 /* local variables moved into u.cf */
+#if 0 /* local variables moved into u.cg */
Mem *pMem;
-#endif /* local variables moved into u.cf */
+#endif /* local variables moved into u.cg */
assert( pOp->p1>0 && pOp->p1<=p->nMem );
- u.cf.pMem = &aMem[pOp->p1];
- assert( (u.cf.pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
- rc = sqlite3VdbeMemFinalize(u.cf.pMem, pOp->p4.pFunc);
+ u.cg.pMem = &aMem[pOp->p1];
+ assert( (u.cg.pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
+ rc = sqlite3VdbeMemFinalize(u.cg.pMem, pOp->p4.pFunc);
if( rc ){
- sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(u.cf.pMem));
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(u.cg.pMem));
}
- sqlite3VdbeChangeEncoding(u.cf.pMem, encoding);
- UPDATE_MAX_BLOBSIZE(u.cf.pMem);
- if( sqlite3VdbeMemTooBig(u.cf.pMem) ){
+ sqlite3VdbeChangeEncoding(u.cg.pMem, encoding);
+ UPDATE_MAX_BLOBSIZE(u.cg.pMem);
+ if( sqlite3VdbeMemTooBig(u.cg.pMem) ){
goto too_big;
}
break;
@@ -68917,25 +70696,25 @@ case OP_AggFinal: {
** mem[P3+2] are initialized to -1.
*/
case OP_Checkpoint: {
-#if 0 /* local variables moved into u.cg */
+#if 0 /* local variables moved into u.ch */
int i; /* Loop counter */
int aRes[3]; /* Results */
Mem *pMem; /* Write results here */
-#endif /* local variables moved into u.cg */
+#endif /* local variables moved into u.ch */
- u.cg.aRes[0] = 0;
- u.cg.aRes[1] = u.cg.aRes[2] = -1;
+ u.ch.aRes[0] = 0;
+ u.ch.aRes[1] = u.ch.aRes[2] = -1;
assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE
|| pOp->p2==SQLITE_CHECKPOINT_FULL
|| pOp->p2==SQLITE_CHECKPOINT_RESTART
);
- rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &u.cg.aRes[1], &u.cg.aRes[2]);
+ rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &u.ch.aRes[1], &u.ch.aRes[2]);
if( rc==SQLITE_BUSY ){
rc = SQLITE_OK;
- u.cg.aRes[0] = 1;
+ u.ch.aRes[0] = 1;
}
- for(u.cg.i=0, u.cg.pMem = &aMem[pOp->p3]; u.cg.i<3; u.cg.i++, u.cg.pMem++){
- sqlite3VdbeMemSetInt64(u.cg.pMem, (i64)u.cg.aRes[u.cg.i]);
+ for(u.ch.i=0, u.ch.pMem = &aMem[pOp->p3]; u.ch.i<3; u.ch.i++, u.ch.pMem++){
+ sqlite3VdbeMemSetInt64(u.ch.pMem, (i64)u.ch.aRes[u.ch.i]);
}
break;
};
@@ -68954,91 +70733,91 @@ case OP_Checkpoint: {
** Write a string containing the final journal-mode to register P2.
*/
case OP_JournalMode: { /* out2-prerelease */
-#if 0 /* local variables moved into u.ch */
+#if 0 /* local variables moved into u.ci */
Btree *pBt; /* Btree to change journal mode of */
Pager *pPager; /* Pager associated with pBt */
int eNew; /* New journal mode */
int eOld; /* The old journal mode */
const char *zFilename; /* Name of database file for pPager */
-#endif /* local variables moved into u.ch */
+#endif /* local variables moved into u.ci */
- u.ch.eNew = pOp->p3;
- assert( u.ch.eNew==PAGER_JOURNALMODE_DELETE
- || u.ch.eNew==PAGER_JOURNALMODE_TRUNCATE
- || u.ch.eNew==PAGER_JOURNALMODE_PERSIST
- || u.ch.eNew==PAGER_JOURNALMODE_OFF
- || u.ch.eNew==PAGER_JOURNALMODE_MEMORY
- || u.ch.eNew==PAGER_JOURNALMODE_WAL
- || u.ch.eNew==PAGER_JOURNALMODE_QUERY
+ u.ci.eNew = pOp->p3;
+ assert( u.ci.eNew==PAGER_JOURNALMODE_DELETE
+ || u.ci.eNew==PAGER_JOURNALMODE_TRUNCATE
+ || u.ci.eNew==PAGER_JOURNALMODE_PERSIST
+ || u.ci.eNew==PAGER_JOURNALMODE_OFF
+ || u.ci.eNew==PAGER_JOURNALMODE_MEMORY
+ || u.ci.eNew==PAGER_JOURNALMODE_WAL
+ || u.ci.eNew==PAGER_JOURNALMODE_QUERY
);
assert( pOp->p1>=0 && pOp->p1<db->nDb );
- u.ch.pBt = db->aDb[pOp->p1].pBt;
- u.ch.pPager = sqlite3BtreePager(u.ch.pBt);
- u.ch.eOld = sqlite3PagerGetJournalMode(u.ch.pPager);
- if( u.ch.eNew==PAGER_JOURNALMODE_QUERY ) u.ch.eNew = u.ch.eOld;
- if( !sqlite3PagerOkToChangeJournalMode(u.ch.pPager) ) u.ch.eNew = u.ch.eOld;
+ u.ci.pBt = db->aDb[pOp->p1].pBt;
+ u.ci.pPager = sqlite3BtreePager(u.ci.pBt);
+ u.ci.eOld = sqlite3PagerGetJournalMode(u.ci.pPager);
+ if( u.ci.eNew==PAGER_JOURNALMODE_QUERY ) u.ci.eNew = u.ci.eOld;
+ if( !sqlite3PagerOkToChangeJournalMode(u.ci.pPager) ) u.ci.eNew = u.ci.eOld;
#ifndef SQLITE_OMIT_WAL
- u.ch.zFilename = sqlite3PagerFilename(u.ch.pPager);
+ u.ci.zFilename = sqlite3PagerFilename(u.ci.pPager);
/* Do not allow a transition to journal_mode=WAL for a database
** in temporary storage or if the VFS does not support shared memory
*/
- if( u.ch.eNew==PAGER_JOURNALMODE_WAL
- && (sqlite3Strlen30(u.ch.zFilename)==0 /* Temp file */
- || !sqlite3PagerWalSupported(u.ch.pPager)) /* No shared-memory support */
+ if( u.ci.eNew==PAGER_JOURNALMODE_WAL
+ && (sqlite3Strlen30(u.ci.zFilename)==0 /* Temp file */
+ || !sqlite3PagerWalSupported(u.ci.pPager)) /* No shared-memory support */
){
- u.ch.eNew = u.ch.eOld;
+ u.ci.eNew = u.ci.eOld;
}
- if( (u.ch.eNew!=u.ch.eOld)
- && (u.ch.eOld==PAGER_JOURNALMODE_WAL || u.ch.eNew==PAGER_JOURNALMODE_WAL)
+ if( (u.ci.eNew!=u.ci.eOld)
+ && (u.ci.eOld==PAGER_JOURNALMODE_WAL || u.ci.eNew==PAGER_JOURNALMODE_WAL)
){
if( !db->autoCommit || db->activeVdbeCnt>1 ){
rc = SQLITE_ERROR;
sqlite3SetString(&p->zErrMsg, db,
"cannot change %s wal mode from within a transaction",
- (u.ch.eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
+ (u.ci.eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
);
break;
}else{
- if( u.ch.eOld==PAGER_JOURNALMODE_WAL ){
+ if( u.ci.eOld==PAGER_JOURNALMODE_WAL ){
/* If leaving WAL mode, close the log file. If successful, the call
** to PagerCloseWal() checkpoints and deletes the write-ahead-log
** file. An EXCLUSIVE lock may still be held on the database file
** after a successful return.
*/
- rc = sqlite3PagerCloseWal(u.ch.pPager);
+ rc = sqlite3PagerCloseWal(u.ci.pPager);
if( rc==SQLITE_OK ){
- sqlite3PagerSetJournalMode(u.ch.pPager, u.ch.eNew);
+ sqlite3PagerSetJournalMode(u.ci.pPager, u.ci.eNew);
}
- }else if( u.ch.eOld==PAGER_JOURNALMODE_MEMORY ){
+ }else if( u.ci.eOld==PAGER_JOURNALMODE_MEMORY ){
/* Cannot transition directly from MEMORY to WAL. Use mode OFF
** as an intermediate */
- sqlite3PagerSetJournalMode(u.ch.pPager, PAGER_JOURNALMODE_OFF);
+ sqlite3PagerSetJournalMode(u.ci.pPager, PAGER_JOURNALMODE_OFF);
}
/* Open a transaction on the database file. Regardless of the journal
** mode, this transaction always uses a rollback journal.
*/
- assert( sqlite3BtreeIsInTrans(u.ch.pBt)==0 );
+ assert( sqlite3BtreeIsInTrans(u.ci.pBt)==0 );
if( rc==SQLITE_OK ){
- rc = sqlite3BtreeSetVersion(u.ch.pBt, (u.ch.eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
+ rc = sqlite3BtreeSetVersion(u.ci.pBt, (u.ci.eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
}
}
}
#endif /* ifndef SQLITE_OMIT_WAL */
if( rc ){
- u.ch.eNew = u.ch.eOld;
+ u.ci.eNew = u.ci.eOld;
}
- u.ch.eNew = sqlite3PagerSetJournalMode(u.ch.pPager, u.ch.eNew);
+ u.ci.eNew = sqlite3PagerSetJournalMode(u.ci.pPager, u.ci.eNew);
pOut = &aMem[pOp->p2];
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
- pOut->z = (char *)sqlite3JournalModename(u.ch.eNew);
+ pOut->z = (char *)sqlite3JournalModename(u.ci.eNew);
pOut->n = sqlite3Strlen30(pOut->z);
pOut->enc = SQLITE_UTF8;
sqlite3VdbeChangeEncoding(pOut, encoding);
@@ -69067,14 +70846,14 @@ case OP_Vacuum: {
** P2. Otherwise, fall through to the next instruction.
*/
case OP_IncrVacuum: { /* jump */
-#if 0 /* local variables moved into u.ci */
+#if 0 /* local variables moved into u.cj */
Btree *pBt;
-#endif /* local variables moved into u.ci */
+#endif /* local variables moved into u.cj */
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
- u.ci.pBt = db->aDb[pOp->p1].pBt;
- rc = sqlite3BtreeIncrVacuum(u.ci.pBt);
+ u.cj.pBt = db->aDb[pOp->p1].pBt;
+ rc = sqlite3BtreeIncrVacuum(u.cj.pBt);
if( rc==SQLITE_DONE ){
pc = pOp->p2 - 1;
rc = SQLITE_OK;
@@ -69144,12 +70923,12 @@ case OP_TableLock: {
** code will be set to SQLITE_LOCKED.
*/
case OP_VBegin: {
-#if 0 /* local variables moved into u.cj */
+#if 0 /* local variables moved into u.ck */
VTable *pVTab;
-#endif /* local variables moved into u.cj */
- u.cj.pVTab = pOp->p4.pVtab;
- rc = sqlite3VtabBegin(db, u.cj.pVTab);
- if( u.cj.pVTab ) importVtabErrMsg(p, u.cj.pVTab->pVtab);
+#endif /* local variables moved into u.ck */
+ u.ck.pVTab = pOp->p4.pVtab;
+ rc = sqlite3VtabBegin(db, u.ck.pVTab);
+ if( u.ck.pVTab ) importVtabErrMsg(p, u.ck.pVTab->pVtab);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -69188,32 +70967,32 @@ case OP_VDestroy: {
** table and stores that cursor in P1.
*/
case OP_VOpen: {
-#if 0 /* local variables moved into u.ck */
+#if 0 /* local variables moved into u.cl */
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
-#endif /* local variables moved into u.ck */
+#endif /* local variables moved into u.cl */
- u.ck.pCur = 0;
- u.ck.pVtabCursor = 0;
- u.ck.pVtab = pOp->p4.pVtab->pVtab;
- u.ck.pModule = (sqlite3_module *)u.ck.pVtab->pModule;
- assert(u.ck.pVtab && u.ck.pModule);
- rc = u.ck.pModule->xOpen(u.ck.pVtab, &u.ck.pVtabCursor);
- importVtabErrMsg(p, u.ck.pVtab);
+ u.cl.pCur = 0;
+ u.cl.pVtabCursor = 0;
+ u.cl.pVtab = pOp->p4.pVtab->pVtab;
+ u.cl.pModule = (sqlite3_module *)u.cl.pVtab->pModule;
+ assert(u.cl.pVtab && u.cl.pModule);
+ rc = u.cl.pModule->xOpen(u.cl.pVtab, &u.cl.pVtabCursor);
+ importVtabErrMsg(p, u.cl.pVtab);
if( SQLITE_OK==rc ){
/* Initialize sqlite3_vtab_cursor base class */
- u.ck.pVtabCursor->pVtab = u.ck.pVtab;
+ u.cl.pVtabCursor->pVtab = u.cl.pVtab;
/* Initialise vdbe cursor object */
- u.ck.pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
- if( u.ck.pCur ){
- u.ck.pCur->pVtabCursor = u.ck.pVtabCursor;
- u.ck.pCur->pModule = u.ck.pVtabCursor->pVtab->pModule;
+ u.cl.pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
+ if( u.cl.pCur ){
+ u.cl.pCur->pVtabCursor = u.cl.pVtabCursor;
+ u.cl.pCur->pModule = u.cl.pVtabCursor->pVtab->pModule;
}else{
db->mallocFailed = 1;
- u.ck.pModule->xClose(u.ck.pVtabCursor);
+ u.cl.pModule->xClose(u.cl.pVtabCursor);
}
}
break;
@@ -69240,7 +71019,7 @@ case OP_VOpen: {
** A jump is made to P2 if the result set after filtering would be empty.
*/
case OP_VFilter: { /* jump */
-#if 0 /* local variables moved into u.cl */
+#if 0 /* local variables moved into u.cm */
int nArg;
int iQuery;
const sqlite3_module *pModule;
@@ -69252,45 +71031,45 @@ case OP_VFilter: { /* jump */
int res;
int i;
Mem **apArg;
-#endif /* local variables moved into u.cl */
+#endif /* local variables moved into u.cm */
- u.cl.pQuery = &aMem[pOp->p3];
- u.cl.pArgc = &u.cl.pQuery[1];
- u.cl.pCur = p->apCsr[pOp->p1];
- assert( memIsValid(u.cl.pQuery) );
- REGISTER_TRACE(pOp->p3, u.cl.pQuery);
- assert( u.cl.pCur->pVtabCursor );
- u.cl.pVtabCursor = u.cl.pCur->pVtabCursor;
- u.cl.pVtab = u.cl.pVtabCursor->pVtab;
- u.cl.pModule = u.cl.pVtab->pModule;
+ u.cm.pQuery = &aMem[pOp->p3];
+ u.cm.pArgc = &u.cm.pQuery[1];
+ u.cm.pCur = p->apCsr[pOp->p1];
+ assert( memIsValid(u.cm.pQuery) );
+ REGISTER_TRACE(pOp->p3, u.cm.pQuery);
+ assert( u.cm.pCur->pVtabCursor );
+ u.cm.pVtabCursor = u.cm.pCur->pVtabCursor;
+ u.cm.pVtab = u.cm.pVtabCursor->pVtab;
+ u.cm.pModule = u.cm.pVtab->pModule;
/* Grab the index number and argc parameters */
- assert( (u.cl.pQuery->flags&MEM_Int)!=0 && u.cl.pArgc->flags==MEM_Int );
- u.cl.nArg = (int)u.cl.pArgc->u.i;
- u.cl.iQuery = (int)u.cl.pQuery->u.i;
+ assert( (u.cm.pQuery->flags&MEM_Int)!=0 && u.cm.pArgc->flags==MEM_Int );
+ u.cm.nArg = (int)u.cm.pArgc->u.i;
+ u.cm.iQuery = (int)u.cm.pQuery->u.i;
/* Invoke the xFilter method */
{
- u.cl.res = 0;
- u.cl.apArg = p->apArg;
- for(u.cl.i = 0; u.cl.i<u.cl.nArg; u.cl.i++){
- u.cl.apArg[u.cl.i] = &u.cl.pArgc[u.cl.i+1];
- sqlite3VdbeMemStoreType(u.cl.apArg[u.cl.i]);
+ u.cm.res = 0;
+ u.cm.apArg = p->apArg;
+ for(u.cm.i = 0; u.cm.i<u.cm.nArg; u.cm.i++){
+ u.cm.apArg[u.cm.i] = &u.cm.pArgc[u.cm.i+1];
+ sqlite3VdbeMemStoreType(u.cm.apArg[u.cm.i]);
}
p->inVtabMethod = 1;
- rc = u.cl.pModule->xFilter(u.cl.pVtabCursor, u.cl.iQuery, pOp->p4.z, u.cl.nArg, u.cl.apArg);
+ rc = u.cm.pModule->xFilter(u.cm.pVtabCursor, u.cm.iQuery, pOp->p4.z, u.cm.nArg, u.cm.apArg);
p->inVtabMethod = 0;
- importVtabErrMsg(p, u.cl.pVtab);
+ importVtabErrMsg(p, u.cm.pVtab);
if( rc==SQLITE_OK ){
- u.cl.res = u.cl.pModule->xEof(u.cl.pVtabCursor);
+ u.cm.res = u.cm.pModule->xEof(u.cm.pVtabCursor);
}
- if( u.cl.res ){
+ if( u.cm.res ){
pc = pOp->p2 - 1;
}
}
- u.cl.pCur->nullRow = 0;
+ u.cm.pCur->nullRow = 0;
break;
}
@@ -69304,51 +71083,51 @@ case OP_VFilter: { /* jump */
** P1 cursor is pointing to into register P3.
*/
case OP_VColumn: {
-#if 0 /* local variables moved into u.cm */
+#if 0 /* local variables moved into u.cn */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
-#endif /* local variables moved into u.cm */
+#endif /* local variables moved into u.cn */
VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- u.cm.pDest = &aMem[pOp->p3];
- memAboutToChange(p, u.cm.pDest);
+ u.cn.pDest = &aMem[pOp->p3];
+ memAboutToChange(p, u.cn.pDest);
if( pCur->nullRow ){
- sqlite3VdbeMemSetNull(u.cm.pDest);
+ sqlite3VdbeMemSetNull(u.cn.pDest);
break;
}
- u.cm.pVtab = pCur->pVtabCursor->pVtab;
- u.cm.pModule = u.cm.pVtab->pModule;
- assert( u.cm.pModule->xColumn );
- memset(&u.cm.sContext, 0, sizeof(u.cm.sContext));
+ u.cn.pVtab = pCur->pVtabCursor->pVtab;
+ u.cn.pModule = u.cn.pVtab->pModule;
+ assert( u.cn.pModule->xColumn );
+ memset(&u.cn.sContext, 0, sizeof(u.cn.sContext));
/* The output cell may already have a buffer allocated. Move
- ** the current contents to u.cm.sContext.s so in case the user-function
+ ** the current contents to u.cn.sContext.s so in case the user-function
** can use the already allocated buffer instead of allocating a
** new one.
*/
- sqlite3VdbeMemMove(&u.cm.sContext.s, u.cm.pDest);
- MemSetTypeFlag(&u.cm.sContext.s, MEM_Null);
+ sqlite3VdbeMemMove(&u.cn.sContext.s, u.cn.pDest);
+ MemSetTypeFlag(&u.cn.sContext.s, MEM_Null);
- rc = u.cm.pModule->xColumn(pCur->pVtabCursor, &u.cm.sContext, pOp->p2);
- importVtabErrMsg(p, u.cm.pVtab);
- if( u.cm.sContext.isError ){
- rc = u.cm.sContext.isError;
+ rc = u.cn.pModule->xColumn(pCur->pVtabCursor, &u.cn.sContext, pOp->p2);
+ importVtabErrMsg(p, u.cn.pVtab);
+ if( u.cn.sContext.isError ){
+ rc = u.cn.sContext.isError;
}
/* Copy the result of the function to the P3 register. We
** do this regardless of whether or not an error occurred to ensure any
- ** dynamic allocation in u.cm.sContext.s (a Mem struct) is released.
+ ** dynamic allocation in u.cn.sContext.s (a Mem struct) is released.
*/
- sqlite3VdbeChangeEncoding(&u.cm.sContext.s, encoding);
- sqlite3VdbeMemMove(u.cm.pDest, &u.cm.sContext.s);
- REGISTER_TRACE(pOp->p3, u.cm.pDest);
- UPDATE_MAX_BLOBSIZE(u.cm.pDest);
+ sqlite3VdbeChangeEncoding(&u.cn.sContext.s, encoding);
+ sqlite3VdbeMemMove(u.cn.pDest, &u.cn.sContext.s);
+ REGISTER_TRACE(pOp->p3, u.cn.pDest);
+ UPDATE_MAX_BLOBSIZE(u.cn.pDest);
- if( sqlite3VdbeMemTooBig(u.cm.pDest) ){
+ if( sqlite3VdbeMemTooBig(u.cn.pDest) ){
goto too_big;
}
break;
@@ -69363,22 +71142,22 @@ case OP_VColumn: {
** the end of its result set, then fall through to the next instruction.
*/
case OP_VNext: { /* jump */
-#if 0 /* local variables moved into u.cn */
+#if 0 /* local variables moved into u.co */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
VdbeCursor *pCur;
-#endif /* local variables moved into u.cn */
+#endif /* local variables moved into u.co */
- u.cn.res = 0;
- u.cn.pCur = p->apCsr[pOp->p1];
- assert( u.cn.pCur->pVtabCursor );
- if( u.cn.pCur->nullRow ){
+ u.co.res = 0;
+ u.co.pCur = p->apCsr[pOp->p1];
+ assert( u.co.pCur->pVtabCursor );
+ if( u.co.pCur->nullRow ){
break;
}
- u.cn.pVtab = u.cn.pCur->pVtabCursor->pVtab;
- u.cn.pModule = u.cn.pVtab->pModule;
- assert( u.cn.pModule->xNext );
+ u.co.pVtab = u.co.pCur->pVtabCursor->pVtab;
+ u.co.pModule = u.co.pVtab->pModule;
+ assert( u.co.pModule->xNext );
/* Invoke the xNext() method of the module. There is no way for the
** underlying implementation to return an error if one occurs during
@@ -69387,14 +71166,14 @@ case OP_VNext: { /* jump */
** some other method is next invoked on the save virtual table cursor.
*/
p->inVtabMethod = 1;
- rc = u.cn.pModule->xNext(u.cn.pCur->pVtabCursor);
+ rc = u.co.pModule->xNext(u.co.pCur->pVtabCursor);
p->inVtabMethod = 0;
- importVtabErrMsg(p, u.cn.pVtab);
+ importVtabErrMsg(p, u.co.pVtab);
if( rc==SQLITE_OK ){
- u.cn.res = u.cn.pModule->xEof(u.cn.pCur->pVtabCursor);
+ u.co.res = u.co.pModule->xEof(u.co.pCur->pVtabCursor);
}
- if( !u.cn.res ){
+ if( !u.co.res ){
/* If there is data, jump to P2 */
pc = pOp->p2 - 1;
}
@@ -69410,24 +71189,24 @@ case OP_VNext: { /* jump */
** in register P1 is passed as the zName argument to the xRename method.
*/
case OP_VRename: {
-#if 0 /* local variables moved into u.co */
+#if 0 /* local variables moved into u.cp */
sqlite3_vtab *pVtab;
Mem *pName;
-#endif /* local variables moved into u.co */
+#endif /* local variables moved into u.cp */
- u.co.pVtab = pOp->p4.pVtab->pVtab;
- u.co.pName = &aMem[pOp->p1];
- assert( u.co.pVtab->pModule->xRename );
- assert( memIsValid(u.co.pName) );
- REGISTER_TRACE(pOp->p1, u.co.pName);
- assert( u.co.pName->flags & MEM_Str );
- testcase( u.co.pName->enc==SQLITE_UTF8 );
- testcase( u.co.pName->enc==SQLITE_UTF16BE );
- testcase( u.co.pName->enc==SQLITE_UTF16LE );
- rc = sqlite3VdbeChangeEncoding(u.co.pName, SQLITE_UTF8);
+ u.cp.pVtab = pOp->p4.pVtab->pVtab;
+ u.cp.pName = &aMem[pOp->p1];
+ assert( u.cp.pVtab->pModule->xRename );
+ assert( memIsValid(u.cp.pName) );
+ REGISTER_TRACE(pOp->p1, u.cp.pName);
+ assert( u.cp.pName->flags & MEM_Str );
+ testcase( u.cp.pName->enc==SQLITE_UTF8 );
+ testcase( u.cp.pName->enc==SQLITE_UTF16BE );
+ testcase( u.cp.pName->enc==SQLITE_UTF16LE );
+ rc = sqlite3VdbeChangeEncoding(u.cp.pName, SQLITE_UTF8);
if( rc==SQLITE_OK ){
- rc = u.co.pVtab->pModule->xRename(u.co.pVtab, u.co.pName->z);
- importVtabErrMsg(p, u.co.pVtab);
+ rc = u.cp.pVtab->pModule->xRename(u.cp.pVtab, u.cp.pName->z);
+ importVtabErrMsg(p, u.cp.pVtab);
p->expired = 0;
}
break;
@@ -69459,7 +71238,7 @@ case OP_VRename: {
** is set to the value of the rowid for the row just inserted.
*/
case OP_VUpdate: {
-#if 0 /* local variables moved into u.cp */
+#if 0 /* local variables moved into u.cq */
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
int nArg;
@@ -69467,33 +71246,33 @@ case OP_VUpdate: {
sqlite_int64 rowid;
Mem **apArg;
Mem *pX;
-#endif /* local variables moved into u.cp */
+#endif /* local variables moved into u.cq */
assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback
|| pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
);
- u.cp.pVtab = pOp->p4.pVtab->pVtab;
- u.cp.pModule = (sqlite3_module *)u.cp.pVtab->pModule;
- u.cp.nArg = pOp->p2;
+ u.cq.pVtab = pOp->p4.pVtab->pVtab;
+ u.cq.pModule = (sqlite3_module *)u.cq.pVtab->pModule;
+ u.cq.nArg = pOp->p2;
assert( pOp->p4type==P4_VTAB );
- if( ALWAYS(u.cp.pModule->xUpdate) ){
+ if( ALWAYS(u.cq.pModule->xUpdate) ){
u8 vtabOnConflict = db->vtabOnConflict;
- u.cp.apArg = p->apArg;
- u.cp.pX = &aMem[pOp->p3];
- for(u.cp.i=0; u.cp.i<u.cp.nArg; u.cp.i++){
- assert( memIsValid(u.cp.pX) );
- memAboutToChange(p, u.cp.pX);
- sqlite3VdbeMemStoreType(u.cp.pX);
- u.cp.apArg[u.cp.i] = u.cp.pX;
- u.cp.pX++;
+ u.cq.apArg = p->apArg;
+ u.cq.pX = &aMem[pOp->p3];
+ for(u.cq.i=0; u.cq.i<u.cq.nArg; u.cq.i++){
+ assert( memIsValid(u.cq.pX) );
+ memAboutToChange(p, u.cq.pX);
+ sqlite3VdbeMemStoreType(u.cq.pX);
+ u.cq.apArg[u.cq.i] = u.cq.pX;
+ u.cq.pX++;
}
db->vtabOnConflict = pOp->p5;
- rc = u.cp.pModule->xUpdate(u.cp.pVtab, u.cp.nArg, u.cp.apArg, &u.cp.rowid);
+ rc = u.cq.pModule->xUpdate(u.cq.pVtab, u.cq.nArg, u.cq.apArg, &u.cq.rowid);
db->vtabOnConflict = vtabOnConflict;
- importVtabErrMsg(p, u.cp.pVtab);
+ importVtabErrMsg(p, u.cq.pVtab);
if( rc==SQLITE_OK && pOp->p1 ){
- assert( u.cp.nArg>1 && u.cp.apArg[0] && (u.cp.apArg[0]->flags&MEM_Null) );
- db->lastRowid = lastRowid = u.cp.rowid;
+ assert( u.cq.nArg>1 && u.cq.apArg[0] && (u.cq.apArg[0]->flags&MEM_Null) );
+ db->lastRowid = lastRowid = u.cq.rowid;
}
if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
if( pOp->p5==OE_Ignore ){
@@ -69553,21 +71332,21 @@ case OP_MaxPgcnt: { /* out2-prerelease */
** the UTF-8 string contained in P4 is emitted on the trace callback.
*/
case OP_Trace: {
-#if 0 /* local variables moved into u.cq */
+#if 0 /* local variables moved into u.cr */
char *zTrace;
char *z;
-#endif /* local variables moved into u.cq */
+#endif /* local variables moved into u.cr */
- if( db->xTrace && (u.cq.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){
- u.cq.z = sqlite3VdbeExpandSql(p, u.cq.zTrace);
- db->xTrace(db->pTraceArg, u.cq.z);
- sqlite3DbFree(db, u.cq.z);
+ if( db->xTrace && (u.cr.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){
+ u.cr.z = sqlite3VdbeExpandSql(p, u.cr.zTrace);
+ db->xTrace(db->pTraceArg, u.cr.z);
+ sqlite3DbFree(db, u.cr.z);
}
#ifdef SQLITE_DEBUG
if( (db->flags & SQLITE_SqlTrace)!=0
- && (u.cq.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
+ && (u.cr.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
){
- sqlite3DebugPrintf("SQL-trace: %s\n", u.cq.zTrace);
+ sqlite3DebugPrintf("SQL-trace: %s\n", u.cr.zTrace);
}
#endif /* SQLITE_DEBUG */
break;
@@ -70260,17 +72039,17 @@ typedef struct SorterRecord SorterRecord;
** being merged (rounded up to the next power of 2).
*/
struct VdbeSorter {
+ i64 iWriteOff; /* Current write offset within file pTemp1 */
+ i64 iReadOff; /* Current read offset within file pTemp1 */
int nInMemory; /* Current size of pRecord list as PMA */
int nTree; /* Used size of aTree/aIter (power of 2) */
+ int nPMA; /* Number of PMAs stored in pTemp1 */
+ int mnPmaSize; /* Minimum PMA size, in bytes */
+ int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */
VdbeSorterIter *aIter; /* Array of iterators to merge */
int *aTree; /* Current state of incremental merge */
- i64 iWriteOff; /* Current write offset within file pTemp1 */
- i64 iReadOff; /* Current read offset within file pTemp1 */
sqlite3_file *pTemp1; /* PMA file 1 */
- int nPMA; /* Number of PMAs stored in pTemp1 */
SorterRecord *pRecord; /* Head of in-memory record list */
- int mnPmaSize; /* Minimum PMA size, in bytes */
- int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */
UnpackedRecord *pUnpacked; /* Used to unpack keys */
};
@@ -70281,10 +72060,10 @@ struct VdbeSorter {
struct VdbeSorterIter {
i64 iReadOff; /* Current read offset */
i64 iEof; /* 1 byte past EOF for this iterator */
- sqlite3_file *pFile; /* File iterator is reading from */
int nAlloc; /* Bytes of space at aAlloc */
- u8 *aAlloc; /* Allocated space */
int nKey; /* Number of bytes in key */
+ sqlite3_file *pFile; /* File iterator is reading from */
+ u8 *aAlloc; /* Allocated space */
u8 *aKey; /* Pointer to current key */
};
@@ -72001,7 +73780,7 @@ static int lookupName(
assert( pExpr->x.pList==0 );
assert( pExpr->x.pSelect==0 );
pOrig = pEList->a[j].pExpr;
- if( !pNC->allowAgg && ExprHasProperty(pOrig, EP_Agg) ){
+ if( (pNC->ncFlags&NC_AllowAgg)==0 && ExprHasProperty(pOrig, EP_Agg) ){
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
return WRC_Abort;
}
@@ -72223,7 +74002,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
if( pDef==0 ){
- pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0);
+ pDef = sqlite3FindFunction(pParse->db, zId, nId, -2, enc, 0);
if( pDef==0 ){
no_such_func = 1;
}else{
@@ -72246,7 +74025,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
}
#endif
- if( is_agg && !pNC->allowAgg ){
+ if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
pNC->nErr++;
is_agg = 0;
@@ -72260,11 +74039,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
if( is_agg ){
pExpr->op = TK_AGG_FUNCTION;
- pNC->hasAgg = 1;
+ pNC->ncFlags |= NC_HasAgg;
}
- if( is_agg ) pNC->allowAgg = 0;
+ if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg;
sqlite3WalkExprList(pWalker, pList);
- if( is_agg ) pNC->allowAgg = 1;
+ if( is_agg ) pNC->ncFlags |= NC_AllowAgg;
/* FIX ME: Compute pExpr->affinity based on the expected return
** type of the function
*/
@@ -72279,7 +74058,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
int nRef = pNC->nRef;
#ifndef SQLITE_OMIT_CHECK
- if( pNC->isCheck ){
+ if( (pNC->ncFlags & NC_IsCheck)!=0 ){
sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints");
}
#endif
@@ -72293,7 +74072,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
#ifndef SQLITE_OMIT_CHECK
case TK_VARIABLE: {
- if( pNC->isCheck ){
+ if( (pNC->ncFlags & NC_IsCheck)!=0 ){
sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints");
}
break;
@@ -72375,7 +74154,7 @@ static int resolveOrderByTermToExprList(
nc.pParse = pParse;
nc.pSrcList = pSelect->pSrc;
nc.pEList = pEList;
- nc.allowAgg = 1;
+ nc.ncFlags = NC_AllowAgg;
nc.nErr = 0;
db = pParse->db;
savedSuppErr = db->suppressErr;
@@ -72489,7 +74268,7 @@ static int resolveCompoundOrderBy(
pE->pColl = pColl;
pE->flags |= EP_IntValue | flags;
pE->u.iValue = iCol;
- pItem->iCol = (u16)iCol;
+ pItem->iOrderByCol = (u16)iCol;
pItem->done = 1;
}else{
moreToDo = 1;
@@ -72538,12 +74317,12 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(
pEList = pSelect->pEList;
assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
- if( pItem->iCol ){
- if( pItem->iCol>pEList->nExpr ){
+ if( pItem->iOrderByCol ){
+ if( pItem->iOrderByCol>pEList->nExpr ){
resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr);
return 1;
}
- resolveAlias(pParse, pEList, pItem->iCol-1, pItem->pExpr, zType);
+ resolveAlias(pParse, pEList, pItem->iOrderByCol-1, pItem->pExpr, zType);
}
}
return 0;
@@ -72573,7 +74352,7 @@ static int resolveOrderGroupBy(
ExprList *pOrderBy, /* An ORDER BY or GROUP BY clause to resolve */
const char *zType /* Either "ORDER" or "GROUP", as appropriate */
){
- int i; /* Loop counter */
+ int i, j; /* Loop counters */
int iCol; /* Column number */
struct ExprList_item *pItem; /* A term of the ORDER BY clause */
Parse *pParse; /* Parsing context */
@@ -72590,7 +74369,7 @@ static int resolveOrderGroupBy(
** a copy of the iCol-th result-set column. The subsequent call to
** sqlite3ResolveOrderGroupBy() will convert the expression to a
** copy of the iCol-th result-set expression. */
- pItem->iCol = (u16)iCol;
+ pItem->iOrderByCol = (u16)iCol;
continue;
}
if( sqlite3ExprIsInteger(pE, &iCol) ){
@@ -72601,15 +74380,20 @@ static int resolveOrderGroupBy(
resolveOutOfRangeError(pParse, zType, i+1, nResult);
return 1;
}
- pItem->iCol = (u16)iCol;
+ pItem->iOrderByCol = (u16)iCol;
continue;
}
/* Otherwise, treat the ORDER BY term as an ordinary expression */
- pItem->iCol = 0;
+ pItem->iOrderByCol = 0;
if( sqlite3ResolveExprNames(pNC, pE) ){
return 1;
}
+ for(j=0; j<pSelect->pEList->nExpr; j++){
+ if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr)==0 ){
+ pItem->iOrderByCol = j+1;
+ }
+ }
}
return sqlite3ResolveOrderGroupBy(pParse, pSelect, pOrderBy, zType);
}
@@ -72672,7 +74456,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
** resolve the result-set expression list.
*/
- sNC.allowAgg = 1;
+ sNC.ncFlags = NC_AllowAgg;
sNC.pSrcList = p->pSrc;
sNC.pNext = pOuterNC;
@@ -72718,10 +74502,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
*/
assert( (p->selFlags & SF_Aggregate)==0 );
pGroupBy = p->pGroupBy;
- if( pGroupBy || sNC.hasAgg ){
+ if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){
p->selFlags |= SF_Aggregate;
}else{
- sNC.allowAgg = 0;
+ sNC.ncFlags &= ~NC_AllowAgg;
}
/* If a HAVING clause is present, then there must be a GROUP BY clause.
@@ -72750,7 +74534,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** outer queries
*/
sNC.pNext = 0;
- sNC.allowAgg = 1;
+ sNC.ncFlags |= NC_AllowAgg;
/* Process the ORDER BY clause for singleton SELECT statements.
** The ORDER BY clause for compounds SELECT statements is handled
@@ -72838,7 +74622,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
**
** Function calls are checked to make sure that the function is
** defined and that the correct number of arguments are specified.
-** If the function is an aggregate function, then the pNC->hasAgg is
+** If the function is an aggregate function, then the NC_HasAgg flag is
** set and the opcode is changed from TK_FUNCTION to TK_AGG_FUNCTION.
** If an expression contains aggregate functions then the EP_Agg
** property on the expression is set.
@@ -72850,7 +74634,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
NameContext *pNC, /* Namespace to resolve expressions in. */
Expr *pExpr /* The expression to be analyzed. */
){
- int savedHasAgg;
+ u8 savedHasAgg;
Walker w;
if( pExpr==0 ) return 0;
@@ -72863,8 +74647,8 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
pParse->nHeight += pExpr->nHeight;
}
#endif
- savedHasAgg = pNC->hasAgg;
- pNC->hasAgg = 0;
+ savedHasAgg = pNC->ncFlags & NC_HasAgg;
+ pNC->ncFlags &= ~NC_HasAgg;
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
w.pParse = pNC->pParse;
@@ -72876,10 +74660,10 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
if( pNC->nErr>0 || w.pParse->nErr>0 ){
ExprSetProperty(pExpr, EP_Error);
}
- if( pNC->hasAgg ){
+ if( pNC->ncFlags & NC_HasAgg ){
ExprSetProperty(pExpr, EP_Agg);
}else if( savedHasAgg ){
- pNC->hasAgg = 1;
+ pNC->ncFlags |= NC_HasAgg;
}
return ExprHasProperty(pExpr, EP_Error);
}
@@ -73399,8 +75183,14 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
Expr *pRight, /* Right operand */
const Token *pToken /* Argument token */
){
- Expr *p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
- sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
+ Expr *p;
+ if( op==TK_AND && pLeft && pRight ){
+ /* Take advantage of short-circuit false optimization for AND */
+ p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
+ }else{
+ p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
+ sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
+ }
if( p ) {
sqlite3ExprCheckHeight(pParse, p->nHeight);
}
@@ -73408,14 +75198,40 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
}
/*
+** Return 1 if an expression must be FALSE in all cases and 0 if the
+** expression might be true. This is an optimization. If is OK to
+** return 0 here even if the expression really is always false (a
+** false negative). But it is a bug to return 1 if the expression
+** might be true in some rare circumstances (a false positive.)
+**
+** Note that if the expression is part of conditional for a
+** LEFT JOIN, then we cannot determine at compile-time whether or not
+** is it true or false, so always return 0.
+*/
+static int exprAlwaysFalse(Expr *p){
+ int v = 0;
+ if( ExprHasProperty(p, EP_FromJoin) ) return 0;
+ if( !sqlite3ExprIsInteger(p, &v) ) return 0;
+ return v==0;
+}
+
+/*
** Join two expressions using an AND operator. If either expression is
** NULL, then just return the other expression.
+**
+** If one side or the other of the AND is known to be false, then instead
+** of returning an AND expression, just return a constant expression with
+** a value of false.
*/
SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){
if( pLeft==0 ){
return pRight;
}else if( pRight==0 ){
return pLeft;
+ }else if( exprAlwaysFalse(pLeft) || exprAlwaysFalse(pRight) ){
+ sqlite3ExprDelete(db, pLeft);
+ sqlite3ExprDelete(db, pRight);
+ return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0);
}else{
Expr *pNew = sqlite3ExprAlloc(db, TK_AND, 0, 0);
sqlite3ExprAttachSubtrees(db, pNew, pLeft, pRight);
@@ -73771,8 +75587,9 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags)
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->iECursor = 0;
- pNew->nExpr = pNew->nAlloc = p->nExpr;
- pNew->a = pItem = sqlite3DbMallocRaw(db, p->nExpr*sizeof(p->a[0]) );
+ pNew->nExpr = i = p->nExpr;
+ if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
+ pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
if( pItem==0 ){
sqlite3DbFree(db, pNew);
return 0;
@@ -73785,7 +75602,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags)
pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
pItem->sortOrder = pOldItem->sortOrder;
pItem->done = 0;
- pItem->iCol = pOldItem->iCol;
+ pItem->iOrderByCol = pOldItem->iOrderByCol;
pItem->iAlias = pOldItem->iAlias;
}
return pNew;
@@ -73840,12 +75657,15 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
- pNew->nId = pNew->nAlloc = p->nId;
+ pNew->nId = p->nId;
pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) );
if( pNew->a==0 ){
sqlite3DbFree(db, pNew);
return 0;
}
+ /* Note that because the size of the allocation for p->a[] is not
+ ** necessarily a power of two, sqlite3IdListAppend() may not be called
+ ** on the duplicate created by this function. */
for(i=0; i<p->nId; i++){
struct IdList_item *pNewItem = &pNew->a[i];
struct IdList_item *pOldItem = &p->a[i];
@@ -73855,7 +75675,7 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
return pNew;
}
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
- Select *pNew;
+ Select *pNew, *pPrior;
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
if( pNew==0 ) return 0;
@@ -73866,7 +75686,9 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
pNew->op = p->op;
- pNew->pPrior = sqlite3SelectDup(db, p->pPrior, flags);
+ pNew->pPrior = pPrior = sqlite3SelectDup(db, p->pPrior, flags);
+ if( pPrior ) pPrior->pNext = pNew;
+ pNew->pNext = 0;
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
pNew->iLimit = 0;
@@ -73905,17 +75727,16 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(
if( pList==0 ){
goto no_mem;
}
- assert( pList->nAlloc==0 );
- }
- if( pList->nAlloc<=pList->nExpr ){
+ 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;
- int n = pList->nAlloc*2 + 4;
- a = sqlite3DbRealloc(db, pList->a, n*sizeof(pList->a[0]));
+ assert( pList->nExpr>0 );
+ a = sqlite3DbRealloc(db, pList->a, pList->nExpr*2*sizeof(pList->a[0]));
if( a==0 ){
goto no_mem;
}
pList->a = a;
- pList->nAlloc = sqlite3DbMallocSize(db, a)/sizeof(a[0]);
}
assert( pList->a!=0 );
if( 1 ){
@@ -74006,8 +75827,7 @@ 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 && pList->nAlloc==0) );
- assert( pList->nExpr<=pList->nAlloc );
+ assert( pList->a!=0 || pList->nExpr==0 );
for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
sqlite3ExprDelete(db, pItem->pExpr);
sqlite3DbFree(db, pItem->zName);
@@ -74289,6 +76109,15 @@ static int isCandidateForInOpt(Select *p){
#endif /* SQLITE_OMIT_SUBQUERY */
/*
+** Code an OP_Once instruction and allocate space for its flag. Return the
+** address of the new instruction.
+*/
+SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){
+ Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
+ return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
+}
+
+/*
** This function is used by the implementation of the IN (...) operator.
** It's job is to find or create a b-tree structure that may be used
** either to test for membership of the (...) set or to iterate through
@@ -74348,6 +76177,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
int eType = 0; /* Type of RHS table. IN_INDEX_* */
int iTab = pParse->nTab++; /* Cursor of the RHS table */
int mustBeUnique = (prNotFound==0); /* True if RHS must be unique */
+ Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
assert( pX->op==TK_IN );
@@ -74358,7 +76188,6 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){
sqlite3 *db = pParse->db; /* Database connection */
- Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
Table *pTab; /* Table <table>. */
Expr *pExpr; /* Expression <column> */
int iCol; /* Index of column <column> */
@@ -74383,10 +76212,9 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
*/
assert(v);
if( iCol<0 ){
- int iMem = ++pParse->nMem;
int iAddr;
- iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
+ iAddr = sqlite3CodeOnce(pParse);
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
eType = IN_INDEX_ROWID;
@@ -74412,12 +76240,11 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
&& sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
&& (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None))
){
- int iMem = ++pParse->nMem;
int iAddr;
char *pKey;
pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx);
- iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
+ iAddr = sqlite3CodeOnce(pParse);
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
pKey,P4_KEYINFO_HANDOFF);
@@ -74427,6 +76254,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
sqlite3VdbeJumpHere(v, iAddr);
if( prNotFound && !pTab->aCol[iCol].notNull ){
*prNotFound = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
}
}
}
@@ -74442,6 +76270,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
eType = IN_INDEX_EPH;
if( prNotFound ){
*prNotFound = rMayHaveNull = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
}else{
testcase( pParse->nQueryLoop>(double)1 );
pParse->nQueryLoop = (double)1;
@@ -74514,9 +76343,8 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
** If all of the above are false, then we can run this code just once
** save the results, and reuse the same result on subsequent invocations.
*/
- if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->pTriggerTab ){
- int mem = ++pParse->nMem;
- testAddr = sqlite3VdbeAddOp1(v, OP_Once, mem);
+ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) ){
+ testAddr = sqlite3CodeOnce(pParse);
}
#ifndef SQLITE_OMIT_EXPLAIN
@@ -74935,15 +76763,6 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
*/
#ifndef NDEBUG
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
-#if 0 /* This code wold remove the entry from the cache if it existed */
- if( p->iReg && p->iTable==iTab && p->iColumn==iCol ){
- cacheEntryClear(pParse, p);
- p->iLevel = pParse->iCacheLevel;
- p->iReg = iReg;
- p->lru = pParse->iCacheCnt++;
- return;
- }
-#endif
assert( p->iReg==0 || p->iTable!=iTab || p->iColumn!=iCol );
}
#endif
@@ -75078,7 +76897,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
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 iReg, /* Store results here */
+ u8 p5 /* P5 value for OP_Column */
){
Vdbe *v = pParse->pVdbe;
int i;
@@ -75093,7 +76913,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
}
assert( v!=0 );
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg);
- sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg);
+ if( p5 ){
+ sqlite3VdbeChangeP5(v, p5);
+ }else{
+ sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg);
+ }
return iReg;
}
@@ -75221,7 +77045,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
inReg = pExpr->iColumn + pParse->ckBase;
}else{
inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
- pExpr->iColumn, pExpr->iTable, target);
+ pExpr->iColumn, pExpr->iTable, target,
+ pExpr->op2);
}
break;
}
@@ -75498,6 +77323,25 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
if( pFarg ){
r1 = sqlite3GetTempRange(pParse, nFarg);
+
+ /* For length() and typeof() functions with a column argument,
+ ** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG
+ ** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
+ ** loading.
+ */
+ if( (pDef->flags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
+ u8 exprOp;
+ assert( nFarg==1 );
+ assert( pFarg->a[0].pExpr!=0 );
+ exprOp = pFarg->a[0].pExpr->op;
+ if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){
+ assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
+ assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
+ testcase( pDef->flags==SQLITE_FUNC_LENGTH );
+ pFarg->a[0].pExpr->op2 = pDef->flags;
+ }
+ }
+
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
sqlite3ExprCodeExprList(pParse, pFarg, r1, 1);
sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */
@@ -75854,6 +77698,264 @@ SQLITE_PRIVATE int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targe
return inReg;
}
+#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
+/*
+** Generate a human-readable explanation of an expression tree.
+*/
+SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
+ int op; /* The opcode being coded */
+ const char *zBinOp = 0; /* Binary operator */
+ const char *zUniOp = 0; /* Unary operator */
+ if( pExpr==0 ){
+ op = TK_NULL;
+ }else{
+ op = pExpr->op;
+ }
+ switch( op ){
+ case TK_AGG_COLUMN: {
+ sqlite3ExplainPrintf(pOut, "AGG{%d:%d}",
+ pExpr->iTable, pExpr->iColumn);
+ break;
+ }
+ case TK_COLUMN: {
+ if( pExpr->iTable<0 ){
+ /* This only happens when coding check constraints */
+ sqlite3ExplainPrintf(pOut, "COLUMN(%d)", pExpr->iColumn);
+ }else{
+ sqlite3ExplainPrintf(pOut, "{%d:%d}",
+ pExpr->iTable, pExpr->iColumn);
+ }
+ break;
+ }
+ case TK_INTEGER: {
+ if( pExpr->flags & EP_IntValue ){
+ sqlite3ExplainPrintf(pOut, "%d", pExpr->u.iValue);
+ }else{
+ sqlite3ExplainPrintf(pOut, "%s", pExpr->u.zToken);
+ }
+ break;
+ }
+#ifndef SQLITE_OMIT_FLOATING_POINT
+ case TK_FLOAT: {
+ sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken);
+ break;
+ }
+#endif
+ case TK_STRING: {
+ sqlite3ExplainPrintf(pOut,"%Q", pExpr->u.zToken);
+ break;
+ }
+ case TK_NULL: {
+ sqlite3ExplainPrintf(pOut,"NULL");
+ break;
+ }
+#ifndef SQLITE_OMIT_BLOB_LITERAL
+ case TK_BLOB: {
+ sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken);
+ break;
+ }
+#endif
+ case TK_VARIABLE: {
+ sqlite3ExplainPrintf(pOut,"VARIABLE(%s,%d)",
+ pExpr->u.zToken, pExpr->iColumn);
+ break;
+ }
+ case TK_REGISTER: {
+ sqlite3ExplainPrintf(pOut,"REGISTER(%d)", pExpr->iTable);
+ break;
+ }
+ case TK_AS: {
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ break;
+ }
+#ifndef SQLITE_OMIT_CAST
+ case TK_CAST: {
+ /* Expressions of the form: CAST(pLeft AS token) */
+ const char *zAff = "unk";
+ switch( sqlite3AffinityType(pExpr->u.zToken) ){
+ case SQLITE_AFF_TEXT: zAff = "TEXT"; break;
+ case SQLITE_AFF_NONE: zAff = "NONE"; break;
+ case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break;
+ case SQLITE_AFF_INTEGER: zAff = "INTEGER"; break;
+ case SQLITE_AFF_REAL: zAff = "REAL"; break;
+ }
+ sqlite3ExplainPrintf(pOut, "CAST-%s(", zAff);
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut, ")");
+ 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_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_AGG_FUNCTION:
+ case TK_CONST_FUNC:
+ case TK_FUNCTION: {
+ ExprList *pFarg; /* List of function arguments */
+ if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ){
+ pFarg = 0;
+ }else{
+ pFarg = pExpr->x.pList;
+ }
+ sqlite3ExplainPrintf(pOut, "%sFUNCTION:%s(",
+ op==TK_AGG_FUNCTION ? "AGG_" : "",
+ pExpr->u.zToken);
+ if( pFarg ){
+ sqlite3ExplainExprList(pOut, pFarg);
+ }
+ sqlite3ExplainPrintf(pOut, ")");
+ break;
+ }
+#ifndef SQLITE_OMIT_SUBQUERY
+ case TK_EXISTS: {
+ sqlite3ExplainPrintf(pOut, "EXISTS(");
+ sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
+ sqlite3ExplainPrintf(pOut,")");
+ break;
+ }
+ case TK_SELECT: {
+ sqlite3ExplainPrintf(pOut, "(");
+ sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
+ sqlite3ExplainPrintf(pOut, ")");
+ break;
+ }
+ case TK_IN: {
+ sqlite3ExplainPrintf(pOut, "IN(");
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut, ",");
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
+ }else{
+ sqlite3ExplainExprList(pOut, pExpr->x.pList);
+ }
+ sqlite3ExplainPrintf(pOut, ")");
+ 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;
+ sqlite3ExplainPrintf(pOut, "BETWEEN(");
+ sqlite3ExplainExpr(pOut, pX);
+ sqlite3ExplainPrintf(pOut, ",");
+ sqlite3ExplainExpr(pOut, pY);
+ sqlite3ExplainPrintf(pOut, ",");
+ sqlite3ExplainExpr(pOut, pZ);
+ sqlite3ExplainPrintf(pOut, ")");
+ 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.
+ */
+ sqlite3ExplainPrintf(pOut, "%s(%d)",
+ pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn);
+ break;
+ }
+ case TK_CASE: {
+ sqlite3ExplainPrintf(pOut, "CASE(");
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut, ",");
+ sqlite3ExplainExprList(pOut, pExpr->x.pList);
+ 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;
+ }
+ sqlite3ExplainPrintf(pOut, "RAISE-%s(%s)", zType, pExpr->u.zToken);
+ break;
+ }
+#endif
+ }
+ if( zBinOp ){
+ sqlite3ExplainPrintf(pOut,"%s(", zBinOp);
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut,",");
+ sqlite3ExplainExpr(pOut, pExpr->pRight);
+ sqlite3ExplainPrintf(pOut,")");
+ }else if( zUniOp ){
+ sqlite3ExplainPrintf(pOut,"%s(", zUniOp);
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut,")");
+ }
+}
+#endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */
+
+#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
+/*
+** Generate a human-readable explanation of an expression list.
+*/
+SQLITE_PRIVATE void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){
+ int i;
+ if( pList==0 || pList->nExpr==0 ){
+ sqlite3ExplainPrintf(pOut, "(empty-list)");
+ return;
+ }else if( pList->nExpr==1 ){
+ sqlite3ExplainExpr(pOut, pList->a[0].pExpr);
+ }else{
+ sqlite3ExplainPush(pOut);
+ for(i=0; i<pList->nExpr; i++){
+ sqlite3ExplainPrintf(pOut, "item[%d] = ", i);
+ sqlite3ExplainPush(pOut);
+ sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
+ sqlite3ExplainPop(pOut);
+ if( i<pList->nExpr-1 ){
+ sqlite3ExplainNL(pOut);
+ }
+ }
+ sqlite3ExplainPop(pOut);
+ }
+}
+#endif /* SQLITE_DEBUG */
+
/*
** Return TRUE if pExpr is an constant expression that is appropriate
** for factoring out of a loop. Appropriate expressions are:
@@ -76375,7 +78477,7 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB){
if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
return 2;
}
- }else if( pA->op!=TK_COLUMN && pA->u.zToken ){
+ }else if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken){
if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2;
if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
return 2;
@@ -76413,6 +78515,41 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
}
/*
+** This is the expression callback for sqlite3FunctionUsesOtherSrc().
+**
+** Determine if an expression references any table other than one of the
+** tables in pWalker->u.pSrcList and abort if it does.
+*/
+static int exprUsesOtherSrc(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
+ int i;
+ SrcList *pSrc = pWalker->u.pSrcList;
+ for(i=0; i<pSrc->nSrc; i++){
+ if( pExpr->iTable==pSrc->a[i].iCursor ) return WRC_Continue;
+ }
+ return WRC_Abort;
+ }else{
+ return WRC_Continue;
+ }
+}
+
+/*
+** Determine if any of the arguments to the pExpr Function references
+** any SrcList other than pSrcList. Return true if they do. Return
+** false if pExpr has no argument or has only constant arguments or
+** only references tables named in pSrcList.
+*/
+static int sqlite3FunctionUsesOtherSrc(Expr *pExpr, SrcList *pSrcList){
+ Walker w;
+ assert( pExpr->op==TK_AGG_FUNCTION );
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = exprUsesOtherSrc;
+ w.u.pSrcList = pSrcList;
+ if( sqlite3WalkExprList(&w, pExpr->x.pList)!=WRC_Continue ) return 1;
+ return 0;
+}
+
+/*
** Add a new element to the pAggInfo->aCol[] array. Return the index of
** the new element. Return a negative number if malloc fails.
*/
@@ -76422,9 +78559,7 @@ static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){
db,
pInfo->aCol,
sizeof(pInfo->aCol[0]),
- 3,
&pInfo->nColumn,
- &pInfo->nColumnAlloc,
&i
);
return i;
@@ -76440,9 +78575,7 @@ static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
db,
pInfo->aFunc,
sizeof(pInfo->aFunc[0]),
- 3,
&pInfo->nFunc,
- &pInfo->nFuncAlloc,
&i
);
return i;
@@ -76531,9 +78664,9 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
return WRC_Prune;
}
case TK_AGG_FUNCTION: {
- /* The pNC->nDepth==0 test causes aggregate functions in subqueries
- ** to be ignored */
- if( pNC->nDepth==0 ){
+ if( (pNC->ncFlags & NC_InAggFunc)==0
+ && !sqlite3FunctionUsesOtherSrc(pExpr, pSrcList)
+ ){
/* Check to see if pExpr is a duplicate of another aggregate
** function that is already in the pAggInfo structure
*/
@@ -76570,22 +78703,16 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
ExprSetIrreducible(pExpr);
pExpr->iAgg = (i16)i;
pExpr->pAggInfo = pAggInfo;
- return WRC_Prune;
}
+ return WRC_Prune;
}
}
return WRC_Continue;
}
static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
- NameContext *pNC = pWalker->u.pNC;
- if( pNC->nDepth==0 ){
- pNC->nDepth++;
- sqlite3WalkSelect(pWalker, pSelect);
- pNC->nDepth--;
- return WRC_Prune;
- }else{
- return WRC_Continue;
- }
+ UNUSED_PARAMETER(pWalker);
+ UNUSED_PARAMETER(pSelect);
+ return WRC_Continue;
}
/*
@@ -76598,6 +78725,7 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
*/
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
Walker w;
+ memset(&w, 0, sizeof(w));
w.xExprCallback = analyzeAggregate;
w.xSelectCallback = analyzeAggregatesInSelect;
w.u.pNC = pNC;
@@ -76678,6 +78806,14 @@ SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
}
}
+/*
+** Mark all temporary registers as being unavailable for reuse.
+*/
+SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){
+ pParse->nTempReg = 0;
+ pParse->nRangeReg = 0;
+}
+
/************** End of expr.c ************************************************/
/************** Begin file alter.c *******************************************/
/*
@@ -77211,7 +79347,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
"WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
"'sqlite_autoindex_' || %Q || substr(name,%d+18) "
"ELSE name END "
- "WHERE tbl_name=%Q AND "
+ "WHERE tbl_name=%Q COLLATE nocase AND "
"(type='table' OR type='index' OR type='trigger');",
zDb, SCHEMA_TABLE(iDb), zName, zName, zName,
#ifndef SQLITE_OMIT_TRIGGER
@@ -78038,6 +80174,7 @@ static void analyzeOneTable(
sqlite3VdbeAddOp2(v, OP_Integer, 0, regNumEq);
sqlite3VdbeAddOp2(v, OP_Integer, 0, regNumLt);
sqlite3VdbeAddOp2(v, OP_Integer, -1, regNumDLt);
+ sqlite3VdbeAddOp3(v, OP_Null, 0, regSample, regAccum);
sqlite3VdbeAddOp4(v, OP_Function, 1, regCount, regAccum,
(char*)&stat3InitFuncdef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, 2);
@@ -78440,6 +80577,7 @@ static int loadStat3(sqlite3 *db, const char *zDb){
int eType; /* Datatype of a sample */
IndexSample *pSample; /* A slot in pIdx->aSample[] */
+ assert( db->lookaside.bEnabled==0 );
if( !sqlite3FindTable(db, "sqlite_stat3", zDb) ){
return SQLITE_OK;
}
@@ -78466,7 +80604,7 @@ static int loadStat3(sqlite3 *db, const char *zDb){
if( pIdx==0 ) continue;
assert( pIdx->nSample==0 );
pIdx->nSample = nSample;
- pIdx->aSample = sqlite3MallocZero( nSample*sizeof(IndexSample) );
+ pIdx->aSample = sqlite3DbMallocZero(db, nSample*sizeof(IndexSample));
pIdx->avgEq = pIdx->aiRowEst[1];
if( pIdx->aSample==0 ){
db->mallocFailed = 1;
@@ -78539,7 +80677,7 @@ static int loadStat3(sqlite3 *db, const char *zDb){
if( n < 1){
pSample->u.z = 0;
}else{
- pSample->u.z = sqlite3Malloc(n);
+ pSample->u.z = sqlite3DbMallocRaw(db, n);
if( pSample->u.z==0 ){
db->mallocFailed = 1;
sqlite3_finalize(pStmt);
@@ -78615,7 +80753,10 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
/* Load the statistics from the sqlite_stat3 table. */
#ifdef SQLITE_ENABLE_STAT3
if( rc==SQLITE_OK ){
+ int lookasideEnabled = db->lookaside.bEnabled;
+ db->lookaside.bEnabled = 0;
rc = loadStat3(db, sInfo.zDatabase);
+ db->lookaside.bEnabled = lookasideEnabled;
}
#endif
@@ -79943,9 +82084,16 @@ static void sqliteDeleteColumnNames(sqlite3 *db, Table *pTable){
** the table data structure from the hash table. But it does destroy
** memory structures of the indices and foreign keys associated with
** the table.
+**
+** The db parameter is optional. It is needed if the Table object
+** contains lookaside memory. (Table objects in the schema do not use
+** lookaside memory, but some ephemeral Table objects do.) Or the
+** db parameter can be used with db->pnBytesFreed to measure the memory
+** used by the Table object.
*/
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 );
@@ -79953,6 +82101,12 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
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. */
+ TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ?
+ db->lookaside.nOut : 0 );
+
/* Delete all indices associated with this table. */
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext;
@@ -79978,12 +82132,15 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
sqlite3DbFree(db, pTable->zColAff);
sqlite3SelectDelete(db, pTable->pSelect);
#ifndef SQLITE_OMIT_CHECK
- sqlite3ExprDelete(db, pTable->pCheck);
+ sqlite3ExprListDelete(db, pTable->pCheck);
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3VtabClear(db, pTable);
#endif
sqlite3DbFree(db, pTable);
+
+ /* Verify that no lookaside memory was used by schema tables */
+ assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
}
/*
@@ -80641,15 +82798,17 @@ SQLITE_PRIVATE void sqlite3AddCheckConstraint(
Parse *pParse, /* Parsing context */
Expr *pCheckExpr /* The check expression */
){
- sqlite3 *db = pParse->db;
#ifndef SQLITE_OMIT_CHECK
Table *pTab = pParse->pNewTable;
if( pTab && !IN_DECLARE_VTAB ){
- pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck, pCheckExpr);
+ pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr);
+ if( pParse->constraintName.n ){
+ sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1);
+ }
}else
#endif
{
- sqlite3ExprDelete(db, pCheckExpr);
+ sqlite3ExprDelete(pParse->db, pCheckExpr);
}
}
@@ -80919,6 +83078,8 @@ SQLITE_PRIVATE void sqlite3EndTable(
if( p->pCheck ){
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
+ ExprList *pList; /* List of all CHECK constraints */
+ int i; /* Loop counter */
memset(&sNC, 0, sizeof(sNC));
memset(&sSrc, 0, sizeof(sSrc));
@@ -80928,9 +83089,12 @@ SQLITE_PRIVATE void sqlite3EndTable(
sSrc.a[0].iCursor = -1;
sNC.pParse = pParse;
sNC.pSrcList = &sSrc;
- sNC.isCheck = 1;
- if( sqlite3ResolveExprNames(&sNC, p->pCheck) ){
- return;
+ sNC.ncFlags = NC_IsCheck;
+ pList = p->pCheck;
+ for(i=0; i<pList->nExpr; i++){
+ if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
+ return;
+ }
}
}
#endif /* !defined(SQLITE_OMIT_CHECK) */
@@ -81079,7 +83243,6 @@ SQLITE_PRIVATE void sqlite3EndTable(
return;
}
pParse->pNewTable = 0;
- db->nTable++;
db->flags |= SQLITE_InternChanges;
#ifndef SQLITE_OMIT_ALTERTABLE
@@ -82102,19 +84265,23 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
nName = sqlite3Strlen30(zName);
nCol = pList->nExpr;
pIndex = sqlite3DbMallocZero(db,
- sizeof(Index) + /* Index structure */
- sizeof(tRowcnt)*(nCol+1) + /* Index.aiRowEst */
- sizeof(int)*nCol + /* Index.aiColumn */
- sizeof(char *)*nCol + /* Index.azColl */
- sizeof(u8)*nCol + /* Index.aSortOrder */
- nName + 1 + /* Index.zName */
- nExtra /* Collation sequence names */
+ ROUND8(sizeof(Index)) + /* Index structure */
+ ROUND8(sizeof(tRowcnt)*(nCol+1)) + /* Index.aiRowEst */
+ sizeof(char *)*nCol + /* Index.azColl */
+ sizeof(int)*nCol + /* Index.aiColumn */
+ sizeof(u8)*nCol + /* Index.aSortOrder */
+ nName + 1 + /* Index.zName */
+ nExtra /* Collation sequence names */
);
if( db->mallocFailed ){
goto exit_create_index;
}
- pIndex->aiRowEst = (tRowcnt*)(&pIndex[1]);
- pIndex->azColl = (char**)(&pIndex->aiRowEst[nCol+1]);
+ zExtra = (char*)pIndex;
+ pIndex->aiRowEst = (tRowcnt*)&zExtra[ROUND8(sizeof(Index))];
+ pIndex->azColl = (char**)
+ ((char*)pIndex->aiRowEst + ROUND8(sizeof(tRowcnt)*nCol+1));
+ assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowEst) );
+ assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) );
pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]);
pIndex->aSortOrder = (u8 *)(&pIndex->aiColumn[nCol]);
pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]);
@@ -82478,45 +84645,43 @@ exit_drop_index:
}
/*
-** pArray is a pointer to an array of objects. Each object in the
-** array is szEntry bytes in size. This routine allocates a new
-** object on the end of the array.
+** pArray is a pointer to an array of objects. Each object in the
+** array is szEntry bytes in size. This routine uses sqlite3DbRealloc()
+** to extend the array so that there is space for a new object at the end.
**
-** *pnEntry is the number of entries already in use. *pnAlloc is
-** the previously allocated size of the array. initSize is the
-** suggested initial array size allocation.
+** When this function is called, *pnEntry contains the current size of
+** the array (in entries - so the allocation is ((*pnEntry) * szEntry) bytes
+** in total).
**
-** The index of the new entry is returned in *pIdx.
+** If the realloc() is successful (i.e. if no OOM condition occurs), the
+** space allocated for the new object is zeroed, *pnEntry updated to
+** reflect the new size of the array and a pointer to the new allocation
+** returned. *pIdx is set to the index of the new array entry in this case.
**
-** This routine returns a pointer to the array of objects. This
-** might be the same as the pArray parameter or it might be a different
-** pointer if the array was resized.
+** Otherwise, if the realloc() fails, *pIdx is set to -1, *pnEntry remains
+** unchanged and a copy of pArray returned.
*/
SQLITE_PRIVATE void *sqlite3ArrayAllocate(
sqlite3 *db, /* Connection to notify of malloc failures */
void *pArray, /* Array of objects. Might be reallocated */
int szEntry, /* Size of each object in the array */
- int initSize, /* Suggested initial allocation, in elements */
int *pnEntry, /* Number of objects currently in use */
- int *pnAlloc, /* Current size of the allocation, in elements */
int *pIdx /* Write the index of a new slot here */
){
char *z;
- if( *pnEntry >= *pnAlloc ){
- void *pNew;
- int newSize;
- newSize = (*pnAlloc)*2 + initSize;
- pNew = sqlite3DbRealloc(db, pArray, newSize*szEntry);
+ int n = *pnEntry;
+ if( (n & (n-1))==0 ){
+ int sz = (n==0) ? 1 : 2*n;
+ void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry);
if( pNew==0 ){
*pIdx = -1;
return pArray;
}
- *pnAlloc = sqlite3DbMallocSize(db, pNew)/szEntry;
pArray = pNew;
}
z = (char*)pArray;
- memset(&z[*pnEntry * szEntry], 0, szEntry);
- *pIdx = *pnEntry;
+ memset(&z[n * szEntry], 0, szEntry);
+ *pIdx = n;
++*pnEntry;
return pArray;
}
@@ -82532,15 +84697,12 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pT
if( pList==0 ){
pList = sqlite3DbMallocZero(db, sizeof(IdList) );
if( pList==0 ) return 0;
- pList->nAlloc = 0;
}
pList->a = sqlite3ArrayAllocate(
db,
pList->a,
sizeof(pList->a[0]),
- 5,
&pList->nId,
- &pList->nAlloc,
&i
);
if( i<0 ){
@@ -83484,38 +85646,57 @@ SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(
** that uses encoding enc. The value returned indicates how well the
** request is matched. A higher value indicates a better match.
**
+** If nArg is -1 that means to only return a match (non-zero) if p->nArg
+** is also -1. In other words, we are searching for a function that
+** takes a variable number of arguments.
+**
+** If nArg is -2 that means that we are searching for any function
+** regardless of the number of arguments it uses, so return a positive
+** match score for any
+**
** The returned value is always between 0 and 6, as follows:
**
-** 0: Not a match, or if nArg<0 and the function is has no implementation.
-** 1: A variable arguments function that prefers UTF-8 when a UTF-16
-** encoding is requested, or vice versa.
-** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is
-** requested, or vice versa.
-** 3: A variable arguments function using the same text encoding.
-** 4: A function with the exact number of arguments requested that
-** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa.
-** 5: A function with the exact number of arguments requested that
-** prefers UTF-16LE when UTF-16BE is requested, or vice versa.
-** 6: An exact match.
-**
-*/
-static int matchQuality(FuncDef *p, int nArg, u8 enc){
- int match = 0;
- if( p->nArg==-1 || p->nArg==nArg
- || (nArg==-1 && (p->xFunc!=0 || p->xStep!=0))
- ){
+** 0: Not a match.
+** 1: UTF8/16 conversion required and function takes any number of arguments.
+** 2: UTF16 byte order change required and function takes any number of args.
+** 3: encoding matches and function takes any number of arguments
+** 4: UTF8/16 conversion required - argument count matches exactly
+** 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 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 */
+static int matchQuality(
+ FuncDef *p, /* The function we are evaluating for match quality */
+ int nArg, /* Desired number of arguments. (-1)==any */
+ u8 enc /* Desired text encoding */
+){
+ int match;
+
+ /* nArg of -2 is a special case */
+ 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;
+
+ /* Give a better score to a function with a specific number of arguments
+ ** than to function that accepts any number of arguments. */
+ if( p->nArg==nArg ){
+ match = 4;
+ }else{
match = 1;
- if( p->nArg==nArg || nArg==-1 ){
- match = 4;
- }
- if( enc==p->iPrefEnc ){
- match += 2;
- }
- else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) ||
- (enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){
- match += 1;
- }
}
+
+ /* Bonus points if the text encoding matches */
+ if( enc==p->iPrefEnc ){
+ match += 2; /* Exact encoding match */
+ }else if( (enc & p->iPrefEnc & 2)!=0 ){
+ match += 1; /* Both are UTF16, but with different byte orders */
+ }
+
return match;
}
@@ -83571,13 +85752,12 @@ SQLITE_PRIVATE void sqlite3FuncDefInsert(
**
** If the createFlag argument is true, then a new (blank) FuncDef
** structure is created and liked into the "db" structure if a
-** no matching function previously existed. When createFlag is true
-** and the nArg parameter is -1, then only a function that accepts
-** any number of arguments will be returned.
+** no matching function previously existed.
**
-** If createFlag is false and nArg is -1, then the first valid
-** function found is returned. A function is valid if either xFunc
-** or xStep is non-zero.
+** If nArg is -2, then the first valid function found is returned. A
+** 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.
**
** If createFlag is false, then a function with the required name and
** number of arguments may be returned even if the eTextRep flag does not
@@ -83589,14 +85769,15 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
int nName, /* Number of characters in the name */
int nArg, /* Number of arguments. -1 means any number */
u8 enc, /* Preferred text encoding */
- int createFlag /* Create new entry if true and does not otherwise exist */
+ u8 createFlag /* Create new entry if true and does not otherwise exist */
){
FuncDef *p; /* Iterator variable */
FuncDef *pBest = 0; /* Best match found so far */
int bestScore = 0; /* Score of best match */
int h; /* Hash value */
-
+ assert( nArg>=(-2) );
+ assert( nArg>=(-1) || createFlag==0 );
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
@@ -83642,7 +85823,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
** exact match for the name, number of arguments and encoding, then add a
** new entry to the hash table and return it.
*/
- if( createFlag && (bestScore<6 || pBest->nArg!=nArg) &&
+ if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
pBest->zName = (char *)&pBest[1];
pBest->nArg = (u16)nArg;
@@ -83868,7 +86049,6 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
*/
if( pOrderBy && (pLimit == 0) ) {
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
- pParse->parseError = 1;
goto limit_where_cleanup_2;
}
@@ -84095,7 +86275,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK
);
if( pWInfo==0 ) goto delete_from_cleanup;
- regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid);
+ regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0);
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
@@ -84402,6 +86582,14 @@ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
}
/*
+** Indicate that the accumulator load should be skipped on this
+** iteration of the aggregate loop.
+*/
+static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){
+ context->skipFlag = 1;
+}
+
+/*
** Implementation of the non-aggregate min() and max() functions
*/
static void minmaxFunc(
@@ -84781,7 +86969,7 @@ static void randomFunc(
** 2s complement of that positive value. The end result can
** therefore be no less than -9223372036854775807.
*/
- r = -(r ^ (((sqlite3_int64)1)<<63));
+ r = -(r & LARGEST_INT64);
}
sqlite3_result_int64(context, r);
}
@@ -85707,11 +87895,12 @@ static void minmaxStep(
Mem *pBest;
UNUSED_PARAMETER(NotUsed);
- if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest));
if( !pBest ) return;
- if( pBest->flags ){
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
+ if( pBest->flags ) sqlite3SkipAccumulatorLoad(context);
+ }else if( pBest->flags ){
int max;
int cmp;
CollSeq *pColl = sqlite3GetFuncCollSeq(context);
@@ -85727,6 +87916,8 @@ static void minmaxStep(
cmp = sqlite3MemCompare(pBest, pArg, pColl);
if( (max && cmp<0) || (!max && cmp>0) ){
sqlite3VdbeMemCopy(pBest, pArg);
+ }else{
+ sqlite3SkipAccumulatorLoad(context);
}
}else{
sqlite3VdbeMemCopy(pBest, pArg);
@@ -85736,7 +87927,7 @@ static void minMaxFinalize(sqlite3_context *context){
sqlite3_value *pRes;
pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
if( pRes ){
- if( ALWAYS(pRes->flags) ){
+ if( pRes->flags ){
sqlite3_result_value(context, pRes);
}
sqlite3VdbeMemRelease(pRes);
@@ -85904,8 +88095,8 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
FUNCTION(max, -1, 1, 1, minmaxFunc ),
FUNCTION(max, 0, 1, 1, 0 ),
AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ),
- FUNCTION(typeof, 1, 0, 0, typeofFunc ),
- FUNCTION(length, 1, 0, 0, lengthFunc ),
+ FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
+ FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ),
@@ -85917,11 +88108,9 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
FUNCTION(lower, 1, 0, 0, lowerFunc ),
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
-/* FUNCTION(coalesce, -1, 0, 0, ifnullFunc ), */
- {-1,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"coalesce",0,0},
+ FUNCTION2(coalesce, -1, 0, 0, ifnullFunc, SQLITE_FUNC_COALESCE),
FUNCTION(hex, 1, 0, 0, hexFunc ),
-/* FUNCTION(ifnull, 2, 0, 0, ifnullFunc ), */
- {2,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"ifnull",0,0},
+ FUNCTION2(ifnull, 2, 0, 0, ifnullFunc, SQLITE_FUNC_COALESCE),
FUNCTION(random, 0, 0, 0, randomFunc ),
FUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
@@ -87248,7 +89437,7 @@ SQLITE_PRIVATE void sqlite3OpenTable(
** 'd' INTEGER
** 'e' REAL
**
-** An extra 'b' is appended to the end of the string to cover the
+** An extra 'd' is appended to the end of the string to cover the
** rowid that appears as the last column in every index.
**
** Memory for the buffer containing the column index affinity string
@@ -87276,7 +89465,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
for(n=0; n<pIdx->nColumn; n++){
pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity;
}
- pIdx->zColAff[n++] = SQLITE_AFF_NONE;
+ pIdx->zColAff[n++] = SQLITE_AFF_INTEGER;
pIdx->zColAff[n] = 0;
}
@@ -87440,6 +89629,7 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
memId = p->regCtr;
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
+ 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);
@@ -88307,7 +90497,7 @@ insert_cleanup:
** cause sqlite3_exec() to return immediately
** with SQLITE_CONSTRAINT.
**
-** any FAIL Sqlite_exec() returns immediately with a
+** any FAIL Sqlite3_exec() returns immediately with a
** return code of SQLITE_CONSTRAINT. The
** transaction is not rolled back and any
** prior changes are retained.
@@ -88357,9 +90547,11 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
int regData; /* Register containing first data column */
int iCur; /* Table cursor number */
Index *pIdx; /* Pointer to one of the indices */
+ sqlite3 *db; /* Database connection */
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
int regOldRowid = (rowidChng && isUpdate) ? rowidChng : regRowid;
+ db = pParse->db;
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
@@ -88392,7 +90584,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
char *zMsg;
sqlite3VdbeAddOp3(v, OP_HaltIfNull,
SQLITE_CONSTRAINT, onError, regData+i);
- zMsg = sqlite3MPrintf(pParse->db, "%s.%s may not be NULL",
+ zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL",
pTab->zName, pTab->aCol[i].zName);
sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
break;
@@ -88414,18 +90606,27 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
/* Test all CHECK constraints
*/
#ifndef SQLITE_OMIT_CHECK
- if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){
- int allOk = sqlite3VdbeMakeLabel(v);
+ if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
+ ExprList *pCheck = pTab->pCheck;
pParse->ckBase = regData;
- sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, SQLITE_JUMPIFNULL);
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
- if( onError==OE_Ignore ){
- sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
- }else{
- if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
- sqlite3HaltConstraint(pParse, onError, 0, 0);
+ for(i=0; i<pCheck->nExpr; i++){
+ int allOk = sqlite3VdbeMakeLabel(v);
+ sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
+ if( onError==OE_Ignore ){
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
+ }else{
+ char *zConsName = pCheck->a[i].zName;
+ if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
+ if( zConsName ){
+ zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
+ }else{
+ zConsName = 0;
+ }
+ sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
+ }
+ sqlite3VdbeResolveLabel(v, allOk);
}
- sqlite3VdbeResolveLabel(v, allOk);
}
#endif /* !defined(SQLITE_OMIT_CHECK) */
@@ -88481,7 +90682,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
** table.
*/
Trigger *pTrigger = 0;
- if( pParse->db->flags&SQLITE_RecTriggers ){
+ if( db->flags&SQLITE_RecTriggers ){
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
}
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
@@ -88570,7 +90771,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
char *zErr;
sqlite3StrAccumInit(&errMsg, 0, 0, 200);
- errMsg.db = pParse->db;
+ errMsg.db = db;
zSep = pIdx->nColumn>1 ? "columns " : "column ";
for(j=0; j<pIdx->nColumn; j++){
char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
@@ -88594,7 +90795,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
Trigger *pTrigger = 0;
assert( onError==OE_Replace );
sqlite3MultiWrite(pParse);
- if( pParse->db->flags&SQLITE_RecTriggers ){
+ if( db->flags&SQLITE_RecTriggers ){
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
}
sqlite3GenerateRowDelete(
@@ -88779,31 +90980,25 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
**
** INSERT INTO tab1 SELECT * FROM tab2;
**
-** This optimization is only attempted if
-**
-** (1) tab1 and tab2 have identical schemas including all the
-** same indices and constraints
-**
-** (2) tab1 and tab2 are different tables
-**
-** (3) There must be no triggers on tab1
-**
-** (4) The result set of the SELECT statement is "*"
+** The xfer optimization transfers raw records from tab2 over to tab1.
+** Columns are not decoded and reassemblied, which greatly improves
+** performance. Raw index records are transferred in the same way.
**
-** (5) The SELECT statement has no WHERE, HAVING, ORDER BY, GROUP BY,
-** or LIMIT clause.
+** The xfer optimization is only attempted if tab1 and tab2 are compatible.
+** There are lots of rules for determining compatibility - see comments
+** embedded in the code for details.
**
-** (6) The SELECT statement is a simple (not a compound) select that
-** contains only tab2 in its FROM clause
+** This routine returns TRUE if the optimization is guaranteed to be used.
+** Sometimes the xfer optimization will only work if the destination table
+** is empty - a factor that can only be determined at run-time. In that
+** case, this routine generates code for the xfer optimization but also
+** does a test to see if the destination table is empty and jumps over the
+** xfer optimization code if the test fails. In that case, this routine
+** returns FALSE so that the caller will know to go ahead and generate
+** an unoptimized transfer. This routine also returns FALSE if there
+** is no chance that the xfer optimization can be applied.
**
-** This method for implementing the INSERT transfers raw records from
-** tab2 over to tab1. The columns are not decoded. Raw records from
-** the indices of tab2 are transfered to tab1 as well. In so doing,
-** the resulting tab1 has much less fragmentation.
-**
-** This routine returns TRUE if the optimization is attempted. If any
-** of the conditions above fail so that the optimization should not
-** be attempted, then this routine returns FALSE.
+** This optimization is particularly useful at making VACUUM run faster.
*/
static int xferOptimization(
Parse *pParse, /* Parser context */
@@ -88840,10 +91035,8 @@ static int xferOptimization(
}
#endif
if( onError==OE_Default ){
- onError = OE_Abort;
- }
- if( onError!=OE_Abort && onError!=OE_Rollback ){
- return 0; /* Cannot do OR REPLACE or OR IGNORE or OR FAIL */
+ if( pDest->iPKey>=0 ) onError = pDest->keyConf;
+ if( onError==OE_Default ) onError = OE_Abort;
}
assert(pSelect->pSrc); /* allocated even if there is no FROM clause */
if( pSelect->pSrc->nSrc!=1 ){
@@ -88932,7 +91125,7 @@ static int xferOptimization(
}
}
#ifndef SQLITE_OMIT_CHECK
- if( pDest->pCheck && sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){
+ if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck, pDest->pCheck) ){
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
}
#endif
@@ -88949,16 +91142,12 @@ static int xferOptimization(
}
#endif
if( (pParse->db->flags & SQLITE_CountRows)!=0 ){
- return 0;
+ return 0; /* xfer opt does not play well with PRAGMA count_changes */
}
- /* If we get this far, it means either:
- **
- ** * We can always do the transfer if the table contains an
- ** an integer primary key
- **
- ** * We can conditionally do the transfer if the destination
- ** table is empty.
+ /* If we get this far, it means that the xfer optimization is at
+ ** least a possibility, though it might only work if the destination
+ ** table (tab1) is initially empty.
*/
#ifdef SQLITE_TEST
sqlite3_xferopt_count++;
@@ -88970,16 +91159,23 @@ static int xferOptimization(
iDest = pParse->nTab++;
regAutoinc = autoIncBegin(pParse, iDbDest, pDest);
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
- if( (pDest->iPKey<0 && pDest->pIndex!=0) || destHasUniqueIdx ){
- /* If tables do not have an INTEGER PRIMARY KEY and there
- ** are indices to be copied and the destination is not empty,
- ** we have to disallow the transfer optimization because the
- ** the rowids might change which will mess up indexing.
+ if( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
+ || destHasUniqueIdx /* (2) */
+ || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */
+ ){
+ /* In some circumstances, we are able to run the xfer optimization
+ ** only if the destination table is initially empty. This code makes
+ ** that determination. Conditions under which the destination must
+ ** be empty:
+ **
+ ** (1) There is no INTEGER PRIMARY KEY but there are indices.
+ ** (If the destination is not initially empty, the rowid fields
+ ** of index entries might need to change.)
**
- ** Or if the destination has a UNIQUE index and is not empty,
- ** we also disallow the transfer optimization because we cannot
- ** insure that all entries in the union of DEST and SRC will be
- ** unique.
+ ** (2) The destination has a unique index. (The xfer optimization
+ ** is unable to test uniqueness.)
+ **
+ ** (3) onError is something other than OE_Abort and OE_Rollback.
*/
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0);
emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
@@ -90271,6 +92467,7 @@ SQLITE_API void sqlite3_reset_auto_extension(void){
SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
int i;
int go = 1;
+ int rc;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
wsdAutoextInit;
@@ -90293,8 +92490,8 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
}
sqlite3_mutex_leave(mutex);
zErrmsg = 0;
- if( xInit && xInit(db, &zErrmsg, &sqlite3Apis) ){
- sqlite3Error(db, SQLITE_ERROR,
+ if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){
+ sqlite3Error(db, rc,
"automatic extension loading failed: %s", zErrmsg);
go = 0;
}
@@ -90321,14 +92518,15 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
-** unrecognized string argument.
+** 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
** should be passed into sqlite3BtreeSetSafetyLevel(). The is done
** to support legacy SQL code. The safety level used to be boolean
** and older scripts may have used numbers 0 for OFF and 1 for ON.
*/
-static u8 getSafetyLevel(const char *z){
+static u8 getSafetyLevel(const char *z, int omitFull, int dflt){
/* 123456789 123456789 */
static const char zText[] = "onoffalseyestruefull";
static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
@@ -90339,19 +92537,19 @@ static u8 getSafetyLevel(const char *z){
return (u8)sqlite3Atoi(z);
}
n = sqlite3Strlen30(z);
- for(i=0; i<ArraySize(iLength); i++){
+ for(i=0; i<ArraySize(iLength)-omitFull; i++){
if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
return iValue[i];
}
}
- return 1;
+ return dflt;
}
/*
** Interpret the given string as a boolean value.
*/
-SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z){
- return getSafetyLevel(z)&1;
+SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z, int dflt){
+ return getSafetyLevel(z,1,dflt)!=0;
}
/* The sqlite3GetBoolean() function is used by other modules but the
@@ -90494,7 +92692,6 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
#endif
/* The following is VERY experimental */
{ "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode },
- { "omit_readlock", SQLITE_NoReadlock },
/* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
** flag if there are any active statements. */
@@ -90526,7 +92723,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
mask &= ~(SQLITE_ForeignKeys);
}
- if( sqlite3GetBoolean(zRight) ){
+ if( sqlite3GetBoolean(zRight, 0) ){
db->flags |= mask;
}else{
db->flags &= ~mask;
@@ -90617,9 +92814,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
const char *zDb = 0; /* The database name */
Token *pId; /* Pointer to <id> token */
int iDb; /* Database index for <database> */
- sqlite3 *db = pParse->db;
- Db *pDb;
- Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db);
+ char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */
+ int rc; /* return value form SQLITE_FCNTL_PRAGMA */
+ sqlite3 *db = pParse->db; /* The database connection */
+ Db *pDb; /* The specific database being pragmaed */
+ Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db); /* Prepared statement */
+
if( v==0 ) return;
sqlite3VdbeRunOnlyOnce(v);
pParse->nMem = 2;
@@ -90650,8 +92850,36 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
goto pragma_out;
}
+
+ /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS
+ ** connection. If it returns SQLITE_OK, then assume that the VFS
+ ** handled the pragma and generate a no-op prepared statement.
+ */
+ aFcntl[0] = 0;
+ aFcntl[1] = zLeft;
+ aFcntl[2] = zRight;
+ aFcntl[3] = 0;
+ rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
+ if( rc==SQLITE_OK ){
+ if( aFcntl[0] ){
+ int mem = ++pParse->nMem;
+ sqlite3VdbeAddOp4(v, OP_String8, 0, mem, 0, aFcntl[0], 0);
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "result", SQLITE_STATIC);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1);
+ sqlite3_free(aFcntl[0]);
+ }
+ }else if( rc!=SQLITE_NOTFOUND ){
+ if( aFcntl[0] ){
+ sqlite3ErrorMsg(pParse, "%s", aFcntl[0]);
+ sqlite3_free(aFcntl[0]);
+ }
+ pParse->nErr++;
+ pParse->rc = rc;
+ }else
+
-#ifndef SQLITE_OMIT_PAGER_PRAGMAS
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
/*
** PRAGMA [database.]default_cache_size
** PRAGMA [database.]default_cache_size=N
@@ -90700,7 +92928,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
}
}else
+#endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
/*
** PRAGMA [database.]page_size
** PRAGMA [database.]page_size=N
@@ -90721,7 +92951,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
** buffer that the pager module resizes using sqlite3_realloc().
*/
db->nextPagesize = sqlite3Atoi(zRight);
- if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
db->mallocFailed = 1;
}
}
@@ -90740,7 +92970,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
int b = -1;
assert( pBt!=0 );
if( zRight ){
- b = sqlite3GetBoolean(zRight);
+ b = sqlite3GetBoolean(zRight, 0);
}
if( pId2->n==0 && b>=0 ){
int ii;
@@ -90761,6 +92991,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
** second form attempts to change this setting. Both
** forms return the current setting.
**
+ ** The absolute value of N is used. This is undocumented and might
+ ** change. The only purpose is to provide an easy way to test
+ ** the sqlite3AbsInt32() function.
+ **
** PRAGMA [database.]page_count
**
** Return the number of pages in the specified database.
@@ -90775,7 +93009,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( sqlite3Tolower(zLeft[0])=='p' ){
sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
}else{
- sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, sqlite3Atoi(zRight));
+ sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg,
+ sqlite3AbsInt32(sqlite3Atoi(zRight)));
}
sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
sqlite3VdbeSetNumCols(v, 1);
@@ -90930,7 +93165,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
** creates the database file. It is important that it is created
** as an auto-vacuum capable db.
*/
- int rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
+ rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
/* When setting the auto_vacuum mode to either "full" or
** "incremental", write the value of meta[6] in the database
@@ -90989,14 +93224,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
** PRAGMA [database.]cache_size=N
**
** The first form reports the current local setting for the
- ** page cache size. The local setting can be different from
- ** the persistent cache size value that is stored in the database
- ** file itself. The value returned is the maximum number of
- ** pages in the page cache. The second form sets the local
- ** page cache size value. It does not change the persistent
- ** cache size stored on the disk so the cache size will revert
- ** to its default value when the database is closed and reopened.
- ** N should be a positive integer.
+ ** page cache size. The second form sets the local
+ ** page cache size value. 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( sqlite3StrICmp(zLeft,"cache_size")==0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
@@ -91004,7 +93236,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( !zRight ){
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
}else{
- int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
+ int size = sqlite3Atoi(zRight);
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
}
@@ -91051,7 +93283,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
- int rc;
int res;
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){
@@ -91096,7 +93327,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
Pager *pPager = sqlite3BtreePager(pDb->pBt);
char *proxy_file_path = NULL;
sqlite3_file *pFile = sqlite3PagerFile(pPager);
- sqlite3OsFileControl(pFile, SQLITE_GET_LOCKPROXYFILE,
+ sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE,
&proxy_file_path);
if( proxy_file_path ){
@@ -91143,7 +93374,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3ErrorMsg(pParse,
"Safety level may not be changed inside a transaction");
}else{
- pDb->safety_level = getSafetyLevel(zRight)+1;
+ pDb->safety_level = getSafetyLevel(zRight,0,1)+1;
}
}
}else
@@ -91396,7 +93627,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
if( zRight ){
- if( sqlite3GetBoolean(zRight) ){
+ if( sqlite3GetBoolean(zRight, 0) ){
sqlite3ParserTrace(stderr, "parser: ");
}else{
sqlite3ParserTrace(0, 0);
@@ -91410,7 +93641,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
if( zRight ){
- sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight));
+ sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight, 0));
}
}else
@@ -91793,6 +94024,16 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else
#endif
+ /*
+ ** PRAGMA shrink_memory
+ **
+ ** This pragma attempts to free as much memory as possible from the
+ ** current database connection.
+ */
+ if( sqlite3StrICmp(zLeft, "shrink_memory")==0 ){
+ sqlite3_db_release_memory(db);
+ }else
+
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Report the current state of file logs for all databases
@@ -92167,9 +94408,13 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
pDb->pSchema->enc = ENC(db);
if( pDb->pSchema->cache_size==0 ){
+#ifndef SQLITE_OMIT_DEPRECATED
size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]);
if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
pDb->pSchema->cache_size = size;
+#else
+ pDb->pSchema->cache_size = SQLITE_DEFAULT_CACHE_SIZE;
+#endif
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
}
@@ -92591,6 +94836,7 @@ static int sqlite3LockAndPrepare(
}
sqlite3BtreeLeaveAll(db);
sqlite3_mutex_leave(db->mutex);
+ assert( rc==SQLITE_OK || *ppStmt==0 );
return rc;
}
@@ -92822,6 +95068,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0));
}
pNew->pEList = pEList;
+ if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
pNew->pSrc = pSrc;
pNew->pWhere = pWhere;
pNew->pGroupBy = pGroupBy;
@@ -94006,9 +96253,17 @@ static int selectColumnsFromExprList(
char *zName; /* Column name */
int nName; /* Size of name in zName[] */
- *pnCol = nCol = pEList->nExpr;
- aCol = *paCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
- if( aCol==0 ) return SQLITE_NOMEM;
+ if( pEList ){
+ nCol = pEList->nExpr;
+ aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
+ testcase( aCol==0 );
+ }else{
+ nCol = 0;
+ aCol = 0;
+ }
+ *pnCol = nCol;
+ *paCol = aCol;
+
for(i=0, pCol=aCol; i<nCol; i++, pCol++){
/* Get an appropriate name for the column
*/
@@ -94360,8 +96615,12 @@ static int multiSelect(
*/
assert( p->pEList && pPrior->pEList );
if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
- sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
- " do not have the same number of result columns", selectOpName(p->op));
+ 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));
+ }
rc = 1;
goto multi_select_end;
}
@@ -94968,8 +97227,8 @@ static int multiSelectOrderBy(
for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){
struct ExprList_item *pItem;
for(j=0, pItem=pOrderBy->a; j<nOrderBy; j++, pItem++){
- assert( pItem->iCol>0 );
- if( pItem->iCol==i ) break;
+ assert( pItem->iOrderByCol>0 );
+ if( pItem->iOrderByCol==i ) break;
}
if( j==nOrderBy ){
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
@@ -94977,7 +97236,7 @@ static int multiSelectOrderBy(
pNew->flags |= EP_IntValue;
pNew->u.iValue = i;
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
- pOrderBy->a[nOrderBy++].iCol = (u16)i;
+ if( pOrderBy ) pOrderBy->a[nOrderBy++].iOrderByCol = (u16)i;
}
}
}
@@ -94993,8 +97252,8 @@ static int multiSelectOrderBy(
if( aPermute ){
struct ExprList_item *pItem;
for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
- assert( pItem->iCol>0 && pItem->iCol<=p->pEList->nExpr );
- aPermute[i] = pItem->iCol - 1;
+ assert( pItem->iOrderByCol>0 && pItem->iOrderByCol<=p->pEList->nExpr );
+ aPermute[i] = pItem->iOrderByCol - 1;
}
pKeyMerge =
sqlite3DbMallocRaw(db, sizeof(*pKeyMerge)+nOrderBy*(sizeof(CollSeq*)+1));
@@ -95337,9 +97596,8 @@ static void substSelect(
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/*
-** This routine attempts to flatten subqueries in order to speed
-** execution. It returns 1 if it makes changes and 0 if no flattening
-** occurs.
+** This routine attempts to flatten subqueries as a performance optimization.
+** This routine returns 1 if it makes changes and 0 if no flattening occurs.
**
** To understand the concept of flattening, consider the following
** query:
@@ -95381,7 +97639,10 @@ static void substSelect(
** (6) The subquery does not use aggregates or the outer query is not
** DISTINCT.
**
-** (7) The subquery has a FROM clause.
+** (7) The subquery has a FROM clause. TODO: For subqueries without
+** A FROM clause, consider adding a FROM close with the special
+** table sqlite_once that consists of a single row containing a
+** single NULL.
**
** (8) The subquery does not use LIMIT or the outer query is not a join.
**
@@ -95414,11 +97675,14 @@ static void substSelect(
**
** * is not itself part of a compound select,
** * is not an aggregate or DISTINCT query, and
-** * has no other tables or sub-selects in the FROM clause.
+** * is not a join
**
** The parent and sub-query may contain WHERE clauses. Subject to
** rules (11), (13) and (14), they may also contain ORDER BY,
-** LIMIT and OFFSET clauses.
+** LIMIT and OFFSET clauses. The subquery cannot use any compound
+** operator other than UNION ALL because all the other compound
+** operators have an implied DISTINCT which is disallowed by
+** restriction (4).
**
** (18) If the sub-query is a compound select, then all terms of the
** ORDER by clause of the parent must be simple references to
@@ -95430,7 +97694,7 @@ static void substSelect(
** (20) If the sub-query is a compound select, then it must not use
** an ORDER BY clause. Ticket #3773. We could relax this constraint
** somewhat by saying that the terms of the ORDER BY clause must
-** appear as unmodified result columns in the outer query. But
+** appear as unmodified result columns in the outer query. But we
** have other optimizations in mind to deal with that case.
**
** (21) The subquery does not use LIMIT or the outer query is not
@@ -95559,19 +97823,21 @@ static int flattenSubquery(
for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
+ assert( pSub->pSrc!=0 );
if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0
|| (pSub1->pPrior && pSub1->op!=TK_ALL)
- || NEVER(pSub1->pSrc==0) || pSub1->pSrc->nSrc!=1
+ || pSub1->pSrc->nSrc<1
){
return 0;
}
+ testcase( pSub1->pSrc->nSrc>1 );
}
/* Restriction 18. */
if( p->pOrderBy ){
int ii;
for(ii=0; ii<p->pOrderBy->nExpr; ii++){
- if( p->pOrderBy->a[ii].iCol==0 ) return 0;
+ if( p->pOrderBy->a[ii].iOrderByCol==0 ) return 0;
}
}
}
@@ -95580,7 +97846,8 @@ static int flattenSubquery(
/* Authorize the subquery */
pParse->zAuthContext = pSubitem->zName;
- sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0);
+ TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0);
+ testcase( i==SQLITE_DENY );
pParse->zAuthContext = zSavedAuthContext;
/* If the sub-query is a compound SELECT statement, then (by restrictions
@@ -95877,6 +98144,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
if( IsVirtual(pTab) ) return 0;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
+ if( pAggInfo->nFunc==0 ) return 0;
if( (pAggInfo->aFunc[0].pFunc->flags&SQLITE_FUNC_COUNT)==0 ) return 0;
if( pExpr->flags&EP_Distinct ) return 0;
@@ -96333,6 +98601,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
Vdbe *v = pParse->pVdbe;
int i;
+ int regHit = 0;
+ int addrHitTest = 0;
struct AggInfo_func *pF;
struct AggInfo_col *pC;
@@ -96368,7 +98638,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
if( !pColl ){
pColl = pParse->db->pDfltColl;
}
- sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
+ if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
+ sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
}
sqlite3VdbeAddOp4(v, OP_AggStep, 0, regAgg, pF->iMem,
(void*)pF->pFunc, P4_FUNCDEF);
@@ -96391,12 +98662,18 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
** Another solution would be to change the OP_SCopy used to copy cached
** values to an OP_Copy.
*/
+ if( regHit ){
+ addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit);
+ }
sqlite3ExprCacheClear(pParse);
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
}
pAggInfo->directMode = 0;
sqlite3ExprCacheClear(pParse);
+ if( addrHitTest ){
+ sqlite3VdbeJumpHere(v, addrHitTest);
+ }
}
/*
@@ -96594,12 +98871,11 @@ SQLITE_PRIVATE int sqlite3Select(
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
pItem->addrFillSub = topAddr+1;
VdbeNoopComment((v, "materialize %s", pItem->pTab->zName));
- if( pItem->isCorrelated==0 && pParse->pTriggerTab==0 ){
+ if( pItem->isCorrelated==0 ){
/* If the subquery is no correlated and if we are not inside of
** a trigger, then we only need to compute the value of the subquery
** once. */
- int regOnce = ++pParse->nMem;
- onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce);
+ onceAddr = sqlite3CodeOnce(pParse);
}
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
@@ -96609,7 +98885,7 @@ SQLITE_PRIVATE int sqlite3Select(
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
VdbeComment((v, "end %s", pItem->pTab->zName));
sqlite3VdbeChangeP1(v, topAddr, retAddr);
-
+ sqlite3ClearTempRegCache(pParse);
}
if( /*pParse->nErr ||*/ db->mallocFailed ){
goto select_end;
@@ -96859,7 +99135,9 @@ SQLITE_PRIVATE int sqlite3Select(
sAggInfo.nAccumulator = sAggInfo.nColumn;
for(i=0; i<sAggInfo.nFunc; i++){
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
+ sNC.ncFlags |= NC_InAggFunc;
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
+ sNC.ncFlags &= ~NC_InAggFunc;
}
if( db->mallocFailed ) goto select_end;
@@ -96904,6 +99182,7 @@ SQLITE_PRIVATE int sqlite3Select(
VdbeComment((v, "clear abort flag"));
sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
VdbeComment((v, "indicate accumulator empty"));
+ sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
/* Begin a loop that will extract all source rows in GROUP BY order.
** This might involve two separate loops with an OP_Sort in between, or
@@ -96956,7 +99235,7 @@ SQLITE_PRIVATE int sqlite3Select(
int r2;
r2 = sqlite3ExprCodeGetColumn(pParse,
- pCol->pTab, pCol->iColumn, pCol->iTable, r1);
+ pCol->pTab, pCol->iColumn, pCol->iTable, r1, 0);
if( r1!=r2 ){
sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1);
}
@@ -97243,101 +99522,101 @@ select_end:
return rc;
}
-#if defined(SQLITE_DEBUG)
+#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
/*
-*******************************************************************************
-** The following code is used for testing and debugging only. The code
-** that follows does not appear in normal builds.
-**
-** These routines are used to print out the content of all or part of a
-** parse structures such as Select or Expr. Such printouts are useful
-** for helping to understand what is happening inside the code generator
-** during the execution of complex SELECT statements.
-**
-** These routine are not called anywhere from within the normal
-** code base. Then are intended to be called from within the debugger
-** or from temporary "printf" statements inserted for debugging.
+** Generate a human-readable description of a the Select object.
*/
-SQLITE_PRIVATE void sqlite3PrintExpr(Expr *p){
- if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
- sqlite3DebugPrintf("(%s", p->u.zToken);
- }else{
- sqlite3DebugPrintf("(%d", p->op);
- }
- if( p->pLeft ){
- sqlite3DebugPrintf(" ");
- sqlite3PrintExpr(p->pLeft);
- }
- if( p->pRight ){
- sqlite3DebugPrintf(" ");
- sqlite3PrintExpr(p->pRight);
- }
- sqlite3DebugPrintf(")");
-}
-SQLITE_PRIVATE void sqlite3PrintExprList(ExprList *pList){
- int i;
- for(i=0; i<pList->nExpr; i++){
- sqlite3PrintExpr(pList->a[i].pExpr);
- if( i<pList->nExpr-1 ){
- sqlite3DebugPrintf(", ");
+static void explainOneSelect(Vdbe *pVdbe, Select *p){
+ sqlite3ExplainPrintf(pVdbe, "SELECT ");
+ if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
+ if( p->selFlags & SF_Distinct ){
+ sqlite3ExplainPrintf(pVdbe, "DISTINCT ");
+ }
+ if( p->selFlags & SF_Aggregate ){
+ sqlite3ExplainPrintf(pVdbe, "agg_flag ");
}
+ sqlite3ExplainNL(pVdbe);
+ sqlite3ExplainPrintf(pVdbe, " ");
}
-}
-SQLITE_PRIVATE void sqlite3PrintSelect(Select *p, int indent){
- sqlite3DebugPrintf("%*sSELECT(%p) ", indent, "", p);
- sqlite3PrintExprList(p->pEList);
- sqlite3DebugPrintf("\n");
- if( p->pSrc ){
- char *zPrefix;
+ sqlite3ExplainExprList(pVdbe, p->pEList);
+ sqlite3ExplainNL(pVdbe);
+ if( p->pSrc && p->pSrc->nSrc ){
int i;
- zPrefix = "FROM";
+ sqlite3ExplainPrintf(pVdbe, "FROM ");
+ sqlite3ExplainPush(pVdbe);
for(i=0; i<p->pSrc->nSrc; i++){
struct SrcList_item *pItem = &p->pSrc->a[i];
- sqlite3DebugPrintf("%*s ", indent+6, zPrefix);
- zPrefix = "";
+ sqlite3ExplainPrintf(pVdbe, "{%d,*} = ", pItem->iCursor);
if( pItem->pSelect ){
- sqlite3DebugPrintf("(\n");
- sqlite3PrintSelect(pItem->pSelect, indent+10);
- sqlite3DebugPrintf("%*s)", indent+8, "");
+ sqlite3ExplainSelect(pVdbe, pItem->pSelect);
+ if( pItem->pTab ){
+ sqlite3ExplainPrintf(pVdbe, " (tabname=%s)", pItem->pTab->zName);
+ }
}else if( pItem->zName ){
- sqlite3DebugPrintf("%s", pItem->zName);
- }
- if( pItem->pTab ){
- sqlite3DebugPrintf("(table: %s)", pItem->pTab->zName);
+ sqlite3ExplainPrintf(pVdbe, "%s", pItem->zName);
}
if( pItem->zAlias ){
- sqlite3DebugPrintf(" AS %s", pItem->zAlias);
+ sqlite3ExplainPrintf(pVdbe, " (AS %s)", pItem->zAlias);
}
- if( i<p->pSrc->nSrc-1 ){
- sqlite3DebugPrintf(",");
+ if( pItem->jointype & JT_LEFT ){
+ sqlite3ExplainPrintf(pVdbe, " LEFT-JOIN");
}
- sqlite3DebugPrintf("\n");
+ sqlite3ExplainNL(pVdbe);
}
+ sqlite3ExplainPop(pVdbe);
}
if( p->pWhere ){
- sqlite3DebugPrintf("%*s WHERE ", indent, "");
- sqlite3PrintExpr(p->pWhere);
- sqlite3DebugPrintf("\n");
+ sqlite3ExplainPrintf(pVdbe, "WHERE ");
+ sqlite3ExplainExpr(pVdbe, p->pWhere);
+ sqlite3ExplainNL(pVdbe);
}
if( p->pGroupBy ){
- sqlite3DebugPrintf("%*s GROUP BY ", indent, "");
- sqlite3PrintExprList(p->pGroupBy);
- sqlite3DebugPrintf("\n");
+ sqlite3ExplainPrintf(pVdbe, "GROUPBY ");
+ sqlite3ExplainExprList(pVdbe, p->pGroupBy);
+ sqlite3ExplainNL(pVdbe);
}
if( p->pHaving ){
- sqlite3DebugPrintf("%*s HAVING ", indent, "");
- sqlite3PrintExpr(p->pHaving);
- sqlite3DebugPrintf("\n");
+ sqlite3ExplainPrintf(pVdbe, "HAVING ");
+ sqlite3ExplainExpr(pVdbe, p->pHaving);
+ sqlite3ExplainNL(pVdbe);
}
if( p->pOrderBy ){
- sqlite3DebugPrintf("%*s ORDER BY ", indent, "");
- sqlite3PrintExprList(p->pOrderBy);
- sqlite3DebugPrintf("\n");
+ sqlite3ExplainPrintf(pVdbe, "ORDERBY ");
+ sqlite3ExplainExprList(pVdbe, p->pOrderBy);
+ sqlite3ExplainNL(pVdbe);
+ }
+ if( p->pLimit ){
+ sqlite3ExplainPrintf(pVdbe, "LIMIT ");
+ sqlite3ExplainExpr(pVdbe, p->pLimit);
+ sqlite3ExplainNL(pVdbe);
+ }
+ if( p->pOffset ){
+ sqlite3ExplainPrintf(pVdbe, "OFFSET ");
+ sqlite3ExplainExpr(pVdbe, p->pOffset);
+ sqlite3ExplainNL(pVdbe);
}
}
+SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
+ if( p==0 ){
+ sqlite3ExplainPrintf(pVdbe, "(null-select)");
+ return;
+ }
+ while( p->pPrior ) p = p->pPrior;
+ sqlite3ExplainPush(pVdbe);
+ while( p ){
+ explainOneSelect(pVdbe, p);
+ p = p->pNext;
+ if( p==0 ) break;
+ sqlite3ExplainNL(pVdbe);
+ sqlite3ExplainPrintf(pVdbe, "%s\n", selectOpName(p->op));
+ }
+ sqlite3ExplainPrintf(pVdbe, "END");
+ sqlite3ExplainPop(pVdbe);
+}
+
/* End of the structure debug printing code
*****************************************************************************/
-#endif /* defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
+#endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */
/************** End of select.c **********************************************/
/************** Begin file table.c *******************************************/
@@ -98445,6 +100724,7 @@ static TriggerPrg *codeRowTrigger(
}
pProgram->nMem = pSubParse->nMem;
pProgram->nCsr = pSubParse->nTab;
+ pProgram->nOnce = pSubParse->nOnce;
pProgram->token = (void *)pTrigger;
pPrg->aColmask[0] = pSubParse->oldmask;
pPrg->aColmask[1] = pSubParse->newmask;
@@ -98792,8 +101072,8 @@ SQLITE_PRIVATE void sqlite3Update(
int regRowCount = 0; /* A count of rows changed */
int regOldRowid; /* The old rowid */
int regNewRowid; /* The new rowid */
- int regNew;
- int regOld = 0;
+ 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 */
memset(&sContext, 0, sizeof(sContext));
@@ -98942,6 +101222,7 @@ SQLITE_PRIVATE void sqlite3Update(
#endif
/* Allocate required registers. */
+ regRowSet = ++pParse->nMem;
regOldRowid = regNewRowid = ++pParse->nMem;
if( pTrigger || hasFK ){
regOld = pParse->nMem + 1;
@@ -98976,7 +101257,7 @@ SQLITE_PRIVATE void sqlite3Update(
/* Begin the database scan
*/
- sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
+ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
pWInfo = sqlite3WhereBegin(
pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED
);
@@ -98987,7 +101268,6 @@ SQLITE_PRIVATE void sqlite3Update(
*/
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regOldRowid);
if( !okOnePass ){
- regRowSet = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
}
@@ -99091,9 +101371,10 @@ 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);
+ /*sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);*/
}else{
j = aXRef[i];
if( j>=0 ){
@@ -99515,6 +101796,18 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
}
#endif
+ rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
+ if( rc!=SQLITE_OK ) goto end_of_vacuum;
+
+ /* Begin a transaction and take an exclusive lock on the main database
+ ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
+ ** to ensure that we do not try to change the page-size on a WAL database.
+ */
+ rc = execSql(db, pzErrMsg, "BEGIN;");
+ if( rc!=SQLITE_OK ) goto end_of_vacuum;
+ rc = sqlite3BtreeBeginTrans(pMain, 2);
+ if( rc!=SQLITE_OK ) goto end_of_vacuum;
+
/* Do not attempt to change the page size for a WAL database */
if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
==PAGER_JOURNALMODE_WAL ){
@@ -99528,20 +101821,12 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
rc = SQLITE_NOMEM;
goto end_of_vacuum;
}
- rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
- if( rc!=SQLITE_OK ){
- goto end_of_vacuum;
- }
#ifndef SQLITE_OMIT_AUTOVACUUM
sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac :
sqlite3BtreeGetAutoVacuum(pMain));
#endif
- /* Begin a transaction */
- rc = execSql(db, pzErrMsg, "BEGIN EXCLUSIVE;");
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
-
/* Query the schema of the main database. Create a mirror schema
** in the temporary database.
*/
@@ -99962,13 +102247,14 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
Parse *pParse, /* Parsing context */
Token *pName1, /* Name of new table, or database name */
Token *pName2, /* Name of new table or NULL */
- Token *pModuleName /* Name of the module for the virtual table */
+ Token *pModuleName, /* Name of the module for the virtual table */
+ int ifNotExists /* No error if the table already exists */
){
int iDb; /* The database the table is being created in */
Table *pTable; /* The new virtual table */
sqlite3 *db; /* Database connection */
- sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
+ sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, ifNotExists);
pTable = pParse->pNewTable;
if( pTable==0 ) return;
assert( 0==pTable->pIndex );
@@ -100003,7 +102289,7 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
** virtual table currently under construction in pParse->pTable.
*/
static void addArgumentToVtab(Parse *pParse){
- if( pParse->sArg.z && ALWAYS(pParse->pNewTable) ){
+ if( pParse->sArg.z && pParse->pNewTable ){
const char *z = (const char*)pParse->sArg.z;
int n = pParse->sArg.n;
sqlite3 *db = pParse->db;
@@ -100130,7 +102416,7 @@ static int vtabCallConstructor(
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
char **pzErr
){
- VtabCtx sCtx;
+ VtabCtx sCtx, *pPriorCtx;
VTable *pVTable;
int rc;
const char *const*azArg = (const char *const*)pTab->azModuleArg;
@@ -100155,9 +102441,10 @@ static int vtabCallConstructor(
assert( xConstruct );
sCtx.pTab = pTab;
sCtx.pVTable = pVTable;
+ pPriorCtx = db->pVtabCtx;
db->pVtabCtx = &sCtx;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
- db->pVtabCtx = 0;
+ db->pVtabCtx = pPriorCtx;
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
if( SQLITE_OK!=rc ){
@@ -101356,7 +103643,7 @@ static WhereTerm *findTerm(
&& pTerm->u.leftColumn==iColumn
&& (pTerm->eOperator & op)!=0
){
- if( pIdx && pTerm->eOperator!=WO_ISNULL ){
+ if( iColumn>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
Expr *pX = pTerm->pExpr;
CollSeq *pColl;
char idxaff;
@@ -101438,7 +103725,10 @@ static int isLikeOrGlob(
#endif
pList = pExpr->x.pList;
pLeft = pList->a[1].pExpr;
- if( pLeft->op!=TK_COLUMN || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT ){
+ if( pLeft->op!=TK_COLUMN
+ || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
+ || IsVirtual(pLeft->pTab)
+ ){
/* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must
** be the name of an indexed column with TEXT affinity. */
return 0;
@@ -102311,15 +104601,19 @@ static int isDistinctRedundant(
** list, or else the WHERE clause contains a term of the form "col=X",
** where X is a constant value. The collation sequences of the
** comparison and select-list expressions must match those of the index.
+ **
+ ** 3. All of those index columns for which the WHERE clause does not
+ ** contain a "col=X" term are subject to a NOT NULL constraint.
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->onError==OE_None ) continue;
for(i=0; i<pIdx->nColumn; i++){
int iCol = pIdx->aiColumn[i];
- if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx)
- && 0>findIndexCol(pParse, pDistinct, iBase, pIdx, i)
- ){
- break;
+ if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){
+ int iIdxCol = findIndexCol(pParse, pDistinct, iBase, pIdx, i);
+ if( iIdxCol<0 || pTab->aCol[pIdx->aiColumn[i]].notNull==0 ){
+ break;
+ }
}
}
if( i==pIdx->nColumn ){
@@ -102467,14 +104761,25 @@ static int isSortingIndex(
}
if( pIdx->onError!=OE_None && i==pIdx->nColumn
&& (wsFlags & WHERE_COLUMN_NULL)==0
- && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){
- /* All terms of this index match some prefix of the ORDER BY clause
- ** and the index is UNIQUE and no terms on the tail of the ORDER BY
- ** clause reference other tables in a join. If this is all true then
- ** the order by clause is superfluous. Not that if the matching
- ** condition is IS NULL then the result is not necessarily unique
- ** even on a UNIQUE index, so disallow those cases. */
- return 1;
+ && !referencesOtherTables(pOrderBy, pMaskSet, j, base)
+ ){
+ Column *aCol = pIdx->pTable->aCol;
+
+ /* All terms of this index match some prefix of the ORDER BY clause,
+ ** the index is UNIQUE, and no terms on the tail of the ORDER BY
+ ** refer to other tables in a join. So, assuming that the index entries
+ ** visited contain no NULL values, then this index delivers rows in
+ ** the required order.
+ **
+ ** It is not possible for any of the first nEqCol index fields to be
+ ** NULL (since the corresponding "=" operator in the WHERE clause would
+ ** not be true). So if all remaining index columns have NOT NULL
+ ** constaints attached to them, we can be confident that the visited
+ ** index entries are free of NULLs. */
+ for(i=nEqCol; i<pIdx->nColumn; i++){
+ if( aCol[pIdx->aiColumn[i]].notNull==0 ) break;
+ }
+ return (i==pIdx->nColumn);
}
return 0;
}
@@ -102757,7 +105062,6 @@ static void constructAutomaticIndex(
int nByte; /* Byte of memory needed for pIdx */
Index *pIdx; /* Object describing the transient index */
Vdbe *v; /* Prepared statement under construction */
- int regIsInit; /* Register set by initialization */
int addrInit; /* Address of the initialization bypass jump */
Table *pTable; /* The table being indexed */
KeyInfo *pKeyinfo; /* Key information for the index */
@@ -102774,8 +105078,7 @@ static void constructAutomaticIndex(
** transient index on 2nd and subsequent iterations of the loop. */
v = pParse->pVdbe;
assert( v!=0 );
- regIsInit = ++pParse->nMem;
- addrInit = sqlite3VdbeAddOp1(v, OP_Once, regIsInit);
+ addrInit = sqlite3CodeOnce(pParse);
/* Count the number of columns that will be added to the index
** and used to match WHERE clause constraints */
@@ -103804,10 +106107,24 @@ static void bestBtreeIndex(
#endif
used |= pTerm->prereqRight;
}
-
- /* Determine the value of rangeDiv */
- if( nEq<pProbe->nColumn && pProbe->bUnordered==0 ){
- int j = pProbe->aiColumn[nEq];
+
+ /* If the index being considered is UNIQUE, and there is an equality
+ ** constraint for all columns in the index, then this search will find
+ ** at most a single row. In this case set the WHERE_UNIQUE flag to
+ ** indicate this to the caller.
+ **
+ ** Otherwise, if the search may find more than one row, test to see if
+ ** there is a range constraint on indexed column (nEq+1) that can be
+ ** optimized using the index.
+ */
+ if( nEq==pProbe->nColumn && pProbe->onError!=OE_None ){
+ testcase( wsFlags & WHERE_COLUMN_IN );
+ testcase( wsFlags & WHERE_COLUMN_NULL );
+ if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
+ wsFlags |= WHERE_UNIQUE;
+ }
+ }else if( pProbe->bUnordered==0 ){
+ int j = (nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[nEq]);
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
@@ -103826,12 +106143,6 @@ static void bestBtreeIndex(
}
wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE);
}
- }else if( pProbe->onError!=OE_None ){
- testcase( wsFlags & WHERE_COLUMN_IN );
- testcase( wsFlags & WHERE_COLUMN_NULL );
- if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
- wsFlags |= WHERE_UNIQUE;
- }
}
/* If there is an ORDER BY clause and the index being considered will
@@ -103849,7 +106160,9 @@ static void bestBtreeIndex(
/* If there is a DISTINCT qualifier and this index will scan rows in
** order of the DISTINCT expressions, clear bDist and set the appropriate
** flags in wsFlags. */
- if( isDistinctIndex(pParse, pWC, pProbe, iCur, pDistinct, nEq) ){
+ if( isDistinctIndex(pParse, pWC, pProbe, iCur, pDistinct, nEq)
+ && (wsFlags & WHERE_COLUMN_IN)==0
+ ){
bDist = 0;
wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_DISTINCT;
}
@@ -104442,10 +106755,12 @@ static char *explainIndexRange(sqlite3 *db, WhereLevel *pLevel, Table *pTab){
j = i;
if( pPlan->wsFlags&WHERE_BTM_LIMIT ){
- explainAppendTerm(&txt, i++, aCol[aiColumn[j]].zName, ">");
+ char *z = (j==pIndex->nColumn ) ? "rowid" : aCol[aiColumn[j]].zName;
+ explainAppendTerm(&txt, i++, z, ">");
}
if( pPlan->wsFlags&WHERE_TOP_LIMIT ){
- explainAppendTerm(&txt, i, aCol[aiColumn[j]].zName, "<");
+ char *z = (j==pIndex->nColumn ) ? "rowid" : aCol[aiColumn[j]].zName;
+ explainAppendTerm(&txt, i, z, "<");
}
sqlite3StrAccumAppend(&txt, ")", 1);
return sqlite3StrAccumFinish(&txt);
@@ -104544,8 +106859,7 @@ static Bitmask codeOneLoopStart(
WhereInfo *pWInfo, /* Complete information about the WHERE clause */
int iLevel, /* Which level of pWInfo->a[] should be coded */
u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
- Bitmask notReady, /* Which tables are currently available */
- Expr *pWhere /* Complete WHERE clause */
+ Bitmask notReady /* Which tables are currently available */
){
int j, k; /* Loop counters */
int iCur; /* The VDBE cursor for the table */
@@ -104803,7 +107117,7 @@ static Bitmask codeOneLoopStart(
pIdx = pLevel->plan.u.pIdx;
iIdxCur = pLevel->iIdxCur;
- k = pIdx->aiColumn[nEq]; /* Column for inequality constraints */
+ k = (nEq==pIdx->nColumn ? -1 : pIdx->aiColumn[nEq]);
/* If this loop satisfies a sort order (pOrderBy) request that
** was passed to this function to implement a "SELECT min(x) ..."
@@ -104849,7 +107163,9 @@ static Bitmask codeOneLoopStart(
** a forward order scan on a descending index, interchange the
** start and end terms (pRangeStart and pRangeEnd).
*/
- if( nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
+ if( (nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC))
+ || (bRev && pIdx->nColumn==nEq)
+ ){
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
}
@@ -105082,10 +107398,25 @@ static Bitmask codeOneLoopStart(
** 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.
*/
if( pWC->nTerm>1 ){
- pAndExpr = sqlite3ExprAlloc(pParse->db, TK_AND, 0, 0);
- pAndExpr->pRight = pWhere;
+ int iTerm;
+ for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
+ Expr *pExpr = pWC->a[iTerm].pExpr;
+ if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
+ if( pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_ORINFO) ) continue;
+ if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
+ pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
+ pAndExpr = sqlite3ExprAnd(pParse->db, pAndExpr, pExpr);
+ }
+ if( pAndExpr ){
+ pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0);
+ }
}
for(ii=0; ii<pOrWc->nTerm; ii++){
@@ -105109,7 +107440,7 @@ static Bitmask codeOneLoopStart(
int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
int r;
r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur,
- regRowid);
+ regRowid, 0);
sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset,
sqlite3VdbeCurrentAddr(v)+2, r, iSet);
}
@@ -105127,7 +107458,10 @@ static Bitmask codeOneLoopStart(
}
}
}
- sqlite3DbFree(pParse->db, pAndExpr);
+ if( pAndExpr ){
+ pAndExpr->pLeft = 0;
+ sqlite3ExprDelete(pParse->db, pAndExpr);
+ }
sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
sqlite3VdbeResolveLabel(v, iLoopBody);
@@ -105783,7 +108117,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
for(i=0; i<nTabList; i++){
pLevel = &pWInfo->a[i];
explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags);
- notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady, pWhere);
+ notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady);
pWInfo->iContinue = pLevel->addrCont;
}
@@ -106019,7 +108353,7 @@ struct LimitVal {
*/
struct LikeOp {
Token eOperator; /* "like" or "glob" or "regexp" */
- int not; /* True if the NOT keyword is present */
+ int bNot; /* True if the NOT keyword is present */
};
/*
@@ -106038,6 +108372,14 @@ struct TrigEvent { int a; IdList * b; };
*/
struct AttachKey { int type; Token key; };
+/*
+** One or more VALUES claues
+*/
+struct ValueList {
+ ExprList *pList;
+ Select *pSelect;
+};
+
/* This is a utility routine used to set the ExprSpan.zStart and
** ExprSpan.zEnd values of pOut so that the span covers the complete
@@ -106161,26 +108503,27 @@ struct AttachKey { int type; Token key; };
** defined, then do no error processing.
*/
#define YYCODETYPE unsigned char
-#define YYNOCODE 253
+#define YYNOCODE 251
#define YYACTIONTYPE unsigned short int
#define YYWILDCARD 67
#define sqlite3ParserTOKENTYPE Token
typedef union {
int yyinit;
sqlite3ParserTOKENTYPE yy0;
- int yy4;
- struct TrigEvent yy90;
- ExprSpan yy118;
- TriggerStep* yy203;
- u8 yy210;
- struct {int value; int mask;} yy215;
- SrcList* yy259;
- struct LimitVal yy292;
- Expr* yy314;
- ExprList* yy322;
- struct LikeOp yy342;
- IdList* yy384;
- Select* yy387;
+ struct LimitVal yy64;
+ Expr* yy122;
+ Select* yy159;
+ IdList* yy180;
+ struct {int value; int mask;} yy207;
+ u8 yy258;
+ struct LikeOp yy318;
+ TriggerStep* yy327;
+ ExprSpan yy342;
+ SrcList* yy347;
+ int yy392;
+ struct TrigEvent yy410;
+ ExprList* yy442;
+ struct ValueList yy487;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
@@ -106189,8 +108532,8 @@ typedef union {
#define sqlite3ParserARG_PDECL ,Parse *pParse
#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
#define sqlite3ParserARG_STORE yypParser->pParse = pParse
-#define YYNSTATE 630
-#define YYNRULE 329
+#define YYNSTATE 627
+#define YYNRULE 327
#define YYFALLBACK 1
#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
@@ -106260,473 +108603,474 @@ static const YYMINORTYPE yyzerominor = { 0 };
** shifting non-terminals after a reduce.
** yy_default[] Default action for each state.
*/
-#define YY_ACTTAB_COUNT (1557)
+#define YY_ACTTAB_COUNT (1564)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 313, 960, 186, 419, 2, 172, 627, 597, 55, 55,
- /* 10 */ 55, 55, 48, 53, 53, 53, 53, 52, 52, 51,
- /* 20 */ 51, 51, 50, 238, 302, 283, 623, 622, 516, 515,
- /* 30 */ 590, 584, 55, 55, 55, 55, 282, 53, 53, 53,
- /* 40 */ 53, 52, 52, 51, 51, 51, 50, 238, 6, 56,
- /* 50 */ 57, 47, 582, 581, 583, 583, 54, 54, 55, 55,
- /* 60 */ 55, 55, 608, 53, 53, 53, 53, 52, 52, 51,
- /* 70 */ 51, 51, 50, 238, 313, 597, 409, 330, 579, 579,
- /* 80 */ 32, 53, 53, 53, 53, 52, 52, 51, 51, 51,
- /* 90 */ 50, 238, 330, 217, 620, 619, 166, 411, 624, 382,
- /* 100 */ 379, 378, 7, 491, 590, 584, 200, 199, 198, 58,
- /* 110 */ 377, 300, 414, 621, 481, 66, 623, 622, 621, 580,
- /* 120 */ 254, 601, 94, 56, 57, 47, 582, 581, 583, 583,
- /* 130 */ 54, 54, 55, 55, 55, 55, 671, 53, 53, 53,
- /* 140 */ 53, 52, 52, 51, 51, 51, 50, 238, 313, 532,
- /* 150 */ 226, 506, 507, 133, 177, 139, 284, 385, 279, 384,
- /* 160 */ 169, 197, 342, 398, 251, 226, 253, 275, 388, 167,
- /* 170 */ 139, 284, 385, 279, 384, 169, 570, 236, 590, 584,
- /* 180 */ 672, 240, 275, 157, 620, 619, 554, 437, 51, 51,
- /* 190 */ 51, 50, 238, 343, 439, 553, 438, 56, 57, 47,
- /* 200 */ 582, 581, 583, 583, 54, 54, 55, 55, 55, 55,
- /* 210 */ 465, 53, 53, 53, 53, 52, 52, 51, 51, 51,
- /* 220 */ 50, 238, 313, 390, 52, 52, 51, 51, 51, 50,
- /* 230 */ 238, 391, 166, 491, 566, 382, 379, 378, 409, 440,
- /* 240 */ 579, 579, 252, 440, 607, 66, 377, 513, 621, 49,
- /* 250 */ 46, 147, 590, 584, 621, 16, 466, 189, 621, 441,
- /* 260 */ 442, 673, 526, 441, 340, 577, 595, 64, 194, 482,
- /* 270 */ 434, 56, 57, 47, 582, 581, 583, 583, 54, 54,
- /* 280 */ 55, 55, 55, 55, 30, 53, 53, 53, 53, 52,
- /* 290 */ 52, 51, 51, 51, 50, 238, 313, 593, 593, 593,
- /* 300 */ 387, 578, 606, 493, 259, 351, 258, 411, 1, 623,
- /* 310 */ 622, 496, 623, 622, 65, 240, 623, 622, 597, 443,
- /* 320 */ 237, 239, 414, 341, 237, 602, 590, 584, 18, 603,
- /* 330 */ 166, 601, 87, 382, 379, 378, 67, 623, 622, 38,
- /* 340 */ 623, 622, 176, 270, 377, 56, 57, 47, 582, 581,
- /* 350 */ 583, 583, 54, 54, 55, 55, 55, 55, 175, 53,
- /* 360 */ 53, 53, 53, 52, 52, 51, 51, 51, 50, 238,
- /* 370 */ 313, 396, 233, 411, 531, 565, 317, 620, 619, 44,
- /* 380 */ 620, 619, 240, 206, 620, 619, 597, 266, 414, 268,
- /* 390 */ 409, 597, 579, 579, 352, 184, 505, 601, 73, 533,
- /* 400 */ 590, 584, 466, 548, 190, 620, 619, 576, 620, 619,
- /* 410 */ 547, 383, 551, 35, 332, 575, 574, 600, 504, 56,
- /* 420 */ 57, 47, 582, 581, 583, 583, 54, 54, 55, 55,
- /* 430 */ 55, 55, 567, 53, 53, 53, 53, 52, 52, 51,
- /* 440 */ 51, 51, 50, 238, 313, 411, 561, 561, 528, 364,
- /* 450 */ 259, 351, 258, 183, 361, 549, 524, 374, 411, 597,
- /* 460 */ 414, 240, 560, 560, 409, 604, 579, 579, 328, 601,
- /* 470 */ 93, 623, 622, 414, 590, 584, 237, 564, 559, 559,
- /* 480 */ 520, 402, 601, 87, 409, 210, 579, 579, 168, 421,
- /* 490 */ 950, 519, 950, 56, 57, 47, 582, 581, 583, 583,
- /* 500 */ 54, 54, 55, 55, 55, 55, 192, 53, 53, 53,
- /* 510 */ 53, 52, 52, 51, 51, 51, 50, 238, 313, 600,
- /* 520 */ 293, 563, 511, 234, 357, 146, 475, 475, 367, 411,
- /* 530 */ 562, 411, 358, 542, 425, 171, 411, 215, 144, 620,
- /* 540 */ 619, 544, 318, 353, 414, 203, 414, 275, 590, 584,
- /* 550 */ 549, 414, 174, 601, 94, 601, 79, 558, 471, 61,
- /* 560 */ 601, 79, 421, 949, 350, 949, 34, 56, 57, 47,
- /* 570 */ 582, 581, 583, 583, 54, 54, 55, 55, 55, 55,
- /* 580 */ 535, 53, 53, 53, 53, 52, 52, 51, 51, 51,
- /* 590 */ 50, 238, 313, 307, 424, 394, 272, 49, 46, 147,
- /* 600 */ 349, 322, 4, 411, 491, 312, 321, 425, 568, 492,
- /* 610 */ 216, 264, 407, 575, 574, 429, 66, 549, 414, 621,
- /* 620 */ 540, 602, 590, 584, 13, 603, 621, 601, 72, 12,
- /* 630 */ 618, 617, 616, 202, 210, 621, 546, 469, 422, 319,
- /* 640 */ 148, 56, 57, 47, 582, 581, 583, 583, 54, 54,
- /* 650 */ 55, 55, 55, 55, 338, 53, 53, 53, 53, 52,
- /* 660 */ 52, 51, 51, 51, 50, 238, 313, 600, 600, 411,
- /* 670 */ 39, 21, 37, 170, 237, 875, 411, 572, 572, 201,
- /* 680 */ 144, 473, 538, 331, 414, 474, 143, 146, 630, 628,
- /* 690 */ 334, 414, 353, 601, 68, 168, 590, 584, 132, 365,
- /* 700 */ 601, 96, 307, 423, 530, 336, 49, 46, 147, 568,
- /* 710 */ 406, 216, 549, 360, 529, 56, 57, 47, 582, 581,
- /* 720 */ 583, 583, 54, 54, 55, 55, 55, 55, 411, 53,
- /* 730 */ 53, 53, 53, 52, 52, 51, 51, 51, 50, 238,
- /* 740 */ 313, 411, 605, 414, 484, 510, 172, 422, 597, 318,
- /* 750 */ 496, 485, 601, 99, 411, 142, 414, 411, 231, 411,
- /* 760 */ 540, 411, 359, 629, 2, 601, 97, 426, 308, 414,
- /* 770 */ 590, 584, 414, 20, 414, 621, 414, 621, 601, 106,
- /* 780 */ 503, 601, 105, 601, 108, 601, 109, 204, 28, 56,
- /* 790 */ 57, 47, 582, 581, 583, 583, 54, 54, 55, 55,
- /* 800 */ 55, 55, 411, 53, 53, 53, 53, 52, 52, 51,
- /* 810 */ 51, 51, 50, 238, 313, 411, 597, 414, 411, 276,
- /* 820 */ 214, 600, 411, 366, 213, 381, 601, 134, 274, 500,
- /* 830 */ 414, 167, 130, 414, 621, 411, 354, 414, 376, 601,
- /* 840 */ 135, 129, 601, 100, 590, 584, 601, 104, 522, 521,
- /* 850 */ 414, 621, 224, 273, 600, 167, 327, 282, 600, 601,
- /* 860 */ 103, 468, 521, 56, 57, 47, 582, 581, 583, 583,
- /* 870 */ 54, 54, 55, 55, 55, 55, 411, 53, 53, 53,
- /* 880 */ 53, 52, 52, 51, 51, 51, 50, 238, 313, 411,
- /* 890 */ 27, 414, 411, 375, 276, 167, 359, 544, 50, 238,
- /* 900 */ 601, 95, 128, 223, 414, 411, 165, 414, 411, 621,
- /* 910 */ 411, 621, 612, 601, 102, 372, 601, 76, 590, 584,
- /* 920 */ 414, 570, 236, 414, 470, 414, 167, 621, 188, 601,
- /* 930 */ 98, 225, 601, 138, 601, 137, 232, 56, 45, 47,
- /* 940 */ 582, 581, 583, 583, 54, 54, 55, 55, 55, 55,
- /* 950 */ 411, 53, 53, 53, 53, 52, 52, 51, 51, 51,
- /* 960 */ 50, 238, 313, 276, 276, 414, 411, 276, 544, 459,
- /* 970 */ 359, 171, 209, 479, 601, 136, 628, 334, 621, 621,
- /* 980 */ 125, 414, 621, 368, 411, 621, 257, 540, 589, 588,
- /* 990 */ 601, 75, 590, 584, 458, 446, 23, 23, 124, 414,
- /* 1000 */ 326, 325, 621, 427, 324, 309, 600, 288, 601, 92,
- /* 1010 */ 586, 585, 57, 47, 582, 581, 583, 583, 54, 54,
- /* 1020 */ 55, 55, 55, 55, 411, 53, 53, 53, 53, 52,
- /* 1030 */ 52, 51, 51, 51, 50, 238, 313, 587, 411, 414,
- /* 1040 */ 411, 207, 611, 476, 171, 472, 160, 123, 601, 91,
- /* 1050 */ 323, 261, 15, 414, 464, 414, 411, 621, 411, 354,
- /* 1060 */ 222, 411, 601, 74, 601, 90, 590, 584, 159, 264,
- /* 1070 */ 158, 414, 461, 414, 621, 600, 414, 121, 120, 25,
- /* 1080 */ 601, 89, 601, 101, 621, 601, 88, 47, 582, 581,
- /* 1090 */ 583, 583, 54, 54, 55, 55, 55, 55, 544, 53,
- /* 1100 */ 53, 53, 53, 52, 52, 51, 51, 51, 50, 238,
- /* 1110 */ 43, 405, 263, 3, 610, 264, 140, 415, 622, 24,
- /* 1120 */ 410, 11, 456, 594, 118, 155, 219, 452, 408, 621,
- /* 1130 */ 621, 621, 156, 43, 405, 621, 3, 286, 621, 113,
- /* 1140 */ 415, 622, 111, 445, 411, 400, 557, 403, 545, 10,
- /* 1150 */ 411, 408, 264, 110, 205, 436, 541, 566, 453, 414,
- /* 1160 */ 621, 621, 63, 621, 435, 414, 411, 621, 601, 94,
- /* 1170 */ 403, 621, 411, 337, 601, 86, 150, 40, 41, 534,
- /* 1180 */ 566, 414, 242, 264, 42, 413, 412, 414, 600, 595,
- /* 1190 */ 601, 85, 191, 333, 107, 451, 601, 84, 621, 539,
- /* 1200 */ 40, 41, 420, 230, 411, 149, 316, 42, 413, 412,
- /* 1210 */ 398, 127, 595, 315, 621, 399, 278, 625, 181, 414,
- /* 1220 */ 593, 593, 593, 592, 591, 14, 450, 411, 601, 71,
- /* 1230 */ 240, 621, 43, 405, 264, 3, 615, 180, 264, 415,
- /* 1240 */ 622, 614, 414, 593, 593, 593, 592, 591, 14, 621,
- /* 1250 */ 408, 601, 70, 621, 417, 33, 405, 613, 3, 411,
- /* 1260 */ 264, 411, 415, 622, 418, 626, 178, 509, 8, 403,
- /* 1270 */ 241, 416, 126, 408, 414, 621, 414, 449, 208, 566,
- /* 1280 */ 240, 221, 621, 601, 83, 601, 82, 599, 297, 277,
- /* 1290 */ 296, 30, 403, 31, 395, 264, 295, 397, 489, 40,
- /* 1300 */ 41, 411, 566, 220, 621, 294, 42, 413, 412, 271,
- /* 1310 */ 621, 595, 600, 621, 59, 60, 414, 269, 267, 623,
- /* 1320 */ 622, 36, 40, 41, 621, 601, 81, 598, 235, 42,
- /* 1330 */ 413, 412, 621, 621, 595, 265, 344, 411, 248, 556,
- /* 1340 */ 173, 185, 593, 593, 593, 592, 591, 14, 218, 29,
- /* 1350 */ 621, 543, 414, 305, 304, 303, 179, 301, 411, 566,
- /* 1360 */ 454, 601, 80, 289, 335, 593, 593, 593, 592, 591,
- /* 1370 */ 14, 411, 287, 414, 151, 392, 246, 260, 411, 196,
- /* 1380 */ 195, 523, 601, 69, 411, 245, 414, 526, 537, 285,
- /* 1390 */ 389, 595, 621, 414, 536, 601, 17, 362, 153, 414,
- /* 1400 */ 466, 463, 601, 78, 154, 414, 462, 152, 601, 77,
- /* 1410 */ 355, 255, 621, 455, 601, 9, 621, 386, 444, 517,
- /* 1420 */ 247, 621, 593, 593, 593, 621, 621, 244, 621, 243,
- /* 1430 */ 430, 518, 292, 621, 329, 621, 145, 393, 280, 513,
- /* 1440 */ 291, 131, 621, 514, 621, 621, 311, 621, 259, 346,
- /* 1450 */ 249, 621, 621, 229, 314, 621, 228, 512, 227, 240,
- /* 1460 */ 494, 488, 310, 164, 487, 486, 373, 480, 163, 262,
- /* 1470 */ 369, 371, 162, 26, 212, 478, 477, 161, 141, 363,
- /* 1480 */ 467, 122, 339, 187, 119, 348, 347, 117, 116, 115,
- /* 1490 */ 114, 112, 182, 457, 320, 22, 433, 432, 448, 19,
- /* 1500 */ 609, 431, 428, 62, 193, 596, 573, 298, 555, 552,
- /* 1510 */ 571, 404, 290, 380, 498, 510, 495, 306, 281, 499,
- /* 1520 */ 250, 5, 497, 460, 345, 447, 569, 550, 238, 299,
- /* 1530 */ 527, 525, 508, 961, 502, 501, 961, 401, 961, 211,
- /* 1540 */ 490, 356, 256, 961, 483, 961, 961, 961, 961, 961,
- /* 1550 */ 961, 961, 961, 961, 961, 961, 370,
+ /* 0 */ 309, 955, 184, 417, 2, 171, 624, 594, 56, 56,
+ /* 10 */ 56, 56, 49, 54, 54, 54, 54, 53, 53, 52,
+ /* 20 */ 52, 52, 51, 233, 620, 619, 298, 620, 619, 234,
+ /* 30 */ 587, 581, 56, 56, 56, 56, 19, 54, 54, 54,
+ /* 40 */ 54, 53, 53, 52, 52, 52, 51, 233, 605, 57,
+ /* 50 */ 58, 48, 579, 578, 580, 580, 55, 55, 56, 56,
+ /* 60 */ 56, 56, 541, 54, 54, 54, 54, 53, 53, 52,
+ /* 70 */ 52, 52, 51, 233, 309, 594, 325, 196, 195, 194,
+ /* 80 */ 33, 54, 54, 54, 54, 53, 53, 52, 52, 52,
+ /* 90 */ 51, 233, 617, 616, 165, 617, 616, 380, 377, 376,
+ /* 100 */ 407, 532, 576, 576, 587, 581, 303, 422, 375, 59,
+ /* 110 */ 53, 53, 52, 52, 52, 51, 233, 50, 47, 146,
+ /* 120 */ 574, 545, 65, 57, 58, 48, 579, 578, 580, 580,
+ /* 130 */ 55, 55, 56, 56, 56, 56, 213, 54, 54, 54,
+ /* 140 */ 54, 53, 53, 52, 52, 52, 51, 233, 309, 223,
+ /* 150 */ 539, 420, 170, 176, 138, 280, 383, 275, 382, 168,
+ /* 160 */ 489, 551, 409, 668, 620, 619, 271, 438, 409, 438,
+ /* 170 */ 550, 604, 67, 482, 507, 618, 599, 412, 587, 581,
+ /* 180 */ 600, 483, 618, 412, 618, 598, 91, 439, 440, 439,
+ /* 190 */ 335, 598, 73, 669, 222, 266, 480, 57, 58, 48,
+ /* 200 */ 579, 578, 580, 580, 55, 55, 56, 56, 56, 56,
+ /* 210 */ 670, 54, 54, 54, 54, 53, 53, 52, 52, 52,
+ /* 220 */ 51, 233, 309, 279, 232, 231, 1, 132, 200, 385,
+ /* 230 */ 620, 619, 617, 616, 278, 435, 289, 563, 175, 262,
+ /* 240 */ 409, 264, 437, 497, 436, 166, 441, 568, 336, 568,
+ /* 250 */ 201, 537, 587, 581, 599, 412, 165, 594, 600, 380,
+ /* 260 */ 377, 376, 597, 598, 92, 523, 618, 569, 569, 592,
+ /* 270 */ 375, 57, 58, 48, 579, 578, 580, 580, 55, 55,
+ /* 280 */ 56, 56, 56, 56, 597, 54, 54, 54, 54, 53,
+ /* 290 */ 53, 52, 52, 52, 51, 233, 309, 463, 617, 616,
+ /* 300 */ 590, 590, 590, 174, 272, 396, 409, 272, 409, 548,
+ /* 310 */ 397, 620, 619, 68, 326, 620, 619, 620, 619, 618,
+ /* 320 */ 546, 412, 618, 412, 471, 594, 587, 581, 472, 598,
+ /* 330 */ 92, 598, 92, 52, 52, 52, 51, 233, 513, 512,
+ /* 340 */ 206, 322, 363, 464, 221, 57, 58, 48, 579, 578,
+ /* 350 */ 580, 580, 55, 55, 56, 56, 56, 56, 529, 54,
+ /* 360 */ 54, 54, 54, 53, 53, 52, 52, 52, 51, 233,
+ /* 370 */ 309, 396, 409, 396, 597, 372, 386, 530, 347, 617,
+ /* 380 */ 616, 575, 202, 617, 616, 617, 616, 412, 620, 619,
+ /* 390 */ 145, 255, 346, 254, 577, 598, 74, 351, 45, 489,
+ /* 400 */ 587, 581, 235, 189, 464, 544, 167, 296, 187, 469,
+ /* 410 */ 479, 67, 62, 39, 618, 546, 597, 345, 573, 57,
+ /* 420 */ 58, 48, 579, 578, 580, 580, 55, 55, 56, 56,
+ /* 430 */ 56, 56, 6, 54, 54, 54, 54, 53, 53, 52,
+ /* 440 */ 52, 52, 51, 233, 309, 562, 558, 407, 528, 576,
+ /* 450 */ 576, 344, 255, 346, 254, 182, 617, 616, 503, 504,
+ /* 460 */ 314, 409, 557, 235, 166, 271, 409, 352, 564, 181,
+ /* 470 */ 407, 546, 576, 576, 587, 581, 412, 537, 556, 561,
+ /* 480 */ 517, 412, 618, 249, 598, 16, 7, 36, 467, 598,
+ /* 490 */ 92, 516, 618, 57, 58, 48, 579, 578, 580, 580,
+ /* 500 */ 55, 55, 56, 56, 56, 56, 541, 54, 54, 54,
+ /* 510 */ 54, 53, 53, 52, 52, 52, 51, 233, 309, 327,
+ /* 520 */ 572, 571, 525, 558, 560, 394, 871, 246, 409, 248,
+ /* 530 */ 171, 392, 594, 219, 407, 409, 576, 576, 502, 557,
+ /* 540 */ 364, 145, 510, 412, 407, 229, 576, 576, 587, 581,
+ /* 550 */ 412, 598, 92, 381, 269, 556, 166, 400, 598, 69,
+ /* 560 */ 501, 419, 945, 199, 945, 198, 546, 57, 58, 48,
+ /* 570 */ 579, 578, 580, 580, 55, 55, 56, 56, 56, 56,
+ /* 580 */ 568, 54, 54, 54, 54, 53, 53, 52, 52, 52,
+ /* 590 */ 51, 233, 309, 317, 419, 944, 508, 944, 308, 597,
+ /* 600 */ 594, 565, 490, 212, 173, 247, 423, 615, 614, 613,
+ /* 610 */ 323, 197, 143, 405, 572, 571, 489, 66, 50, 47,
+ /* 620 */ 146, 594, 587, 581, 232, 231, 559, 427, 67, 555,
+ /* 630 */ 15, 618, 186, 543, 303, 421, 35, 206, 432, 423,
+ /* 640 */ 552, 57, 58, 48, 579, 578, 580, 580, 55, 55,
+ /* 650 */ 56, 56, 56, 56, 205, 54, 54, 54, 54, 53,
+ /* 660 */ 53, 52, 52, 52, 51, 233, 309, 569, 569, 260,
+ /* 670 */ 268, 597, 12, 373, 568, 166, 409, 313, 409, 420,
+ /* 680 */ 409, 473, 473, 365, 618, 50, 47, 146, 597, 594,
+ /* 690 */ 468, 412, 166, 412, 351, 412, 587, 581, 32, 598,
+ /* 700 */ 94, 598, 97, 598, 95, 627, 625, 329, 142, 50,
+ /* 710 */ 47, 146, 333, 349, 358, 57, 58, 48, 579, 578,
+ /* 720 */ 580, 580, 55, 55, 56, 56, 56, 56, 409, 54,
+ /* 730 */ 54, 54, 54, 53, 53, 52, 52, 52, 51, 233,
+ /* 740 */ 309, 409, 388, 412, 409, 22, 565, 404, 212, 362,
+ /* 750 */ 389, 598, 104, 359, 409, 156, 412, 409, 603, 412,
+ /* 760 */ 537, 331, 569, 569, 598, 103, 493, 598, 105, 412,
+ /* 770 */ 587, 581, 412, 260, 549, 618, 11, 598, 106, 521,
+ /* 780 */ 598, 133, 169, 457, 456, 170, 35, 601, 618, 57,
+ /* 790 */ 58, 48, 579, 578, 580, 580, 55, 55, 56, 56,
+ /* 800 */ 56, 56, 409, 54, 54, 54, 54, 53, 53, 52,
+ /* 810 */ 52, 52, 51, 233, 309, 409, 259, 412, 409, 50,
+ /* 820 */ 47, 146, 357, 318, 355, 598, 134, 527, 352, 337,
+ /* 830 */ 412, 409, 356, 412, 357, 409, 357, 618, 598, 98,
+ /* 840 */ 129, 598, 102, 618, 587, 581, 412, 21, 235, 618,
+ /* 850 */ 412, 618, 211, 143, 598, 101, 30, 167, 598, 93,
+ /* 860 */ 350, 535, 203, 57, 58, 48, 579, 578, 580, 580,
+ /* 870 */ 55, 55, 56, 56, 56, 56, 409, 54, 54, 54,
+ /* 880 */ 54, 53, 53, 52, 52, 52, 51, 233, 309, 409,
+ /* 890 */ 526, 412, 409, 425, 215, 305, 597, 551, 141, 598,
+ /* 900 */ 100, 40, 409, 38, 412, 409, 550, 412, 409, 228,
+ /* 910 */ 220, 314, 598, 77, 500, 598, 96, 412, 587, 581,
+ /* 920 */ 412, 338, 253, 412, 218, 598, 137, 379, 598, 136,
+ /* 930 */ 28, 598, 135, 270, 715, 210, 481, 57, 58, 48,
+ /* 940 */ 579, 578, 580, 580, 55, 55, 56, 56, 56, 56,
+ /* 950 */ 409, 54, 54, 54, 54, 53, 53, 52, 52, 52,
+ /* 960 */ 51, 233, 309, 409, 272, 412, 409, 315, 147, 597,
+ /* 970 */ 272, 626, 2, 598, 76, 209, 409, 127, 412, 618,
+ /* 980 */ 126, 412, 409, 621, 235, 618, 598, 90, 374, 598,
+ /* 990 */ 89, 412, 587, 581, 27, 260, 350, 412, 618, 598,
+ /* 1000 */ 75, 321, 541, 541, 125, 598, 88, 320, 278, 597,
+ /* 1010 */ 618, 57, 46, 48, 579, 578, 580, 580, 55, 55,
+ /* 1020 */ 56, 56, 56, 56, 409, 54, 54, 54, 54, 53,
+ /* 1030 */ 53, 52, 52, 52, 51, 233, 309, 409, 450, 412,
+ /* 1040 */ 164, 284, 282, 272, 609, 424, 304, 598, 87, 370,
+ /* 1050 */ 409, 477, 412, 409, 608, 409, 607, 602, 618, 618,
+ /* 1060 */ 598, 99, 586, 585, 122, 412, 587, 581, 412, 618,
+ /* 1070 */ 412, 618, 618, 598, 86, 366, 598, 17, 598, 85,
+ /* 1080 */ 319, 185, 519, 518, 583, 582, 58, 48, 579, 578,
+ /* 1090 */ 580, 580, 55, 55, 56, 56, 56, 56, 409, 54,
+ /* 1100 */ 54, 54, 54, 53, 53, 52, 52, 52, 51, 233,
+ /* 1110 */ 309, 584, 409, 412, 409, 260, 260, 260, 408, 591,
+ /* 1120 */ 474, 598, 84, 170, 409, 466, 518, 412, 121, 412,
+ /* 1130 */ 618, 618, 618, 618, 618, 598, 83, 598, 72, 412,
+ /* 1140 */ 587, 581, 51, 233, 625, 329, 470, 598, 71, 257,
+ /* 1150 */ 159, 120, 14, 462, 157, 158, 117, 260, 448, 447,
+ /* 1160 */ 446, 48, 579, 578, 580, 580, 55, 55, 56, 56,
+ /* 1170 */ 56, 56, 618, 54, 54, 54, 54, 53, 53, 52,
+ /* 1180 */ 52, 52, 51, 233, 44, 403, 260, 3, 409, 459,
+ /* 1190 */ 260, 413, 619, 118, 398, 10, 25, 24, 554, 348,
+ /* 1200 */ 217, 618, 406, 412, 409, 618, 4, 44, 403, 618,
+ /* 1210 */ 3, 598, 82, 618, 413, 619, 455, 542, 115, 412,
+ /* 1220 */ 538, 401, 536, 274, 506, 406, 251, 598, 81, 216,
+ /* 1230 */ 273, 563, 618, 243, 453, 618, 154, 618, 618, 618,
+ /* 1240 */ 449, 416, 623, 110, 401, 618, 409, 236, 64, 123,
+ /* 1250 */ 487, 41, 42, 531, 563, 204, 409, 267, 43, 411,
+ /* 1260 */ 410, 412, 265, 592, 108, 618, 107, 434, 332, 598,
+ /* 1270 */ 80, 412, 618, 263, 41, 42, 443, 618, 409, 598,
+ /* 1280 */ 70, 43, 411, 410, 433, 261, 592, 149, 618, 597,
+ /* 1290 */ 256, 237, 188, 412, 590, 590, 590, 589, 588, 13,
+ /* 1300 */ 618, 598, 18, 328, 235, 618, 44, 403, 360, 3,
+ /* 1310 */ 418, 461, 339, 413, 619, 227, 124, 590, 590, 590,
+ /* 1320 */ 589, 588, 13, 618, 406, 409, 618, 409, 139, 34,
+ /* 1330 */ 403, 387, 3, 148, 622, 312, 413, 619, 311, 330,
+ /* 1340 */ 412, 460, 412, 401, 180, 353, 412, 406, 598, 79,
+ /* 1350 */ 598, 78, 250, 563, 598, 9, 618, 612, 611, 610,
+ /* 1360 */ 618, 8, 452, 442, 242, 415, 401, 618, 239, 235,
+ /* 1370 */ 179, 238, 428, 41, 42, 288, 563, 618, 618, 618,
+ /* 1380 */ 43, 411, 410, 618, 144, 592, 618, 618, 177, 61,
+ /* 1390 */ 618, 596, 391, 620, 619, 287, 41, 42, 414, 618,
+ /* 1400 */ 293, 30, 393, 43, 411, 410, 292, 618, 592, 31,
+ /* 1410 */ 618, 395, 291, 60, 230, 37, 590, 590, 590, 589,
+ /* 1420 */ 588, 13, 214, 553, 183, 290, 172, 301, 300, 299,
+ /* 1430 */ 178, 297, 595, 563, 451, 29, 285, 390, 540, 590,
+ /* 1440 */ 590, 590, 589, 588, 13, 283, 520, 534, 150, 533,
+ /* 1450 */ 241, 281, 384, 192, 191, 324, 515, 514, 276, 240,
+ /* 1460 */ 510, 523, 307, 511, 128, 592, 509, 225, 226, 486,
+ /* 1470 */ 485, 224, 152, 491, 464, 306, 484, 163, 153, 371,
+ /* 1480 */ 478, 151, 162, 258, 369, 161, 367, 208, 475, 476,
+ /* 1490 */ 26, 160, 465, 140, 361, 131, 590, 590, 590, 116,
+ /* 1500 */ 119, 454, 343, 155, 114, 342, 113, 112, 445, 111,
+ /* 1510 */ 130, 109, 431, 316, 426, 430, 23, 429, 20, 606,
+ /* 1520 */ 190, 507, 255, 341, 244, 63, 294, 593, 310, 570,
+ /* 1530 */ 277, 402, 354, 235, 567, 496, 495, 492, 494, 302,
+ /* 1540 */ 458, 378, 286, 245, 566, 5, 252, 547, 193, 444,
+ /* 1550 */ 233, 340, 207, 524, 368, 505, 334, 522, 499, 399,
+ /* 1560 */ 295, 498, 956, 488,
};
static const YYCODETYPE yy_lookahead[] = {
/* 0 */ 19, 142, 143, 144, 145, 24, 1, 26, 77, 78,
/* 10 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
- /* 20 */ 89, 90, 91, 92, 15, 98, 26, 27, 7, 8,
- /* 30 */ 49, 50, 77, 78, 79, 80, 109, 82, 83, 84,
- /* 40 */ 85, 86, 87, 88, 89, 90, 91, 92, 22, 68,
+ /* 20 */ 89, 90, 91, 92, 26, 27, 15, 26, 27, 197,
+ /* 30 */ 49, 50, 77, 78, 79, 80, 204, 82, 83, 84,
+ /* 40 */ 85, 86, 87, 88, 89, 90, 91, 92, 23, 68,
/* 50 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
- /* 60 */ 79, 80, 23, 82, 83, 84, 85, 86, 87, 88,
- /* 70 */ 89, 90, 91, 92, 19, 94, 112, 19, 114, 115,
+ /* 60 */ 79, 80, 166, 82, 83, 84, 85, 86, 87, 88,
+ /* 70 */ 89, 90, 91, 92, 19, 94, 19, 105, 106, 107,
/* 80 */ 25, 82, 83, 84, 85, 86, 87, 88, 89, 90,
- /* 90 */ 91, 92, 19, 22, 94, 95, 96, 150, 150, 99,
- /* 100 */ 100, 101, 76, 150, 49, 50, 105, 106, 107, 54,
- /* 110 */ 110, 158, 165, 165, 161, 162, 26, 27, 165, 113,
- /* 120 */ 16, 174, 175, 68, 69, 70, 71, 72, 73, 74,
- /* 130 */ 75, 76, 77, 78, 79, 80, 118, 82, 83, 84,
- /* 140 */ 85, 86, 87, 88, 89, 90, 91, 92, 19, 23,
- /* 150 */ 92, 97, 98, 24, 96, 97, 98, 99, 100, 101,
- /* 160 */ 102, 25, 97, 216, 60, 92, 62, 109, 221, 25,
- /* 170 */ 97, 98, 99, 100, 101, 102, 86, 87, 49, 50,
- /* 180 */ 118, 116, 109, 25, 94, 95, 32, 97, 88, 89,
- /* 190 */ 90, 91, 92, 128, 104, 41, 106, 68, 69, 70,
+ /* 90 */ 91, 92, 94, 95, 96, 94, 95, 99, 100, 101,
+ /* 100 */ 112, 205, 114, 115, 49, 50, 22, 23, 110, 54,
+ /* 110 */ 86, 87, 88, 89, 90, 91, 92, 221, 222, 223,
+ /* 120 */ 23, 120, 25, 68, 69, 70, 71, 72, 73, 74,
+ /* 130 */ 75, 76, 77, 78, 79, 80, 22, 82, 83, 84,
+ /* 140 */ 85, 86, 87, 88, 89, 90, 91, 92, 19, 92,
+ /* 150 */ 23, 67, 25, 96, 97, 98, 99, 100, 101, 102,
+ /* 160 */ 150, 32, 150, 118, 26, 27, 109, 150, 150, 150,
+ /* 170 */ 41, 161, 162, 180, 181, 165, 113, 165, 49, 50,
+ /* 180 */ 117, 188, 165, 165, 165, 173, 174, 170, 171, 170,
+ /* 190 */ 171, 173, 174, 118, 184, 16, 186, 68, 69, 70,
/* 200 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- /* 210 */ 11, 82, 83, 84, 85, 86, 87, 88, 89, 90,
- /* 220 */ 91, 92, 19, 19, 86, 87, 88, 89, 90, 91,
- /* 230 */ 92, 27, 96, 150, 66, 99, 100, 101, 112, 150,
- /* 240 */ 114, 115, 138, 150, 161, 162, 110, 103, 165, 222,
- /* 250 */ 223, 224, 49, 50, 165, 22, 57, 24, 165, 170,
- /* 260 */ 171, 118, 94, 170, 171, 23, 98, 25, 185, 186,
- /* 270 */ 243, 68, 69, 70, 71, 72, 73, 74, 75, 76,
- /* 280 */ 77, 78, 79, 80, 126, 82, 83, 84, 85, 86,
- /* 290 */ 87, 88, 89, 90, 91, 92, 19, 129, 130, 131,
- /* 300 */ 88, 23, 172, 173, 105, 106, 107, 150, 22, 26,
- /* 310 */ 27, 181, 26, 27, 22, 116, 26, 27, 26, 230,
- /* 320 */ 231, 197, 165, 230, 231, 113, 49, 50, 204, 117,
- /* 330 */ 96, 174, 175, 99, 100, 101, 22, 26, 27, 136,
- /* 340 */ 26, 27, 118, 16, 110, 68, 69, 70, 71, 72,
- /* 350 */ 73, 74, 75, 76, 77, 78, 79, 80, 118, 82,
+ /* 210 */ 118, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ /* 220 */ 91, 92, 19, 98, 86, 87, 22, 24, 160, 88,
+ /* 230 */ 26, 27, 94, 95, 109, 97, 224, 66, 118, 60,
+ /* 240 */ 150, 62, 104, 23, 106, 25, 229, 230, 229, 230,
+ /* 250 */ 160, 150, 49, 50, 113, 165, 96, 26, 117, 99,
+ /* 260 */ 100, 101, 194, 173, 174, 94, 165, 129, 130, 98,
+ /* 270 */ 110, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ /* 280 */ 77, 78, 79, 80, 194, 82, 83, 84, 85, 86,
+ /* 290 */ 87, 88, 89, 90, 91, 92, 19, 11, 94, 95,
+ /* 300 */ 129, 130, 131, 118, 150, 215, 150, 150, 150, 25,
+ /* 310 */ 220, 26, 27, 22, 213, 26, 27, 26, 27, 165,
+ /* 320 */ 25, 165, 165, 165, 30, 94, 49, 50, 34, 173,
+ /* 330 */ 174, 173, 174, 88, 89, 90, 91, 92, 7, 8,
+ /* 340 */ 160, 187, 48, 57, 187, 68, 69, 70, 71, 72,
+ /* 350 */ 73, 74, 75, 76, 77, 78, 79, 80, 23, 82,
/* 360 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
- /* 370 */ 19, 214, 215, 150, 23, 23, 155, 94, 95, 22,
- /* 380 */ 94, 95, 116, 160, 94, 95, 94, 60, 165, 62,
- /* 390 */ 112, 26, 114, 115, 128, 23, 36, 174, 175, 88,
- /* 400 */ 49, 50, 57, 120, 22, 94, 95, 23, 94, 95,
- /* 410 */ 120, 51, 25, 136, 169, 170, 171, 194, 58, 68,
+ /* 370 */ 19, 215, 150, 215, 194, 19, 220, 88, 220, 94,
+ /* 380 */ 95, 23, 160, 94, 95, 94, 95, 165, 26, 27,
+ /* 390 */ 95, 105, 106, 107, 113, 173, 174, 217, 22, 150,
+ /* 400 */ 49, 50, 116, 119, 57, 120, 50, 158, 22, 21,
+ /* 410 */ 161, 162, 232, 136, 165, 120, 194, 237, 23, 68,
/* 420 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
- /* 430 */ 79, 80, 23, 82, 83, 84, 85, 86, 87, 88,
- /* 440 */ 89, 90, 91, 92, 19, 150, 12, 12, 23, 228,
- /* 450 */ 105, 106, 107, 23, 233, 25, 165, 19, 150, 94,
- /* 460 */ 165, 116, 28, 28, 112, 174, 114, 115, 108, 174,
- /* 470 */ 175, 26, 27, 165, 49, 50, 231, 11, 44, 44,
- /* 480 */ 46, 46, 174, 175, 112, 160, 114, 115, 50, 22,
- /* 490 */ 23, 57, 25, 68, 69, 70, 71, 72, 73, 74,
- /* 500 */ 75, 76, 77, 78, 79, 80, 119, 82, 83, 84,
- /* 510 */ 85, 86, 87, 88, 89, 90, 91, 92, 19, 194,
- /* 520 */ 225, 23, 23, 215, 19, 95, 105, 106, 107, 150,
- /* 530 */ 23, 150, 27, 23, 67, 25, 150, 206, 207, 94,
- /* 540 */ 95, 166, 104, 218, 165, 22, 165, 109, 49, 50,
- /* 550 */ 120, 165, 25, 174, 175, 174, 175, 23, 21, 234,
- /* 560 */ 174, 175, 22, 23, 239, 25, 25, 68, 69, 70,
+ /* 430 */ 79, 80, 22, 82, 83, 84, 85, 86, 87, 88,
+ /* 440 */ 89, 90, 91, 92, 19, 23, 12, 112, 23, 114,
+ /* 450 */ 115, 63, 105, 106, 107, 23, 94, 95, 97, 98,
+ /* 460 */ 104, 150, 28, 116, 25, 109, 150, 150, 23, 23,
+ /* 470 */ 112, 25, 114, 115, 49, 50, 165, 150, 44, 11,
+ /* 480 */ 46, 165, 165, 16, 173, 174, 76, 136, 100, 173,
+ /* 490 */ 174, 57, 165, 68, 69, 70, 71, 72, 73, 74,
+ /* 500 */ 75, 76, 77, 78, 79, 80, 166, 82, 83, 84,
+ /* 510 */ 85, 86, 87, 88, 89, 90, 91, 92, 19, 169,
+ /* 520 */ 170, 171, 23, 12, 23, 214, 138, 60, 150, 62,
+ /* 530 */ 24, 215, 26, 216, 112, 150, 114, 115, 36, 28,
+ /* 540 */ 213, 95, 103, 165, 112, 205, 114, 115, 49, 50,
+ /* 550 */ 165, 173, 174, 51, 23, 44, 25, 46, 173, 174,
+ /* 560 */ 58, 22, 23, 22, 25, 160, 120, 68, 69, 70,
/* 570 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- /* 580 */ 205, 82, 83, 84, 85, 86, 87, 88, 89, 90,
- /* 590 */ 91, 92, 19, 22, 23, 216, 23, 222, 223, 224,
- /* 600 */ 63, 220, 35, 150, 150, 163, 220, 67, 166, 167,
- /* 610 */ 168, 150, 169, 170, 171, 161, 162, 25, 165, 165,
- /* 620 */ 150, 113, 49, 50, 25, 117, 165, 174, 175, 35,
- /* 630 */ 7, 8, 9, 160, 160, 165, 120, 100, 67, 247,
- /* 640 */ 248, 68, 69, 70, 71, 72, 73, 74, 75, 76,
- /* 650 */ 77, 78, 79, 80, 193, 82, 83, 84, 85, 86,
- /* 660 */ 87, 88, 89, 90, 91, 92, 19, 194, 194, 150,
- /* 670 */ 135, 24, 137, 35, 231, 138, 150, 129, 130, 206,
- /* 680 */ 207, 30, 27, 213, 165, 34, 118, 95, 0, 1,
- /* 690 */ 2, 165, 218, 174, 175, 50, 49, 50, 22, 48,
- /* 700 */ 174, 175, 22, 23, 23, 244, 222, 223, 224, 166,
- /* 710 */ 167, 168, 120, 239, 23, 68, 69, 70, 71, 72,
+ /* 580 */ 230, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ /* 590 */ 91, 92, 19, 215, 22, 23, 23, 25, 163, 194,
+ /* 600 */ 94, 166, 167, 168, 25, 138, 67, 7, 8, 9,
+ /* 610 */ 108, 206, 207, 169, 170, 171, 150, 22, 221, 222,
+ /* 620 */ 223, 26, 49, 50, 86, 87, 23, 161, 162, 23,
+ /* 630 */ 22, 165, 24, 120, 22, 23, 25, 160, 241, 67,
+ /* 640 */ 176, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ /* 650 */ 77, 78, 79, 80, 160, 82, 83, 84, 85, 86,
+ /* 660 */ 87, 88, 89, 90, 91, 92, 19, 129, 130, 150,
+ /* 670 */ 23, 194, 35, 23, 230, 25, 150, 155, 150, 67,
+ /* 680 */ 150, 105, 106, 107, 165, 221, 222, 223, 194, 94,
+ /* 690 */ 23, 165, 25, 165, 217, 165, 49, 50, 25, 173,
+ /* 700 */ 174, 173, 174, 173, 174, 0, 1, 2, 118, 221,
+ /* 710 */ 222, 223, 193, 219, 237, 68, 69, 70, 71, 72,
/* 720 */ 73, 74, 75, 76, 77, 78, 79, 80, 150, 82,
/* 730 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
- /* 740 */ 19, 150, 173, 165, 181, 182, 24, 67, 26, 104,
- /* 750 */ 181, 188, 174, 175, 150, 39, 165, 150, 52, 150,
- /* 760 */ 150, 150, 150, 144, 145, 174, 175, 249, 250, 165,
- /* 770 */ 49, 50, 165, 52, 165, 165, 165, 165, 174, 175,
- /* 780 */ 29, 174, 175, 174, 175, 174, 175, 160, 22, 68,
+ /* 740 */ 19, 150, 19, 165, 150, 24, 166, 167, 168, 227,
+ /* 750 */ 27, 173, 174, 231, 150, 25, 165, 150, 172, 165,
+ /* 760 */ 150, 242, 129, 130, 173, 174, 180, 173, 174, 165,
+ /* 770 */ 49, 50, 165, 150, 176, 165, 35, 173, 174, 165,
+ /* 780 */ 173, 174, 35, 23, 23, 25, 25, 173, 165, 68,
/* 790 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
/* 800 */ 79, 80, 150, 82, 83, 84, 85, 86, 87, 88,
- /* 810 */ 89, 90, 91, 92, 19, 150, 94, 165, 150, 150,
- /* 820 */ 160, 194, 150, 213, 160, 52, 174, 175, 23, 23,
- /* 830 */ 165, 25, 22, 165, 165, 150, 150, 165, 52, 174,
- /* 840 */ 175, 22, 174, 175, 49, 50, 174, 175, 190, 191,
- /* 850 */ 165, 165, 240, 23, 194, 25, 187, 109, 194, 174,
- /* 860 */ 175, 190, 191, 68, 69, 70, 71, 72, 73, 74,
+ /* 810 */ 89, 90, 91, 92, 19, 150, 193, 165, 150, 221,
+ /* 820 */ 222, 223, 150, 213, 19, 173, 174, 23, 150, 97,
+ /* 830 */ 165, 150, 27, 165, 150, 150, 150, 165, 173, 174,
+ /* 840 */ 22, 173, 174, 165, 49, 50, 165, 52, 116, 165,
+ /* 850 */ 165, 165, 206, 207, 173, 174, 126, 50, 173, 174,
+ /* 860 */ 128, 27, 160, 68, 69, 70, 71, 72, 73, 74,
/* 870 */ 75, 76, 77, 78, 79, 80, 150, 82, 83, 84,
/* 880 */ 85, 86, 87, 88, 89, 90, 91, 92, 19, 150,
- /* 890 */ 22, 165, 150, 23, 150, 25, 150, 166, 91, 92,
- /* 900 */ 174, 175, 22, 217, 165, 150, 102, 165, 150, 165,
- /* 910 */ 150, 165, 150, 174, 175, 19, 174, 175, 49, 50,
- /* 920 */ 165, 86, 87, 165, 23, 165, 25, 165, 24, 174,
- /* 930 */ 175, 187, 174, 175, 174, 175, 205, 68, 69, 70,
+ /* 890 */ 23, 165, 150, 23, 216, 25, 194, 32, 39, 173,
+ /* 900 */ 174, 135, 150, 137, 165, 150, 41, 165, 150, 52,
+ /* 910 */ 238, 104, 173, 174, 29, 173, 174, 165, 49, 50,
+ /* 920 */ 165, 219, 238, 165, 238, 173, 174, 52, 173, 174,
+ /* 930 */ 22, 173, 174, 23, 23, 160, 25, 68, 69, 70,
/* 940 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
/* 950 */ 150, 82, 83, 84, 85, 86, 87, 88, 89, 90,
- /* 960 */ 91, 92, 19, 150, 150, 165, 150, 150, 166, 23,
- /* 970 */ 150, 25, 160, 20, 174, 175, 1, 2, 165, 165,
- /* 980 */ 104, 165, 165, 43, 150, 165, 240, 150, 49, 50,
- /* 990 */ 174, 175, 49, 50, 23, 23, 25, 25, 53, 165,
- /* 1000 */ 187, 187, 165, 23, 187, 25, 194, 205, 174, 175,
- /* 1010 */ 71, 72, 69, 70, 71, 72, 73, 74, 75, 76,
+ /* 960 */ 91, 92, 19, 150, 150, 165, 150, 245, 246, 194,
+ /* 970 */ 150, 144, 145, 173, 174, 160, 150, 22, 165, 165,
+ /* 980 */ 22, 165, 150, 150, 116, 165, 173, 174, 52, 173,
+ /* 990 */ 174, 165, 49, 50, 22, 150, 128, 165, 165, 173,
+ /* 1000 */ 174, 187, 166, 166, 22, 173, 174, 187, 109, 194,
+ /* 1010 */ 165, 68, 69, 70, 71, 72, 73, 74, 75, 76,
/* 1020 */ 77, 78, 79, 80, 150, 82, 83, 84, 85, 86,
- /* 1030 */ 87, 88, 89, 90, 91, 92, 19, 98, 150, 165,
- /* 1040 */ 150, 160, 150, 59, 25, 53, 104, 22, 174, 175,
- /* 1050 */ 213, 138, 5, 165, 1, 165, 150, 165, 150, 150,
- /* 1060 */ 240, 150, 174, 175, 174, 175, 49, 50, 118, 150,
- /* 1070 */ 35, 165, 27, 165, 165, 194, 165, 108, 127, 76,
- /* 1080 */ 174, 175, 174, 175, 165, 174, 175, 70, 71, 72,
- /* 1090 */ 73, 74, 75, 76, 77, 78, 79, 80, 166, 82,
+ /* 1030 */ 87, 88, 89, 90, 91, 92, 19, 150, 193, 165,
+ /* 1040 */ 102, 205, 205, 150, 150, 247, 248, 173, 174, 19,
+ /* 1050 */ 150, 20, 165, 150, 150, 150, 150, 150, 165, 165,
+ /* 1060 */ 173, 174, 49, 50, 104, 165, 49, 50, 165, 165,
+ /* 1070 */ 165, 165, 165, 173, 174, 43, 173, 174, 173, 174,
+ /* 1080 */ 187, 24, 190, 191, 71, 72, 69, 70, 71, 72,
+ /* 1090 */ 73, 74, 75, 76, 77, 78, 79, 80, 150, 82,
/* 1100 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
- /* 1110 */ 19, 20, 193, 22, 150, 150, 150, 26, 27, 76,
- /* 1120 */ 150, 22, 1, 150, 119, 121, 217, 20, 37, 165,
- /* 1130 */ 165, 165, 16, 19, 20, 165, 22, 205, 165, 119,
- /* 1140 */ 26, 27, 108, 128, 150, 150, 150, 56, 150, 22,
- /* 1150 */ 150, 37, 150, 127, 160, 23, 150, 66, 193, 165,
- /* 1160 */ 165, 165, 16, 165, 23, 165, 150, 165, 174, 175,
- /* 1170 */ 56, 165, 150, 65, 174, 175, 15, 86, 87, 88,
- /* 1180 */ 66, 165, 140, 150, 93, 94, 95, 165, 194, 98,
- /* 1190 */ 174, 175, 22, 3, 164, 193, 174, 175, 165, 150,
- /* 1200 */ 86, 87, 4, 180, 150, 248, 251, 93, 94, 95,
- /* 1210 */ 216, 180, 98, 251, 165, 221, 150, 149, 6, 165,
- /* 1220 */ 129, 130, 131, 132, 133, 134, 193, 150, 174, 175,
- /* 1230 */ 116, 165, 19, 20, 150, 22, 149, 151, 150, 26,
- /* 1240 */ 27, 149, 165, 129, 130, 131, 132, 133, 134, 165,
- /* 1250 */ 37, 174, 175, 165, 149, 19, 20, 13, 22, 150,
- /* 1260 */ 150, 150, 26, 27, 146, 147, 151, 150, 25, 56,
- /* 1270 */ 152, 159, 154, 37, 165, 165, 165, 193, 160, 66,
- /* 1280 */ 116, 193, 165, 174, 175, 174, 175, 194, 199, 150,
- /* 1290 */ 200, 126, 56, 124, 123, 150, 201, 122, 150, 86,
- /* 1300 */ 87, 150, 66, 193, 165, 202, 93, 94, 95, 150,
- /* 1310 */ 165, 98, 194, 165, 125, 22, 165, 150, 150, 26,
- /* 1320 */ 27, 135, 86, 87, 165, 174, 175, 203, 226, 93,
- /* 1330 */ 94, 95, 165, 165, 98, 150, 218, 150, 193, 157,
- /* 1340 */ 118, 157, 129, 130, 131, 132, 133, 134, 5, 104,
- /* 1350 */ 165, 211, 165, 10, 11, 12, 13, 14, 150, 66,
- /* 1360 */ 17, 174, 175, 210, 246, 129, 130, 131, 132, 133,
- /* 1370 */ 134, 150, 210, 165, 31, 121, 33, 150, 150, 86,
- /* 1380 */ 87, 176, 174, 175, 150, 42, 165, 94, 211, 210,
- /* 1390 */ 150, 98, 165, 165, 211, 174, 175, 150, 55, 165,
- /* 1400 */ 57, 150, 174, 175, 61, 165, 150, 64, 174, 175,
- /* 1410 */ 150, 150, 165, 150, 174, 175, 165, 104, 150, 184,
- /* 1420 */ 150, 165, 129, 130, 131, 165, 165, 150, 165, 150,
- /* 1430 */ 150, 176, 150, 165, 47, 165, 150, 150, 176, 103,
- /* 1440 */ 150, 22, 165, 178, 165, 165, 179, 165, 105, 106,
- /* 1450 */ 107, 165, 165, 229, 111, 165, 92, 176, 229, 116,
- /* 1460 */ 184, 176, 179, 156, 176, 176, 18, 157, 156, 237,
- /* 1470 */ 45, 157, 156, 135, 157, 157, 238, 156, 68, 157,
- /* 1480 */ 189, 189, 139, 219, 22, 157, 18, 192, 192, 192,
- /* 1490 */ 192, 189, 219, 199, 157, 242, 40, 157, 199, 242,
- /* 1500 */ 153, 157, 38, 245, 196, 166, 232, 198, 177, 177,
- /* 1510 */ 232, 227, 209, 178, 166, 182, 166, 148, 177, 177,
- /* 1520 */ 209, 196, 177, 199, 209, 199, 166, 208, 92, 195,
- /* 1530 */ 174, 174, 183, 252, 183, 183, 252, 191, 252, 235,
- /* 1540 */ 186, 241, 241, 252, 186, 252, 252, 252, 252, 252,
- /* 1550 */ 252, 252, 252, 252, 252, 252, 236,
+ /* 1110 */ 19, 98, 150, 165, 150, 150, 150, 150, 150, 150,
+ /* 1120 */ 59, 173, 174, 25, 150, 190, 191, 165, 53, 165,
+ /* 1130 */ 165, 165, 165, 165, 165, 173, 174, 173, 174, 165,
+ /* 1140 */ 49, 50, 91, 92, 1, 2, 53, 173, 174, 138,
+ /* 1150 */ 104, 22, 5, 1, 35, 118, 127, 150, 193, 193,
+ /* 1160 */ 193, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ /* 1170 */ 79, 80, 165, 82, 83, 84, 85, 86, 87, 88,
+ /* 1180 */ 89, 90, 91, 92, 19, 20, 150, 22, 150, 27,
+ /* 1190 */ 150, 26, 27, 108, 150, 22, 76, 76, 150, 25,
+ /* 1200 */ 193, 165, 37, 165, 150, 165, 22, 19, 20, 165,
+ /* 1210 */ 22, 173, 174, 165, 26, 27, 23, 150, 119, 165,
+ /* 1220 */ 150, 56, 150, 150, 150, 37, 16, 173, 174, 193,
+ /* 1230 */ 150, 66, 165, 193, 1, 165, 121, 165, 165, 165,
+ /* 1240 */ 20, 146, 147, 119, 56, 165, 150, 152, 16, 154,
+ /* 1250 */ 150, 86, 87, 88, 66, 160, 150, 150, 93, 94,
+ /* 1260 */ 95, 165, 150, 98, 108, 165, 127, 23, 65, 173,
+ /* 1270 */ 174, 165, 165, 150, 86, 87, 128, 165, 150, 173,
+ /* 1280 */ 174, 93, 94, 95, 23, 150, 98, 15, 165, 194,
+ /* 1290 */ 150, 140, 22, 165, 129, 130, 131, 132, 133, 134,
+ /* 1300 */ 165, 173, 174, 3, 116, 165, 19, 20, 150, 22,
+ /* 1310 */ 4, 150, 217, 26, 27, 179, 179, 129, 130, 131,
+ /* 1320 */ 132, 133, 134, 165, 37, 150, 165, 150, 164, 19,
+ /* 1330 */ 20, 150, 22, 246, 149, 249, 26, 27, 249, 244,
+ /* 1340 */ 165, 150, 165, 56, 6, 150, 165, 37, 173, 174,
+ /* 1350 */ 173, 174, 150, 66, 173, 174, 165, 149, 149, 13,
+ /* 1360 */ 165, 25, 150, 150, 150, 149, 56, 165, 150, 116,
+ /* 1370 */ 151, 150, 150, 86, 87, 150, 66, 165, 165, 165,
+ /* 1380 */ 93, 94, 95, 165, 150, 98, 165, 165, 151, 22,
+ /* 1390 */ 165, 194, 150, 26, 27, 150, 86, 87, 159, 165,
+ /* 1400 */ 199, 126, 123, 93, 94, 95, 200, 165, 98, 124,
+ /* 1410 */ 165, 122, 201, 125, 225, 135, 129, 130, 131, 132,
+ /* 1420 */ 133, 134, 5, 157, 157, 202, 118, 10, 11, 12,
+ /* 1430 */ 13, 14, 203, 66, 17, 104, 210, 121, 211, 129,
+ /* 1440 */ 130, 131, 132, 133, 134, 210, 175, 211, 31, 211,
+ /* 1450 */ 33, 210, 104, 86, 87, 47, 175, 183, 175, 42,
+ /* 1460 */ 103, 94, 178, 177, 22, 98, 175, 92, 228, 175,
+ /* 1470 */ 175, 228, 55, 183, 57, 178, 175, 156, 61, 18,
+ /* 1480 */ 157, 64, 156, 235, 157, 156, 45, 157, 236, 157,
+ /* 1490 */ 135, 156, 189, 68, 157, 218, 129, 130, 131, 22,
+ /* 1500 */ 189, 199, 157, 156, 192, 18, 192, 192, 199, 192,
+ /* 1510 */ 218, 189, 40, 157, 38, 157, 240, 157, 240, 153,
+ /* 1520 */ 196, 181, 105, 106, 107, 243, 198, 166, 111, 230,
+ /* 1530 */ 176, 226, 239, 116, 230, 176, 166, 166, 176, 148,
+ /* 1540 */ 199, 177, 209, 209, 166, 196, 239, 208, 185, 199,
+ /* 1550 */ 92, 209, 233, 173, 234, 182, 139, 173, 182, 191,
+ /* 1560 */ 195, 182, 250, 186,
};
-#define YY_SHIFT_USE_DFLT (-74)
-#define YY_SHIFT_COUNT (418)
-#define YY_SHIFT_MIN (-73)
-#define YY_SHIFT_MAX (1468)
+#define YY_SHIFT_USE_DFLT (-70)
+#define YY_SHIFT_COUNT (416)
+#define YY_SHIFT_MIN (-69)
+#define YY_SHIFT_MAX (1487)
static const short yy_shift_ofst[] = {
- /* 0 */ 975, 1114, 1343, 1114, 1213, 1213, 90, 90, 0, -19,
- /* 10 */ 1213, 1213, 1213, 1213, 1213, 345, 445, 721, 1091, 1213,
- /* 20 */ 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213,
- /* 30 */ 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213,
- /* 40 */ 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1236, 1213, 1213,
- /* 50 */ 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213,
- /* 60 */ 1213, 199, 445, 445, 835, 835, 365, 1164, 55, 647,
- /* 70 */ 573, 499, 425, 351, 277, 203, 129, 795, 795, 795,
- /* 80 */ 795, 795, 795, 795, 795, 795, 795, 795, 795, 795,
- /* 90 */ 795, 795, 795, 795, 795, 869, 795, 943, 1017, 1017,
- /* 100 */ -69, -45, -45, -45, -45, -45, -1, 58, 138, 100,
- /* 110 */ 445, 445, 445, 445, 445, 445, 445, 445, 445, 445,
- /* 120 */ 445, 445, 445, 445, 445, 445, 537, 438, 445, 445,
- /* 130 */ 445, 445, 445, 365, 807, 1436, -74, -74, -74, 1293,
- /* 140 */ 73, 434, 434, 311, 314, 290, 283, 286, 540, 467,
- /* 150 */ 445, 445, 445, 445, 445, 445, 445, 445, 445, 445,
- /* 160 */ 445, 445, 445, 445, 445, 445, 445, 445, 445, 445,
- /* 170 */ 445, 445, 445, 445, 445, 445, 445, 445, 445, 445,
- /* 180 */ 445, 445, 65, 722, 722, 722, 688, 266, 1164, 1164,
- /* 190 */ 1164, -74, -74, -74, 136, 168, 168, 234, 360, 360,
- /* 200 */ 360, 430, 372, 435, 352, 278, 126, -36, -36, -36,
- /* 210 */ -36, 421, 651, -36, -36, 592, 292, 212, 623, 158,
- /* 220 */ 204, 204, 505, 158, 505, 144, 365, 154, 365, 154,
- /* 230 */ 645, 154, 204, 154, 154, 535, 548, 548, 365, 387,
- /* 240 */ 508, 233, 1464, 1222, 1222, 1456, 1456, 1222, 1462, 1410,
- /* 250 */ 1165, 1468, 1468, 1468, 1468, 1222, 1165, 1462, 1410, 1410,
- /* 260 */ 1222, 1448, 1338, 1425, 1222, 1222, 1448, 1222, 1448, 1222,
- /* 270 */ 1448, 1419, 1313, 1313, 1313, 1387, 1364, 1364, 1419, 1313,
- /* 280 */ 1336, 1313, 1387, 1313, 1313, 1254, 1245, 1254, 1245, 1254,
- /* 290 */ 1245, 1222, 1222, 1186, 1189, 1175, 1169, 1171, 1165, 1164,
- /* 300 */ 1243, 1244, 1244, 1212, 1212, 1212, 1212, -74, -74, -74,
- /* 310 */ -74, -74, -74, 939, 104, 680, 571, 327, 1, 980,
- /* 320 */ 26, 972, 971, 946, 901, 870, 830, 806, 54, 21,
- /* 330 */ -73, 510, 242, 1198, 1190, 1170, 1042, 1161, 1108, 1146,
- /* 340 */ 1141, 1132, 1015, 1127, 1026, 1034, 1020, 1107, 1004, 1116,
- /* 350 */ 1121, 1005, 1099, 951, 1043, 1003, 969, 1045, 1035, 950,
- /* 360 */ 1053, 1047, 1025, 942, 913, 992, 1019, 945, 984, 940,
- /* 370 */ 876, 904, 953, 896, 748, 804, 880, 786, 868, 819,
- /* 380 */ 805, 810, 773, 751, 766, 706, 716, 691, 681, 568,
- /* 390 */ 655, 638, 676, 516, 541, 594, 599, 567, 541, 534,
- /* 400 */ 507, 527, 498, 523, 466, 382, 409, 384, 357, 6,
- /* 410 */ 240, 224, 143, 62, 18, 71, 39, 9, 5,
+ /* 0 */ 1143, 1188, 1417, 1188, 1287, 1287, 138, 138, -2, -19,
+ /* 10 */ 1287, 1287, 1287, 1287, 347, 362, 129, 129, 795, 1165,
+ /* 20 */ 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
+ /* 30 */ 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
+ /* 40 */ 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1310, 1287,
+ /* 50 */ 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
+ /* 60 */ 1287, 1287, 286, 362, 362, 538, 538, 231, 1253, 55,
+ /* 70 */ 721, 647, 573, 499, 425, 351, 277, 203, 869, 869,
+ /* 80 */ 869, 869, 869, 869, 869, 869, 869, 869, 869, 869,
+ /* 90 */ 869, 869, 869, 943, 869, 1017, 1091, 1091, -69, -45,
+ /* 100 */ -45, -45, -45, -45, -1, 24, 245, 362, 362, 362,
+ /* 110 */ 362, 362, 362, 362, 362, 362, 362, 362, 362, 362,
+ /* 120 */ 362, 362, 362, 388, 356, 362, 362, 362, 362, 362,
+ /* 130 */ 732, 868, 231, 1051, 1458, -70, -70, -70, 1367, 57,
+ /* 140 */ 434, 434, 289, 291, 285, 1, 204, 572, 539, 362,
+ /* 150 */ 362, 362, 362, 362, 362, 362, 362, 362, 362, 362,
+ /* 160 */ 362, 362, 362, 362, 362, 362, 362, 362, 362, 362,
+ /* 170 */ 362, 362, 362, 362, 362, 362, 362, 362, 362, 362,
+ /* 180 */ 362, 506, 506, 506, 705, 1253, 1253, 1253, -70, -70,
+ /* 190 */ -70, 171, 171, 160, 502, 502, 502, 446, 432, 511,
+ /* 200 */ 422, 358, 335, -12, -12, -12, -12, 576, 294, -12,
+ /* 210 */ -12, 295, 595, 141, 600, 730, 723, 723, 805, 730,
+ /* 220 */ 805, 439, 911, 231, 865, 231, 865, 807, 865, 723,
+ /* 230 */ 766, 633, 633, 231, 284, 63, 608, 1476, 1308, 1308,
+ /* 240 */ 1472, 1472, 1308, 1477, 1425, 1275, 1487, 1487, 1487, 1487,
+ /* 250 */ 1308, 1461, 1275, 1477, 1425, 1425, 1308, 1461, 1355, 1441,
+ /* 260 */ 1308, 1308, 1461, 1308, 1461, 1308, 1461, 1442, 1348, 1348,
+ /* 270 */ 1348, 1408, 1375, 1375, 1442, 1348, 1357, 1348, 1408, 1348,
+ /* 280 */ 1348, 1316, 1331, 1316, 1331, 1316, 1331, 1308, 1308, 1280,
+ /* 290 */ 1288, 1289, 1285, 1279, 1275, 1253, 1336, 1346, 1346, 1338,
+ /* 300 */ 1338, 1338, 1338, -70, -70, -70, -70, -70, -70, 1013,
+ /* 310 */ 467, 612, 84, 179, -28, 870, 410, 761, 760, 667,
+ /* 320 */ 650, 531, 220, 361, 331, 125, 127, 97, 1306, 1300,
+ /* 330 */ 1270, 1151, 1272, 1203, 1232, 1261, 1244, 1148, 1174, 1139,
+ /* 340 */ 1156, 1124, 1220, 1115, 1210, 1233, 1099, 1193, 1184, 1174,
+ /* 350 */ 1173, 1029, 1121, 1120, 1085, 1162, 1119, 1037, 1152, 1147,
+ /* 360 */ 1129, 1046, 1011, 1093, 1098, 1075, 1061, 1032, 960, 1057,
+ /* 370 */ 1031, 1030, 899, 938, 982, 936, 972, 958, 910, 955,
+ /* 380 */ 875, 885, 908, 857, 859, 867, 804, 590, 834, 747,
+ /* 390 */ 818, 513, 611, 741, 673, 637, 611, 606, 603, 579,
+ /* 400 */ 501, 541, 468, 386, 445, 395, 376, 281, 185, 120,
+ /* 410 */ 92, 75, 45, 114, 25, 11, 5,
};
-#define YY_REDUCE_USE_DFLT (-142)
-#define YY_REDUCE_COUNT (312)
-#define YY_REDUCE_MIN (-141)
-#define YY_REDUCE_MAX (1369)
+#define YY_REDUCE_USE_DFLT (-169)
+#define YY_REDUCE_COUNT (308)
+#define YY_REDUCE_MIN (-168)
+#define YY_REDUCE_MAX (1391)
static const short yy_reduce_ofst[] = {
- /* 0 */ -141, 994, 1118, 223, 157, -53, 93, 89, 83, 375,
- /* 10 */ 386, 381, 379, 308, 295, 325, -47, 27, 1240, 1234,
- /* 20 */ 1228, 1221, 1208, 1187, 1151, 1111, 1109, 1077, 1054, 1022,
- /* 30 */ 1016, 1000, 911, 908, 906, 890, 888, 874, 834, 816,
- /* 40 */ 800, 760, 758, 755, 742, 739, 726, 685, 672, 668,
- /* 50 */ 665, 652, 611, 609, 607, 604, 591, 578, 526, 519,
- /* 60 */ 453, 474, 454, 461, 443, 245, 442, 473, 484, 484,
- /* 70 */ 484, 484, 484, 484, 484, 484, 484, 484, 484, 484,
- /* 80 */ 484, 484, 484, 484, 484, 484, 484, 484, 484, 484,
- /* 90 */ 484, 484, 484, 484, 484, 484, 484, 484, 484, 484,
- /* 100 */ 484, 484, 484, 484, 484, 484, 484, 130, 484, 484,
- /* 110 */ 1145, 909, 1110, 1088, 1084, 1033, 1002, 965, 820, 837,
- /* 120 */ 746, 686, 612, 817, 610, 919, 221, 563, 814, 813,
- /* 130 */ 744, 669, 470, 543, 484, 484, 484, 484, 484, 291,
- /* 140 */ 569, 671, 658, 970, 1290, 1287, 1286, 1282, 518, 518,
- /* 150 */ 1280, 1279, 1277, 1270, 1268, 1263, 1261, 1260, 1256, 1251,
- /* 160 */ 1247, 1227, 1185, 1168, 1167, 1159, 1148, 1139, 1117, 1066,
- /* 170 */ 1049, 1006, 998, 996, 995, 973, 970, 966, 964, 892,
- /* 180 */ 762, -52, 881, 932, 802, 731, 619, 812, 664, 660,
- /* 190 */ 627, 392, 331, 124, 1358, 1357, 1356, 1354, 1352, 1351,
- /* 200 */ 1349, 1319, 1334, 1346, 1334, 1334, 1334, 1334, 1334, 1334,
- /* 210 */ 1334, 1320, 1304, 1334, 1334, 1319, 1360, 1325, 1369, 1326,
- /* 220 */ 1315, 1311, 1301, 1324, 1300, 1335, 1350, 1345, 1348, 1342,
- /* 230 */ 1333, 1341, 1303, 1332, 1331, 1284, 1278, 1274, 1339, 1309,
- /* 240 */ 1308, 1347, 1258, 1344, 1340, 1257, 1253, 1337, 1273, 1302,
- /* 250 */ 1299, 1298, 1297, 1296, 1295, 1328, 1294, 1264, 1292, 1291,
- /* 260 */ 1322, 1321, 1238, 1232, 1318, 1317, 1316, 1314, 1312, 1310,
- /* 270 */ 1307, 1283, 1289, 1288, 1285, 1276, 1229, 1224, 1267, 1281,
- /* 280 */ 1265, 1262, 1235, 1255, 1205, 1183, 1179, 1177, 1162, 1140,
- /* 290 */ 1153, 1184, 1182, 1102, 1124, 1103, 1095, 1090, 1089, 1093,
- /* 300 */ 1112, 1115, 1086, 1105, 1092, 1087, 1068, 962, 955, 957,
- /* 310 */ 1031, 1023, 1030,
+ /* 0 */ -141, 90, 1095, 222, 158, 156, 19, 17, 10, -104,
+ /* 10 */ 378, 316, 311, 12, 180, 249, 598, 464, 397, 1181,
+ /* 20 */ 1177, 1175, 1128, 1106, 1096, 1054, 1038, 974, 964, 962,
+ /* 30 */ 948, 905, 903, 900, 887, 874, 832, 826, 816, 813,
+ /* 40 */ 800, 758, 755, 752, 742, 739, 726, 685, 681, 668,
+ /* 50 */ 665, 652, 607, 604, 594, 591, 578, 530, 528, 526,
+ /* 60 */ 385, 18, 477, 466, 519, 444, 350, 435, 405, 488,
+ /* 70 */ 488, 488, 488, 488, 488, 488, 488, 488, 488, 488,
+ /* 80 */ 488, 488, 488, 488, 488, 488, 488, 488, 488, 488,
+ /* 90 */ 488, 488, 488, 488, 488, 488, 488, 488, 488, 488,
+ /* 100 */ 488, 488, 488, 488, 488, 488, 488, 1040, 678, 1036,
+ /* 110 */ 1007, 967, 966, 965, 845, 686, 610, 684, 317, 672,
+ /* 120 */ 893, 327, 623, 522, -7, 820, 814, 157, 154, 101,
+ /* 130 */ 702, 494, 580, 488, 488, 488, 488, 488, 614, 586,
+ /* 140 */ 935, 892, 968, 1245, 1242, 1234, 1225, 798, 798, 1222,
+ /* 150 */ 1221, 1218, 1214, 1213, 1212, 1202, 1195, 1191, 1161, 1158,
+ /* 160 */ 1140, 1135, 1123, 1112, 1107, 1100, 1080, 1074, 1073, 1072,
+ /* 170 */ 1070, 1067, 1048, 1044, 969, 968, 907, 906, 904, 894,
+ /* 180 */ 833, 837, 836, 340, 827, 815, 775, 68, 722, 646,
+ /* 190 */ -168, 1384, 1380, 1377, 1379, 1376, 1373, 1339, 1365, 1368,
+ /* 200 */ 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1320, 1319, 1365,
+ /* 210 */ 1365, 1339, 1378, 1349, 1391, 1350, 1342, 1334, 1307, 1341,
+ /* 220 */ 1293, 1364, 1363, 1371, 1362, 1370, 1359, 1340, 1354, 1333,
+ /* 230 */ 1305, 1304, 1299, 1361, 1328, 1324, 1366, 1282, 1360, 1358,
+ /* 240 */ 1278, 1276, 1356, 1292, 1322, 1309, 1317, 1315, 1314, 1312,
+ /* 250 */ 1345, 1347, 1302, 1277, 1311, 1303, 1337, 1335, 1252, 1248,
+ /* 260 */ 1332, 1330, 1329, 1327, 1326, 1323, 1321, 1297, 1301, 1295,
+ /* 270 */ 1294, 1290, 1243, 1240, 1284, 1291, 1286, 1283, 1274, 1281,
+ /* 280 */ 1271, 1238, 1241, 1236, 1235, 1227, 1226, 1267, 1266, 1189,
+ /* 290 */ 1229, 1223, 1211, 1206, 1201, 1197, 1239, 1237, 1219, 1216,
+ /* 300 */ 1209, 1208, 1185, 1089, 1086, 1087, 1137, 1136, 1164,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 635, 870, 959, 959, 959, 870, 899, 899, 959, 759,
- /* 10 */ 959, 959, 959, 959, 868, 959, 959, 933, 959, 959,
- /* 20 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 30 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 40 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 50 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 60 */ 959, 959, 959, 959, 899, 899, 674, 763, 794, 959,
- /* 70 */ 959, 959, 959, 959, 959, 959, 959, 932, 934, 809,
- /* 80 */ 808, 802, 801, 912, 774, 799, 792, 785, 796, 871,
- /* 90 */ 864, 865, 863, 867, 872, 959, 795, 831, 848, 830,
- /* 100 */ 842, 847, 854, 846, 843, 833, 832, 666, 834, 835,
- /* 110 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 120 */ 959, 959, 959, 959, 959, 959, 661, 728, 959, 959,
- /* 130 */ 959, 959, 959, 959, 836, 837, 851, 850, 849, 959,
- /* 140 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 150 */ 959, 939, 937, 959, 883, 959, 959, 959, 959, 959,
- /* 160 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 170 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 180 */ 959, 641, 959, 759, 759, 759, 635, 959, 959, 959,
- /* 190 */ 959, 951, 763, 753, 719, 959, 959, 959, 959, 959,
- /* 200 */ 959, 959, 959, 959, 959, 959, 959, 804, 742, 922,
- /* 210 */ 924, 959, 905, 740, 663, 761, 676, 751, 643, 798,
- /* 220 */ 776, 776, 917, 798, 917, 700, 959, 788, 959, 788,
- /* 230 */ 697, 788, 776, 788, 788, 866, 959, 959, 959, 760,
- /* 240 */ 751, 959, 944, 767, 767, 936, 936, 767, 810, 732,
- /* 250 */ 798, 739, 739, 739, 739, 767, 798, 810, 732, 732,
- /* 260 */ 767, 658, 911, 909, 767, 767, 658, 767, 658, 767,
- /* 270 */ 658, 876, 730, 730, 730, 715, 880, 880, 876, 730,
- /* 280 */ 700, 730, 715, 730, 730, 780, 775, 780, 775, 780,
- /* 290 */ 775, 767, 767, 959, 793, 781, 791, 789, 798, 959,
- /* 300 */ 718, 651, 651, 640, 640, 640, 640, 956, 956, 951,
- /* 310 */ 702, 702, 684, 959, 959, 959, 959, 959, 959, 959,
- /* 320 */ 885, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 330 */ 959, 959, 959, 959, 636, 946, 959, 959, 943, 959,
- /* 340 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 350 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 915,
- /* 360 */ 959, 959, 959, 959, 959, 959, 908, 907, 959, 959,
- /* 370 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 380 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 959,
- /* 390 */ 959, 959, 959, 959, 790, 959, 782, 959, 869, 959,
- /* 400 */ 959, 959, 959, 959, 959, 959, 959, 959, 959, 745,
- /* 410 */ 819, 959, 818, 822, 817, 668, 959, 649, 959, 632,
- /* 420 */ 637, 955, 958, 957, 954, 953, 952, 947, 945, 942,
- /* 430 */ 941, 940, 938, 935, 931, 889, 887, 894, 893, 892,
- /* 440 */ 891, 890, 888, 886, 884, 805, 803, 800, 797, 930,
- /* 450 */ 882, 741, 738, 737, 657, 948, 914, 923, 921, 811,
- /* 460 */ 920, 919, 918, 916, 913, 900, 807, 806, 733, 874,
- /* 470 */ 873, 660, 904, 903, 902, 906, 910, 901, 769, 659,
- /* 480 */ 656, 665, 722, 721, 729, 727, 726, 725, 724, 723,
- /* 490 */ 720, 667, 675, 686, 714, 699, 698, 879, 881, 878,
- /* 500 */ 877, 707, 706, 712, 711, 710, 709, 708, 705, 704,
- /* 510 */ 703, 696, 695, 701, 694, 717, 716, 713, 693, 736,
- /* 520 */ 735, 734, 731, 692, 691, 690, 822, 689, 688, 828,
- /* 530 */ 827, 815, 858, 756, 755, 754, 766, 765, 778, 777,
- /* 540 */ 813, 812, 779, 764, 758, 757, 773, 772, 771, 770,
- /* 550 */ 762, 752, 784, 787, 786, 783, 860, 768, 857, 929,
- /* 560 */ 928, 927, 926, 925, 862, 861, 829, 826, 679, 680,
- /* 570 */ 898, 896, 897, 895, 682, 681, 678, 677, 859, 747,
- /* 580 */ 746, 855, 852, 844, 840, 856, 853, 845, 841, 839,
- /* 590 */ 838, 824, 823, 821, 820, 816, 825, 670, 748, 744,
- /* 600 */ 743, 814, 750, 749, 687, 685, 683, 664, 662, 655,
- /* 610 */ 653, 652, 654, 650, 648, 647, 646, 645, 644, 673,
- /* 620 */ 672, 671, 669, 668, 642, 639, 638, 634, 633, 631,
+ /* 0 */ 632, 866, 954, 954, 866, 866, 954, 954, 954, 756,
+ /* 10 */ 954, 954, 954, 864, 954, 954, 784, 784, 928, 954,
+ /* 20 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 954,
+ /* 30 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 954,
+ /* 40 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 954,
+ /* 50 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 954,
+ /* 60 */ 954, 954, 954, 954, 954, 954, 954, 671, 760, 790,
+ /* 70 */ 954, 954, 954, 954, 954, 954, 954, 954, 927, 929,
+ /* 80 */ 798, 797, 907, 771, 795, 788, 792, 867, 860, 861,
+ /* 90 */ 859, 863, 868, 954, 791, 827, 844, 826, 838, 843,
+ /* 100 */ 850, 842, 839, 829, 828, 830, 831, 954, 954, 954,
+ /* 110 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 954,
+ /* 120 */ 954, 954, 954, 658, 725, 954, 954, 954, 954, 954,
+ /* 130 */ 954, 954, 954, 832, 833, 847, 846, 845, 954, 663,
+ /* 140 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 954,
+ /* 150 */ 934, 932, 954, 879, 954, 954, 954, 954, 954, 954,
+ /* 160 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 954,
+ /* 170 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 954,
+ /* 180 */ 638, 756, 756, 756, 632, 954, 954, 954, 946, 760,
+ /* 190 */ 750, 954, 954, 954, 954, 954, 954, 954, 954, 954,
+ /* 200 */ 954, 954, 954, 800, 739, 917, 919, 954, 900, 737,
+ /* 210 */ 660, 758, 673, 748, 640, 794, 773, 773, 912, 794,
+ /* 220 */ 912, 696, 719, 954, 784, 954, 784, 693, 784, 773,
+ /* 230 */ 862, 954, 954, 954, 757, 748, 954, 939, 764, 764,
+ /* 240 */ 931, 931, 764, 806, 729, 794, 736, 736, 736, 736,
+ /* 250 */ 764, 655, 794, 806, 729, 729, 764, 655, 906, 904,
+ /* 260 */ 764, 764, 655, 764, 655, 764, 655, 872, 727, 727,
+ /* 270 */ 727, 711, 876, 876, 872, 727, 696, 727, 711, 727,
+ /* 280 */ 727, 777, 772, 777, 772, 777, 772, 764, 764, 954,
+ /* 290 */ 789, 778, 787, 785, 794, 954, 714, 648, 648, 637,
+ /* 300 */ 637, 637, 637, 951, 951, 946, 698, 698, 681, 954,
+ /* 310 */ 954, 954, 954, 954, 954, 954, 881, 954, 954, 954,
+ /* 320 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 633,
+ /* 330 */ 941, 954, 954, 938, 954, 954, 954, 954, 799, 954,
+ /* 340 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 916,
+ /* 350 */ 954, 954, 954, 954, 954, 954, 954, 910, 954, 954,
+ /* 360 */ 954, 954, 954, 954, 903, 902, 954, 954, 954, 954,
+ /* 370 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 954,
+ /* 380 */ 954, 954, 954, 954, 954, 954, 954, 954, 954, 954,
+ /* 390 */ 954, 954, 786, 954, 779, 954, 865, 954, 954, 954,
+ /* 400 */ 954, 954, 954, 954, 954, 954, 954, 742, 815, 954,
+ /* 410 */ 814, 818, 813, 665, 954, 646, 954, 629, 634, 950,
+ /* 420 */ 953, 952, 949, 948, 947, 942, 940, 937, 936, 935,
+ /* 430 */ 933, 930, 926, 885, 883, 890, 889, 888, 887, 886,
+ /* 440 */ 884, 882, 880, 801, 796, 793, 925, 878, 738, 735,
+ /* 450 */ 734, 654, 943, 909, 918, 805, 804, 807, 915, 914,
+ /* 460 */ 913, 911, 908, 895, 803, 802, 730, 870, 869, 657,
+ /* 470 */ 899, 898, 897, 901, 905, 896, 766, 656, 653, 662,
+ /* 480 */ 717, 718, 726, 724, 723, 722, 721, 720, 716, 664,
+ /* 490 */ 672, 710, 695, 694, 875, 877, 874, 873, 703, 702,
+ /* 500 */ 708, 707, 706, 705, 704, 701, 700, 699, 692, 691,
+ /* 510 */ 697, 690, 713, 712, 709, 689, 733, 732, 731, 728,
+ /* 520 */ 688, 687, 686, 818, 685, 684, 824, 823, 811, 854,
+ /* 530 */ 753, 752, 751, 763, 762, 775, 774, 809, 808, 776,
+ /* 540 */ 761, 755, 754, 770, 769, 768, 767, 759, 749, 781,
+ /* 550 */ 783, 782, 780, 856, 765, 853, 924, 923, 922, 921,
+ /* 560 */ 920, 858, 857, 825, 822, 676, 677, 893, 892, 894,
+ /* 570 */ 891, 679, 678, 675, 674, 855, 744, 743, 851, 848,
+ /* 580 */ 840, 836, 852, 849, 841, 837, 835, 834, 820, 819,
+ /* 590 */ 817, 816, 812, 821, 667, 745, 741, 740, 810, 747,
+ /* 600 */ 746, 683, 682, 680, 661, 659, 652, 650, 649, 651,
+ /* 610 */ 647, 645, 644, 643, 642, 641, 670, 669, 668, 666,
+ /* 620 */ 665, 639, 636, 635, 631, 630, 628,
};
/* The next table maps tokens into fallback tokens. If a construct
@@ -106929,26 +109273,26 @@ static const char *const yyTokenName[] = {
"select", "column", "columnid", "type",
"carglist", "id", "ids", "typetoken",
"typename", "signed", "plus_num", "minus_num",
- "carg", "ccons", "term", "expr",
- "onconf", "sortorder", "autoinc", "idxlist_opt",
- "refargs", "defer_subclause", "refarg", "refact",
- "init_deferred_pred_opt", "conslist", "tcons", "idxlist",
+ "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", "oneselect", "multiselect_op",
"distinct", "selcollist", "from", "where_opt",
"groupby_opt", "having_opt", "orderby_opt", "limit_opt",
"sclp", "as", "seltablist", "stl_prefix",
"joinop", "indexed_opt", "on_opt", "using_opt",
- "joinop2", "inscollist", "sortlist", "sortitem",
- "nexprlist", "setlist", "insert_cmd", "inscollist_opt",
- "itemlist", "exprlist", "likeop", "between_op",
- "in_op", "case_operand", "case_exprlist", "case_else",
- "uniqueflag", "collate", "nmnum", "plus_opt",
- "number", "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",
+ "joinop2", "inscollist", "sortlist", "nexprlist",
+ "setlist", "insert_cmd", "inscollist_opt", "valuelist",
+ "exprlist", "likeop", "between_op", "in_op",
+ "case_operand", "case_exprlist", "case_else", "uniqueflag",
+ "collate", "nmnum", "number", "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",
};
#endif /* NDEBUG */
@@ -107009,46 +109353,46 @@ static const char *const yyRuleName[] = {
/* 50 */ "typename ::= typename ids",
/* 51 */ "signed ::= plus_num",
/* 52 */ "signed ::= minus_num",
- /* 53 */ "carglist ::= carglist carg",
+ /* 53 */ "carglist ::= carglist ccons",
/* 54 */ "carglist ::=",
- /* 55 */ "carg ::= CONSTRAINT nm ccons",
- /* 56 */ "carg ::= ccons",
- /* 57 */ "ccons ::= DEFAULT term",
- /* 58 */ "ccons ::= DEFAULT LP expr RP",
- /* 59 */ "ccons ::= DEFAULT PLUS term",
- /* 60 */ "ccons ::= DEFAULT MINUS term",
- /* 61 */ "ccons ::= DEFAULT id",
- /* 62 */ "ccons ::= NULL onconf",
- /* 63 */ "ccons ::= NOT NULL onconf",
- /* 64 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
- /* 65 */ "ccons ::= UNIQUE onconf",
- /* 66 */ "ccons ::= CHECK LP expr RP",
- /* 67 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
- /* 68 */ "ccons ::= defer_subclause",
- /* 69 */ "ccons ::= COLLATE ids",
- /* 70 */ "autoinc ::=",
- /* 71 */ "autoinc ::= AUTOINCR",
- /* 72 */ "refargs ::=",
- /* 73 */ "refargs ::= refargs refarg",
- /* 74 */ "refarg ::= MATCH nm",
- /* 75 */ "refarg ::= ON INSERT refact",
- /* 76 */ "refarg ::= ON DELETE refact",
- /* 77 */ "refarg ::= ON UPDATE refact",
- /* 78 */ "refact ::= SET NULL",
- /* 79 */ "refact ::= SET DEFAULT",
- /* 80 */ "refact ::= CASCADE",
- /* 81 */ "refact ::= RESTRICT",
- /* 82 */ "refact ::= NO ACTION",
- /* 83 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
- /* 84 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
- /* 85 */ "init_deferred_pred_opt ::=",
- /* 86 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
- /* 87 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
- /* 88 */ "conslist_opt ::=",
- /* 89 */ "conslist_opt ::= COMMA conslist",
- /* 90 */ "conslist ::= conslist COMMA tcons",
- /* 91 */ "conslist ::= conslist tcons",
- /* 92 */ "conslist ::= tcons",
+ /* 55 */ "ccons ::= CONSTRAINT nm",
+ /* 56 */ "ccons ::= DEFAULT term",
+ /* 57 */ "ccons ::= DEFAULT LP expr RP",
+ /* 58 */ "ccons ::= DEFAULT PLUS term",
+ /* 59 */ "ccons ::= DEFAULT MINUS term",
+ /* 60 */ "ccons ::= DEFAULT id",
+ /* 61 */ "ccons ::= NULL onconf",
+ /* 62 */ "ccons ::= NOT NULL onconf",
+ /* 63 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
+ /* 64 */ "ccons ::= UNIQUE onconf",
+ /* 65 */ "ccons ::= CHECK LP expr RP",
+ /* 66 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
+ /* 67 */ "ccons ::= defer_subclause",
+ /* 68 */ "ccons ::= COLLATE ids",
+ /* 69 */ "autoinc ::=",
+ /* 70 */ "autoinc ::= AUTOINCR",
+ /* 71 */ "refargs ::=",
+ /* 72 */ "refargs ::= refargs refarg",
+ /* 73 */ "refarg ::= MATCH nm",
+ /* 74 */ "refarg ::= ON INSERT refact",
+ /* 75 */ "refarg ::= ON DELETE refact",
+ /* 76 */ "refarg ::= ON UPDATE refact",
+ /* 77 */ "refact ::= SET NULL",
+ /* 78 */ "refact ::= SET DEFAULT",
+ /* 79 */ "refact ::= CASCADE",
+ /* 80 */ "refact ::= RESTRICT",
+ /* 81 */ "refact ::= NO ACTION",
+ /* 82 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
+ /* 83 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
+ /* 84 */ "init_deferred_pred_opt ::=",
+ /* 85 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
+ /* 86 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
+ /* 87 */ "conslist_opt ::=",
+ /* 88 */ "conslist_opt ::= COMMA conslist",
+ /* 89 */ "conslist ::= conslist tconscomma tcons",
+ /* 90 */ "conslist ::= tcons",
+ /* 91 */ "tconscomma ::= COMMA",
+ /* 92 */ "tconscomma ::=",
/* 93 */ "tcons ::= CONSTRAINT nm",
/* 94 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf",
/* 95 */ "tcons ::= UNIQUE LP idxlist RP onconf",
@@ -107109,182 +109453,180 @@ static const char *const yyRuleName[] = {
/* 150 */ "using_opt ::=",
/* 151 */ "orderby_opt ::=",
/* 152 */ "orderby_opt ::= ORDER BY sortlist",
- /* 153 */ "sortlist ::= sortlist COMMA sortitem sortorder",
- /* 154 */ "sortlist ::= sortitem sortorder",
- /* 155 */ "sortitem ::= expr",
- /* 156 */ "sortorder ::= ASC",
- /* 157 */ "sortorder ::= DESC",
- /* 158 */ "sortorder ::=",
- /* 159 */ "groupby_opt ::=",
- /* 160 */ "groupby_opt ::= GROUP BY nexprlist",
- /* 161 */ "having_opt ::=",
- /* 162 */ "having_opt ::= HAVING expr",
- /* 163 */ "limit_opt ::=",
- /* 164 */ "limit_opt ::= LIMIT expr",
- /* 165 */ "limit_opt ::= LIMIT expr OFFSET expr",
- /* 166 */ "limit_opt ::= LIMIT expr COMMA expr",
- /* 167 */ "cmd ::= DELETE FROM fullname indexed_opt where_opt",
- /* 168 */ "where_opt ::=",
- /* 169 */ "where_opt ::= WHERE expr",
- /* 170 */ "cmd ::= UPDATE orconf fullname indexed_opt SET setlist where_opt",
- /* 171 */ "setlist ::= setlist COMMA nm EQ expr",
- /* 172 */ "setlist ::= nm EQ expr",
- /* 173 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP",
- /* 174 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select",
- /* 175 */ "cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES",
- /* 176 */ "insert_cmd ::= INSERT orconf",
- /* 177 */ "insert_cmd ::= REPLACE",
- /* 178 */ "itemlist ::= itemlist COMMA expr",
- /* 179 */ "itemlist ::= expr",
- /* 180 */ "inscollist_opt ::=",
- /* 181 */ "inscollist_opt ::= LP inscollist RP",
- /* 182 */ "inscollist ::= inscollist COMMA nm",
- /* 183 */ "inscollist ::= nm",
- /* 184 */ "expr ::= term",
- /* 185 */ "expr ::= LP expr RP",
- /* 186 */ "term ::= NULL",
- /* 187 */ "expr ::= id",
- /* 188 */ "expr ::= JOIN_KW",
- /* 189 */ "expr ::= nm DOT nm",
- /* 190 */ "expr ::= nm DOT nm DOT nm",
- /* 191 */ "term ::= INTEGER|FLOAT|BLOB",
- /* 192 */ "term ::= STRING",
- /* 193 */ "expr ::= REGISTER",
- /* 194 */ "expr ::= VARIABLE",
- /* 195 */ "expr ::= expr COLLATE ids",
- /* 196 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 197 */ "expr ::= ID LP distinct exprlist RP",
- /* 198 */ "expr ::= ID LP STAR RP",
- /* 199 */ "term ::= CTIME_KW",
- /* 200 */ "expr ::= expr AND expr",
- /* 201 */ "expr ::= expr OR expr",
- /* 202 */ "expr ::= expr LT|GT|GE|LE expr",
- /* 203 */ "expr ::= expr EQ|NE expr",
- /* 204 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
- /* 205 */ "expr ::= expr PLUS|MINUS expr",
- /* 206 */ "expr ::= expr STAR|SLASH|REM expr",
- /* 207 */ "expr ::= expr CONCAT expr",
- /* 208 */ "likeop ::= LIKE_KW",
- /* 209 */ "likeop ::= NOT LIKE_KW",
- /* 210 */ "likeop ::= MATCH",
- /* 211 */ "likeop ::= NOT MATCH",
- /* 212 */ "expr ::= expr likeop expr",
- /* 213 */ "expr ::= expr likeop expr ESCAPE expr",
- /* 214 */ "expr ::= expr ISNULL|NOTNULL",
- /* 215 */ "expr ::= expr NOT NULL",
- /* 216 */ "expr ::= expr IS expr",
- /* 217 */ "expr ::= expr IS NOT expr",
- /* 218 */ "expr ::= NOT expr",
- /* 219 */ "expr ::= BITNOT expr",
- /* 220 */ "expr ::= MINUS expr",
- /* 221 */ "expr ::= PLUS expr",
- /* 222 */ "between_op ::= BETWEEN",
- /* 223 */ "between_op ::= NOT BETWEEN",
- /* 224 */ "expr ::= expr between_op expr AND expr",
- /* 225 */ "in_op ::= IN",
- /* 226 */ "in_op ::= NOT IN",
- /* 227 */ "expr ::= expr in_op LP exprlist RP",
- /* 228 */ "expr ::= LP select RP",
- /* 229 */ "expr ::= expr in_op LP select RP",
- /* 230 */ "expr ::= expr in_op nm dbnm",
- /* 231 */ "expr ::= EXISTS LP select RP",
- /* 232 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 233 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 234 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 235 */ "case_else ::= ELSE expr",
- /* 236 */ "case_else ::=",
- /* 237 */ "case_operand ::= expr",
- /* 238 */ "case_operand ::=",
- /* 239 */ "exprlist ::= nexprlist",
- /* 240 */ "exprlist ::=",
- /* 241 */ "nexprlist ::= nexprlist COMMA expr",
- /* 242 */ "nexprlist ::= expr",
- /* 243 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP",
- /* 244 */ "uniqueflag ::= UNIQUE",
- /* 245 */ "uniqueflag ::=",
- /* 246 */ "idxlist_opt ::=",
- /* 247 */ "idxlist_opt ::= LP idxlist RP",
- /* 248 */ "idxlist ::= idxlist COMMA nm collate sortorder",
- /* 249 */ "idxlist ::= nm collate sortorder",
- /* 250 */ "collate ::=",
- /* 251 */ "collate ::= COLLATE ids",
- /* 252 */ "cmd ::= DROP INDEX ifexists fullname",
- /* 253 */ "cmd ::= VACUUM",
- /* 254 */ "cmd ::= VACUUM nm",
- /* 255 */ "cmd ::= PRAGMA nm dbnm",
- /* 256 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
- /* 257 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
- /* 258 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 259 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
- /* 260 */ "nmnum ::= plus_num",
- /* 261 */ "nmnum ::= nm",
- /* 262 */ "nmnum ::= ON",
- /* 263 */ "nmnum ::= DELETE",
- /* 264 */ "nmnum ::= DEFAULT",
- /* 265 */ "plus_num ::= plus_opt number",
+ /* 153 */ "sortlist ::= sortlist COMMA expr sortorder",
+ /* 154 */ "sortlist ::= expr sortorder",
+ /* 155 */ "sortorder ::= ASC",
+ /* 156 */ "sortorder ::= DESC",
+ /* 157 */ "sortorder ::=",
+ /* 158 */ "groupby_opt ::=",
+ /* 159 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 160 */ "having_opt ::=",
+ /* 161 */ "having_opt ::= HAVING expr",
+ /* 162 */ "limit_opt ::=",
+ /* 163 */ "limit_opt ::= LIMIT expr",
+ /* 164 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 165 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 166 */ "cmd ::= DELETE FROM fullname indexed_opt where_opt",
+ /* 167 */ "where_opt ::=",
+ /* 168 */ "where_opt ::= WHERE expr",
+ /* 169 */ "cmd ::= UPDATE orconf fullname indexed_opt SET setlist where_opt",
+ /* 170 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 171 */ "setlist ::= nm EQ expr",
+ /* 172 */ "cmd ::= insert_cmd INTO fullname inscollist_opt valuelist",
+ /* 173 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select",
+ /* 174 */ "cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES",
+ /* 175 */ "insert_cmd ::= INSERT orconf",
+ /* 176 */ "insert_cmd ::= REPLACE",
+ /* 177 */ "valuelist ::= VALUES LP nexprlist RP",
+ /* 178 */ "valuelist ::= valuelist COMMA LP exprlist RP",
+ /* 179 */ "inscollist_opt ::=",
+ /* 180 */ "inscollist_opt ::= LP inscollist RP",
+ /* 181 */ "inscollist ::= inscollist COMMA nm",
+ /* 182 */ "inscollist ::= nm",
+ /* 183 */ "expr ::= term",
+ /* 184 */ "expr ::= LP expr RP",
+ /* 185 */ "term ::= NULL",
+ /* 186 */ "expr ::= id",
+ /* 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 ::= REGISTER",
+ /* 193 */ "expr ::= VARIABLE",
+ /* 194 */ "expr ::= expr COLLATE ids",
+ /* 195 */ "expr ::= CAST LP expr AS typetoken RP",
+ /* 196 */ "expr ::= ID LP distinct exprlist RP",
+ /* 197 */ "expr ::= ID LP STAR RP",
+ /* 198 */ "term ::= CTIME_KW",
+ /* 199 */ "expr ::= expr AND expr",
+ /* 200 */ "expr ::= expr OR expr",
+ /* 201 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 202 */ "expr ::= expr EQ|NE expr",
+ /* 203 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 204 */ "expr ::= expr PLUS|MINUS expr",
+ /* 205 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 206 */ "expr ::= expr CONCAT expr",
+ /* 207 */ "likeop ::= LIKE_KW",
+ /* 208 */ "likeop ::= NOT LIKE_KW",
+ /* 209 */ "likeop ::= MATCH",
+ /* 210 */ "likeop ::= NOT MATCH",
+ /* 211 */ "expr ::= expr likeop expr",
+ /* 212 */ "expr ::= expr likeop expr ESCAPE expr",
+ /* 213 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 214 */ "expr ::= expr NOT NULL",
+ /* 215 */ "expr ::= expr IS expr",
+ /* 216 */ "expr ::= expr IS NOT expr",
+ /* 217 */ "expr ::= NOT expr",
+ /* 218 */ "expr ::= BITNOT expr",
+ /* 219 */ "expr ::= MINUS expr",
+ /* 220 */ "expr ::= PLUS expr",
+ /* 221 */ "between_op ::= BETWEEN",
+ /* 222 */ "between_op ::= NOT BETWEEN",
+ /* 223 */ "expr ::= expr between_op expr AND expr",
+ /* 224 */ "in_op ::= IN",
+ /* 225 */ "in_op ::= NOT IN",
+ /* 226 */ "expr ::= expr in_op LP exprlist RP",
+ /* 227 */ "expr ::= LP select RP",
+ /* 228 */ "expr ::= expr in_op LP select RP",
+ /* 229 */ "expr ::= expr in_op nm dbnm",
+ /* 230 */ "expr ::= EXISTS LP select RP",
+ /* 231 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 232 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 233 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 234 */ "case_else ::= ELSE expr",
+ /* 235 */ "case_else ::=",
+ /* 236 */ "case_operand ::= expr",
+ /* 237 */ "case_operand ::=",
+ /* 238 */ "exprlist ::= nexprlist",
+ /* 239 */ "exprlist ::=",
+ /* 240 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 241 */ "nexprlist ::= expr",
+ /* 242 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP",
+ /* 243 */ "uniqueflag ::= UNIQUE",
+ /* 244 */ "uniqueflag ::=",
+ /* 245 */ "idxlist_opt ::=",
+ /* 246 */ "idxlist_opt ::= LP idxlist RP",
+ /* 247 */ "idxlist ::= idxlist COMMA nm collate sortorder",
+ /* 248 */ "idxlist ::= nm collate sortorder",
+ /* 249 */ "collate ::=",
+ /* 250 */ "collate ::= COLLATE ids",
+ /* 251 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 252 */ "cmd ::= VACUUM",
+ /* 253 */ "cmd ::= VACUUM nm",
+ /* 254 */ "cmd ::= PRAGMA nm dbnm",
+ /* 255 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 256 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 257 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 258 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
+ /* 259 */ "nmnum ::= plus_num",
+ /* 260 */ "nmnum ::= nm",
+ /* 261 */ "nmnum ::= ON",
+ /* 262 */ "nmnum ::= DELETE",
+ /* 263 */ "nmnum ::= DEFAULT",
+ /* 264 */ "plus_num ::= PLUS number",
+ /* 265 */ "plus_num ::= number",
/* 266 */ "minus_num ::= MINUS number",
/* 267 */ "number ::= INTEGER|FLOAT",
- /* 268 */ "plus_opt ::= PLUS",
- /* 269 */ "plus_opt ::=",
- /* 270 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
- /* 271 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 272 */ "trigger_time ::= BEFORE",
- /* 273 */ "trigger_time ::= AFTER",
- /* 274 */ "trigger_time ::= INSTEAD OF",
- /* 275 */ "trigger_time ::=",
- /* 276 */ "trigger_event ::= DELETE|INSERT",
- /* 277 */ "trigger_event ::= UPDATE",
- /* 278 */ "trigger_event ::= UPDATE OF inscollist",
- /* 279 */ "foreach_clause ::=",
- /* 280 */ "foreach_clause ::= FOR EACH ROW",
- /* 281 */ "when_clause ::=",
- /* 282 */ "when_clause ::= WHEN expr",
- /* 283 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
- /* 284 */ "trigger_cmd_list ::= trigger_cmd SEMI",
- /* 285 */ "trnm ::= nm",
- /* 286 */ "trnm ::= nm DOT nm",
- /* 287 */ "tridxby ::=",
- /* 288 */ "tridxby ::= INDEXED BY nm",
- /* 289 */ "tridxby ::= NOT INDEXED",
- /* 290 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
- /* 291 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt VALUES LP itemlist RP",
- /* 292 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select",
- /* 293 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
- /* 294 */ "trigger_cmd ::= select",
- /* 295 */ "expr ::= RAISE LP IGNORE RP",
- /* 296 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 297 */ "raisetype ::= ROLLBACK",
- /* 298 */ "raisetype ::= ABORT",
- /* 299 */ "raisetype ::= FAIL",
- /* 300 */ "cmd ::= DROP TRIGGER ifexists fullname",
- /* 301 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
- /* 302 */ "cmd ::= DETACH database_kw_opt expr",
- /* 303 */ "key_opt ::=",
- /* 304 */ "key_opt ::= KEY expr",
- /* 305 */ "database_kw_opt ::= DATABASE",
- /* 306 */ "database_kw_opt ::=",
- /* 307 */ "cmd ::= REINDEX",
- /* 308 */ "cmd ::= REINDEX nm dbnm",
- /* 309 */ "cmd ::= ANALYZE",
- /* 310 */ "cmd ::= ANALYZE nm dbnm",
- /* 311 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 312 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
- /* 313 */ "add_column_fullname ::= fullname",
- /* 314 */ "kwcolumn_opt ::=",
- /* 315 */ "kwcolumn_opt ::= COLUMNKW",
- /* 316 */ "cmd ::= create_vtab",
- /* 317 */ "cmd ::= create_vtab LP vtabarglist RP",
- /* 318 */ "create_vtab ::= createkw VIRTUAL TABLE nm dbnm USING nm",
- /* 319 */ "vtabarglist ::= vtabarg",
- /* 320 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
- /* 321 */ "vtabarg ::=",
- /* 322 */ "vtabarg ::= vtabarg vtabargtoken",
- /* 323 */ "vtabargtoken ::= ANY",
- /* 324 */ "vtabargtoken ::= lp anylist RP",
- /* 325 */ "lp ::= LP",
- /* 326 */ "anylist ::=",
- /* 327 */ "anylist ::= anylist LP anylist RP",
- /* 328 */ "anylist ::= anylist ANY",
+ /* 268 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
+ /* 269 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 270 */ "trigger_time ::= BEFORE",
+ /* 271 */ "trigger_time ::= AFTER",
+ /* 272 */ "trigger_time ::= INSTEAD OF",
+ /* 273 */ "trigger_time ::=",
+ /* 274 */ "trigger_event ::= DELETE|INSERT",
+ /* 275 */ "trigger_event ::= UPDATE",
+ /* 276 */ "trigger_event ::= UPDATE OF inscollist",
+ /* 277 */ "foreach_clause ::=",
+ /* 278 */ "foreach_clause ::= FOR EACH ROW",
+ /* 279 */ "when_clause ::=",
+ /* 280 */ "when_clause ::= WHEN expr",
+ /* 281 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 282 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 283 */ "trnm ::= nm",
+ /* 284 */ "trnm ::= nm DOT nm",
+ /* 285 */ "tridxby ::=",
+ /* 286 */ "tridxby ::= INDEXED BY nm",
+ /* 287 */ "tridxby ::= NOT INDEXED",
+ /* 288 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
+ /* 289 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt valuelist",
+ /* 290 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select",
+ /* 291 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
+ /* 292 */ "trigger_cmd ::= select",
+ /* 293 */ "expr ::= RAISE LP IGNORE RP",
+ /* 294 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 295 */ "raisetype ::= ROLLBACK",
+ /* 296 */ "raisetype ::= ABORT",
+ /* 297 */ "raisetype ::= FAIL",
+ /* 298 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 299 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 300 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 301 */ "key_opt ::=",
+ /* 302 */ "key_opt ::= KEY expr",
+ /* 303 */ "database_kw_opt ::= DATABASE",
+ /* 304 */ "database_kw_opt ::=",
+ /* 305 */ "cmd ::= REINDEX",
+ /* 306 */ "cmd ::= REINDEX nm dbnm",
+ /* 307 */ "cmd ::= ANALYZE",
+ /* 308 */ "cmd ::= ANALYZE nm dbnm",
+ /* 309 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 310 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
+ /* 311 */ "add_column_fullname ::= fullname",
+ /* 312 */ "kwcolumn_opt ::=",
+ /* 313 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 314 */ "cmd ::= create_vtab",
+ /* 315 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 316 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
+ /* 317 */ "vtabarglist ::= vtabarg",
+ /* 318 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 319 */ "vtabarg ::=",
+ /* 320 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 321 */ "vtabargtoken ::= ANY",
+ /* 322 */ "vtabargtoken ::= lp anylist RP",
+ /* 323 */ "lp ::= LP",
+ /* 324 */ "anylist ::=",
+ /* 325 */ "anylist ::= anylist LP anylist RP",
+ /* 326 */ "anylist ::= anylist ANY",
};
#endif /* NDEBUG */
@@ -107366,29 +109708,28 @@ static void yy_destructor(
case 160: /* select */
case 194: /* oneselect */
{
-sqlite3SelectDelete(pParse->db, (yypminor->yy387));
+sqlite3SelectDelete(pParse->db, (yypminor->yy159));
}
break;
- case 174: /* term */
- case 175: /* expr */
+ case 173: /* term */
+ case 174: /* expr */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy118).pExpr);
+sqlite3ExprDelete(pParse->db, (yypminor->yy342).pExpr);
}
break;
- case 179: /* idxlist_opt */
+ case 178: /* idxlist_opt */
case 187: /* idxlist */
case 197: /* selcollist */
case 200: /* groupby_opt */
case 202: /* orderby_opt */
case 204: /* sclp */
case 214: /* sortlist */
- case 216: /* nexprlist */
- case 217: /* setlist */
- case 220: /* itemlist */
- case 221: /* exprlist */
- case 226: /* case_exprlist */
+ case 215: /* nexprlist */
+ case 216: /* setlist */
+ case 220: /* exprlist */
+ case 225: /* case_exprlist */
{
-sqlite3ExprListDelete(pParse->db, (yypminor->yy322));
+sqlite3ExprListDelete(pParse->db, (yypminor->yy442));
}
break;
case 193: /* fullname */
@@ -107396,37 +109737,44 @@ sqlite3ExprListDelete(pParse->db, (yypminor->yy322));
case 206: /* seltablist */
case 207: /* stl_prefix */
{
-sqlite3SrcListDelete(pParse->db, (yypminor->yy259));
+sqlite3SrcListDelete(pParse->db, (yypminor->yy347));
}
break;
case 199: /* where_opt */
case 201: /* having_opt */
case 210: /* on_opt */
- case 215: /* sortitem */
- case 225: /* case_operand */
- case 227: /* case_else */
- case 238: /* when_clause */
- case 243: /* key_opt */
+ case 224: /* case_operand */
+ case 226: /* case_else */
+ case 236: /* when_clause */
+ case 241: /* key_opt */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy314));
+sqlite3ExprDelete(pParse->db, (yypminor->yy122));
}
break;
case 211: /* using_opt */
case 213: /* inscollist */
- case 219: /* inscollist_opt */
+ case 218: /* inscollist_opt */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy384));
+sqlite3IdListDelete(pParse->db, (yypminor->yy180));
}
break;
- case 234: /* trigger_cmd_list */
- case 239: /* trigger_cmd */
+ case 219: /* valuelist */
{
-sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy203));
+
+ sqlite3ExprListDelete(pParse->db, (yypminor->yy487).pList);
+ sqlite3SelectDelete(pParse->db, (yypminor->yy487).pSelect);
+
+}
+ break;
+ case 232: /* trigger_cmd_list */
+ case 237: /* trigger_cmd */
+{
+sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy327));
}
break;
- case 236: /* trigger_event */
+ case 234: /* trigger_event */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy90).b);
+sqlite3IdListDelete(pParse->db, (yypminor->yy410).b);
}
break;
default: break; /* If no destructor action specified: do nothing */
@@ -107615,7 +109963,6 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
UNUSED_PARAMETER(yypMinor); /* Silence some compiler warnings */
sqlite3ErrorMsg(pParse, "parser stack overflow");
- pParse->parseError = 1;
sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
}
@@ -107727,44 +110074,44 @@ static const struct {
{ 169, 1 },
{ 164, 2 },
{ 164, 0 },
+ { 172, 2 },
+ { 172, 2 },
+ { 172, 4 },
{ 172, 3 },
+ { 172, 3 },
+ { 172, 2 },
+ { 172, 2 },
+ { 172, 3 },
+ { 172, 5 },
+ { 172, 2 },
+ { 172, 4 },
+ { 172, 4 },
{ 172, 1 },
- { 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, 1 },
- { 180, 0 },
- { 180, 2 },
+ { 172, 2 },
+ { 177, 0 },
+ { 177, 1 },
+ { 179, 0 },
+ { 179, 2 },
+ { 181, 2 },
+ { 181, 3 },
+ { 181, 3 },
+ { 181, 3 },
{ 182, 2 },
- { 182, 3 },
- { 182, 3 },
- { 182, 3 },
- { 183, 2 },
+ { 182, 2 },
+ { 182, 1 },
+ { 182, 1 },
+ { 182, 2 },
+ { 180, 3 },
+ { 180, 2 },
+ { 183, 0 },
{ 183, 2 },
- { 183, 1 },
- { 183, 1 },
{ 183, 2 },
- { 181, 3 },
- { 181, 2 },
- { 184, 0 },
- { 184, 2 },
- { 184, 2 },
{ 159, 0 },
{ 159, 2 },
- { 185, 3 },
- { 185, 2 },
+ { 184, 3 },
+ { 184, 1 },
{ 185, 1 },
+ { 185, 0 },
{ 186, 2 },
{ 186, 7 },
{ 186, 5 },
@@ -107772,8 +110119,8 @@ static const struct {
{ 186, 10 },
{ 188, 0 },
{ 188, 1 },
- { 176, 0 },
- { 176, 3 },
+ { 175, 0 },
+ { 175, 3 },
{ 189, 0 },
{ 189, 2 },
{ 190, 1 },
@@ -107827,10 +110174,9 @@ static const struct {
{ 202, 3 },
{ 214, 4 },
{ 214, 2 },
- { 215, 1 },
- { 177, 1 },
- { 177, 1 },
- { 177, 0 },
+ { 176, 1 },
+ { 176, 1 },
+ { 176, 0 },
{ 200, 0 },
{ 200, 3 },
{ 201, 0 },
@@ -107843,87 +110189,87 @@ static const struct {
{ 199, 0 },
{ 199, 2 },
{ 147, 7 },
- { 217, 5 },
- { 217, 3 },
- { 147, 8 },
+ { 216, 5 },
+ { 216, 3 },
+ { 147, 5 },
{ 147, 5 },
{ 147, 6 },
- { 218, 2 },
- { 218, 1 },
- { 220, 3 },
- { 220, 1 },
- { 219, 0 },
- { 219, 3 },
+ { 217, 2 },
+ { 217, 1 },
+ { 219, 4 },
+ { 219, 5 },
+ { 218, 0 },
+ { 218, 3 },
{ 213, 3 },
{ 213, 1 },
- { 175, 1 },
- { 175, 3 },
{ 174, 1 },
- { 175, 1 },
- { 175, 1 },
- { 175, 3 },
- { 175, 5 },
+ { 174, 3 },
+ { 173, 1 },
{ 174, 1 },
{ 174, 1 },
- { 175, 1 },
- { 175, 1 },
- { 175, 3 },
- { 175, 6 },
- { 175, 5 },
- { 175, 4 },
+ { 174, 3 },
+ { 174, 5 },
+ { 173, 1 },
+ { 173, 1 },
{ 174, 1 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
- { 222, 1 },
- { 222, 2 },
+ { 174, 1 },
+ { 174, 3 },
+ { 174, 6 },
+ { 174, 5 },
+ { 174, 4 },
+ { 173, 1 },
+ { 174, 3 },
+ { 174, 3 },
+ { 174, 3 },
+ { 174, 3 },
+ { 174, 3 },
+ { 174, 3 },
+ { 174, 3 },
+ { 174, 3 },
+ { 221, 1 },
+ { 221, 2 },
+ { 221, 1 },
+ { 221, 2 },
+ { 174, 3 },
+ { 174, 5 },
+ { 174, 2 },
+ { 174, 3 },
+ { 174, 3 },
+ { 174, 4 },
+ { 174, 2 },
+ { 174, 2 },
+ { 174, 2 },
+ { 174, 2 },
{ 222, 1 },
{ 222, 2 },
- { 175, 3 },
- { 175, 5 },
- { 175, 2 },
- { 175, 3 },
- { 175, 3 },
- { 175, 4 },
- { 175, 2 },
- { 175, 2 },
- { 175, 2 },
- { 175, 2 },
+ { 174, 5 },
{ 223, 1 },
{ 223, 2 },
- { 175, 5 },
+ { 174, 5 },
+ { 174, 3 },
+ { 174, 5 },
+ { 174, 4 },
+ { 174, 4 },
+ { 174, 5 },
+ { 225, 5 },
+ { 225, 4 },
+ { 226, 2 },
+ { 226, 0 },
{ 224, 1 },
- { 224, 2 },
- { 175, 5 },
- { 175, 3 },
- { 175, 5 },
- { 175, 4 },
- { 175, 4 },
- { 175, 5 },
- { 226, 5 },
- { 226, 4 },
- { 227, 2 },
- { 227, 0 },
- { 225, 1 },
- { 225, 0 },
- { 221, 1 },
- { 221, 0 },
- { 216, 3 },
- { 216, 1 },
+ { 224, 0 },
+ { 220, 1 },
+ { 220, 0 },
+ { 215, 3 },
+ { 215, 1 },
{ 147, 11 },
- { 228, 1 },
- { 228, 0 },
- { 179, 0 },
- { 179, 3 },
+ { 227, 1 },
+ { 227, 0 },
+ { 178, 0 },
+ { 178, 3 },
{ 187, 5 },
{ 187, 3 },
- { 229, 0 },
- { 229, 2 },
+ { 228, 0 },
+ { 228, 2 },
{ 147, 4 },
{ 147, 1 },
{ 147, 2 },
@@ -107932,75 +110278,74 @@ static const struct {
{ 147, 6 },
{ 147, 5 },
{ 147, 6 },
- { 230, 1 },
- { 230, 1 },
- { 230, 1 },
- { 230, 1 },
- { 230, 1 },
+ { 229, 1 },
+ { 229, 1 },
+ { 229, 1 },
+ { 229, 1 },
+ { 229, 1 },
{ 170, 2 },
+ { 170, 1 },
{ 171, 2 },
- { 232, 1 },
- { 231, 1 },
- { 231, 0 },
+ { 230, 1 },
{ 147, 5 },
- { 233, 11 },
- { 235, 1 },
- { 235, 1 },
- { 235, 2 },
- { 235, 0 },
- { 236, 1 },
- { 236, 1 },
- { 236, 3 },
- { 237, 0 },
- { 237, 3 },
- { 238, 0 },
- { 238, 2 },
+ { 231, 11 },
+ { 233, 1 },
+ { 233, 1 },
+ { 233, 2 },
+ { 233, 0 },
+ { 234, 1 },
+ { 234, 1 },
{ 234, 3 },
- { 234, 2 },
- { 240, 1 },
- { 240, 3 },
- { 241, 0 },
- { 241, 3 },
- { 241, 2 },
- { 239, 7 },
- { 239, 8 },
- { 239, 5 },
- { 239, 5 },
- { 239, 1 },
- { 175, 4 },
- { 175, 6 },
+ { 235, 0 },
+ { 235, 3 },
+ { 236, 0 },
+ { 236, 2 },
+ { 232, 3 },
+ { 232, 2 },
+ { 238, 1 },
+ { 238, 3 },
+ { 239, 0 },
+ { 239, 3 },
+ { 239, 2 },
+ { 237, 7 },
+ { 237, 5 },
+ { 237, 5 },
+ { 237, 5 },
+ { 237, 1 },
+ { 174, 4 },
+ { 174, 6 },
{ 191, 1 },
{ 191, 1 },
{ 191, 1 },
{ 147, 4 },
{ 147, 6 },
{ 147, 3 },
- { 243, 0 },
- { 243, 2 },
- { 242, 1 },
- { 242, 0 },
+ { 241, 0 },
+ { 241, 2 },
+ { 240, 1 },
+ { 240, 0 },
{ 147, 1 },
{ 147, 3 },
{ 147, 1 },
{ 147, 3 },
{ 147, 6 },
{ 147, 6 },
- { 244, 1 },
- { 245, 0 },
- { 245, 1 },
+ { 242, 1 },
+ { 243, 0 },
+ { 243, 1 },
{ 147, 1 },
{ 147, 4 },
- { 246, 7 },
+ { 244, 8 },
+ { 245, 1 },
+ { 245, 3 },
+ { 246, 0 },
+ { 246, 2 },
{ 247, 1 },
{ 247, 3 },
- { 248, 0 },
- { 248, 2 },
- { 249, 1 },
- { 249, 3 },
- { 250, 1 },
- { 251, 0 },
- { 251, 4 },
- { 251, 2 },
+ { 248, 1 },
+ { 249, 0 },
+ { 249, 4 },
+ { 249, 2 },
};
static void yy_accept(yyParser*); /* Forward Declaration */
@@ -108068,17 +110413,17 @@ static void yy_reduce(
{ sqlite3FinishCoding(pParse); }
break;
case 9: /* cmd ::= BEGIN transtype trans_opt */
-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy4);}
+{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy392);}
break;
case 13: /* transtype ::= */
-{yygotominor.yy4 = TK_DEFERRED;}
+{yygotominor.yy392 = TK_DEFERRED;}
break;
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.yy4 = yymsp[0].major;}
+{yygotominor.yy392 = yymsp[0].major;}
break;
case 17: /* cmd ::= COMMIT trans_opt */
case 18: /* cmd ::= END trans_opt */ yytestcase(yyruleno==18);
@@ -108104,7 +110449,7 @@ static void yy_reduce(
break;
case 26: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
- sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy4,0,0,yymsp[-2].minor.yy4);
+ sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy392,0,0,yymsp[-2].minor.yy392);
}
break;
case 27: /* createkw ::= CREATE */
@@ -108115,27 +110460,27 @@ static void yy_reduce(
break;
case 28: /* ifnotexists ::= */
case 31: /* temp ::= */ yytestcase(yyruleno==31);
- case 70: /* autoinc ::= */ yytestcase(yyruleno==70);
- case 83: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ yytestcase(yyruleno==83);
- case 85: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==85);
- case 87: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==87);
+ case 69: /* autoinc ::= */ yytestcase(yyruleno==69);
+ case 82: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ yytestcase(yyruleno==82);
+ case 84: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==84);
+ case 86: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==86);
case 98: /* defer_subclause_opt ::= */ yytestcase(yyruleno==98);
case 109: /* ifexists ::= */ yytestcase(yyruleno==109);
case 120: /* distinct ::= ALL */ yytestcase(yyruleno==120);
case 121: /* distinct ::= */ yytestcase(yyruleno==121);
- case 222: /* between_op ::= BETWEEN */ yytestcase(yyruleno==222);
- case 225: /* in_op ::= IN */ yytestcase(yyruleno==225);
-{yygotominor.yy4 = 0;}
+ case 221: /* between_op ::= BETWEEN */ yytestcase(yyruleno==221);
+ case 224: /* in_op ::= IN */ yytestcase(yyruleno==224);
+{yygotominor.yy392 = 0;}
break;
case 29: /* ifnotexists ::= IF NOT EXISTS */
case 30: /* temp ::= TEMP */ yytestcase(yyruleno==30);
- case 71: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==71);
- case 86: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==86);
+ case 70: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==70);
+ case 85: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==85);
case 108: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==108);
case 119: /* distinct ::= DISTINCT */ yytestcase(yyruleno==119);
- case 223: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==223);
- case 226: /* in_op ::= NOT IN */ yytestcase(yyruleno==226);
-{yygotominor.yy4 = 1;}
+ case 222: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==222);
+ case 225: /* in_op ::= NOT IN */ yytestcase(yyruleno==225);
+{yygotominor.yy392 = 1;}
break;
case 32: /* create_table_args ::= LP columnlist conslist_opt RP */
{
@@ -108144,8 +110489,8 @@ static void yy_reduce(
break;
case 33: /* create_table_args ::= AS select */
{
- sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy387);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387);
+ sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy159);
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy159);
}
break;
case 36: /* column ::= columnid type carglist */
@@ -108158,6 +110503,7 @@ static void yy_reduce(
{
sqlite3AddColumn(pParse,&yymsp[0].minor.yy0);
yygotominor.yy0 = yymsp[0].minor.yy0;
+ pParse->constraintName.n = 0;
}
break;
case 38: /* id ::= ID */
@@ -108172,16 +110518,17 @@ static void yy_reduce(
case 128: /* as ::= ids */ yytestcase(yyruleno==128);
case 138: /* dbnm ::= DOT nm */ yytestcase(yyruleno==138);
case 147: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==147);
- case 251: /* collate ::= COLLATE ids */ yytestcase(yyruleno==251);
- case 260: /* nmnum ::= plus_num */ yytestcase(yyruleno==260);
- case 261: /* nmnum ::= nm */ yytestcase(yyruleno==261);
- case 262: /* nmnum ::= ON */ yytestcase(yyruleno==262);
- case 263: /* nmnum ::= DELETE */ yytestcase(yyruleno==263);
- case 264: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==264);
- case 265: /* plus_num ::= plus_opt number */ yytestcase(yyruleno==265);
+ case 250: /* collate ::= COLLATE ids */ yytestcase(yyruleno==250);
+ case 259: /* nmnum ::= plus_num */ yytestcase(yyruleno==259);
+ case 260: /* nmnum ::= nm */ yytestcase(yyruleno==260);
+ case 261: /* nmnum ::= ON */ yytestcase(yyruleno==261);
+ case 262: /* nmnum ::= DELETE */ yytestcase(yyruleno==262);
+ case 263: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==263);
+ case 264: /* plus_num ::= PLUS number */ yytestcase(yyruleno==264);
+ case 265: /* plus_num ::= number */ yytestcase(yyruleno==265);
case 266: /* minus_num ::= MINUS number */ yytestcase(yyruleno==266);
case 267: /* number ::= INTEGER|FLOAT */ yytestcase(yyruleno==267);
- case 285: /* trnm ::= nm */ yytestcase(yyruleno==285);
+ case 283: /* trnm ::= nm */ yytestcase(yyruleno==283);
{yygotominor.yy0 = yymsp[0].minor.yy0;}
break;
case 45: /* type ::= typetoken */
@@ -108202,189 +110549,199 @@ static void yy_reduce(
case 50: /* typename ::= typename ids */
{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 57: /* ccons ::= DEFAULT term */
- case 59: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==59);
-{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy118);}
+ case 55: /* ccons ::= CONSTRAINT nm */
+ case 93: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==93);
+{pParse->constraintName = yymsp[0].minor.yy0;}
break;
- case 58: /* ccons ::= DEFAULT LP expr RP */
-{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy118);}
+ case 56: /* ccons ::= DEFAULT term */
+ case 58: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==58);
+{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy342);}
break;
- case 60: /* ccons ::= DEFAULT MINUS term */
+ case 57: /* ccons ::= DEFAULT LP expr RP */
+{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy342);}
+ break;
+ case 59: /* ccons ::= DEFAULT MINUS term */
{
ExprSpan v;
- v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy118.pExpr, 0, 0);
+ v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy342.pExpr, 0, 0);
v.zStart = yymsp[-1].minor.yy0.z;
- v.zEnd = yymsp[0].minor.yy118.zEnd;
+ v.zEnd = yymsp[0].minor.yy342.zEnd;
sqlite3AddDefaultValue(pParse,&v);
}
break;
- case 61: /* ccons ::= DEFAULT id */
+ case 60: /* ccons ::= DEFAULT id */
{
ExprSpan v;
spanExpr(&v, pParse, TK_STRING, &yymsp[0].minor.yy0);
sqlite3AddDefaultValue(pParse,&v);
}
break;
- case 63: /* ccons ::= NOT NULL onconf */
-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy4);}
+ case 62: /* ccons ::= NOT NULL onconf */
+{sqlite3AddNotNull(pParse, yymsp[0].minor.yy392);}
break;
- case 64: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy4,yymsp[0].minor.yy4,yymsp[-2].minor.yy4);}
+ case 63: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
+{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy392,yymsp[0].minor.yy392,yymsp[-2].minor.yy392);}
break;
- case 65: /* ccons ::= UNIQUE onconf */
-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy4,0,0,0,0);}
+ case 64: /* ccons ::= UNIQUE onconf */
+{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy392,0,0,0,0);}
break;
- case 66: /* ccons ::= CHECK LP expr RP */
-{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy118.pExpr);}
+ case 65: /* ccons ::= CHECK LP expr RP */
+{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy342.pExpr);}
break;
- case 67: /* ccons ::= REFERENCES nm idxlist_opt refargs */
-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy4);}
+ case 66: /* ccons ::= REFERENCES nm idxlist_opt refargs */
+{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy442,yymsp[0].minor.yy392);}
break;
- case 68: /* ccons ::= defer_subclause */
-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy4);}
+ case 67: /* ccons ::= defer_subclause */
+{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy392);}
break;
- case 69: /* ccons ::= COLLATE ids */
+ case 68: /* ccons ::= COLLATE ids */
{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
break;
- case 72: /* refargs ::= */
-{ yygotominor.yy4 = OE_None*0x0101; /* EV: R-19803-45884 */}
+ case 71: /* refargs ::= */
+{ yygotominor.yy392 = OE_None*0x0101; /* EV: R-19803-45884 */}
break;
- case 73: /* refargs ::= refargs refarg */
-{ yygotominor.yy4 = (yymsp[-1].minor.yy4 & ~yymsp[0].minor.yy215.mask) | yymsp[0].minor.yy215.value; }
+ case 72: /* refargs ::= refargs refarg */
+{ yygotominor.yy392 = (yymsp[-1].minor.yy392 & ~yymsp[0].minor.yy207.mask) | yymsp[0].minor.yy207.value; }
break;
- case 74: /* refarg ::= MATCH nm */
- case 75: /* refarg ::= ON INSERT refact */ yytestcase(yyruleno==75);
-{ yygotominor.yy215.value = 0; yygotominor.yy215.mask = 0x000000; }
+ case 73: /* refarg ::= MATCH nm */
+ case 74: /* refarg ::= ON INSERT refact */ yytestcase(yyruleno==74);
+{ yygotominor.yy207.value = 0; yygotominor.yy207.mask = 0x000000; }
break;
- case 76: /* refarg ::= ON DELETE refact */
-{ yygotominor.yy215.value = yymsp[0].minor.yy4; yygotominor.yy215.mask = 0x0000ff; }
+ case 75: /* refarg ::= ON DELETE refact */
+{ yygotominor.yy207.value = yymsp[0].minor.yy392; yygotominor.yy207.mask = 0x0000ff; }
break;
- case 77: /* refarg ::= ON UPDATE refact */
-{ yygotominor.yy215.value = yymsp[0].minor.yy4<<8; yygotominor.yy215.mask = 0x00ff00; }
+ case 76: /* refarg ::= ON UPDATE refact */
+{ yygotominor.yy207.value = yymsp[0].minor.yy392<<8; yygotominor.yy207.mask = 0x00ff00; }
break;
- case 78: /* refact ::= SET NULL */
-{ yygotominor.yy4 = OE_SetNull; /* EV: R-33326-45252 */}
+ case 77: /* refact ::= SET NULL */
+{ yygotominor.yy392 = OE_SetNull; /* EV: R-33326-45252 */}
break;
- case 79: /* refact ::= SET DEFAULT */
-{ yygotominor.yy4 = OE_SetDflt; /* EV: R-33326-45252 */}
+ case 78: /* refact ::= SET DEFAULT */
+{ yygotominor.yy392 = OE_SetDflt; /* EV: R-33326-45252 */}
break;
- case 80: /* refact ::= CASCADE */
-{ yygotominor.yy4 = OE_Cascade; /* EV: R-33326-45252 */}
+ case 79: /* refact ::= CASCADE */
+{ yygotominor.yy392 = OE_Cascade; /* EV: R-33326-45252 */}
break;
- case 81: /* refact ::= RESTRICT */
-{ yygotominor.yy4 = OE_Restrict; /* EV: R-33326-45252 */}
+ case 80: /* refact ::= RESTRICT */
+{ yygotominor.yy392 = OE_Restrict; /* EV: R-33326-45252 */}
break;
- case 82: /* refact ::= NO ACTION */
-{ yygotominor.yy4 = OE_None; /* EV: R-33326-45252 */}
+ case 81: /* refact ::= NO ACTION */
+{ yygotominor.yy392 = OE_None; /* EV: R-33326-45252 */}
break;
- case 84: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ case 83: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
case 99: /* defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==99);
case 101: /* onconf ::= ON CONFLICT resolvetype */ yytestcase(yyruleno==101);
case 104: /* resolvetype ::= raisetype */ yytestcase(yyruleno==104);
-{yygotominor.yy4 = yymsp[0].minor.yy4;}
+{yygotominor.yy392 = yymsp[0].minor.yy392;}
break;
- case 88: /* conslist_opt ::= */
+ case 87: /* conslist_opt ::= */
{yygotominor.yy0.n = 0; yygotominor.yy0.z = 0;}
break;
- case 89: /* conslist_opt ::= COMMA conslist */
+ case 88: /* conslist_opt ::= COMMA conslist */
{yygotominor.yy0 = yymsp[-1].minor.yy0;}
break;
+ case 91: /* tconscomma ::= COMMA */
+{pParse->constraintName.n = 0;}
+ break;
case 94: /* tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf */
-{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy4,yymsp[-2].minor.yy4,0);}
+{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy442,yymsp[0].minor.yy392,yymsp[-2].minor.yy392,0);}
break;
case 95: /* tcons ::= UNIQUE LP idxlist RP onconf */
-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy4,0,0,0,0);}
+{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy442,yymsp[0].minor.yy392,0,0,0,0);}
break;
case 96: /* tcons ::= CHECK LP expr RP onconf */
-{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy118.pExpr);}
+{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy342.pExpr);}
break;
case 97: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt */
{
- sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy4);
- sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy4);
+ sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy442, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy442, yymsp[-1].minor.yy392);
+ sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy392);
}
break;
case 100: /* onconf ::= */
-{yygotominor.yy4 = OE_Default;}
+{yygotominor.yy392 = OE_Default;}
break;
case 102: /* orconf ::= */
-{yygotominor.yy210 = OE_Default;}
+{yygotominor.yy258 = OE_Default;}
break;
case 103: /* orconf ::= OR resolvetype */
-{yygotominor.yy210 = (u8)yymsp[0].minor.yy4;}
+{yygotominor.yy258 = (u8)yymsp[0].minor.yy392;}
break;
case 105: /* resolvetype ::= IGNORE */
-{yygotominor.yy4 = OE_Ignore;}
+{yygotominor.yy392 = OE_Ignore;}
break;
case 106: /* resolvetype ::= REPLACE */
-{yygotominor.yy4 = OE_Replace;}
+{yygotominor.yy392 = OE_Replace;}
break;
case 107: /* cmd ::= DROP TABLE ifexists fullname */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy259, 0, yymsp[-1].minor.yy4);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy347, 0, yymsp[-1].minor.yy392);
}
break;
case 110: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm AS select */
{
- sqlite3CreateView(pParse, &yymsp[-7].minor.yy0, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, yymsp[0].minor.yy387, yymsp[-6].minor.yy4, yymsp[-4].minor.yy4);
+ sqlite3CreateView(pParse, &yymsp[-7].minor.yy0, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, yymsp[0].minor.yy159, yymsp[-6].minor.yy392, yymsp[-4].minor.yy392);
}
break;
case 111: /* cmd ::= DROP VIEW ifexists fullname */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy259, 1, yymsp[-1].minor.yy4);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy347, 1, yymsp[-1].minor.yy392);
}
break;
case 112: /* cmd ::= select */
{
SelectDest dest = {SRT_Output, 0, 0, 0, 0};
- sqlite3Select(pParse, yymsp[0].minor.yy387, &dest);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387);
+ sqlite3Select(pParse, yymsp[0].minor.yy159, &dest);
+ sqlite3ExplainBegin(pParse->pVdbe);
+ sqlite3ExplainSelect(pParse->pVdbe, yymsp[0].minor.yy159);
+ sqlite3ExplainFinish(pParse->pVdbe);
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy159);
}
break;
case 113: /* select ::= oneselect */
-{yygotominor.yy387 = yymsp[0].minor.yy387;}
+{yygotominor.yy159 = yymsp[0].minor.yy159;}
break;
case 114: /* select ::= select multiselect_op oneselect */
{
- if( yymsp[0].minor.yy387 ){
- yymsp[0].minor.yy387->op = (u8)yymsp[-1].minor.yy4;
- yymsp[0].minor.yy387->pPrior = yymsp[-2].minor.yy387;
+ if( yymsp[0].minor.yy159 ){
+ yymsp[0].minor.yy159->op = (u8)yymsp[-1].minor.yy392;
+ yymsp[0].minor.yy159->pPrior = yymsp[-2].minor.yy159;
}else{
- sqlite3SelectDelete(pParse->db, yymsp[-2].minor.yy387);
+ sqlite3SelectDelete(pParse->db, yymsp[-2].minor.yy159);
}
- yygotominor.yy387 = yymsp[0].minor.yy387;
+ yygotominor.yy159 = yymsp[0].minor.yy159;
}
break;
case 116: /* multiselect_op ::= UNION ALL */
-{yygotominor.yy4 = TK_ALL;}
+{yygotominor.yy392 = TK_ALL;}
break;
case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
- yygotominor.yy387 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy259,yymsp[-4].minor.yy314,yymsp[-3].minor.yy322,yymsp[-2].minor.yy314,yymsp[-1].minor.yy322,yymsp[-7].minor.yy4,yymsp[0].minor.yy292.pLimit,yymsp[0].minor.yy292.pOffset);
+ yygotominor.yy159 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy442,yymsp[-5].minor.yy347,yymsp[-4].minor.yy122,yymsp[-3].minor.yy442,yymsp[-2].minor.yy122,yymsp[-1].minor.yy442,yymsp[-7].minor.yy392,yymsp[0].minor.yy64.pLimit,yymsp[0].minor.yy64.pOffset);
}
break;
case 122: /* sclp ::= selcollist COMMA */
- case 247: /* idxlist_opt ::= LP idxlist RP */ yytestcase(yyruleno==247);
-{yygotominor.yy322 = yymsp[-1].minor.yy322;}
+ case 246: /* idxlist_opt ::= LP idxlist RP */ yytestcase(yyruleno==246);
+{yygotominor.yy442 = yymsp[-1].minor.yy442;}
break;
case 123: /* sclp ::= */
case 151: /* orderby_opt ::= */ yytestcase(yyruleno==151);
- case 159: /* groupby_opt ::= */ yytestcase(yyruleno==159);
- case 240: /* exprlist ::= */ yytestcase(yyruleno==240);
- case 246: /* idxlist_opt ::= */ yytestcase(yyruleno==246);
-{yygotominor.yy322 = 0;}
+ case 158: /* groupby_opt ::= */ yytestcase(yyruleno==158);
+ case 239: /* exprlist ::= */ yytestcase(yyruleno==239);
+ case 245: /* idxlist_opt ::= */ yytestcase(yyruleno==245);
+{yygotominor.yy442 = 0;}
break;
case 124: /* selcollist ::= sclp expr as */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, yymsp[-1].minor.yy118.pExpr);
- if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yygotominor.yy322, &yymsp[0].minor.yy0, 1);
- sqlite3ExprListSetSpan(pParse,yygotominor.yy322,&yymsp[-1].minor.yy118);
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy442, yymsp[-1].minor.yy342.pExpr);
+ if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yygotominor.yy442, &yymsp[0].minor.yy0, 1);
+ sqlite3ExprListSetSpan(pParse,yygotominor.yy442,&yymsp[-1].minor.yy342);
}
break;
case 125: /* selcollist ::= sclp STAR */
{
Expr *p = sqlite3Expr(pParse->db, TK_ALL, 0);
- yygotominor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy322, p);
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy442, p);
}
break;
case 126: /* selcollist ::= sclp nm DOT STAR */
@@ -108392,50 +110749,50 @@ static void yy_reduce(
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);
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, pDot);
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy442, pDot);
}
break;
case 129: /* as ::= */
{yygotominor.yy0.n = 0;}
break;
case 130: /* from ::= */
-{yygotominor.yy259 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy259));}
+{yygotominor.yy347 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy347));}
break;
case 131: /* from ::= FROM seltablist */
{
- yygotominor.yy259 = yymsp[0].minor.yy259;
- sqlite3SrcListShiftJoinType(yygotominor.yy259);
+ yygotominor.yy347 = yymsp[0].minor.yy347;
+ sqlite3SrcListShiftJoinType(yygotominor.yy347);
}
break;
case 132: /* stl_prefix ::= seltablist joinop */
{
- yygotominor.yy259 = yymsp[-1].minor.yy259;
- if( ALWAYS(yygotominor.yy259 && yygotominor.yy259->nSrc>0) ) yygotominor.yy259->a[yygotominor.yy259->nSrc-1].jointype = (u8)yymsp[0].minor.yy4;
+ yygotominor.yy347 = yymsp[-1].minor.yy347;
+ if( ALWAYS(yygotominor.yy347 && yygotominor.yy347->nSrc>0) ) yygotominor.yy347->a[yygotominor.yy347->nSrc-1].jointype = (u8)yymsp[0].minor.yy392;
}
break;
case 133: /* stl_prefix ::= */
-{yygotominor.yy259 = 0;}
+{yygotominor.yy347 = 0;}
break;
case 134: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
{
- yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
- sqlite3SrcListIndexedBy(pParse, yygotominor.yy259, &yymsp[-2].minor.yy0);
+ yygotominor.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, yygotominor.yy347, &yymsp[-2].minor.yy0);
}
break;
case 135: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
{
- yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy387,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
+ yygotominor.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);
}
break;
case 136: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
{
- if( yymsp[-6].minor.yy259==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy314==0 && yymsp[0].minor.yy384==0 ){
- yygotominor.yy259 = yymsp[-4].minor.yy259;
+ if( yymsp[-6].minor.yy347==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy122==0 && yymsp[0].minor.yy180==0 ){
+ yygotominor.yy347 = yymsp[-4].minor.yy347;
}else{
Select *pSubquery;
- sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy259);
- pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy259,0,0,0,0,0,0,0);
- yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
+ sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy347);
+ pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy347,0,0,0,0,0,0,0);
+ yygotominor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy122,yymsp[0].minor.yy180);
}
}
break;
@@ -108444,322 +110801,340 @@ static void yy_reduce(
{yygotominor.yy0.z=0; yygotominor.yy0.n=0;}
break;
case 139: /* fullname ::= nm dbnm */
-{yygotominor.yy259 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
+{yygotominor.yy347 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
break;
case 140: /* joinop ::= COMMA|JOIN */
-{ yygotominor.yy4 = JT_INNER; }
+{ yygotominor.yy392 = JT_INNER; }
break;
case 141: /* joinop ::= JOIN_KW JOIN */
-{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
+{ yygotominor.yy392 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
break;
case 142: /* joinop ::= JOIN_KW nm JOIN */
-{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); }
+{ yygotominor.yy392 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); }
break;
case 143: /* joinop ::= JOIN_KW nm nm JOIN */
-{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); }
+{ yygotominor.yy392 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); }
break;
case 144: /* on_opt ::= ON expr */
- case 155: /* sortitem ::= expr */ yytestcase(yyruleno==155);
- case 162: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==162);
- case 169: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==169);
- case 235: /* case_else ::= ELSE expr */ yytestcase(yyruleno==235);
- case 237: /* case_operand ::= expr */ yytestcase(yyruleno==237);
-{yygotominor.yy314 = yymsp[0].minor.yy118.pExpr;}
+ case 161: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==161);
+ case 168: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==168);
+ case 234: /* case_else ::= ELSE expr */ yytestcase(yyruleno==234);
+ case 236: /* case_operand ::= expr */ yytestcase(yyruleno==236);
+{yygotominor.yy122 = yymsp[0].minor.yy342.pExpr;}
break;
case 145: /* on_opt ::= */
- case 161: /* having_opt ::= */ yytestcase(yyruleno==161);
- case 168: /* where_opt ::= */ yytestcase(yyruleno==168);
- case 236: /* case_else ::= */ yytestcase(yyruleno==236);
- case 238: /* case_operand ::= */ yytestcase(yyruleno==238);
-{yygotominor.yy314 = 0;}
+ case 160: /* having_opt ::= */ yytestcase(yyruleno==160);
+ case 167: /* where_opt ::= */ yytestcase(yyruleno==167);
+ case 235: /* case_else ::= */ yytestcase(yyruleno==235);
+ case 237: /* case_operand ::= */ yytestcase(yyruleno==237);
+{yygotominor.yy122 = 0;}
break;
case 148: /* indexed_opt ::= NOT INDEXED */
{yygotominor.yy0.z=0; yygotominor.yy0.n=1;}
break;
case 149: /* using_opt ::= USING LP inscollist RP */
- case 181: /* inscollist_opt ::= LP inscollist RP */ yytestcase(yyruleno==181);
-{yygotominor.yy384 = yymsp[-1].minor.yy384;}
+ case 180: /* inscollist_opt ::= LP inscollist RP */ yytestcase(yyruleno==180);
+{yygotominor.yy180 = yymsp[-1].minor.yy180;}
break;
case 150: /* using_opt ::= */
- case 180: /* inscollist_opt ::= */ yytestcase(yyruleno==180);
-{yygotominor.yy384 = 0;}
+ case 179: /* inscollist_opt ::= */ yytestcase(yyruleno==179);
+{yygotominor.yy180 = 0;}
break;
case 152: /* orderby_opt ::= ORDER BY sortlist */
- case 160: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==160);
- case 239: /* exprlist ::= nexprlist */ yytestcase(yyruleno==239);
-{yygotominor.yy322 = yymsp[0].minor.yy322;}
+ case 159: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==159);
+ case 238: /* exprlist ::= nexprlist */ yytestcase(yyruleno==238);
+{yygotominor.yy442 = yymsp[0].minor.yy442;}
break;
- case 153: /* sortlist ::= sortlist COMMA sortitem sortorder */
+ case 153: /* sortlist ::= sortlist COMMA expr sortorder */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322,yymsp[-1].minor.yy314);
- if( yygotominor.yy322 ) yygotominor.yy322->a[yygotominor.yy322->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy4;
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy442,yymsp[-1].minor.yy342.pExpr);
+ if( yygotominor.yy442 ) yygotominor.yy442->a[yygotominor.yy442->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy392;
}
break;
- case 154: /* sortlist ::= sortitem sortorder */
+ case 154: /* sortlist ::= expr sortorder */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy314);
- if( yygotominor.yy322 && ALWAYS(yygotominor.yy322->a) ) yygotominor.yy322->a[0].sortOrder = (u8)yymsp[0].minor.yy4;
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy342.pExpr);
+ if( yygotominor.yy442 && ALWAYS(yygotominor.yy442->a) ) yygotominor.yy442->a[0].sortOrder = (u8)yymsp[0].minor.yy392;
}
break;
- case 156: /* sortorder ::= ASC */
- case 158: /* sortorder ::= */ yytestcase(yyruleno==158);
-{yygotominor.yy4 = SQLITE_SO_ASC;}
+ case 155: /* sortorder ::= ASC */
+ case 157: /* sortorder ::= */ yytestcase(yyruleno==157);
+{yygotominor.yy392 = SQLITE_SO_ASC;}
break;
- case 157: /* sortorder ::= DESC */
-{yygotominor.yy4 = SQLITE_SO_DESC;}
+ case 156: /* sortorder ::= DESC */
+{yygotominor.yy392 = SQLITE_SO_DESC;}
break;
- case 163: /* limit_opt ::= */
-{yygotominor.yy292.pLimit = 0; yygotominor.yy292.pOffset = 0;}
+ case 162: /* limit_opt ::= */
+{yygotominor.yy64.pLimit = 0; yygotominor.yy64.pOffset = 0;}
break;
- case 164: /* limit_opt ::= LIMIT expr */
-{yygotominor.yy292.pLimit = yymsp[0].minor.yy118.pExpr; yygotominor.yy292.pOffset = 0;}
+ case 163: /* limit_opt ::= LIMIT expr */
+{yygotominor.yy64.pLimit = yymsp[0].minor.yy342.pExpr; yygotominor.yy64.pOffset = 0;}
break;
- case 165: /* limit_opt ::= LIMIT expr OFFSET expr */
-{yygotominor.yy292.pLimit = yymsp[-2].minor.yy118.pExpr; yygotominor.yy292.pOffset = yymsp[0].minor.yy118.pExpr;}
+ case 164: /* limit_opt ::= LIMIT expr OFFSET expr */
+{yygotominor.yy64.pLimit = yymsp[-2].minor.yy342.pExpr; yygotominor.yy64.pOffset = yymsp[0].minor.yy342.pExpr;}
break;
- case 166: /* limit_opt ::= LIMIT expr COMMA expr */
-{yygotominor.yy292.pOffset = yymsp[-2].minor.yy118.pExpr; yygotominor.yy292.pLimit = yymsp[0].minor.yy118.pExpr;}
+ case 165: /* limit_opt ::= LIMIT expr COMMA expr */
+{yygotominor.yy64.pOffset = yymsp[-2].minor.yy342.pExpr; yygotominor.yy64.pLimit = yymsp[0].minor.yy342.pExpr;}
break;
- case 167: /* cmd ::= DELETE FROM fullname indexed_opt where_opt */
+ case 166: /* cmd ::= DELETE FROM fullname indexed_opt where_opt */
{
- sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy259, &yymsp[-1].minor.yy0);
- sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy259,yymsp[0].minor.yy314);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy347, &yymsp[-1].minor.yy0);
+ sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy347,yymsp[0].minor.yy122);
}
break;
- case 170: /* cmd ::= UPDATE orconf fullname indexed_opt SET setlist where_opt */
+ case 169: /* cmd ::= UPDATE orconf fullname indexed_opt SET setlist where_opt */
{
- sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy259, &yymsp[-3].minor.yy0);
- sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy322,"set list");
- sqlite3Update(pParse,yymsp[-4].minor.yy259,yymsp[-1].minor.yy322,yymsp[0].minor.yy314,yymsp[-5].minor.yy210);
+ 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.yy258);
}
break;
- case 171: /* setlist ::= setlist COMMA nm EQ expr */
+ case 170: /* setlist ::= setlist COMMA nm EQ expr */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy118.pExpr);
- sqlite3ExprListSetName(pParse, yygotominor.yy322, &yymsp[-2].minor.yy0, 1);
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy442, yymsp[0].minor.yy342.pExpr);
+ sqlite3ExprListSetName(pParse, yygotominor.yy442, &yymsp[-2].minor.yy0, 1);
}
break;
- case 172: /* setlist ::= nm EQ expr */
+ case 171: /* setlist ::= nm EQ expr */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy118.pExpr);
- sqlite3ExprListSetName(pParse, yygotominor.yy322, &yymsp[-2].minor.yy0, 1);
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy342.pExpr);
+ sqlite3ExprListSetName(pParse, yygotominor.yy442, &yymsp[-2].minor.yy0, 1);
}
break;
- case 173: /* cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP */
-{sqlite3Insert(pParse, yymsp[-5].minor.yy259, yymsp[-1].minor.yy322, 0, yymsp[-4].minor.yy384, yymsp[-7].minor.yy210);}
+ case 172: /* cmd ::= insert_cmd INTO fullname inscollist_opt valuelist */
+{sqlite3Insert(pParse, yymsp[-2].minor.yy347, yymsp[0].minor.yy487.pList, yymsp[0].minor.yy487.pSelect, yymsp[-1].minor.yy180, yymsp[-4].minor.yy258);}
break;
- case 174: /* cmd ::= insert_cmd INTO fullname inscollist_opt select */
-{sqlite3Insert(pParse, yymsp[-2].minor.yy259, 0, yymsp[0].minor.yy387, yymsp[-1].minor.yy384, yymsp[-4].minor.yy210);}
+ case 173: /* cmd ::= insert_cmd INTO fullname inscollist_opt select */
+{sqlite3Insert(pParse, yymsp[-2].minor.yy347, 0, yymsp[0].minor.yy159, yymsp[-1].minor.yy180, yymsp[-4].minor.yy258);}
break;
- case 175: /* cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES */
-{sqlite3Insert(pParse, yymsp[-3].minor.yy259, 0, 0, yymsp[-2].minor.yy384, yymsp[-5].minor.yy210);}
+ case 174: /* cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES */
+{sqlite3Insert(pParse, yymsp[-3].minor.yy347, 0, 0, yymsp[-2].minor.yy180, yymsp[-5].minor.yy258);}
break;
- case 176: /* insert_cmd ::= INSERT orconf */
-{yygotominor.yy210 = yymsp[0].minor.yy210;}
+ case 175: /* insert_cmd ::= INSERT orconf */
+{yygotominor.yy258 = yymsp[0].minor.yy258;}
break;
- case 177: /* insert_cmd ::= REPLACE */
-{yygotominor.yy210 = OE_Replace;}
+ case 176: /* insert_cmd ::= REPLACE */
+{yygotominor.yy258 = OE_Replace;}
break;
- case 178: /* itemlist ::= itemlist COMMA expr */
- case 241: /* nexprlist ::= nexprlist COMMA expr */ yytestcase(yyruleno==241);
-{yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy118.pExpr);}
+ case 177: /* valuelist ::= VALUES LP nexprlist RP */
+{
+ yygotominor.yy487.pList = yymsp[-1].minor.yy442;
+ yygotominor.yy487.pSelect = 0;
+}
break;
- case 179: /* itemlist ::= expr */
- case 242: /* nexprlist ::= expr */ yytestcase(yyruleno==242);
-{yygotominor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy118.pExpr);}
+ case 178: /* valuelist ::= valuelist COMMA LP exprlist RP */
+{
+ Select *pRight = sqlite3SelectNew(pParse, yymsp[-1].minor.yy442, 0, 0, 0, 0, 0, 0, 0, 0);
+ if( yymsp[-4].minor.yy487.pList ){
+ yymsp[-4].minor.yy487.pSelect = sqlite3SelectNew(pParse, yymsp[-4].minor.yy487.pList, 0, 0, 0, 0, 0, 0, 0, 0);
+ yymsp[-4].minor.yy487.pList = 0;
+ }
+ yygotominor.yy487.pList = 0;
+ if( yymsp[-4].minor.yy487.pSelect==0 || pRight==0 ){
+ sqlite3SelectDelete(pParse->db, pRight);
+ sqlite3SelectDelete(pParse->db, yymsp[-4].minor.yy487.pSelect);
+ yygotominor.yy487.pSelect = 0;
+ }else{
+ pRight->op = TK_ALL;
+ pRight->pPrior = yymsp[-4].minor.yy487.pSelect;
+ pRight->selFlags |= SF_Values;
+ pRight->pPrior->selFlags |= SF_Values;
+ yygotominor.yy487.pSelect = pRight;
+ }
+}
break;
- case 182: /* inscollist ::= inscollist COMMA nm */
-{yygotominor.yy384 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy384,&yymsp[0].minor.yy0);}
+ case 181: /* inscollist ::= inscollist COMMA nm */
+{yygotominor.yy180 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy180,&yymsp[0].minor.yy0);}
break;
- case 183: /* inscollist ::= nm */
-{yygotominor.yy384 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0);}
+ case 182: /* inscollist ::= nm */
+{yygotominor.yy180 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0);}
break;
- case 184: /* expr ::= term */
-{yygotominor.yy118 = yymsp[0].minor.yy118;}
+ case 183: /* expr ::= term */
+{yygotominor.yy342 = yymsp[0].minor.yy342;}
break;
- case 185: /* expr ::= LP expr RP */
-{yygotominor.yy118.pExpr = yymsp[-1].minor.yy118.pExpr; spanSet(&yygotominor.yy118,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);}
+ case 184: /* expr ::= LP expr RP */
+{yygotominor.yy342.pExpr = yymsp[-1].minor.yy342.pExpr; spanSet(&yygotominor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);}
break;
- case 186: /* term ::= NULL */
- case 191: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==191);
- case 192: /* term ::= STRING */ yytestcase(yyruleno==192);
-{spanExpr(&yygotominor.yy118, pParse, yymsp[0].major, &yymsp[0].minor.yy0);}
+ case 185: /* term ::= NULL */
+ case 190: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==190);
+ case 191: /* term ::= STRING */ yytestcase(yyruleno==191);
+{spanExpr(&yygotominor.yy342, pParse, yymsp[0].major, &yymsp[0].minor.yy0);}
break;
- case 187: /* expr ::= id */
- case 188: /* expr ::= JOIN_KW */ yytestcase(yyruleno==188);
-{spanExpr(&yygotominor.yy118, pParse, TK_ID, &yymsp[0].minor.yy0);}
+ case 186: /* expr ::= id */
+ case 187: /* expr ::= JOIN_KW */ yytestcase(yyruleno==187);
+{spanExpr(&yygotominor.yy342, pParse, TK_ID, &yymsp[0].minor.yy0);}
break;
- case 189: /* expr ::= nm DOT nm */
+ 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);
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
- spanSet(&yygotominor.yy118,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
+ spanSet(&yygotominor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
}
break;
- case 190: /* 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);
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
- spanSet(&yygotominor.yy118,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
+ spanSet(&yygotominor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
}
break;
- case 193: /* expr ::= REGISTER */
+ case 192: /* expr ::= REGISTER */
{
/* 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. */
if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &yymsp[0].minor.yy0);
- yygotominor.yy118.pExpr = 0;
+ yygotominor.yy342.pExpr = 0;
}else{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &yymsp[0].minor.yy0);
- if( yygotominor.yy118.pExpr ) sqlite3GetInt32(&yymsp[0].minor.yy0.z[1], &yygotominor.yy118.pExpr->iTable);
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &yymsp[0].minor.yy0);
+ if( yygotominor.yy342.pExpr ) sqlite3GetInt32(&yymsp[0].minor.yy0.z[1], &yygotominor.yy342.pExpr->iTable);
}
- spanSet(&yygotominor.yy118, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
+ spanSet(&yygotominor.yy342, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
}
break;
- case 194: /* expr ::= VARIABLE */
+ case 193: /* expr ::= VARIABLE */
{
- spanExpr(&yygotominor.yy118, pParse, TK_VARIABLE, &yymsp[0].minor.yy0);
- sqlite3ExprAssignVarNumber(pParse, yygotominor.yy118.pExpr);
- spanSet(&yygotominor.yy118, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
+ spanExpr(&yygotominor.yy342, pParse, TK_VARIABLE, &yymsp[0].minor.yy0);
+ sqlite3ExprAssignVarNumber(pParse, yygotominor.yy342.pExpr);
+ spanSet(&yygotominor.yy342, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
}
break;
- case 195: /* expr ::= expr COLLATE ids */
+ case 194: /* expr ::= expr COLLATE ids */
{
- yygotominor.yy118.pExpr = sqlite3ExprSetCollByToken(pParse, yymsp[-2].minor.yy118.pExpr, &yymsp[0].minor.yy0);
- yygotominor.yy118.zStart = yymsp[-2].minor.yy118.zStart;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yygotominor.yy342.pExpr = sqlite3ExprSetCollByToken(pParse, yymsp[-2].minor.yy342.pExpr, &yymsp[0].minor.yy0);
+ yygotominor.yy342.zStart = yymsp[-2].minor.yy342.zStart;
+ yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 196: /* expr ::= CAST LP expr AS typetoken RP */
+ case 195: /* expr ::= CAST LP expr AS typetoken RP */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy118.pExpr, 0, &yymsp[-1].minor.yy0);
- spanSet(&yygotominor.yy118,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy342.pExpr, 0, &yymsp[-1].minor.yy0);
+ spanSet(&yygotominor.yy342,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
}
break;
- case 197: /* expr ::= ID LP distinct exprlist RP */
+ case 196: /* expr ::= ID LP distinct exprlist RP */
{
- if( yymsp[-1].minor.yy322 && yymsp[-1].minor.yy322->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
+ if( yymsp[-1].minor.yy442 && yymsp[-1].minor.yy442->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
}
- yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0);
- spanSet(&yygotominor.yy118,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
- if( yymsp[-2].minor.yy4 && yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->flags |= EP_Distinct;
+ yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy442, &yymsp[-4].minor.yy0);
+ spanSet(&yygotominor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
+ if( yymsp[-2].minor.yy392 && yygotominor.yy342.pExpr ){
+ yygotominor.yy342.pExpr->flags |= EP_Distinct;
}
}
break;
- case 198: /* expr ::= ID LP STAR RP */
+ case 197: /* expr ::= ID LP STAR RP */
{
- yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
- spanSet(&yygotominor.yy118,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
+ yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
+ spanSet(&yygotominor.yy342,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
}
break;
- case 199: /* term ::= CTIME_KW */
+ case 198: /* term ::= CTIME_KW */
{
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
** treated as functions that return constants */
- yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, 0,&yymsp[0].minor.yy0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->op = TK_CONST_FUNC;
+ yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, 0,&yymsp[0].minor.yy0);
+ if( yygotominor.yy342.pExpr ){
+ yygotominor.yy342.pExpr->op = TK_CONST_FUNC;
}
- spanSet(&yygotominor.yy118, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
+ spanSet(&yygotominor.yy342, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
}
break;
- case 200: /* expr ::= expr AND expr */
- case 201: /* expr ::= expr OR expr */ yytestcase(yyruleno==201);
- case 202: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==202);
- case 203: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==203);
- case 204: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==204);
- case 205: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==205);
- case 206: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==206);
- case 207: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==207);
-{spanBinaryExpr(&yygotominor.yy118,pParse,yymsp[-1].major,&yymsp[-2].minor.yy118,&yymsp[0].minor.yy118);}
+ case 199: /* expr ::= expr AND expr */
+ case 200: /* expr ::= expr OR expr */ yytestcase(yyruleno==200);
+ case 201: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==201);
+ case 202: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==202);
+ case 203: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==203);
+ case 204: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==204);
+ case 205: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==205);
+ case 206: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==206);
+{spanBinaryExpr(&yygotominor.yy342,pParse,yymsp[-1].major,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy342);}
break;
- case 208: /* likeop ::= LIKE_KW */
- case 210: /* likeop ::= MATCH */ yytestcase(yyruleno==210);
-{yygotominor.yy342.eOperator = yymsp[0].minor.yy0; yygotominor.yy342.not = 0;}
+ case 207: /* likeop ::= LIKE_KW */
+ case 209: /* likeop ::= MATCH */ yytestcase(yyruleno==209);
+{yygotominor.yy318.eOperator = yymsp[0].minor.yy0; yygotominor.yy318.bNot = 0;}
break;
- case 209: /* likeop ::= NOT LIKE_KW */
- case 211: /* likeop ::= NOT MATCH */ yytestcase(yyruleno==211);
-{yygotominor.yy342.eOperator = yymsp[0].minor.yy0; yygotominor.yy342.not = 1;}
+ case 208: /* likeop ::= NOT LIKE_KW */
+ case 210: /* likeop ::= NOT MATCH */ yytestcase(yyruleno==210);
+{yygotominor.yy318.eOperator = yymsp[0].minor.yy0; yygotominor.yy318.bNot = 1;}
break;
- case 212: /* expr ::= expr likeop expr */
+ case 211: /* expr ::= expr likeop expr */
{
ExprList *pList;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy118.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy118.pExpr);
- yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy342.eOperator);
- if( yymsp[-1].minor.yy342.not ) yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy118.pExpr, 0, 0);
- yygotominor.yy118.zStart = yymsp[-2].minor.yy118.zStart;
- yygotominor.yy118.zEnd = yymsp[0].minor.yy118.zEnd;
- if( yygotominor.yy118.pExpr ) yygotominor.yy118.pExpr->flags |= EP_InfixFunc;
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy342.pExpr);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy342.pExpr);
+ yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy318.eOperator);
+ if( yymsp[-1].minor.yy318.bNot ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
+ yygotominor.yy342.zStart = yymsp[-2].minor.yy342.zStart;
+ yygotominor.yy342.zEnd = yymsp[0].minor.yy342.zEnd;
+ if( yygotominor.yy342.pExpr ) yygotominor.yy342.pExpr->flags |= EP_InfixFunc;
}
break;
- case 213: /* expr ::= expr likeop expr ESCAPE expr */
+ case 212: /* expr ::= expr likeop expr ESCAPE expr */
{
ExprList *pList;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy118.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy118.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy118.pExpr);
- yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy342.eOperator);
- if( yymsp[-3].minor.yy342.not ) yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy118.pExpr, 0, 0);
- yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart;
- yygotominor.yy118.zEnd = yymsp[0].minor.yy118.zEnd;
- if( yygotominor.yy118.pExpr ) yygotominor.yy118.pExpr->flags |= EP_InfixFunc;
+ 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);
+ yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy318.eOperator);
+ if( yymsp[-3].minor.yy318.bNot ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
+ yygotominor.yy342.zStart = yymsp[-4].minor.yy342.zStart;
+ yygotominor.yy342.zEnd = yymsp[0].minor.yy342.zEnd;
+ if( yygotominor.yy342.pExpr ) yygotominor.yy342.pExpr->flags |= EP_InfixFunc;
}
break;
- case 214: /* expr ::= expr ISNULL|NOTNULL */
-{spanUnaryPostfix(&yygotominor.yy118,pParse,yymsp[0].major,&yymsp[-1].minor.yy118,&yymsp[0].minor.yy0);}
+ case 213: /* expr ::= expr ISNULL|NOTNULL */
+{spanUnaryPostfix(&yygotominor.yy342,pParse,yymsp[0].major,&yymsp[-1].minor.yy342,&yymsp[0].minor.yy0);}
break;
- case 215: /* expr ::= expr NOT NULL */
-{spanUnaryPostfix(&yygotominor.yy118,pParse,TK_NOTNULL,&yymsp[-2].minor.yy118,&yymsp[0].minor.yy0);}
+ case 214: /* expr ::= expr NOT NULL */
+{spanUnaryPostfix(&yygotominor.yy342,pParse,TK_NOTNULL,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy0);}
break;
- case 216: /* expr ::= expr IS expr */
+ case 215: /* expr ::= expr IS expr */
{
- spanBinaryExpr(&yygotominor.yy118,pParse,TK_IS,&yymsp[-2].minor.yy118,&yymsp[0].minor.yy118);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy118.pExpr, yygotominor.yy118.pExpr, TK_ISNULL);
+ spanBinaryExpr(&yygotominor.yy342,pParse,TK_IS,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy342);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy342.pExpr, yygotominor.yy342.pExpr, TK_ISNULL);
}
break;
- case 217: /* expr ::= expr IS NOT expr */
+ case 216: /* expr ::= expr IS NOT expr */
{
- spanBinaryExpr(&yygotominor.yy118,pParse,TK_ISNOT,&yymsp[-3].minor.yy118,&yymsp[0].minor.yy118);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy118.pExpr, yygotominor.yy118.pExpr, TK_NOTNULL);
+ spanBinaryExpr(&yygotominor.yy342,pParse,TK_ISNOT,&yymsp[-3].minor.yy342,&yymsp[0].minor.yy342);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy342.pExpr, yygotominor.yy342.pExpr, TK_NOTNULL);
}
break;
- case 218: /* expr ::= NOT expr */
- case 219: /* expr ::= BITNOT expr */ yytestcase(yyruleno==219);
-{spanUnaryPrefix(&yygotominor.yy118,pParse,yymsp[-1].major,&yymsp[0].minor.yy118,&yymsp[-1].minor.yy0);}
+ case 217: /* expr ::= NOT expr */
+ case 218: /* expr ::= BITNOT expr */ yytestcase(yyruleno==218);
+{spanUnaryPrefix(&yygotominor.yy342,pParse,yymsp[-1].major,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);}
break;
- case 220: /* expr ::= MINUS expr */
-{spanUnaryPrefix(&yygotominor.yy118,pParse,TK_UMINUS,&yymsp[0].minor.yy118,&yymsp[-1].minor.yy0);}
+ case 219: /* expr ::= MINUS expr */
+{spanUnaryPrefix(&yygotominor.yy342,pParse,TK_UMINUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);}
break;
- case 221: /* expr ::= PLUS expr */
-{spanUnaryPrefix(&yygotominor.yy118,pParse,TK_UPLUS,&yymsp[0].minor.yy118,&yymsp[-1].minor.yy0);}
+ case 220: /* expr ::= PLUS expr */
+{spanUnaryPrefix(&yygotominor.yy342,pParse,TK_UPLUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);}
break;
- case 224: /* expr ::= expr between_op expr AND expr */
+ case 223: /* expr ::= expr between_op expr AND expr */
{
- ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy118.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy118.pExpr);
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy118.pExpr, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pList = pList;
+ ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy342.pExpr);
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy342.pExpr, 0, 0);
+ if( yygotominor.yy342.pExpr ){
+ yygotominor.yy342.pExpr->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
- if( yymsp[-3].minor.yy4 ) yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy118.pExpr, 0, 0);
- yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart;
- yygotominor.yy118.zEnd = yymsp[0].minor.yy118.zEnd;
+ if( yymsp[-3].minor.yy392 ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
+ yygotominor.yy342.zStart = yymsp[-4].minor.yy342.zStart;
+ yygotominor.yy342.zEnd = yymsp[0].minor.yy342.zEnd;
}
break;
- case 227: /* expr ::= expr in_op LP exprlist RP */
+ case 226: /* expr ::= expr in_op LP exprlist RP */
{
- if( yymsp[-1].minor.yy322==0 ){
+ if( yymsp[-1].minor.yy442==0 ){
/* Expressions of the form
**
** expr1 IN ()
@@ -108768,226 +111143,232 @@ static void yy_reduce(
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy4]);
- sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy118.pExpr);
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy392]);
+ sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy342.pExpr);
}else{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy118.pExpr, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pList = yymsp[-1].minor.yy322;
- sqlite3ExprSetHeight(pParse, yygotominor.yy118.pExpr);
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy342.pExpr, 0, 0);
+ if( yygotominor.yy342.pExpr ){
+ yygotominor.yy342.pExpr->x.pList = yymsp[-1].minor.yy442;
+ sqlite3ExprSetHeight(pParse, yygotominor.yy342.pExpr);
}else{
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy442);
}
- if( yymsp[-3].minor.yy4 ) yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy118.pExpr, 0, 0);
+ if( yymsp[-3].minor.yy392 ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
}
- yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yygotominor.yy342.zStart = yymsp[-4].minor.yy342.zStart;
+ yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 228: /* expr ::= LP select RP */
+ case 227: /* expr ::= LP select RP */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pSelect = yymsp[-1].minor.yy387;
- ExprSetProperty(yygotominor.yy118.pExpr, EP_xIsSelect);
- sqlite3ExprSetHeight(pParse, yygotominor.yy118.pExpr);
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
+ if( yygotominor.yy342.pExpr ){
+ yygotominor.yy342.pExpr->x.pSelect = yymsp[-1].minor.yy159;
+ ExprSetProperty(yygotominor.yy342.pExpr, EP_xIsSelect);
+ sqlite3ExprSetHeight(pParse, yygotominor.yy342.pExpr);
}else{
- sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy387);
+ sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy159);
}
- yygotominor.yy118.zStart = yymsp[-2].minor.yy0.z;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yygotominor.yy342.zStart = yymsp[-2].minor.yy0.z;
+ yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 229: /* expr ::= expr in_op LP select RP */
+ case 228: /* expr ::= expr in_op LP select RP */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy118.pExpr, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pSelect = yymsp[-1].minor.yy387;
- ExprSetProperty(yygotominor.yy118.pExpr, EP_xIsSelect);
- sqlite3ExprSetHeight(pParse, yygotominor.yy118.pExpr);
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy342.pExpr, 0, 0);
+ if( yygotominor.yy342.pExpr ){
+ yygotominor.yy342.pExpr->x.pSelect = yymsp[-1].minor.yy159;
+ ExprSetProperty(yygotominor.yy342.pExpr, EP_xIsSelect);
+ sqlite3ExprSetHeight(pParse, yygotominor.yy342.pExpr);
}else{
- sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy387);
+ sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy159);
}
- if( yymsp[-3].minor.yy4 ) yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy118.pExpr, 0, 0);
- yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ if( yymsp[-3].minor.yy392 ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
+ yygotominor.yy342.zStart = yymsp[-4].minor.yy342.zStart;
+ yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 230: /* expr ::= expr in_op nm dbnm */
+ case 229: /* expr ::= expr in_op nm dbnm */
{
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy118.pExpr, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
- ExprSetProperty(yygotominor.yy118.pExpr, EP_xIsSelect);
- sqlite3ExprSetHeight(pParse, yygotominor.yy118.pExpr);
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy342.pExpr, 0, 0);
+ if( yygotominor.yy342.pExpr ){
+ yygotominor.yy342.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
+ ExprSetProperty(yygotominor.yy342.pExpr, EP_xIsSelect);
+ sqlite3ExprSetHeight(pParse, yygotominor.yy342.pExpr);
}else{
sqlite3SrcListDelete(pParse->db, pSrc);
}
- if( yymsp[-2].minor.yy4 ) yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy118.pExpr, 0, 0);
- yygotominor.yy118.zStart = yymsp[-3].minor.yy118.zStart;
- yygotominor.yy118.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];
+ if( yymsp[-2].minor.yy392 ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
+ yygotominor.yy342.zStart = yymsp[-3].minor.yy342.zStart;
+ yygotominor.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];
}
break;
- case 231: /* expr ::= EXISTS LP select RP */
+ case 230: /* expr ::= EXISTS LP select RP */
{
- Expr *p = yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
+ Expr *p = yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
if( p ){
- p->x.pSelect = yymsp[-1].minor.yy387;
+ p->x.pSelect = yymsp[-1].minor.yy159;
ExprSetProperty(p, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, p);
}else{
- sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy387);
+ sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy159);
}
- yygotominor.yy118.zStart = yymsp[-3].minor.yy0.z;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yygotominor.yy342.zStart = yymsp[-3].minor.yy0.z;
+ yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 232: /* expr ::= CASE case_operand case_exprlist case_else END */
+ case 231: /* expr ::= CASE case_operand case_exprlist case_else END */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy314, yymsp[-1].minor.yy314, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pList = yymsp[-2].minor.yy322;
- sqlite3ExprSetHeight(pParse, yygotominor.yy118.pExpr);
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy122, yymsp[-1].minor.yy122, 0);
+ if( yygotominor.yy342.pExpr ){
+ yygotominor.yy342.pExpr->x.pList = yymsp[-2].minor.yy442;
+ sqlite3ExprSetHeight(pParse, yygotominor.yy342.pExpr);
}else{
- sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322);
+ sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy442);
}
- yygotominor.yy118.zStart = yymsp[-4].minor.yy0.z;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yygotominor.yy342.zStart = yymsp[-4].minor.yy0.z;
+ yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 233: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ case 232: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy118.pExpr);
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,yygotominor.yy322, yymsp[0].minor.yy118.pExpr);
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, yymsp[-2].minor.yy342.pExpr);
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse,yygotominor.yy442, yymsp[0].minor.yy342.pExpr);
}
break;
- case 234: /* case_exprlist ::= WHEN expr THEN expr */
+ case 233: /* case_exprlist ::= WHEN expr THEN expr */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy118.pExpr);
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,yygotominor.yy322, yymsp[0].minor.yy118.pExpr);
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr);
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse,yygotominor.yy442, yymsp[0].minor.yy342.pExpr);
}
break;
- case 243: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP */
+ case 240: /* nexprlist ::= nexprlist COMMA expr */
+{yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy442,yymsp[0].minor.yy342.pExpr);}
+ break;
+ case 241: /* nexprlist ::= expr */
+{yygotominor.yy442 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy342.pExpr);}
+ break;
+ case 242: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP */
{
sqlite3CreateIndex(pParse, &yymsp[-6].minor.yy0, &yymsp[-5].minor.yy0,
- sqlite3SrcListAppend(pParse->db,0,&yymsp[-3].minor.yy0,0), yymsp[-1].minor.yy322, yymsp[-9].minor.yy4,
- &yymsp[-10].minor.yy0, &yymsp[0].minor.yy0, SQLITE_SO_ASC, yymsp[-7].minor.yy4);
+ sqlite3SrcListAppend(pParse->db,0,&yymsp[-3].minor.yy0,0), yymsp[-1].minor.yy442, yymsp[-9].minor.yy392,
+ &yymsp[-10].minor.yy0, &yymsp[0].minor.yy0, SQLITE_SO_ASC, yymsp[-7].minor.yy392);
}
break;
- case 244: /* uniqueflag ::= UNIQUE */
- case 298: /* raisetype ::= ABORT */ yytestcase(yyruleno==298);
-{yygotominor.yy4 = OE_Abort;}
+ case 243: /* uniqueflag ::= UNIQUE */
+ case 296: /* raisetype ::= ABORT */ yytestcase(yyruleno==296);
+{yygotominor.yy392 = OE_Abort;}
break;
- case 245: /* uniqueflag ::= */
-{yygotominor.yy4 = OE_None;}
+ case 244: /* uniqueflag ::= */
+{yygotominor.yy392 = OE_None;}
break;
- case 248: /* idxlist ::= idxlist COMMA nm collate sortorder */
+ case 247: /* idxlist ::= idxlist COMMA nm collate sortorder */
{
Expr *p = 0;
if( yymsp[-1].minor.yy0.n>0 ){
p = sqlite3Expr(pParse->db, TK_COLUMN, 0);
sqlite3ExprSetCollByToken(pParse, p, &yymsp[-1].minor.yy0);
}
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, p);
- sqlite3ExprListSetName(pParse,yygotominor.yy322,&yymsp[-2].minor.yy0,1);
- sqlite3ExprListCheckLength(pParse, yygotominor.yy322, "index");
- if( yygotominor.yy322 ) yygotominor.yy322->a[yygotominor.yy322->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy4;
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, p);
+ sqlite3ExprListSetName(pParse,yygotominor.yy442,&yymsp[-2].minor.yy0,1);
+ sqlite3ExprListCheckLength(pParse, yygotominor.yy442, "index");
+ if( yygotominor.yy442 ) yygotominor.yy442->a[yygotominor.yy442->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy392;
}
break;
- case 249: /* idxlist ::= nm collate sortorder */
+ case 248: /* idxlist ::= nm collate sortorder */
{
Expr *p = 0;
if( yymsp[-1].minor.yy0.n>0 ){
p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
sqlite3ExprSetCollByToken(pParse, p, &yymsp[-1].minor.yy0);
}
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,0, p);
- sqlite3ExprListSetName(pParse, yygotominor.yy322, &yymsp[-2].minor.yy0, 1);
- sqlite3ExprListCheckLength(pParse, yygotominor.yy322, "index");
- if( yygotominor.yy322 ) yygotominor.yy322->a[yygotominor.yy322->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy4;
+ yygotominor.yy442 = sqlite3ExprListAppend(pParse,0, p);
+ sqlite3ExprListSetName(pParse, yygotominor.yy442, &yymsp[-2].minor.yy0, 1);
+ sqlite3ExprListCheckLength(pParse, yygotominor.yy442, "index");
+ if( yygotominor.yy442 ) yygotominor.yy442->a[yygotominor.yy442->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy392;
}
break;
- case 250: /* collate ::= */
+ case 249: /* collate ::= */
{yygotominor.yy0.z = 0; yygotominor.yy0.n = 0;}
break;
- case 252: /* cmd ::= DROP INDEX ifexists fullname */
-{sqlite3DropIndex(pParse, yymsp[0].minor.yy259, yymsp[-1].minor.yy4);}
+ case 251: /* cmd ::= DROP INDEX ifexists fullname */
+{sqlite3DropIndex(pParse, yymsp[0].minor.yy347, yymsp[-1].minor.yy392);}
break;
- case 253: /* cmd ::= VACUUM */
- case 254: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==254);
+ case 252: /* cmd ::= VACUUM */
+ case 253: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==253);
{sqlite3Vacuum(pParse);}
break;
- case 255: /* cmd ::= PRAGMA nm dbnm */
+ case 254: /* cmd ::= PRAGMA nm dbnm */
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
break;
- case 256: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+ case 255: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
break;
- case 257: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ case 256: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
break;
- case 258: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
+ case 257: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
break;
- case 259: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ case 258: /* 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 270: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ case 268: /* 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.yy203, &all);
+ sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy327, &all);
}
break;
- case 271: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ case 269: /* 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.yy4, yymsp[-4].minor.yy90.a, yymsp[-4].minor.yy90.b, yymsp[-2].minor.yy259, yymsp[0].minor.yy314, yymsp[-10].minor.yy4, yymsp[-8].minor.yy4);
+ 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);
yygotominor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0);
}
break;
- case 272: /* trigger_time ::= BEFORE */
- case 275: /* trigger_time ::= */ yytestcase(yyruleno==275);
-{ yygotominor.yy4 = TK_BEFORE; }
+ case 270: /* trigger_time ::= BEFORE */
+ case 273: /* trigger_time ::= */ yytestcase(yyruleno==273);
+{ yygotominor.yy392 = TK_BEFORE; }
break;
- case 273: /* trigger_time ::= AFTER */
-{ yygotominor.yy4 = TK_AFTER; }
+ case 271: /* trigger_time ::= AFTER */
+{ yygotominor.yy392 = TK_AFTER; }
break;
- case 274: /* trigger_time ::= INSTEAD OF */
-{ yygotominor.yy4 = TK_INSTEAD;}
+ case 272: /* trigger_time ::= INSTEAD OF */
+{ yygotominor.yy392 = TK_INSTEAD;}
break;
- case 276: /* trigger_event ::= DELETE|INSERT */
- case 277: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==277);
-{yygotominor.yy90.a = yymsp[0].major; yygotominor.yy90.b = 0;}
+ case 274: /* trigger_event ::= DELETE|INSERT */
+ case 275: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==275);
+{yygotominor.yy410.a = yymsp[0].major; yygotominor.yy410.b = 0;}
break;
- case 278: /* trigger_event ::= UPDATE OF inscollist */
-{yygotominor.yy90.a = TK_UPDATE; yygotominor.yy90.b = yymsp[0].minor.yy384;}
+ case 276: /* trigger_event ::= UPDATE OF inscollist */
+{yygotominor.yy410.a = TK_UPDATE; yygotominor.yy410.b = yymsp[0].minor.yy180;}
break;
- case 281: /* when_clause ::= */
- case 303: /* key_opt ::= */ yytestcase(yyruleno==303);
-{ yygotominor.yy314 = 0; }
+ case 279: /* when_clause ::= */
+ case 301: /* key_opt ::= */ yytestcase(yyruleno==301);
+{ yygotominor.yy122 = 0; }
break;
- case 282: /* when_clause ::= WHEN expr */
- case 304: /* key_opt ::= KEY expr */ yytestcase(yyruleno==304);
-{ yygotominor.yy314 = yymsp[0].minor.yy118.pExpr; }
+ case 280: /* when_clause ::= WHEN expr */
+ case 302: /* key_opt ::= KEY expr */ yytestcase(yyruleno==302);
+{ yygotominor.yy122 = yymsp[0].minor.yy342.pExpr; }
break;
- case 283: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ case 281: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
- assert( yymsp[-2].minor.yy203!=0 );
- yymsp[-2].minor.yy203->pLast->pNext = yymsp[-1].minor.yy203;
- yymsp[-2].minor.yy203->pLast = yymsp[-1].minor.yy203;
- yygotominor.yy203 = yymsp[-2].minor.yy203;
+ 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;
+ yygotominor.yy327 = yymsp[-2].minor.yy327;
}
break;
- case 284: /* trigger_cmd_list ::= trigger_cmd SEMI */
+ case 282: /* trigger_cmd_list ::= trigger_cmd SEMI */
{
- assert( yymsp[-1].minor.yy203!=0 );
- yymsp[-1].minor.yy203->pLast = yymsp[-1].minor.yy203;
- yygotominor.yy203 = yymsp[-1].minor.yy203;
+ assert( yymsp[-1].minor.yy327!=0 );
+ yymsp[-1].minor.yy327->pLast = yymsp[-1].minor.yy327;
+ yygotominor.yy327 = yymsp[-1].minor.yy327;
}
break;
- case 286: /* trnm ::= nm DOT nm */
+ case 284: /* trnm ::= nm DOT nm */
{
yygotominor.yy0 = yymsp[0].minor.yy0;
sqlite3ErrorMsg(pParse,
@@ -108995,121 +111376,121 @@ static void yy_reduce(
"statements within triggers");
}
break;
- case 288: /* tridxby ::= INDEXED BY nm */
+ case 286: /* tridxby ::= INDEXED BY nm */
{
sqlite3ErrorMsg(pParse,
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 289: /* tridxby ::= NOT INDEXED */
+ case 287: /* tridxby ::= NOT INDEXED */
{
sqlite3ErrorMsg(pParse,
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 290: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
-{ yygotominor.yy203 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy322, yymsp[0].minor.yy314, yymsp[-5].minor.yy210); }
+ case 288: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
+{ yygotominor.yy327 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy442, yymsp[0].minor.yy122, yymsp[-5].minor.yy258); }
break;
- case 291: /* trigger_cmd ::= insert_cmd INTO trnm inscollist_opt VALUES LP itemlist RP */
-{yygotominor.yy203 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy384, yymsp[-1].minor.yy322, 0, yymsp[-7].minor.yy210);}
+ case 289: /* trigger_cmd ::= insert_cmd INTO trnm inscollist_opt valuelist */
+{yygotominor.yy327 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy180, yymsp[0].minor.yy487.pList, yymsp[0].minor.yy487.pSelect, yymsp[-4].minor.yy258);}
break;
- case 292: /* trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select */
-{yygotominor.yy203 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy384, 0, yymsp[0].minor.yy387, yymsp[-4].minor.yy210);}
+ case 290: /* trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select */
+{yygotominor.yy327 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy180, 0, yymsp[0].minor.yy159, yymsp[-4].minor.yy258);}
break;
- case 293: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
-{yygotominor.yy203 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy314);}
+ case 291: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
+{yygotominor.yy327 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy122);}
break;
- case 294: /* trigger_cmd ::= select */
-{yygotominor.yy203 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy387); }
+ case 292: /* trigger_cmd ::= select */
+{yygotominor.yy327 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy159); }
break;
- case 295: /* expr ::= RAISE LP IGNORE RP */
+ case 293: /* expr ::= RAISE LP IGNORE RP */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->affinity = OE_Ignore;
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
+ if( yygotominor.yy342.pExpr ){
+ yygotominor.yy342.pExpr->affinity = OE_Ignore;
}
- yygotominor.yy118.zStart = yymsp[-3].minor.yy0.z;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yygotominor.yy342.zStart = yymsp[-3].minor.yy0.z;
+ yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 296: /* expr ::= RAISE LP raisetype COMMA nm RP */
+ case 294: /* expr ::= RAISE LP raisetype COMMA nm RP */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0);
- if( yygotominor.yy118.pExpr ) {
- yygotominor.yy118.pExpr->affinity = (char)yymsp[-3].minor.yy4;
+ yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0);
+ if( yygotominor.yy342.pExpr ) {
+ yygotominor.yy342.pExpr->affinity = (char)yymsp[-3].minor.yy392;
}
- yygotominor.yy118.zStart = yymsp[-5].minor.yy0.z;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yygotominor.yy342.zStart = yymsp[-5].minor.yy0.z;
+ yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 297: /* raisetype ::= ROLLBACK */
-{yygotominor.yy4 = OE_Rollback;}
+ case 295: /* raisetype ::= ROLLBACK */
+{yygotominor.yy392 = OE_Rollback;}
break;
- case 299: /* raisetype ::= FAIL */
-{yygotominor.yy4 = OE_Fail;}
+ case 297: /* raisetype ::= FAIL */
+{yygotominor.yy392 = OE_Fail;}
break;
- case 300: /* cmd ::= DROP TRIGGER ifexists fullname */
+ case 298: /* cmd ::= DROP TRIGGER ifexists fullname */
{
- sqlite3DropTrigger(pParse,yymsp[0].minor.yy259,yymsp[-1].minor.yy4);
+ sqlite3DropTrigger(pParse,yymsp[0].minor.yy347,yymsp[-1].minor.yy392);
}
break;
- case 301: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ case 299: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
- sqlite3Attach(pParse, yymsp[-3].minor.yy118.pExpr, yymsp[-1].minor.yy118.pExpr, yymsp[0].minor.yy314);
+ sqlite3Attach(pParse, yymsp[-3].minor.yy342.pExpr, yymsp[-1].minor.yy342.pExpr, yymsp[0].minor.yy122);
}
break;
- case 302: /* cmd ::= DETACH database_kw_opt expr */
+ case 300: /* cmd ::= DETACH database_kw_opt expr */
{
- sqlite3Detach(pParse, yymsp[0].minor.yy118.pExpr);
+ sqlite3Detach(pParse, yymsp[0].minor.yy342.pExpr);
}
break;
- case 307: /* cmd ::= REINDEX */
+ case 305: /* cmd ::= REINDEX */
{sqlite3Reindex(pParse, 0, 0);}
break;
- case 308: /* cmd ::= REINDEX nm dbnm */
+ case 306: /* cmd ::= REINDEX nm dbnm */
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 309: /* cmd ::= ANALYZE */
+ case 307: /* cmd ::= ANALYZE */
{sqlite3Analyze(pParse, 0, 0);}
break;
- case 310: /* cmd ::= ANALYZE nm dbnm */
+ case 308: /* cmd ::= ANALYZE nm dbnm */
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 311: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+ case 309: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
- sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy259,&yymsp[0].minor.yy0);
+ sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy347,&yymsp[0].minor.yy0);
}
break;
- case 312: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */
+ case 310: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */
{
sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy0);
}
break;
- case 313: /* add_column_fullname ::= fullname */
+ case 311: /* add_column_fullname ::= fullname */
{
pParse->db->lookaside.bEnabled = 0;
- sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy259);
+ sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy347);
}
break;
- case 316: /* cmd ::= create_vtab */
+ case 314: /* cmd ::= create_vtab */
{sqlite3VtabFinishParse(pParse,0);}
break;
- case 317: /* cmd ::= create_vtab LP vtabarglist RP */
+ case 315: /* cmd ::= create_vtab LP vtabarglist RP */
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
break;
- case 318: /* create_vtab ::= createkw VIRTUAL TABLE nm dbnm USING nm */
+ case 316: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
{
- sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
+ sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy392);
}
break;
- case 321: /* vtabarg ::= */
+ case 319: /* vtabarg ::= */
{sqlite3VtabArgInit(pParse);}
break;
- case 323: /* vtabargtoken ::= ANY */
- case 324: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==324);
- case 325: /* lp ::= LP */ yytestcase(yyruleno==325);
+ case 321: /* vtabargtoken ::= ANY */
+ case 322: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==322);
+ case 323: /* lp ::= LP */ yytestcase(yyruleno==323);
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
break;
default:
@@ -109129,30 +111510,25 @@ static void yy_reduce(
/* (44) type ::= */ yytestcase(yyruleno==44);
/* (51) signed ::= plus_num */ yytestcase(yyruleno==51);
/* (52) signed ::= minus_num */ yytestcase(yyruleno==52);
- /* (53) carglist ::= carglist carg */ yytestcase(yyruleno==53);
+ /* (53) carglist ::= carglist ccons */ yytestcase(yyruleno==53);
/* (54) carglist ::= */ yytestcase(yyruleno==54);
- /* (55) carg ::= CONSTRAINT nm ccons */ yytestcase(yyruleno==55);
- /* (56) carg ::= ccons */ yytestcase(yyruleno==56);
- /* (62) ccons ::= NULL onconf */ yytestcase(yyruleno==62);
- /* (90) conslist ::= conslist COMMA tcons */ yytestcase(yyruleno==90);
- /* (91) conslist ::= conslist tcons */ yytestcase(yyruleno==91);
- /* (92) conslist ::= tcons */ yytestcase(yyruleno==92);
- /* (93) tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==93);
- /* (268) plus_opt ::= PLUS */ yytestcase(yyruleno==268);
- /* (269) plus_opt ::= */ yytestcase(yyruleno==269);
- /* (279) foreach_clause ::= */ yytestcase(yyruleno==279);
- /* (280) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==280);
- /* (287) tridxby ::= */ yytestcase(yyruleno==287);
- /* (305) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==305);
- /* (306) database_kw_opt ::= */ yytestcase(yyruleno==306);
- /* (314) kwcolumn_opt ::= */ yytestcase(yyruleno==314);
- /* (315) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==315);
- /* (319) vtabarglist ::= vtabarg */ yytestcase(yyruleno==319);
- /* (320) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==320);
- /* (322) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==322);
- /* (326) anylist ::= */ yytestcase(yyruleno==326);
- /* (327) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==327);
- /* (328) anylist ::= anylist ANY */ yytestcase(yyruleno==328);
+ /* (61) ccons ::= NULL onconf */ yytestcase(yyruleno==61);
+ /* (89) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==89);
+ /* (90) conslist ::= tcons */ yytestcase(yyruleno==90);
+ /* (92) tconscomma ::= */ yytestcase(yyruleno==92);
+ /* (277) foreach_clause ::= */ yytestcase(yyruleno==277);
+ /* (278) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==278);
+ /* (285) tridxby ::= */ yytestcase(yyruleno==285);
+ /* (303) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==303);
+ /* (304) database_kw_opt ::= */ yytestcase(yyruleno==304);
+ /* (312) kwcolumn_opt ::= */ yytestcase(yyruleno==312);
+ /* (313) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==313);
+ /* (317) vtabarglist ::= vtabarg */ yytestcase(yyruleno==317);
+ /* (318) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==318);
+ /* (320) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==320);
+ /* (324) anylist ::= */ yytestcase(yyruleno==324);
+ /* (325) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==325);
+ /* (326) anylist ::= anylist ANY */ yytestcase(yyruleno==326);
break;
};
yygoto = yyRuleInfo[yyruleno].lhs;
@@ -109216,7 +111592,6 @@ static void yy_syntax_error(
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);
- pParse->parseError = 1;
sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
@@ -109811,7 +112186,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
case '-': {
if( z[1]=='-' ){
- /* IMP: R-15891-05542 -- syntax diagram for comments */
+ /* IMP: R-50417-27976 -- syntax diagram for comments */
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
*tokenType = TK_SPACE; /* IMP: R-22934-25134 */
return i;
@@ -109844,7 +112219,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
*tokenType = TK_SLASH;
return 1;
}
- /* IMP: R-15891-05542 -- syntax diagram for comments */
+ /* IMP: R-50417-27976 -- syntax diagram for comments */
for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
if( c ) i++;
*tokenType = TK_SPACE; /* IMP: R-22934-25134 */
@@ -110638,8 +113013,8 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
*/
SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
-/* IMPLEMENTATION-OF: R-54823-41343 The sqlite3_threadsafe() function returns
-** zero if and only if SQLite was compiled mutexing code omitted due to
+/* IMPLEMENTATION-OF: R-20790-14025 The sqlite3_threadsafe() function returns
+** zero if and only if SQLite was compiled with mutexing code omitted due to
** the SQLITE_THREADSAFE compile-time option being set to 0.
*/
SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
@@ -110828,8 +113203,8 @@ SQLITE_API int sqlite3_initialize(void){
*/
#ifdef SQLITE_EXTRA_INIT
if( rc==SQLITE_OK && sqlite3GlobalConfig.isInit ){
- int SQLITE_EXTRA_INIT(void);
- rc = SQLITE_EXTRA_INIT();
+ int SQLITE_EXTRA_INIT(const char*);
+ rc = SQLITE_EXTRA_INIT(0);
}
#endif
@@ -110846,6 +113221,10 @@ SQLITE_API int sqlite3_initialize(void){
*/
SQLITE_API int sqlite3_shutdown(void){
if( sqlite3GlobalConfig.isInit ){
+#ifdef SQLITE_EXTRA_SHUTDOWN
+ void SQLITE_EXTRA_SHUTDOWN(void);
+ SQLITE_EXTRA_SHUTDOWN();
+#endif
sqlite3_os_end();
sqlite3_reset_auto_extension();
sqlite3GlobalConfig.isInit = 0;
@@ -110954,16 +113333,25 @@ SQLITE_API int sqlite3_config(int op, ...){
}
case SQLITE_CONFIG_PCACHE: {
- /* Specify an alternative page cache implementation */
- sqlite3GlobalConfig.pcache = *va_arg(ap, sqlite3_pcache_methods*);
+ /* no-op */
break;
}
-
case SQLITE_CONFIG_GETPCACHE: {
- if( sqlite3GlobalConfig.pcache.xInit==0 ){
+ /* now an error */
+ rc = SQLITE_ERROR;
+ break;
+ }
+
+ case SQLITE_CONFIG_PCACHE2: {
+ /* Specify an alternative page cache implementation */
+ sqlite3GlobalConfig.pcache2 = *va_arg(ap, sqlite3_pcache_methods2*);
+ break;
+ }
+ case SQLITE_CONFIG_GETPCACHE2: {
+ if( sqlite3GlobalConfig.pcache2.xInit==0 ){
sqlite3PCacheSetDefault();
}
- *va_arg(ap, sqlite3_pcache_methods*) = sqlite3GlobalConfig.pcache;
+ *va_arg(ap, sqlite3_pcache_methods2*) = sqlite3GlobalConfig.pcache2;
break;
}
@@ -111062,21 +113450,21 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
if( db->lookaside.bMalloced ){
sqlite3_free(db->lookaside.pStart);
}
- /* The size of a lookaside slot needs to be larger than a pointer
- ** to be useful.
+ /* The size of a lookaside slot after ROUNDDOWN8 needs to be larger
+ ** than a pointer to be useful.
*/
+ sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0;
if( cnt<0 ) cnt = 0;
if( sz==0 || cnt==0 ){
sz = 0;
pStart = 0;
}else if( pBuf==0 ){
- sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
sqlite3BeginBenignMalloc();
pStart = sqlite3Malloc( sz*cnt ); /* IMP: R-61949-35727 */
sqlite3EndBenignMalloc();
+ if( pStart ) cnt = sqlite3MallocSize(pStart)/sz;
}else{
- sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
pStart = pBuf;
}
db->lookaside.pStart = pStart;
@@ -111111,6 +113499,26 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){
}
/*
+** Free up as much memory as we can from the given database
+** connection.
+*/
+SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){
+ int i;
+ sqlite3_mutex_enter(db->mutex);
+ sqlite3BtreeEnterAll(db);
+ for(i=0; i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ Pager *pPager = sqlite3BtreePager(pBt);
+ sqlite3PagerShrink(pPager);
+ }
+ }
+ sqlite3BtreeLeaveAll(db);
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+}
+
+/*
** Configuration settings for an individual database connection
*/
SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
@@ -111405,19 +113813,23 @@ SQLITE_API int sqlite3_close(sqlite3 *db){
}
/*
-** Rollback all database files.
+** Rollback all database files. If tripCode is not SQLITE_OK, then
+** any open cursors are invalidated ("tripped" - as in "tripping a circuit
+** breaker") and made to return tripCode if there are any further
+** attempts to use that cursor.
*/
-SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db){
+SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
int i;
int inTrans = 0;
assert( sqlite3_mutex_held(db->mutex) );
sqlite3BeginBenignMalloc();
for(i=0; i<db->nDb; i++){
- if( db->aDb[i].pBt ){
- if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
+ Btree *p = db->aDb[i].pBt;
+ if( p ){
+ if( sqlite3BtreeIsInTrans(p) ){
inTrans = 1;
}
- sqlite3BtreeRollback(db->aDb[i].pBt);
+ sqlite3BtreeRollback(p, tripCode);
db->aDb[i].inTrans = 0;
}
}
@@ -111472,12 +113884,21 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
/* SQLITE_RANGE */ "bind or column index out of range",
/* SQLITE_NOTADB */ "file is encrypted or is not a database",
};
- rc &= 0xff;
- if( ALWAYS(rc>=0) && rc<(int)(sizeof(aMsg)/sizeof(aMsg[0])) && aMsg[rc]!=0 ){
- return aMsg[rc];
- }else{
- return "unknown error";
+ const char *zErr = "unknown error";
+ switch( rc ){
+ case SQLITE_ABORT_ROLLBACK: {
+ zErr = "abort due to ROLLBACK";
+ break;
+ }
+ default: {
+ rc &= 0xff;
+ if( ALWAYS(rc>=0) && rc<ArraySize(aMsg) && aMsg[rc]!=0 ){
+ zErr = aMsg[rc];
+ }
+ break;
+ }
}
+ return zErr;
}
/*
@@ -111855,9 +114276,8 @@ SQLITE_API void *sqlite3_profile(
}
#endif /* SQLITE_OMIT_TRACE */
-/*** EXPERIMENTAL ***
-**
-** Register a function to be invoked when a transaction comments.
+/*
+** Register a function to be invoked when a transaction commits.
** If the invoked function returns non-zero, then the commit becomes a
** rollback.
*/
@@ -112217,7 +114637,6 @@ static int createCollation(
sqlite3* db,
const char *zName,
u8 enc,
- u8 collType,
void* pCtx,
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDel)(void*)
@@ -112282,7 +114701,6 @@ static int createCollation(
pColl->pUser = pCtx;
pColl->xDel = xDel;
pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED));
- pColl->type = collType;
sqlite3Error(db, SQLITE_OK, 0);
return SQLITE_OK;
}
@@ -112743,14 +115161,10 @@ static int openDatabase(
** and UTF-16, so add a version for each to avoid any unnecessary
** conversions. The only error that can occur here is a malloc() failure.
*/
- createCollation(db, "BINARY", SQLITE_UTF8, SQLITE_COLL_BINARY, 0,
- binCollFunc, 0);
- createCollation(db, "BINARY", SQLITE_UTF16BE, SQLITE_COLL_BINARY, 0,
- binCollFunc, 0);
- createCollation(db, "BINARY", SQLITE_UTF16LE, SQLITE_COLL_BINARY, 0,
- binCollFunc, 0);
- createCollation(db, "RTRIM", SQLITE_UTF8, SQLITE_COLL_USER, (void*)1,
- 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, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0);
if( db->mallocFailed ){
goto opendb_out;
}
@@ -112758,8 +115172,7 @@ static int openDatabase(
assert( db->pDfltColl!=0 );
/* Also add a UTF-8 case-insensitive collation sequence. */
- createCollation(db, "NOCASE", SQLITE_UTF8, SQLITE_COLL_NOCASE, 0,
- nocaseCollatingFunc, 0);
+ createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
/* Parse the filename/URI argument. */
db->openFlags = flags;
@@ -112808,10 +115221,13 @@ static int openDatabase(
/* Load automatic extensions - extensions that have been registered
** using the sqlite3_automatic_extension() API.
*/
- sqlite3AutoLoadExtensions(db);
rc = sqlite3_errcode(db);
- if( rc!=SQLITE_OK ){
- goto opendb_out;
+ if( rc==SQLITE_OK ){
+ sqlite3AutoLoadExtensions(db);
+ rc = sqlite3_errcode(db);
+ if( rc!=SQLITE_OK ){
+ goto opendb_out;
+ }
}
#ifdef SQLITE_ENABLE_FTS1
@@ -112952,7 +115368,7 @@ SQLITE_API int sqlite3_create_collation(
int rc;
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
- rc = createCollation(db, zName, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, 0);
+ rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, 0);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
@@ -112972,7 +115388,7 @@ SQLITE_API int sqlite3_create_collation_v2(
int rc;
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
- rc = createCollation(db, zName, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, xDel);
+ rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xDel);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
@@ -112995,7 +115411,7 @@ SQLITE_API int sqlite3_create_collation16(
assert( !db->mallocFailed );
zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE);
if( zName8 ){
- rc = createCollation(db, zName8, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, 0);
+ rc = createCollation(db, zName8, (u8)enc, pCtx, xCompare, 0);
sqlite3DbFree(db, zName8);
}
rc = sqlite3ApiExit(db, rc);
@@ -113252,35 +115668,27 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
*/
SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
int rc = SQLITE_ERROR;
- int iDb;
+ Btree *pBtree;
+
sqlite3_mutex_enter(db->mutex);
- if( zDbName==0 ){
- iDb = 0;
- }else{
- for(iDb=0; iDb<db->nDb; iDb++){
- if( strcmp(db->aDb[iDb].zName, zDbName)==0 ) break;
- }
- }
- if( iDb<db->nDb ){
- Btree *pBtree = db->aDb[iDb].pBt;
- if( pBtree ){
- Pager *pPager;
- sqlite3_file *fd;
- sqlite3BtreeEnter(pBtree);
- pPager = sqlite3BtreePager(pBtree);
- assert( pPager!=0 );
- fd = sqlite3PagerFile(pPager);
- assert( fd!=0 );
- if( op==SQLITE_FCNTL_FILE_POINTER ){
- *(sqlite3_file**)pArg = fd;
- rc = SQLITE_OK;
- }else if( fd->pMethods ){
- rc = sqlite3OsFileControl(fd, op, pArg);
- }else{
- rc = SQLITE_NOTFOUND;
- }
- sqlite3BtreeLeave(pBtree);
+ pBtree = sqlite3DbNameToBtree(db, zDbName);
+ if( pBtree ){
+ Pager *pPager;
+ sqlite3_file *fd;
+ sqlite3BtreeEnter(pBtree);
+ pPager = sqlite3BtreePager(pBtree);
+ assert( pPager!=0 );
+ fd = sqlite3PagerFile(pPager);
+ assert( fd!=0 );
+ if( op==SQLITE_FCNTL_FILE_POINTER ){
+ *(sqlite3_file**)pArg = fd;
+ rc = SQLITE_OK;
+ }else if( fd->pMethods ){
+ rc = sqlite3OsFileControl(fd, op, pArg);
+ }else{
+ rc = SQLITE_NOTFOUND;
}
+ sqlite3BtreeLeave(pBtree);
}
sqlite3_mutex_leave(db->mutex);
return rc;
@@ -113478,15 +115886,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){
}
#endif
- /* sqlite3_test_control(SQLITE_TESTCTRL_PGHDRSZ)
- **
- ** Return the size of a pcache header in bytes.
- */
- case SQLITE_TESTCTRL_PGHDRSZ: {
- rc = sizeof(PgHdr);
- break;
- }
-
/* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree);
**
** Pass pFree into sqlite3ScratchFree().
@@ -113514,6 +115913,22 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
+#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
+ /* sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT,
+ ** sqlite3_stmt*,const char**);
+ **
+ ** If compiled with SQLITE_ENABLE_TREE_EXPLAIN, each sqlite3_stmt holds
+ ** a string that describes the optimized parse tree. This test-control
+ ** returns a pointer to that string.
+ */
+ case SQLITE_TESTCTRL_EXPLAIN_STMT: {
+ sqlite3_stmt *pStmt = va_arg(ap, sqlite3_stmt*);
+ const char **pzRet = va_arg(ap, const char**);
+ *pzRet = sqlite3VdbeExplanation((Vdbe*)pStmt);
+ break;
+ }
+#endif
+
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
@@ -113532,6 +115947,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
** returns a NULL pointer.
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
+ if( zFilename==0 ) return 0;
zFilename += sqlite3Strlen30(zFilename) + 1;
while( zFilename[0] ){
int x = strcmp(zFilename, zParam);
@@ -113542,6 +115958,64 @@ SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *
return 0;
}
+/*
+** Return a boolean value for a query parameter.
+*/
+SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
+ const char *z = sqlite3_uri_parameter(zFilename, zParam);
+ bDflt = bDflt!=0;
+ return z ? sqlite3GetBoolean(z, bDflt) : bDflt;
+}
+
+/*
+** Return a 64-bit integer value for a query parameter.
+*/
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(
+ const char *zFilename, /* Filename as passed to xOpen */
+ const char *zParam, /* URI parameter sought */
+ sqlite3_int64 bDflt /* return if parameter is missing */
+){
+ const char *z = sqlite3_uri_parameter(zFilename, zParam);
+ sqlite3_int64 v;
+ if( z && sqlite3Atoi64(z, &v, sqlite3Strlen30(z), SQLITE_UTF8)==SQLITE_OK ){
+ bDflt = v;
+ }
+ return bDflt;
+}
+
+/*
+** Return the Btree pointer identified by zDbName. Return NULL if not found.
+*/
+SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
+ int i;
+ for(i=0; i<db->nDb; i++){
+ if( db->aDb[i].pBt
+ && (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0)
+ ){
+ return db->aDb[i].pBt;
+ }
+ }
+ return 0;
+}
+
+/*
+** Return the filename of the database associated with a database
+** connection.
+*/
+SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
+ Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
+ return pBt ? sqlite3BtreeGetFilename(pBt) : 0;
+}
+
+/*
+** Return 1 if database is read-only or 0 if read/write. Return -1 if
+** no such database exists.
+*/
+SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
+ Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
+ return pBt ? sqlite3PagerIsreadonly(sqlite3BtreePager(pBt)) : -1;
+}
+
/************** End of main.c ************************************************/
/************** Begin file notify.c ******************************************/
/*
@@ -113949,7 +116423,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
** A doclist is stored like this:
**
** array {
-** varint docid;
+** varint docid; (delta from previous doclist)
** array { (position list for column 0)
** varint position; (2 more than the delta from previous position)
** }
@@ -113980,8 +116454,8 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
** at D signals the start of a new column; the 1 at E indicates that the
** new column is column number 1. There are two positions at 12 and 45
** (14-2 and 35-2+12). The 0 at H indicate the end-of-document. The
-** 234 at I is the next docid. It has one position 72 (72-2) and then
-** terminates with the 0 at K.
+** 234 at I is the delta to next docid (357). It has one position 70
+** (72-2) and then terminates with the 0 at K.
**
** A "position-list" is the list of positions for multiple columns for
** a single docid. A "column-list" is the set of positions for a single
@@ -114165,10 +116639,6 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
** will eventually overtake the earlier data and knock it out. The
** query logic likewise merges doclists so that newer data knocks out
** older data.
-**
-** TODO(shess) Provide a VACUUM type operation to clear out all
-** deletions and duplications. This would basically be a forced merge
-** into a single segment.
*/
/************** Include fts3Int.h in the middle of fts3.c ********************/
@@ -114264,7 +116734,7 @@ typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor;
struct sqlite3_tokenizer_module {
/*
- ** Structure version. Should always be set to 0.
+ ** Structure version. Should always be set to 0 or 1.
*/
int iVersion;
@@ -114345,6 +116815,15 @@ struct sqlite3_tokenizer_module {
int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */
int *piPosition /* OUT: Number of tokens returned before this one */
);
+
+ /***********************************************************************
+ ** Methods below this point are only available if iVersion>=1.
+ */
+
+ /*
+ ** Configure the language id of a tokenizer cursor.
+ */
+ int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid);
};
struct sqlite3_tokenizer {
@@ -114511,6 +116990,9 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
#ifndef MIN
# define MIN(x,y) ((x)<(y)?(x):(y))
#endif
+#ifndef MAX
+# define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
/*
** Maximum length of a varint encoded integer. The varint format is different
@@ -114565,7 +117047,7 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
# define NEVER(X) (0)
#else
# define ALWAYS(x) (x)
-# define NEVER(X) (x)
+# define NEVER(x) (x)
#endif
/*
@@ -114575,6 +117057,7 @@ typedef unsigned char u8; /* 1-byte (or larger) unsigned integer */
typedef short int i16; /* 2-byte (or larger) signed integer */
typedef unsigned int u32; /* 4-byte unsigned integer */
typedef sqlite3_uint64 u64; /* 8-byte unsigned integer */
+typedef sqlite3_int64 i64; /* 8-byte signed integer */
/*
** Macro used to suppress compiler warnings for unused parameters.
@@ -114636,36 +117119,44 @@ struct Fts3Table {
char **azColumn; /* column names. malloced */
sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */
char *zContentTbl; /* content=xxx option, or NULL */
+ char *zLanguageid; /* languageid=xxx option, or NULL */
+ u8 bAutoincrmerge; /* True if automerge=1 */
+ u32 nLeafAdd; /* Number of leaf blocks added this trans */
/* Precompiled statements used by the implementation. Each of these
** statements is run and reset within a single virtual table API call.
*/
- sqlite3_stmt *aStmt[27];
+ sqlite3_stmt *aStmt[37];
char *zReadExprlist;
char *zWriteExprlist;
int nNodeSize; /* Soft limit for node size */
+ u8 bFts4; /* True for FTS4, false for FTS3 */
u8 bHasStat; /* True if %_stat table exists */
u8 bHasDocsize; /* True if %_docsize table exists */
u8 bDescIdx; /* True if doclists are in reverse order */
+ u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */
int nPgsz; /* Page size for host database */
char *zSegmentsTbl; /* Name of %_segments table */
sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
- /* TODO: Fix the first paragraph of this comment.
- **
- ** The following hash table is used to buffer pending index updates during
- ** transactions. Variable nPendingData estimates the memory size of the
- ** pending data, including hash table overhead, but not malloc overhead.
- ** When nPendingData exceeds nMaxPendingData, the buffer is flushed
- ** automatically. Variable iPrevDocid is the docid of the most recently
- ** inserted record.
+ /*
+ ** The following array of hash tables is used to buffer pending index
+ ** updates during transactions. All pending updates buffered at any one
+ ** time must share a common language-id (see the FTS4 langid= feature).
+ ** The current language id is stored in variable iPrevLangid.
**
** A single FTS4 table may have multiple full-text indexes. For each index
** there is an entry in the aIndex[] array. Index 0 is an index of all the
** terms that appear in the document set. Each subsequent index in aIndex[]
** is an index of prefixes of a specific length.
+ **
+ ** Variable nPendingData contains an estimate the memory consumed by the
+ ** pending data structures, including hash table overhead, but not including
+ ** malloc overhead. When nPendingData exceeds nMaxPendingData, all hash
+ ** tables are flushed to disk. Variable iPrevDocid is the docid of the most
+ ** recently inserted record.
*/
int nIndex; /* Size of aIndex[] */
struct Fts3Index {
@@ -114675,12 +117166,13 @@ struct Fts3Table {
int nMaxPendingData; /* Max pending data before flush to disk */
int nPendingData; /* Current bytes of pending data */
sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */
+ int iPrevLangid; /* Langid of recently inserted document */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
/* State variables used for validating that the transaction control
** methods of the virtual table are called at appropriate times. These
- ** values do not contribution to the FTS computation; they are used for
- ** verifying the SQLite core.
+ ** values do not contribute to FTS functionality; they are used for
+ ** verifying the operation of the SQLite core.
*/
int inTransaction; /* True after xBegin but before xCommit/xRollback */
int mxSavepoint; /* Largest valid xSavepoint integer */
@@ -114699,6 +117191,7 @@ struct Fts3Cursor {
u8 isRequireSeek; /* True if must seek pStmt to %_content row */
sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */
Fts3Expr *pExpr; /* Parsed MATCH query string */
+ int iLangid; /* Language being queried for */
int nPhrase; /* Number of matchable phrases in query */
Fts3DeferredToken *pDeferred; /* Deferred search tokens, if any */
sqlite3_int64 iPrevId; /* Previous id read from aDoclist */
@@ -114845,12 +117338,12 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sql
SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *);
SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *);
SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *);
-SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(int, sqlite3_int64,
+SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(int, int, sqlite3_int64,
sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
Fts3Table*,int,const char*,int,int,Fts3SegReader**);
SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *);
-SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, int, int, sqlite3_stmt **);
+SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, int, int, int, sqlite3_stmt **);
SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *);
SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*, int*);
@@ -114862,6 +117355,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int);
SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *);
SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *);
SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *);
+SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *, int *);
/* Special values interpreted by sqlite3SegReaderCursor() */
#define FTS3_SEGCURSOR_PENDING -1
@@ -114871,8 +117365,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(Fts3Table*, Fts3MultiSegReader*, Ft
SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(Fts3Table *, Fts3MultiSegReader *);
SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(Fts3MultiSegReader *);
-SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
- Fts3Table *, int, int, const char *, int, int, int, Fts3MultiSegReader *);
+SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(Fts3Table *,
+ int, int, int, const char *, int, int, int, Fts3MultiSegReader *);
/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
#define FTS3_SEGMENT_REQUIRE_POS 0x00000001
@@ -114913,6 +117407,8 @@ struct Fts3MultiSegReader {
int nDoclist; /* Size of aDoclist[] in bytes */
};
+SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
+
/* fts3.c */
SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64);
SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
@@ -114922,6 +117418,7 @@ SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*);
SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
+SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int*, Fts3Table*);
/* fts3_tokenizer.c */
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
@@ -114939,7 +117436,7 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const ch
SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
/* fts3_expr.c */
-SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *,
+SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int,
char **, int, int, int, const char *, int, Fts3Expr **
);
SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *);
@@ -114948,6 +117445,10 @@ SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db);
#endif
+SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int,
+ sqlite3_tokenizer_cursor **
+);
+
/* fts3_aux.c */
SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db);
@@ -114957,7 +117458,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart(
Fts3Table*, Fts3MultiSegReader*, int, const char*, int);
SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *);
-SQLITE_PRIVATE char *sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol);
+SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **);
SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
@@ -115142,6 +117643,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
sqlite3_free(p->zReadExprlist);
sqlite3_free(p->zWriteExprlist);
sqlite3_free(p->zContentTbl);
+ sqlite3_free(p->zLanguageid);
/* Invoke the tokenizer destructor to free the tokenizer. */
p->pTokenizer->pModule->xDestroy(p->pTokenizer);
@@ -115218,7 +117720,9 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
int rc; /* Return code */
char *zSql; /* SQL statement passed to declare_vtab() */
char *zCols; /* List of user defined columns */
+ const char *zLanguageid;
+ zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid");
sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
/* Create a list of user columns for the virtual table */
@@ -115229,7 +117733,8 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
/* Create the whole "CREATE TABLE" statement to pass to SQLite */
zSql = sqlite3_mprintf(
- "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN)", zCols, p->zName
+ "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN, %Q HIDDEN)",
+ zCols, p->zName, zLanguageid
);
if( !zCols || !zSql ){
rc = SQLITE_NOMEM;
@@ -115244,6 +117749,18 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
}
/*
+** Create the %_stat table if it does not already exist.
+*/
+SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int *pRc, Fts3Table *p){
+ fts3DbExec(pRc, p->db,
+ "CREATE TABLE IF NOT EXISTS %Q.'%q_stat'"
+ "(id INTEGER PRIMARY KEY, value BLOB);",
+ p->zDb, p->zName
+ );
+ if( (*pRc)==SQLITE_OK ) p->bHasStat = 1;
+}
+
+/*
** Create the backing store tables (%_content, %_segments and %_segdir)
** required by the FTS3 table passed as the only argument. This is done
** as part of the vtab xCreate() method.
@@ -115258,6 +117775,7 @@ static int fts3CreateTables(Fts3Table *p){
sqlite3 *db = p->db; /* The database connection */
if( p->zContentTbl==0 ){
+ const char *zLanguageid = p->zLanguageid;
char *zContentCols; /* Columns of %_content table */
/* Create a list of user columns for the content table */
@@ -115266,6 +117784,9 @@ static int fts3CreateTables(Fts3Table *p){
char *z = p->azColumn[i];
zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
}
+ if( zLanguageid && zContentCols ){
+ zContentCols = sqlite3_mprintf("%z, langid", zContentCols, zLanguageid);
+ }
if( zContentCols==0 ) rc = SQLITE_NOMEM;
/* Create the content table */
@@ -115299,11 +117820,9 @@ static int fts3CreateTables(Fts3Table *p){
p->zDb, p->zName
);
}
+ assert( p->bHasStat==p->bFts4 );
if( p->bHasStat ){
- fts3DbExec(&rc, db,
- "CREATE TABLE %Q.'%q_stat'(id INTEGER PRIMARY KEY, value BLOB);",
- p->zDb, p->zName
- );
+ sqlite3Fts3CreateStatTable(&rc, p);
}
return rc;
}
@@ -115385,6 +117904,7 @@ static void fts3Appendf(
char *z;
va_start(ap, zFormat);
z = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
if( z && *pz ){
char *z2 = sqlite3_mprintf("%s%s", *pz, z);
sqlite3_free(z);
@@ -115409,7 +117929,7 @@ static void fts3Appendf(
static char *fts3QuoteId(char const *zInput){
int nRet;
char *zRet;
- nRet = 2 + strlen(zInput)*2 + 1;
+ nRet = 2 + (int)strlen(zInput)*2 + 1;
zRet = sqlite3_malloc(nRet);
if( zRet ){
int i;
@@ -115464,14 +117984,20 @@ static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){
for(i=0; i<p->nColumn; i++){
fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]);
}
+ if( p->zLanguageid ){
+ fts3Appendf(pRc, &zRet, ", x.%Q", "langid");
+ }
sqlite3_free(zFree);
}else{
fts3Appendf(pRc, &zRet, "rowid");
for(i=0; i<p->nColumn; i++){
fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]);
}
+ if( p->zLanguageid ){
+ fts3Appendf(pRc, &zRet, ", x.%Q", p->zLanguageid);
+ }
}
- fts3Appendf(pRc, &zRet, "FROM '%q'.'%q%s' AS x",
+ fts3Appendf(pRc, &zRet, " FROM '%q'.'%q%s' AS x",
p->zDb,
(p->zContentTbl ? p->zContentTbl : p->zName),
(p->zContentTbl ? "" : "_content")
@@ -115514,6 +118040,9 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
for(i=0; i<p->nColumn; i++){
fts3Appendf(pRc, &zRet, ",%s(?)", zFunction);
}
+ if( p->zLanguageid ){
+ fts3Appendf(pRc, &zRet, ", ?");
+ }
sqlite3_free(zFree);
return zRet;
}
@@ -115656,7 +118185,7 @@ static int fts3ContentColumns(
nCol = sqlite3_column_count(pStmt);
for(i=0; i<nCol; i++){
const char *zCol = sqlite3_column_name(pStmt, i);
- nStr += strlen(zCol) + 1;
+ nStr += (int)strlen(zCol) + 1;
}
/* Allocate and populate the array to return. */
@@ -115667,7 +118196,7 @@ static int fts3ContentColumns(
char *p = (char *)&azCol[nCol];
for(i=0; i<nCol; i++){
const char *zCol = sqlite3_column_name(pStmt, i);
- int n = strlen(zCol)+1;
+ int n = (int)strlen(zCol)+1;
memcpy(p, zCol, n);
azCol[i] = p;
p += n;
@@ -115729,6 +118258,7 @@ static int fts3InitVtab(
char *zCompress = 0; /* compress=? parameter (or NULL) */
char *zUncompress = 0; /* uncompress=? parameter (or NULL) */
char *zContent = 0; /* content=? parameter (or NULL) */
+ char *zLanguageid = 0; /* languageid=? parameter (or NULL) */
assert( strlen(argv[0])==4 );
assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4)
@@ -115778,7 +118308,8 @@ static int fts3InitVtab(
{ "compress", 8 }, /* 2 -> COMPRESS */
{ "uncompress", 10 }, /* 3 -> UNCOMPRESS */
{ "order", 5 }, /* 4 -> ORDER */
- { "content", 7 } /* 5 -> CONTENT */
+ { "content", 7 }, /* 5 -> CONTENT */
+ { "languageid", 10 } /* 6 -> LANGUAGEID */
};
int iOpt;
@@ -115832,12 +118363,18 @@ static int fts3InitVtab(
bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
break;
- default: /* CONTENT */
- assert( iOpt==5 );
- sqlite3_free(zUncompress);
+ case 5: /* CONTENT */
+ sqlite3_free(zContent);
zContent = zVal;
zVal = 0;
break;
+
+ case 6: /* LANGUAGEID */
+ assert( iOpt==6 );
+ sqlite3_free(zLanguageid);
+ zLanguageid = zVal;
+ zVal = 0;
+ break;
}
}
sqlite3_free(zVal);
@@ -115867,8 +118404,21 @@ static int fts3InitVtab(
sqlite3_free((void*)aCol);
aCol = 0;
rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString);
+
+ /* If a languageid= option was specified, remove the language id
+ ** column from the aCol[] array. */
+ if( rc==SQLITE_OK && zLanguageid ){
+ int j;
+ for(j=0; j<nCol; j++){
+ if( sqlite3_stricmp(zLanguageid, aCol[j])==0 ){
+ int k;
+ for(k=j; k<nCol; k++) aCol[k] = aCol[k+1];
+ nCol--;
+ break;
+ }
+ }
+ }
}
- assert( rc!=SQLITE_OK || nCol>0 );
}
if( rc!=SQLITE_OK ) goto fts3_init_out;
@@ -115913,9 +118463,13 @@ static int fts3InitVtab(
p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
p->bHasDocsize = (isFts4 && bNoDocsize==0);
p->bHasStat = isFts4;
+ p->bFts4 = isFts4;
p->bDescIdx = bDescIdx;
+ p->bAutoincrmerge = 0xff; /* 0xff means setting unknown */
p->zContentTbl = zContent;
+ p->zLanguageid = zLanguageid;
zContent = 0;
+ zLanguageid = 0;
TESTONLY( p->inTransaction = -1 );
TESTONLY( p->mxSavepoint = -1 );
@@ -115964,6 +118518,16 @@ static int fts3InitVtab(
rc = fts3CreateTables(p);
}
+ /* Check to see if a legacy fts3 table has been "upgraded" by the
+ ** addition of a %_stat table so that it can use incremental merge.
+ */
+ if( !isFts4 && !isCreate ){
+ int rc2 = SQLITE_OK;
+ fts3DbExec(&rc2, db, "SELECT 1 FROM %Q.'%q_stat' WHERE id=2",
+ p->zDb, p->zName);
+ if( rc2==SQLITE_OK ) p->bHasStat = 1;
+ }
+
/* Figure out the page-size for the database. This is required in order to
** estimate the cost of loading large doclists from the database. */
fts3DatabasePageSize(&rc, p);
@@ -115978,6 +118542,7 @@ fts3_init_out:
sqlite3_free(zCompress);
sqlite3_free(zUncompress);
sqlite3_free(zContent);
+ sqlite3_free(zLanguageid);
sqlite3_free((void *)aCol);
if( rc!=SQLITE_OK ){
if( p ){
@@ -116029,6 +118594,7 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
Fts3Table *p = (Fts3Table *)pVTab;
int i; /* Iterator variable */
int iCons = -1; /* Index of constraint to use */
+ int iLangidCons = -1; /* Index of langid=x constraint, if present */
/* By default use a full table scan. This is an expensive option,
** so search through the constraints to see if a more efficient
@@ -116041,7 +118607,8 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
if( pCons->usable==0 ) continue;
/* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */
- if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
+ if( iCons<0
+ && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
&& (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1 )
){
pInfo->idxNum = FTS3_DOCID_SEARCH;
@@ -116064,7 +118631,13 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
pInfo->idxNum = FTS3_FULLTEXT_SEARCH + pCons->iColumn;
pInfo->estimatedCost = 2.0;
iCons = i;
- break;
+ }
+
+ /* Equality constraint on the langid column */
+ if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
+ && pCons->iColumn==p->nColumn + 2
+ ){
+ iLangidCons = i;
}
}
@@ -116072,6 +118645,9 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
pInfo->aConstraintUsage[iCons].argvIndex = 1;
pInfo->aConstraintUsage[iCons].omit = 1;
}
+ if( iLangidCons>=0 ){
+ pInfo->aConstraintUsage[iLangidCons].argvIndex = 2;
+ }
/* Regardless of the strategy selected, FTS can deliver rows in rowid (or
** docid) order. Both ascending and descending are possible.
@@ -116955,7 +119531,7 @@ static int fts3DoclistOrMerge(
}
*paOut = aOut;
- *pnOut = (p-aOut);
+ *pnOut = (int)(p-aOut);
assert( *pnOut<=n1+n2+FTS3_VARINT_MAX-1 );
return SQLITE_OK;
}
@@ -117019,7 +119595,7 @@ static void fts3DoclistPhraseMerge(
}
}
- *pnRight = p - aOut;
+ *pnRight = (int)(p - aOut);
}
/*
@@ -117221,6 +119797,7 @@ static int fts3SegReaderCursorAppend(
*/
static int fts3SegReaderCursor(
Fts3Table *p, /* FTS3 table handle */
+ int iLangid, /* Language id */
int iIndex, /* Index to search (from 0 to p->nIndex-1) */
int iLevel, /* Level of segments to scan */
const char *zTerm, /* Term to query for */
@@ -117249,7 +119826,7 @@ static int fts3SegReaderCursor(
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
if( rc==SQLITE_OK ){
- rc = sqlite3Fts3AllSegdirs(p, iIndex, iLevel, &pStmt);
+ rc = sqlite3Fts3AllSegdirs(p, iLangid, iIndex, iLevel, &pStmt);
}
while( rc==SQLITE_OK && SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
@@ -117272,7 +119849,9 @@ static int fts3SegReaderCursor(
}
rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1,
- iStartBlock, iLeavesEndBlock, iEndBlock, zRoot, nRoot, &pSeg
+ (isPrefix==0 && isScan==0),
+ iStartBlock, iLeavesEndBlock,
+ iEndBlock, zRoot, nRoot, &pSeg
);
if( rc!=SQLITE_OK ) goto finished;
rc = fts3SegReaderCursorAppend(pCsr, pSeg);
@@ -117292,6 +119871,7 @@ static int fts3SegReaderCursor(
*/
SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
Fts3Table *p, /* FTS3 table handle */
+ int iLangid, /* Language-id to search */
int iIndex, /* Index to search (from 0 to p->nIndex-1) */
int iLevel, /* Level of segments to scan */
const char *zTerm, /* Term to query for */
@@ -117309,14 +119889,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
assert( FTS3_SEGCURSOR_ALL<0 && FTS3_SEGCURSOR_PENDING<0 );
assert( isPrefix==0 || isScan==0 );
- /* "isScan" is only set to true by the ft4aux module, an ordinary
- ** full-text tables. */
- assert( isScan==0 || p->aIndex==0 );
-
memset(pCsr, 0, sizeof(Fts3MultiSegReader));
-
return fts3SegReaderCursor(
- p, iIndex, iLevel, zTerm, nTerm, isPrefix, isScan, pCsr
+ p, iLangid, iIndex, iLevel, zTerm, nTerm, isPrefix, isScan, pCsr
);
}
@@ -117328,11 +119903,14 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
*/
static int fts3SegReaderCursorAddZero(
Fts3Table *p, /* FTS virtual table handle */
+ int iLangid,
const char *zTerm, /* Term to scan doclist of */
int nTerm, /* Number of bytes in zTerm */
Fts3MultiSegReader *pCsr /* Fts3MultiSegReader to modify */
){
- return fts3SegReaderCursor(p, 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0,pCsr);
+ return fts3SegReaderCursor(p,
+ iLangid, 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0,pCsr
+ );
}
/*
@@ -117368,8 +119946,9 @@ static int fts3TermSegReaderCursor(
for(i=1; bFound==0 && i<p->nIndex; i++){
if( p->aIndex[i].nPrefix==nTerm ){
bFound = 1;
- rc = sqlite3Fts3SegReaderCursor(
- p, i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0, pSegcsr);
+ rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
+ i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0, pSegcsr
+ );
pSegcsr->bLookup = 1;
}
}
@@ -117377,19 +119956,21 @@ static int fts3TermSegReaderCursor(
for(i=1; bFound==0 && i<p->nIndex; i++){
if( p->aIndex[i].nPrefix==nTerm+1 ){
bFound = 1;
- rc = sqlite3Fts3SegReaderCursor(
- p, i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 1, 0, pSegcsr
+ rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
+ i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 1, 0, pSegcsr
);
if( rc==SQLITE_OK ){
- rc = fts3SegReaderCursorAddZero(p, zTerm, nTerm, pSegcsr);
+ rc = fts3SegReaderCursorAddZero(
+ p, pCsr->iLangid, zTerm, nTerm, pSegcsr
+ );
}
}
}
}
if( bFound==0 ){
- rc = sqlite3Fts3SegReaderCursor(
- p, 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, isPrefix, 0, pSegcsr
+ rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
+ 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, isPrefix, 0, pSegcsr
);
pSegcsr->bLookup = !isPrefix;
}
@@ -117544,7 +120125,7 @@ static int fts3FilterMethod(
UNUSED_PARAMETER(nVal);
assert( idxNum>=0 && idxNum<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
- assert( nVal==0 || nVal==1 );
+ assert( nVal==0 || nVal==1 || nVal==2 );
assert( (nVal==0)==(idxNum==FTS3_FULLSCAN_SEARCH) );
assert( p->pSegments==0 );
@@ -117569,8 +120150,11 @@ static int fts3FilterMethod(
return SQLITE_NOMEM;
}
- rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->bHasStat,
- p->nColumn, iCol, zQuery, -1, &pCsr->pExpr
+ pCsr->iLangid = 0;
+ if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]);
+
+ rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
+ p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr
);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_ERROR ){
@@ -117641,10 +120225,17 @@ static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
/*
** This is the xColumn method, called by SQLite to request a value from
** the row that the supplied cursor currently points to.
+**
+** If:
+**
+** (iCol < p->nColumn) -> The value of the iCol'th user column.
+** (iCol == p->nColumn) -> Magic column with the same name as the table.
+** (iCol == p->nColumn+1) -> Docid column
+** (iCol == p->nColumn+2) -> Langid column
*/
static int fts3ColumnMethod(
sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
- sqlite3_context *pContext, /* Context for sqlite3_result_xxx() calls */
+ sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
int iCol /* Index of column to read value from */
){
int rc = SQLITE_OK; /* Return Code */
@@ -117652,22 +120243,34 @@ static int fts3ColumnMethod(
Fts3Table *p = (Fts3Table *)pCursor->pVtab;
/* The column value supplied by SQLite must be in range. */
- assert( iCol>=0 && iCol<=p->nColumn+1 );
+ assert( iCol>=0 && iCol<=p->nColumn+2 );
if( iCol==p->nColumn+1 ){
/* This call is a request for the "docid" column. Since "docid" is an
** alias for "rowid", use the xRowid() method to obtain the value.
*/
- sqlite3_result_int64(pContext, pCsr->iPrevId);
+ sqlite3_result_int64(pCtx, pCsr->iPrevId);
}else if( iCol==p->nColumn ){
/* The extra column whose name is the same as the table.
- ** Return a blob which is a pointer to the cursor.
- */
- sqlite3_result_blob(pContext, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
+ ** Return a blob which is a pointer to the cursor. */
+ sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
+ }else if( iCol==p->nColumn+2 && pCsr->pExpr ){
+ sqlite3_result_int64(pCtx, pCsr->iLangid);
}else{
+ /* The requested column is either a user column (one that contains
+ ** indexed data), or the language-id column. */
rc = fts3CursorSeek(0, pCsr);
- if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
- sqlite3_result_value(pContext, sqlite3_column_value(pCsr->pStmt, iCol+1));
+
+ if( rc==SQLITE_OK ){
+ if( iCol==p->nColumn+2 ){
+ int iLangid = 0;
+ if( p->zLanguageid ){
+ iLangid = sqlite3_column_int(pCsr->pStmt, p->nColumn+1);
+ }
+ sqlite3_result_int(pCtx, iLangid);
+ }else if( sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
+ sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
+ }
}
}
@@ -117694,8 +120297,42 @@ static int fts3UpdateMethod(
** hash-table to the database.
*/
static int fts3SyncMethod(sqlite3_vtab *pVtab){
- int rc = sqlite3Fts3PendingTermsFlush((Fts3Table *)pVtab);
- sqlite3Fts3SegmentsClose((Fts3Table *)pVtab);
+
+ /* Following an incremental-merge operation, assuming that the input
+ ** segments are not completely consumed (the usual case), they are updated
+ ** in place to remove the entries that have already been merged. This
+ ** involves updating the leaf block that contains the smallest unmerged
+ ** entry and each block (if any) between the leaf and the root node. So
+ ** if the height of the input segment b-trees is N, and input segments
+ ** are merged eight at a time, updating the input segments at the end
+ ** of an incremental-merge requires writing (8*(1+N)) blocks. N is usually
+ ** small - often between 0 and 2. So the overhead of the incremental
+ ** merge is somewhere between 8 and 24 blocks. To avoid this overhead
+ ** dwarfing the actual productive work accomplished, the incremental merge
+ ** is only attempted if it will write at least 64 leaf blocks. Hence
+ ** nMinMerge.
+ **
+ ** Of course, updating the input segments also involves deleting a bunch
+ ** of blocks from the segments table. But this is not considered overhead
+ ** as it would also be required by a crisis-merge that used the same input
+ ** segments.
+ */
+ const u32 nMinMerge = 64; /* Minimum amount of incr-merge work to do */
+
+ Fts3Table *p = (Fts3Table*)pVtab;
+ int rc = sqlite3Fts3PendingTermsFlush(p);
+
+ if( rc==SQLITE_OK && p->bAutoincrmerge==1 && p->nLeafAdd>(nMinMerge/16) ){
+ int mxLevel = 0; /* Maximum relative level value in db */
+ int A; /* Incr-merge parameter A */
+
+ rc = sqlite3Fts3MaxLevel(p, &mxLevel);
+ assert( rc==SQLITE_OK || mxLevel==0 );
+ A = p->nLeafAdd * mxLevel;
+ A += (A/2);
+ if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, 8);
+ }
+ sqlite3Fts3SegmentsClose(p);
return rc;
}
@@ -117703,13 +120340,14 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
** Implementation of xBegin() method. This is a no-op.
*/
static int fts3BeginMethod(sqlite3_vtab *pVtab){
- TESTONLY( Fts3Table *p = (Fts3Table*)pVtab );
+ Fts3Table *p = (Fts3Table*)pVtab;
UNUSED_PARAMETER(pVtab);
assert( p->pSegments==0 );
assert( p->nPendingData==0 );
assert( p->inTransaction!=1 );
TESTONLY( p->inTransaction = 1 );
TESTONLY( p->mxSavepoint = -1; );
+ p->nLeafAdd = 0;
return SQLITE_OK;
}
@@ -118004,11 +120642,15 @@ static int fts3RenameMethod(
** Flush the contents of the pending-terms table to disk.
*/
static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
+ int rc = SQLITE_OK;
UNUSED_PARAMETER(iSavepoint);
assert( ((Fts3Table *)pVtab)->inTransaction );
assert( ((Fts3Table *)pVtab)->mxSavepoint < iSavepoint );
TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint );
- return fts3SyncMethod(pVtab);
+ if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){
+ rc = fts3SyncMethod(pVtab);
+ }
+ return rc;
}
/*
@@ -118368,7 +121010,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
fts3PoslistPhraseMerge(&aOut, iToken-iPrev, 0, 1, &p1, &p2);
sqlite3_free(aPoslist);
aPoslist = pList;
- nPoslist = aOut - aPoslist;
+ nPoslist = (int)(aOut - aPoslist);
if( nPoslist==0 ){
sqlite3_free(aPoslist);
pPhrase->doclist.pList = 0;
@@ -118412,7 +121054,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
pPhrase->doclist.pList = aOut;
if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){
pPhrase->doclist.bFreeList = 1;
- pPhrase->doclist.nList = (aOut - pPhrase->doclist.pList);
+ pPhrase->doclist.nList = (int)(aOut - pPhrase->doclist.pList);
}else{
sqlite3_free(aOut);
pPhrase->doclist.pList = 0;
@@ -118481,7 +121123,7 @@ SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(
int nDoclist, /* Length of aDoclist in bytes */
char **ppIter, /* IN/OUT: Iterator pointer */
sqlite3_int64 *piDocid, /* IN/OUT: Docid pointer */
- int *pnList, /* IN/OUT: List length pointer */
+ int *pnList, /* OUT: List length pointer */
u8 *pbEof /* OUT: End-of-file flag */
){
char *p = *ppIter;
@@ -118508,7 +121150,7 @@ SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(
iMul = (bDescIdx ? -1 : 1);
}
- *pnList = pEnd - pNext;
+ *pnList = (int)(pEnd - pNext);
*ppIter = pNext;
*piDocid = iDocid;
}else{
@@ -118522,13 +121164,48 @@ SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(
}else{
char *pSave = p;
fts3ReversePoslist(aDoclist, &p);
- *pnList = (pSave - p);
+ *pnList = (int)(pSave - p);
}
*ppIter = p;
}
}
/*
+** Iterate forwards through a doclist.
+*/
+SQLITE_PRIVATE void sqlite3Fts3DoclistNext(
+ int bDescIdx, /* True if the doclist is desc */
+ char *aDoclist, /* Pointer to entire doclist */
+ int nDoclist, /* Length of aDoclist in bytes */
+ char **ppIter, /* IN/OUT: Iterator pointer */
+ sqlite3_int64 *piDocid, /* IN/OUT: Docid pointer */
+ u8 *pbEof /* OUT: End-of-file flag */
+){
+ char *p = *ppIter;
+
+ assert( nDoclist>0 );
+ assert( *pbEof==0 );
+ assert( p || *piDocid==0 );
+ assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) );
+
+ if( p==0 ){
+ p = aDoclist;
+ p += sqlite3Fts3GetVarint(p, piDocid);
+ }else{
+ fts3PoslistCopy(0, &p);
+ if( p>=&aDoclist[nDoclist] ){
+ *pbEof = 1;
+ }else{
+ sqlite3_int64 iVar;
+ p += sqlite3Fts3GetVarint(p, &iVar);
+ *piDocid += ((bDescIdx ? -1 : 1) * iVar);
+ }
+ }
+
+ *ppIter = p;
+}
+
+/*
** Attempt to move the phrase iterator to point to the next matching docid.
** If an error occurs, return an SQLite error code. Otherwise, return
** SQLITE_OK.
@@ -118582,7 +121259,7 @@ static int fts3EvalPhraseNext(
}
pDL->pList = pIter;
fts3PoslistCopy(0, &pIter);
- pDL->nList = (pIter - pDL->pList);
+ pDL->nList = (int)(pIter - pDL->pList);
/* pIter now points just past the 0x00 that terminates the position-
** list for document pDL->iDocid. However, if this position-list was
@@ -118923,7 +121600,7 @@ static int fts3EvalStart(Fts3Cursor *pCsr){
fts3EvalAllocateReaders(pCsr, pCsr->pExpr, &nToken, &nOr, &rc);
/* Determine which, if any, tokens in the expression should be deferred. */
- if( rc==SQLITE_OK && nToken>1 && pTab->bHasStat ){
+ if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){
Fts3TokenAndCost *aTC;
Fts3Expr **apOr;
aTC = (Fts3TokenAndCost *)sqlite3_malloc(
@@ -118940,8 +121617,8 @@ static int fts3EvalStart(Fts3Cursor *pCsr){
Fts3Expr **ppOr = apOr;
fts3EvalTokenCosts(pCsr, 0, pCsr->pExpr, &pTC, &ppOr, &rc);
- nToken = pTC-aTC;
- nOr = ppOr-apOr;
+ nToken = (int)(pTC-aTC);
+ nOr = (int)(ppOr-apOr);
if( rc==SQLITE_OK ){
rc = fts3EvalSelectDeferred(pCsr, 0, aTC, nToken);
@@ -119013,7 +121690,7 @@ static int fts3EvalNearTrim(
&pOut, aTmp, nParam1, nParam2, paPoslist, &p2
);
if( res ){
- nNew = (pOut - pPhrase->doclist.pList) - 1;
+ nNew = (int)(pOut - pPhrase->doclist.pList) - 1;
assert( pPhrase->doclist.pList[nNew]=='\0' );
assert( nNew<=pPhrase->doclist.nList && nNew>0 );
memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew);
@@ -119683,26 +122360,87 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(
** This function works regardless of whether or not the phrase is deferred,
** incremental, or neither.
*/
-SQLITE_PRIVATE char *sqlite3Fts3EvalPhrasePoslist(
+SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
Fts3Cursor *pCsr, /* FTS3 cursor object */
Fts3Expr *pExpr, /* Phrase to return doclist for */
- int iCol /* Column to return position list for */
+ int iCol, /* Column to return position list for */
+ char **ppOut /* OUT: Pointer to position list */
){
Fts3Phrase *pPhrase = pExpr->pPhrase;
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
- char *pIter = pPhrase->doclist.pList;
+ char *pIter;
int iThis;
+ sqlite3_int64 iDocid;
+ /* If this phrase is applies specifically to some column other than
+ ** column iCol, return a NULL pointer. */
+ *ppOut = 0;
assert( iCol>=0 && iCol<pTab->nColumn );
- if( !pIter
- || pExpr->bEof
- || pExpr->iDocid!=pCsr->iPrevId
- || (pPhrase->iColumn<pTab->nColumn && pPhrase->iColumn!=iCol)
- ){
- return 0;
+ if( (pPhrase->iColumn<pTab->nColumn && pPhrase->iColumn!=iCol) ){
+ return SQLITE_OK;
+ }
+
+ iDocid = pExpr->iDocid;
+ pIter = pPhrase->doclist.pList;
+ if( iDocid!=pCsr->iPrevId || pExpr->bEof ){
+ int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */
+ int bOr = 0;
+ u8 bEof = 0;
+ Fts3Expr *p;
+
+ /* Check if this phrase descends from an OR expression node. If not,
+ ** return NULL. Otherwise, the entry that corresponds to docid
+ ** pCsr->iPrevId may lie earlier in the doclist buffer. */
+ for(p=pExpr->pParent; p; p=p->pParent){
+ if( p->eType==FTSQUERY_OR ) bOr = 1;
+ }
+ if( bOr==0 ) return SQLITE_OK;
+
+ /* This is the descendent of an OR node. In this case we cannot use
+ ** an incremental phrase. Load the entire doclist for the phrase
+ ** into memory in this case. */
+ if( pPhrase->bIncr ){
+ int rc = SQLITE_OK;
+ int bEofSave = pExpr->bEof;
+ fts3EvalRestart(pCsr, pExpr, &rc);
+ while( rc==SQLITE_OK && !pExpr->bEof ){
+ fts3EvalNextRow(pCsr, pExpr, &rc);
+ if( bEofSave==0 && pExpr->iDocid==iDocid ) break;
+ }
+ pIter = pPhrase->doclist.pList;
+ assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
+ if( rc!=SQLITE_OK ) return rc;
+ }
+
+ if( pExpr->bEof ){
+ pIter = 0;
+ iDocid = 0;
+ }
+ bEof = (pPhrase->doclist.nAll==0);
+ assert( bDescDoclist==0 || bDescDoclist==1 );
+ assert( pCsr->bDesc==0 || pCsr->bDesc==1 );
+
+ if( pCsr->bDesc==bDescDoclist ){
+ int dummy;
+ while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
+ sqlite3Fts3DoclistPrev(
+ bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
+ &pIter, &iDocid, &dummy, &bEof
+ );
+ }
+ }else{
+ while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
+ sqlite3Fts3DoclistNext(
+ bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
+ &pIter, &iDocid, &bEof
+ );
+ }
+ }
+
+ if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0;
}
+ if( pIter==0 ) return SQLITE_OK;
- assert( pPhrase->doclist.nList>0 );
if( *pIter==0x01 ){
pIter++;
pIter += sqlite3Fts3GetVarint32(pIter, &iThis);
@@ -119716,7 +122454,8 @@ SQLITE_PRIVATE char *sqlite3Fts3EvalPhrasePoslist(
pIter += sqlite3Fts3GetVarint32(pIter, &iThis);
}
- return ((iCol==iThis)?pIter:0);
+ *ppOut = ((iCol==iThis)?pIter:0);
+ return SQLITE_OK;
}
/*
@@ -119739,6 +122478,7 @@ SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *pPhrase){
}
}
+
/*
** Return SQLITE_CORRUPT_VTAB.
*/
@@ -119846,9 +122586,9 @@ static int fts3auxConnectMethod(
}
zDb = argv[1];
- nDb = strlen(zDb);
+ nDb = (int)strlen(zDb);
zFts3 = argv[3];
- nFts3 = strlen(zFts3);
+ nFts3 = (int)strlen(zFts3);
rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
if( rc!=SQLITE_OK ) return rc;
@@ -120143,7 +122883,7 @@ static int fts3auxFilterMethod(
if( pCsr->zStop==0 ) return SQLITE_NOMEM;
}
- rc = sqlite3Fts3SegReaderCursor(pFts3, 0, FTS3_SEGCURSOR_ALL,
+ rc = sqlite3Fts3SegReaderCursor(pFts3, 0, 0, FTS3_SEGCURSOR_ALL,
pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr
);
if( rc==SQLITE_OK ){
@@ -120335,6 +123075,7 @@ SQLITE_API int sqlite3_fts3_enable_parentheses = 0;
typedef struct ParseContext ParseContext;
struct ParseContext {
sqlite3_tokenizer *pTokenizer; /* Tokenizer module */
+ int iLangid; /* Language id used with tokenizer */
const char **azCol; /* Array of column names for fts3 table */
int bFts4; /* True to allow FTS4-only syntax */
int nCol; /* Number of entries in azCol[] */
@@ -120370,6 +123111,33 @@ static void *fts3MallocZero(int nByte){
return pRet;
}
+SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer(
+ sqlite3_tokenizer *pTokenizer,
+ int iLangid,
+ const char *z,
+ int n,
+ sqlite3_tokenizer_cursor **ppCsr
+){
+ sqlite3_tokenizer_module const *pModule = pTokenizer->pModule;
+ sqlite3_tokenizer_cursor *pCsr = 0;
+ int rc;
+
+ rc = pModule->xOpen(pTokenizer, z, n, &pCsr);
+ assert( rc==SQLITE_OK || pCsr==0 );
+ if( rc==SQLITE_OK ){
+ pCsr->pTokenizer = pTokenizer;
+ if( pModule->iVersion>=1 ){
+ rc = pModule->xLanguageid(pCsr, iLangid);
+ if( rc!=SQLITE_OK ){
+ pModule->xClose(pCsr);
+ pCsr = 0;
+ }
+ }
+ }
+ *ppCsr = pCsr;
+ return rc;
+}
+
/*
** Extract the next token from buffer z (length n) using the tokenizer
@@ -120397,15 +123165,13 @@ static int getNextToken(
Fts3Expr *pRet = 0;
int nConsumed = 0;
- rc = pModule->xOpen(pTokenizer, z, n, &pCursor);
+ rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor);
if( rc==SQLITE_OK ){
const char *zToken;
int nToken, iStart, iEnd, iPosition;
int nByte; /* total space to allocate */
- pCursor->pTokenizer = pTokenizer;
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
-
if( rc==SQLITE_OK ){
nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
pRet = (Fts3Expr *)fts3MallocZero(nByte);
@@ -120511,10 +123277,10 @@ static int getNextString(
** appends buffer zTemp to buffer p, and fills in the Fts3Expr and Fts3Phrase
** structures.
*/
- rc = pModule->xOpen(pTokenizer, zInput, nInput, &pCursor);
+ rc = sqlite3Fts3OpenTokenizer(
+ pTokenizer, pParse->iLangid, zInput, nInput, &pCursor);
if( rc==SQLITE_OK ){
int ii;
- pCursor->pTokenizer = pTokenizer;
for(ii=0; rc==SQLITE_OK; ii++){
const char *zByte;
int nByte, iBegin, iEnd, iPos;
@@ -120988,6 +123754,7 @@ exprparse_out:
*/
SQLITE_PRIVATE int sqlite3Fts3ExprParse(
sqlite3_tokenizer *pTokenizer, /* Tokenizer module */
+ int iLangid, /* Language id for tokenizer */
char **azCol, /* Array of column names for fts3 table */
int bFts4, /* True to allow FTS4-only syntax */
int nCol, /* Number of entries in azCol[] */
@@ -120998,11 +123765,13 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(
int nParsed;
int rc;
ParseContext sParse;
+
+ memset(&sParse, 0, sizeof(ParseContext));
sParse.pTokenizer = pTokenizer;
+ sParse.iLangid = iLangid;
sParse.azCol = (const char **)azCol;
sParse.nCol = nCol;
sParse.iDefaultCol = iDefaultCol;
- sParse.nNest = 0;
sParse.bFts4 = bFts4;
if( z==0 ){
*ppExpr = 0;
@@ -121193,7 +123962,7 @@ static void fts3ExprTest(
}
rc = sqlite3Fts3ExprParse(
- pTokenizer, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
+ pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
);
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
sqlite3_result_error(context, "Error parsing expression", -1);
@@ -121652,7 +124421,7 @@ typedef struct porter_tokenizer {
} porter_tokenizer;
/*
-** Class derived from sqlit3_tokenizer_cursor
+** Class derived from sqlite3_tokenizer_cursor
*/
typedef struct porter_tokenizer_cursor {
sqlite3_tokenizer_cursor base;
@@ -122242,6 +125011,7 @@ static const sqlite3_tokenizer_module porterTokenizerModule = {
porterOpen,
porterClose,
porterNext,
+ 0
};
/*
@@ -122547,11 +125317,10 @@ static void testFunc(
goto finish;
}
pTokenizer->pModule = p;
- if( SQLITE_OK!=p->xOpen(pTokenizer, zInput, nInput, &pCsr) ){
+ if( sqlite3Fts3OpenTokenizer(pTokenizer, 0, zInput, nInput, &pCsr) ){
zErr = "error in xOpen()";
goto finish;
}
- pCsr->pTokenizer = pTokenizer;
while( SQLITE_OK==p->xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos) ){
Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(iPos));
@@ -122967,6 +125736,7 @@ static const sqlite3_tokenizer_module simpleTokenizerModule = {
simpleOpen,
simpleClose,
simpleNext,
+ 0,
};
/*
@@ -123008,6 +125778,9 @@ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(
/* #include <assert.h> */
/* #include <stdlib.h> */
+
+#define FTS_MAX_APPENDABLE_HEIGHT 16
+
/*
** When full-text index nodes are loaded from disk, the buffer that they
** are loaded into has the following number of bytes of padding at the end
@@ -123047,6 +125820,29 @@ int test_fts3_node_chunk_threshold = (4*1024)*4;
# define FTS3_NODE_CHUNK_THRESHOLD (FTS3_NODE_CHUNKSIZE*4)
#endif
+/*
+** The two values that may be meaningfully bound to the :1 parameter in
+** statements SQL_REPLACE_STAT and SQL_SELECT_STAT.
+*/
+#define FTS_STAT_DOCTOTAL 0
+#define FTS_STAT_INCRMERGEHINT 1
+#define FTS_STAT_AUTOINCRMERGE 2
+
+/*
+** If FTS_LOG_MERGES is defined, call sqlite3_log() to report each automatic
+** and incremental merge operation that takes place. This is used for
+** debugging FTS only, it should not usually be turned on in production
+** systems.
+*/
+#ifdef FTS3_LOG_MERGES
+static void fts3LogMerge(int nMerge, sqlite3_int64 iAbsLevel){
+ sqlite3_log(SQLITE_OK, "%d-way merge from level %d", nMerge, (int)iAbsLevel);
+}
+#else
+#define fts3LogMerge(x, y)
+#endif
+
+
typedef struct PendingList PendingList;
typedef struct SegmentNode SegmentNode;
typedef struct SegmentWriter SegmentWriter;
@@ -123094,6 +125890,7 @@ struct Fts3DeferredToken {
*/
struct Fts3SegReader {
int iIdx; /* Index within level, or 0x7FFFFFFF for PT */
+ int bLookup; /* True for a lookup only */
sqlite3_int64 iStartBlock; /* Rowid of first leaf block to traverse */
sqlite3_int64 iLeafEndBlock; /* Rowid of final leaf block to traverse */
@@ -123207,13 +126004,22 @@ struct SegmentNode {
#define SQL_DELETE_DOCSIZE 19
#define SQL_REPLACE_DOCSIZE 20
#define SQL_SELECT_DOCSIZE 21
-#define SQL_SELECT_DOCTOTAL 22
-#define SQL_REPLACE_DOCTOTAL 23
+#define SQL_SELECT_STAT 22
+#define SQL_REPLACE_STAT 23
#define SQL_SELECT_ALL_PREFIX_LEVEL 24
#define SQL_DELETE_ALL_TERMS_SEGDIR 25
-
#define SQL_DELETE_SEGDIR_RANGE 26
+#define SQL_SELECT_ALL_LANGID 27
+#define SQL_FIND_MERGE_LEVEL 28
+#define SQL_MAX_LEAF_NODE_ESTIMATE 29
+#define SQL_DELETE_SEGDIR_ENTRY 30
+#define SQL_SHIFT_SEGDIR_ENTRY 31
+#define SQL_SELECT_SEGDIR 32
+#define SQL_CHOMP_SEGDIR 33
+#define SQL_SEGMENT_IS_APPENDABLE 34
+#define SQL_SELECT_INDEXES 35
+#define SQL_SELECT_MXLEVEL 36
/*
** This function is used to obtain an SQLite prepared statement handle
@@ -123242,9 +126048,9 @@ static int fts3SqlStmt(
/* 6 */ "DELETE FROM %Q.'%q_stat'",
/* 7 */ "SELECT %s WHERE rowid=?",
/* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1",
-/* 9 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)",
+/* 9 */ "REPLACE INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)",
/* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)",
-/* 11 */ "INSERT INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
+/* 11 */ "REPLACE INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
/* Return segments in order from oldest to newest.*/
/* 12 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
@@ -123262,13 +126068,61 @@ static int fts3SqlStmt(
/* 19 */ "DELETE FROM %Q.'%q_docsize' WHERE docid = ?",
/* 20 */ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)",
/* 21 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?",
-/* 22 */ "SELECT value FROM %Q.'%q_stat' WHERE id=0",
-/* 23 */ "REPLACE INTO %Q.'%q_stat' VALUES(0,?)",
+/* 22 */ "SELECT value FROM %Q.'%q_stat' WHERE id=?",
+/* 23 */ "REPLACE INTO %Q.'%q_stat' VALUES(?,?)",
/* 24 */ "",
/* 25 */ "",
/* 26 */ "DELETE FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?",
-
+/* 27 */ "SELECT DISTINCT level / (1024 * ?) FROM %Q.'%q_segdir'",
+
+/* This statement is used to determine which level to read the input from
+** when performing an incremental merge. It returns the absolute level number
+** 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 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
+** created by merging the oldest :2 segments from absolute level :1. See
+** function sqlite3Fts3Incrmerge() for details. */
+/* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) "
+ " FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?",
+
+/* SQL_DELETE_SEGDIR_ENTRY
+** Delete the %_segdir entry on absolute level :1 with index :2. */
+/* 30 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?",
+
+/* SQL_SHIFT_SEGDIR_ENTRY
+** Modify the idx value for the segment with idx=:3 on absolute level :2
+** to :1. */
+/* 31 */ "UPDATE %Q.'%q_segdir' SET idx = ? WHERE level=? AND idx=?",
+
+/* SQL_SELECT_SEGDIR
+** Read a single entry from the %_segdir table. The entry from absolute
+** level :1 with index value :2. */
+/* 32 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
+ "FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?",
+
+/* SQL_CHOMP_SEGDIR
+** Update the start_block (:1) and root (:2) fields of the %_segdir
+** entry located on absolute level :3 with index :4. */
+/* 33 */ "UPDATE %Q.'%q_segdir' SET start_block = ?, root = ?"
+ "WHERE level = ? AND idx = ?",
+
+/* SQL_SEGMENT_IS_APPENDABLE
+** Return a single row if the segment with end_block=? is appendable. Or
+** no rows otherwise. */
+/* 34 */ "SELECT 1 FROM %Q.'%q_segments' WHERE blockid=? AND block IS NULL",
+
+/* SQL_SELECT_INDEXES
+** Return the list of valid segment indexes for absolute level ? */
+/* 35 */ "SELECT idx FROM %Q.'%q_segdir' WHERE level=? ORDER BY 1 ASC",
+
+/* SQL_SELECT_MXLEVEL
+** Return the largest relative level in the FTS index or indexes. */
+/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'"
};
int rc = SQLITE_OK;
sqlite3_stmt *pStmt;
@@ -123306,22 +126160,18 @@ static int fts3SqlStmt(
return rc;
}
+
static int fts3SelectDocsize(
Fts3Table *pTab, /* FTS3 table handle */
- int eStmt, /* Either SQL_SELECT_DOCSIZE or DOCTOTAL */
sqlite3_int64 iDocid, /* Docid to bind for SQL_SELECT_DOCSIZE */
sqlite3_stmt **ppStmt /* OUT: Statement handle */
){
sqlite3_stmt *pStmt = 0; /* Statement requested from fts3SqlStmt() */
int rc; /* Return code */
- assert( eStmt==SQL_SELECT_DOCSIZE || eStmt==SQL_SELECT_DOCTOTAL );
-
- rc = fts3SqlStmt(pTab, eStmt, &pStmt, 0);
+ rc = fts3SqlStmt(pTab, SQL_SELECT_DOCSIZE, &pStmt, 0);
if( rc==SQLITE_OK ){
- if( eStmt==SQL_SELECT_DOCSIZE ){
- sqlite3_bind_int64(pStmt, 1, iDocid);
- }
+ sqlite3_bind_int64(pStmt, 1, iDocid);
rc = sqlite3_step(pStmt);
if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){
rc = sqlite3_reset(pStmt);
@@ -123340,7 +126190,21 @@ SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(
Fts3Table *pTab, /* Fts3 table handle */
sqlite3_stmt **ppStmt /* OUT: Statement handle */
){
- return fts3SelectDocsize(pTab, SQL_SELECT_DOCTOTAL, 0, ppStmt);
+ sqlite3_stmt *pStmt = 0;
+ int rc;
+ rc = fts3SqlStmt(pTab, SQL_SELECT_STAT, &pStmt, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL);
+ if( sqlite3_step(pStmt)!=SQLITE_ROW
+ || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB
+ ){
+ rc = sqlite3_reset(pStmt);
+ if( rc==SQLITE_OK ) rc = FTS_CORRUPT_VTAB;
+ pStmt = 0;
+ }
+ }
+ *ppStmt = pStmt;
+ return rc;
}
SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(
@@ -123348,7 +126212,7 @@ SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(
sqlite3_int64 iDocid, /* Docid to read size data for */
sqlite3_stmt **ppStmt /* OUT: Statement handle */
){
- return fts3SelectDocsize(pTab, SQL_SELECT_DOCSIZE, iDocid, ppStmt);
+ return fts3SelectDocsize(pTab, iDocid, ppStmt);
}
/*
@@ -123415,6 +126279,44 @@ SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *p){
}
/*
+** FTS maintains a separate indexes for each language-id (a 32-bit integer).
+** Within each language id, a separate index is maintained to store the
+** document terms, and each configured prefix size (configured the FTS
+** "prefix=" option). And each index consists of multiple levels ("relative
+** levels").
+**
+** All three of these values (the language id, the specific index and the
+** level within the index) are encoded in 64-bit integer values stored
+** in the %_segdir table on disk. This function is used to convert three
+** separate component values into the single 64-bit integer value that
+** can be used to query the %_segdir table.
+**
+** Specifically, each language-id/index combination is allocated 1024
+** 64-bit integer level values ("absolute levels"). The main terms index
+** for language-id 0 is allocate values 0-1023. The first prefix index
+** (if any) for language-id 0 is allocated values 1024-2047. And so on.
+** Language 1 indexes are allocated immediately following language 0.
+**
+** So, for a system with nPrefix prefix indexes configured, the block of
+** absolute levels that corresponds to language-id iLangid and index
+** iIndex starts at absolute level ((iLangid * (nPrefix+1) + iIndex) * 1024).
+*/
+static sqlite3_int64 getAbsoluteLevel(
+ Fts3Table *p, /* FTS3 table handle */
+ int iLangid, /* Language id */
+ int iIndex, /* Index in p->aIndex[] */
+ int iLevel /* Level of segments */
+){
+ sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */
+ assert( iLangid>=0 );
+ assert( p->nIndex>0 );
+ assert( iIndex>=0 && iIndex<p->nIndex );
+
+ iBase = ((sqlite3_int64)iLangid * p->nIndex + iIndex) * FTS3_SEGDIR_MAXLEVEL;
+ return iBase + iLevel;
+}
+
+/*
** Set *ppStmt to a statement handle that may be used to iterate through
** all rows in the %_segdir table, from oldest to newest. If successful,
** return SQLITE_OK. If an error occurs while preparing the statement,
@@ -123433,8 +126335,9 @@ SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *p){
*/
SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(
Fts3Table *p, /* FTS3 table */
+ int iLangid, /* Language being queried */
int iIndex, /* Index for p->aIndex[] */
- int iLevel, /* Level to select */
+ int iLevel, /* Level to select (relative level) */
sqlite3_stmt **ppStmt /* OUT: Compiled statement */
){
int rc;
@@ -123448,14 +126351,16 @@ SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(
/* "SELECT * FROM %_segdir WHERE level BETWEEN ? AND ? ORDER BY ..." */
rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE, &pStmt, 0);
if( rc==SQLITE_OK ){
- sqlite3_bind_int(pStmt, 1, iIndex*FTS3_SEGDIR_MAXLEVEL);
- sqlite3_bind_int(pStmt, 2, (iIndex+1)*FTS3_SEGDIR_MAXLEVEL-1);
+ sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
+ sqlite3_bind_int64(pStmt, 2,
+ getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
+ );
}
}else{
/* "SELECT * FROM %_segdir WHERE level = ? ORDER BY ..." */
rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0);
if( rc==SQLITE_OK ){
- sqlite3_bind_int(pStmt, 1, iLevel+iIndex*FTS3_SEGDIR_MAXLEVEL);
+ sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex,iLevel));
}
}
*ppStmt = pStmt;
@@ -123621,6 +126526,7 @@ static int fts3PendingTermsAddOne(
*/
static int fts3PendingTermsAdd(
Fts3Table *p, /* Table into which text will be inserted */
+ int iLangid, /* Language id to use */
const char *zText, /* Text of document to be inserted */
int iCol, /* Column into which text is being inserted */
u32 *pnWord /* OUT: Number of tokens inserted */
@@ -123650,11 +126556,10 @@ static int fts3PendingTermsAdd(
return SQLITE_OK;
}
- rc = pModule->xOpen(pTokenizer, zText, -1, &pCsr);
+ rc = sqlite3Fts3OpenTokenizer(pTokenizer, iLangid, zText, -1, &pCsr);
if( rc!=SQLITE_OK ){
return rc;
}
- pCsr->pTokenizer = pTokenizer;
xNext = pModule->xNext;
while( SQLITE_OK==rc
@@ -123697,18 +126602,28 @@ static int fts3PendingTermsAdd(
** fts3PendingTermsAdd() are to add term/position-list pairs for the
** contents of the document with docid iDocid.
*/
-static int fts3PendingTermsDocid(Fts3Table *p, sqlite_int64 iDocid){
+static int fts3PendingTermsDocid(
+ Fts3Table *p, /* Full-text table handle */
+ int iLangid, /* Language id of row being written */
+ sqlite_int64 iDocid /* Docid of row being written */
+){
+ assert( iLangid>=0 );
+
/* TODO(shess) Explore whether partially flushing the buffer on
** forced-flush would provide better performance. I suspect that if
** we ordered the doclists by size and flushed the largest until the
** buffer was half empty, that would let the less frequent terms
** generate longer doclists.
*/
- if( iDocid<=p->iPrevDocid || p->nPendingData>p->nMaxPendingData ){
+ if( iDocid<=p->iPrevDocid
+ || p->iPrevLangid!=iLangid
+ || p->nPendingData>p->nMaxPendingData
+ ){
int rc = sqlite3Fts3PendingTermsFlush(p);
if( rc!=SQLITE_OK ) return rc;
}
p->iPrevDocid = iDocid;
+ p->iPrevLangid = iLangid;
return SQLITE_OK;
}
@@ -123737,11 +126652,16 @@ SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){
** Argument apVal is the same as the similarly named argument passed to
** fts3InsertData(). Parameter iDocid is the docid of the new row.
*/
-static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal, u32 *aSz){
+static int fts3InsertTerms(
+ Fts3Table *p,
+ int iLangid,
+ sqlite3_value **apVal,
+ u32 *aSz
+){
int i; /* Iterator variable */
for(i=2; i<p->nColumn+2; i++){
const char *zText = (const char *)sqlite3_value_text(apVal[i]);
- int rc = fts3PendingTermsAdd(p, zText, i-2, &aSz[i-2]);
+ int rc = fts3PendingTermsAdd(p, iLangid, zText, i-2, &aSz[i-2]);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -123762,6 +126682,7 @@ static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal, u32 *aSz){
** apVal[p->nColumn+1] Right-most user-defined column
** apVal[p->nColumn+2] Hidden column with same name as table
** apVal[p->nColumn+3] Hidden "docid" column (alias for rowid)
+** apVal[p->nColumn+4] Hidden languageid column
*/
static int fts3InsertData(
Fts3Table *p, /* Full-text table */
@@ -123792,9 +126713,13 @@ static int fts3InsertData(
** defined columns in the FTS3 table, plus one for the docid field.
*/
rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]);
- if( rc!=SQLITE_OK ){
- return rc;
+ if( rc==SQLITE_OK && p->zLanguageid ){
+ rc = sqlite3_bind_int(
+ pContentInsert, p->nColumn+2,
+ sqlite3_value_int(apVal[p->nColumn+4])
+ );
}
+ if( rc!=SQLITE_OK ) return rc;
/* There is a quirk here. The users INSERT statement may have specified
** a value for the "rowid" field, for the "docid" field, or for both.
@@ -123855,6 +126780,15 @@ static int fts3DeleteAll(Fts3Table *p, int bContent){
}
/*
+**
+*/
+static int langidFromSelect(Fts3Table *p, sqlite3_stmt *pSelect){
+ int iLangid = 0;
+ if( p->zLanguageid ) iLangid = sqlite3_column_int(pSelect, p->nColumn+1);
+ return iLangid;
+}
+
+/*
** The first element in the apVal[] array is assumed to contain the docid
** (an integer) of a row about to be deleted. Remove all terms from the
** full-text index.
@@ -123873,16 +126807,18 @@ static void fts3DeleteTerms(
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pSelect) ){
int i;
- for(i=1; i<=p->nColumn; i++){
+ int iLangid = langidFromSelect(p, pSelect);
+ rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pSelect, 0));
+ for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){
const char *zText = (const char *)sqlite3_column_text(pSelect, i);
- rc = fts3PendingTermsAdd(p, zText, -1, &aSz[i-1]);
- if( rc!=SQLITE_OK ){
- sqlite3_reset(pSelect);
- *pRC = rc;
- return;
- }
+ rc = fts3PendingTermsAdd(p, iLangid, zText, -1, &aSz[i-1]);
aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i);
}
+ if( rc!=SQLITE_OK ){
+ sqlite3_reset(pSelect);
+ *pRC = rc;
+ return;
+ }
}
rc = sqlite3_reset(pSelect);
}else{
@@ -123895,7 +126831,7 @@ static void fts3DeleteTerms(
** Forward declaration to account for the circular dependency between
** functions fts3SegmentMerge() and fts3AllocateSegdirIdx().
*/
-static int fts3SegmentMerge(Fts3Table *, int, int);
+static int fts3SegmentMerge(Fts3Table *, int, int, int);
/*
** This function allocates a new level iLevel index in the segdir table.
@@ -123914,6 +126850,7 @@ static int fts3SegmentMerge(Fts3Table *, int, int);
*/
static int fts3AllocateSegdirIdx(
Fts3Table *p,
+ int iLangid, /* Language id */
int iIndex, /* Index for p->aIndex */
int iLevel,
int *piIdx
@@ -123922,10 +126859,15 @@ static int fts3AllocateSegdirIdx(
sqlite3_stmt *pNextIdx; /* Query for next idx at level iLevel */
int iNext = 0; /* Result of query pNextIdx */
+ assert( iLangid>=0 );
+ assert( p->nIndex>=1 );
+
/* Set variable iNext to the next available segdir index at level iLevel. */
rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pNextIdx, 0);
if( rc==SQLITE_OK ){
- sqlite3_bind_int(pNextIdx, 1, iIndex*FTS3_SEGDIR_MAXLEVEL + iLevel);
+ sqlite3_bind_int64(
+ pNextIdx, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel)
+ );
if( SQLITE_ROW==sqlite3_step(pNextIdx) ){
iNext = sqlite3_column_int(pNextIdx, 0);
}
@@ -123939,7 +126881,8 @@ static int fts3AllocateSegdirIdx(
** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext.
*/
if( iNext>=FTS3_MERGE_COUNT ){
- rc = fts3SegmentMerge(p, iIndex, iLevel);
+ fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel));
+ rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel);
*piIdx = 0;
}else{
*piIdx = iNext;
@@ -123986,7 +126929,7 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
int rc; /* Return code */
/* pnBlob must be non-NULL. paBlob may be NULL or non-NULL. */
- assert( pnBlob);
+ assert( pnBlob );
if( p->pSegments ){
rc = sqlite3_blob_reopen(p->pSegments, iBlockid);
@@ -124073,6 +127016,18 @@ static int fts3SegReaderRequire(Fts3SegReader *pReader, char *pFrom, int nByte){
}
/*
+** Set an Fts3SegReader cursor to point at EOF.
+*/
+static void fts3SegReaderSetEof(Fts3SegReader *pSeg){
+ if( !fts3SegReaderIsRootOnly(pSeg) ){
+ sqlite3_free(pSeg->aNode);
+ sqlite3_blob_close(pSeg->pBlob);
+ pSeg->pBlob = 0;
+ }
+ pSeg->aNode = 0;
+}
+
+/*
** Move the iterator passed as the first argument to the next term in the
** segment. If successful, SQLITE_OK is returned. If there is no next term,
** SQLITE_DONE. Otherwise, an SQLite error code.
@@ -124111,12 +127066,7 @@ static int fts3SegReaderNext(
return SQLITE_OK;
}
- if( !fts3SegReaderIsRootOnly(pReader) ){
- sqlite3_free(pReader->aNode);
- sqlite3_blob_close(pReader->pBlob);
- pReader->pBlob = 0;
- }
- pReader->aNode = 0;
+ fts3SegReaderSetEof(pReader);
/* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf
** blocks have already been traversed. */
@@ -124320,7 +127270,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
int rc = SQLITE_OK;
int pgsz = p->nPgsz;
- assert( p->bHasStat );
+ assert( p->bFts4 );
assert( pgsz>0 );
for(ii=0; rc==SQLITE_OK && ii<pMsr->nSegment; ii++){
@@ -124363,6 +127313,7 @@ SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
*/
SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
int iAge, /* Segment "age". */
+ int bLookup, /* True for a lookup only */
sqlite3_int64 iStartLeaf, /* First leaf to traverse */
sqlite3_int64 iEndLeaf, /* Final leaf to traverse */
sqlite3_int64 iEndBlock, /* Final block of segment */
@@ -124370,7 +127321,6 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
int nRoot, /* Size of buffer containing root node */
Fts3SegReader **ppReader /* OUT: Allocated Fts3SegReader */
){
- int rc = SQLITE_OK; /* Return code */
Fts3SegReader *pReader; /* Newly allocated SegReader object */
int nExtra = 0; /* Bytes to allocate segment root node */
@@ -124385,6 +127335,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
}
memset(pReader, 0, sizeof(Fts3SegReader));
pReader->iIdx = iAge;
+ pReader->bLookup = bLookup;
pReader->iStartBlock = iStartLeaf;
pReader->iLeafEndBlock = iEndLeaf;
pReader->iEndBlock = iEndBlock;
@@ -124398,13 +127349,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
}else{
pReader->iCurrentBlock = iStartLeaf-1;
}
-
- if( rc==SQLITE_OK ){
- *ppReader = pReader;
- }else{
- sqlite3Fts3SegReaderFree(pReader);
- }
- return rc;
+ *ppReader = pReader;
+ return SQLITE_OK;
}
/*
@@ -124454,6 +127400,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
Fts3SegReader **ppReader /* OUT: SegReader for pending-terms */
){
Fts3SegReader *pReader = 0; /* Fts3SegReader object to return */
+ Fts3HashElem *pE; /* Iterator variable */
Fts3HashElem **aElem = 0; /* Array of term hash entries to scan */
int nElem = 0; /* Size of array at aElem */
int rc = SQLITE_OK; /* Return Code */
@@ -124462,7 +127409,6 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
pHash = &p->aIndex[iIndex].hPending;
if( bPrefix ){
int nAlloc = 0; /* Size of allocated array at aElem */
- Fts3HashElem *pE = 0; /* Iterator variable */
for(pE=fts3HashFirst(pHash); pE; pE=fts3HashNext(pE)){
char *zKey = (char *)fts3HashKey(pE);
@@ -124496,8 +127442,13 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
}else{
/* The query is a simple term lookup that matches at most one term in
- ** the index. All that is required is a straight hash-lookup. */
- Fts3HashElem *pE = fts3HashFindElem(pHash, zTerm, nTerm);
+ ** the index. All that is required is a straight hash-lookup.
+ **
+ ** Because the stack address of pE may be accessed via the aElem pointer
+ ** below, the "Fts3HashElem *pE" must be declared so that it is valid
+ ** within this entire function, not just this "else{...}" block.
+ */
+ pE = fts3HashFindElem(pHash, zTerm, nTerm);
if( pE ){
aElem = &pE;
nElem = 1;
@@ -124677,12 +127628,33 @@ static int fts3WriteSegment(
return rc;
}
+/*
+** Find the largest relative level number in the table. If successful, set
+** *pnMax to this value and return SQLITE_OK. Otherwise, if an error occurs,
+** set *pnMax to zero and return an SQLite error code.
+*/
+SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *p, int *pnMax){
+ int rc;
+ int mxLevel = 0;
+ sqlite3_stmt *pStmt = 0;
+
+ rc = fts3SqlStmt(p, SQL_SELECT_MXLEVEL, &pStmt, 0);
+ if( rc==SQLITE_OK ){
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ mxLevel = sqlite3_column_int(pStmt, 0);
+ }
+ rc = sqlite3_reset(pStmt);
+ }
+ *pnMax = mxLevel;
+ return rc;
+}
+
/*
** Insert a record into the %_segdir table.
*/
static int fts3WriteSegdir(
Fts3Table *p, /* Virtual table handle */
- int iLevel, /* Value for "level" field */
+ sqlite3_int64 iLevel, /* Value for "level" field (absolute level) */
int iIdx, /* Value for "idx" field */
sqlite3_int64 iStartBlock, /* Value for "start_block" field */
sqlite3_int64 iLeafEndBlock, /* Value for "leaves_end_block" field */
@@ -124693,7 +127665,7 @@ static int fts3WriteSegdir(
sqlite3_stmt *pStmt;
int rc = fts3SqlStmt(p, SQL_INSERT_SEGDIR, &pStmt, 0);
if( rc==SQLITE_OK ){
- sqlite3_bind_int(pStmt, 1, iLevel);
+ sqlite3_bind_int64(pStmt, 1, iLevel);
sqlite3_bind_int(pStmt, 2, iIdx);
sqlite3_bind_int64(pStmt, 3, iStartBlock);
sqlite3_bind_int64(pStmt, 4, iLeafEndBlock);
@@ -124993,6 +127965,7 @@ static int fts3SegWriterAdd(
/* The current leaf node is full. Write it out to the database. */
rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
if( rc!=SQLITE_OK ) return rc;
+ p->nLeafAdd++;
/* Add the current term to the interior node tree. The term added to
** the interior tree must:
@@ -125076,7 +128049,7 @@ static int fts3SegWriterAdd(
static int fts3SegWriterFlush(
Fts3Table *p, /* Virtual table handle */
SegmentWriter *pWriter, /* SegmentWriter to flush to the db */
- int iLevel, /* Value for 'level' column of %_segdir */
+ sqlite3_int64 iLevel, /* Value for 'level' column of %_segdir */
int iIdx /* Value for 'idx' column of %_segdir */
){
int rc; /* Return code */
@@ -125101,6 +128074,7 @@ static int fts3SegWriterFlush(
rc = fts3WriteSegdir(
p, iLevel, iIdx, 0, 0, 0, pWriter->aData, pWriter->nData);
}
+ p->nLeafAdd++;
return rc;
}
@@ -125154,7 +128128,12 @@ static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){
**
** Return SQLITE_OK if successful, or an SQLite error code if not.
*/
-static int fts3SegmentMaxLevel(Fts3Table *p, int iIndex, int *pnMax){
+static int fts3SegmentMaxLevel(
+ Fts3Table *p,
+ int iLangid,
+ int iIndex,
+ sqlite3_int64 *pnMax
+){
sqlite3_stmt *pStmt;
int rc;
assert( iIndex>=0 && iIndex<p->nIndex );
@@ -125167,15 +128146,40 @@ static int fts3SegmentMaxLevel(Fts3Table *p, int iIndex, int *pnMax){
*/
rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0);
if( rc!=SQLITE_OK ) return rc;
- sqlite3_bind_int(pStmt, 1, iIndex*FTS3_SEGDIR_MAXLEVEL);
- sqlite3_bind_int(pStmt, 2, (iIndex+1)*FTS3_SEGDIR_MAXLEVEL - 1);
+ sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
+ sqlite3_bind_int64(pStmt, 2,
+ getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
+ );
if( SQLITE_ROW==sqlite3_step(pStmt) ){
- *pnMax = sqlite3_column_int(pStmt, 0);
+ *pnMax = sqlite3_column_int64(pStmt, 0);
}
return sqlite3_reset(pStmt);
}
/*
+** Delete all entries in the %_segments table associated with the segment
+** opened with seg-reader pSeg. This function does not affect the contents
+** of the %_segdir table.
+*/
+static int fts3DeleteSegment(
+ Fts3Table *p, /* FTS table handle */
+ Fts3SegReader *pSeg /* Segment to delete */
+){
+ int rc = SQLITE_OK; /* Return code */
+ if( pSeg->iStartBlock ){
+ sqlite3_stmt *pDelete; /* SQL statement to delete rows */
+ rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDelete, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int64(pDelete, 1, pSeg->iStartBlock);
+ sqlite3_bind_int64(pDelete, 2, pSeg->iEndBlock);
+ sqlite3_step(pDelete);
+ rc = sqlite3_reset(pDelete);
+ }
+ }
+ return rc;
+}
+
+/*
** This function is used after merging multiple segments into a single large
** segment to delete the old, now redundant, segment b-trees. Specifically,
** it:
@@ -125191,24 +128195,18 @@ static int fts3SegmentMaxLevel(Fts3Table *p, int iIndex, int *pnMax){
*/
static int fts3DeleteSegdir(
Fts3Table *p, /* Virtual table handle */
+ int iLangid, /* Language id */
int iIndex, /* Index for p->aIndex */
int iLevel, /* Level of %_segdir entries to delete */
Fts3SegReader **apSegment, /* Array of SegReader objects */
int nReader /* Size of array apSegment */
){
- int rc; /* Return Code */
+ int rc = SQLITE_OK; /* Return Code */
int i; /* Iterator variable */
- sqlite3_stmt *pDelete; /* SQL statement to delete rows */
+ sqlite3_stmt *pDelete = 0; /* SQL statement to delete rows */
- rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDelete, 0);
for(i=0; rc==SQLITE_OK && i<nReader; i++){
- Fts3SegReader *pSegment = apSegment[i];
- if( pSegment->iStartBlock ){
- sqlite3_bind_int64(pDelete, 1, pSegment->iStartBlock);
- sqlite3_bind_int64(pDelete, 2, pSegment->iEndBlock);
- sqlite3_step(pDelete);
- rc = sqlite3_reset(pDelete);
- }
+ rc = fts3DeleteSegment(p, apSegment[i]);
}
if( rc!=SQLITE_OK ){
return rc;
@@ -125218,13 +128216,17 @@ static int fts3DeleteSegdir(
if( iLevel==FTS3_SEGCURSOR_ALL ){
rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_RANGE, &pDelete, 0);
if( rc==SQLITE_OK ){
- sqlite3_bind_int(pDelete, 1, iIndex*FTS3_SEGDIR_MAXLEVEL);
- sqlite3_bind_int(pDelete, 2, (iIndex+1) * FTS3_SEGDIR_MAXLEVEL - 1);
+ sqlite3_bind_int64(pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
+ sqlite3_bind_int64(pDelete, 2,
+ getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
+ );
}
}else{
rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pDelete, 0);
if( rc==SQLITE_OK ){
- sqlite3_bind_int(pDelete, 1, iIndex*FTS3_SEGDIR_MAXLEVEL + iLevel);
+ sqlite3_bind_int64(
+ pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel)
+ );
}
}
@@ -125387,11 +128389,16 @@ static int fts3SegReaderStart(
** b-tree leaf nodes contain more than one term.
*/
for(i=0; pCsr->bRestart==0 && i<pCsr->nSegment; i++){
+ int res = 0;
Fts3SegReader *pSeg = pCsr->apSegment[i];
do {
int rc = fts3SegReaderNext(p, pSeg, 0);
if( rc!=SQLITE_OK ) return rc;
- }while( zTerm && fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 );
+ }while( zTerm && (res = fts3SegReaderTermCmp(pSeg, zTerm, nTerm))<0 );
+
+ if( pSeg->bLookup && res!=0 ){
+ fts3SegReaderSetEof(pSeg);
+ }
}
fts3SegReaderSort(pCsr->apSegment, nSeg, nSeg, fts3SegReaderCmp);
@@ -125512,7 +128519,12 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
** forward. Then sort the list in order of current term again.
*/
for(i=0; i<pCsr->nAdvance; i++){
- rc = fts3SegReaderNext(p, apSegment[i], 0);
+ Fts3SegReader *pSeg = apSegment[i];
+ if( pSeg->bLookup ){
+ fts3SegReaderSetEof(pSeg);
+ }else{
+ rc = fts3SegReaderNext(p, pSeg, 0);
+ }
if( rc!=SQLITE_OK ) return rc;
}
fts3SegReaderSort(apSegment, nSegment, pCsr->nAdvance, fts3SegReaderCmp);
@@ -125683,13 +128695,18 @@ SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(
** Otherwise, if successful, SQLITE_OK is returned. If an error occurs,
** an SQLite error code is returned.
*/
-static int fts3SegmentMerge(Fts3Table *p, int iIndex, int iLevel){
+static int fts3SegmentMerge(
+ Fts3Table *p,
+ int iLangid, /* Language id to merge */
+ int iIndex, /* Index in p->aIndex[] to merge */
+ int iLevel /* Level to merge */
+){
int rc; /* Return code */
int iIdx = 0; /* Index of new segment */
- int iNewLevel = 0; /* Level/index to create new segment at */
+ sqlite3_int64 iNewLevel = 0; /* Level/index to create new segment at */
SegmentWriter *pWriter = 0; /* Used to write the new, merged, segment */
Fts3SegFilter filter; /* Segment term filter condition */
- Fts3MultiSegReader csr; /* Cursor to iterate through level(s) */
+ Fts3MultiSegReader csr; /* Cursor to iterate through level(s) */
int bIgnoreEmpty = 0; /* True to ignore empty segments */
assert( iLevel==FTS3_SEGCURSOR_ALL
@@ -125699,7 +128716,7 @@ static int fts3SegmentMerge(Fts3Table *p, int iIndex, int iLevel){
assert( iLevel<FTS3_SEGDIR_MAXLEVEL );
assert( iIndex>=0 && iIndex<p->nIndex );
- rc = sqlite3Fts3SegReaderCursor(p, iIndex, iLevel, 0, 0, 1, 0, &csr);
+ rc = sqlite3Fts3SegReaderCursor(p, iLangid, iIndex, iLevel, 0, 0, 1, 0, &csr);
if( rc!=SQLITE_OK || csr.nSegment==0 ) goto finished;
if( iLevel==FTS3_SEGCURSOR_ALL ){
@@ -125711,24 +128728,24 @@ static int fts3SegmentMerge(Fts3Table *p, int iIndex, int iLevel){
rc = SQLITE_DONE;
goto finished;
}
- rc = fts3SegmentMaxLevel(p, iIndex, &iNewLevel);
+ rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iNewLevel);
bIgnoreEmpty = 1;
}else if( iLevel==FTS3_SEGCURSOR_PENDING ){
- iNewLevel = iIndex * FTS3_SEGDIR_MAXLEVEL;
- rc = fts3AllocateSegdirIdx(p, iIndex, 0, &iIdx);
+ iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, 0);
+ rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, 0, &iIdx);
}else{
/* This call is to merge all segments at level iLevel. find the next
** available segment index at level iLevel+1. The call to
** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to
** a single iLevel+2 segment if necessary. */
- rc = fts3AllocateSegdirIdx(p, iIndex, iLevel+1, &iIdx);
- iNewLevel = iIndex * FTS3_SEGDIR_MAXLEVEL + iLevel+1;
+ rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx);
+ iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1);
}
if( rc!=SQLITE_OK ) goto finished;
assert( csr.nSegment>0 );
- assert( iNewLevel>=(iIndex*FTS3_SEGDIR_MAXLEVEL) );
- assert( iNewLevel<((iIndex+1)*FTS3_SEGDIR_MAXLEVEL) );
+ assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) );
+ assert( iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL) );
memset(&filter, 0, sizeof(Fts3SegFilter));
filter.flags = FTS3_SEGMENT_REQUIRE_POS;
@@ -125745,7 +128762,9 @@ static int fts3SegmentMerge(Fts3Table *p, int iIndex, int iLevel){
assert( pWriter );
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
- rc = fts3DeleteSegdir(p, iIndex, iLevel, csr.apSegment, csr.nSegment);
+ rc = fts3DeleteSegdir(
+ p, iLangid, iIndex, iLevel, csr.apSegment, csr.nSegment
+ );
if( rc!=SQLITE_OK ) goto finished;
}
rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx);
@@ -125763,11 +128782,28 @@ static int fts3SegmentMerge(Fts3Table *p, int iIndex, int iLevel){
SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
int rc = SQLITE_OK;
int i;
+
for(i=0; rc==SQLITE_OK && i<p->nIndex; i++){
- rc = fts3SegmentMerge(p, i, FTS3_SEGCURSOR_PENDING);
+ rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
}
sqlite3Fts3PendingTermsClear(p);
+
+ /* Determine the auto-incr-merge setting if unknown. If enabled,
+ ** estimate the number of leaf blocks of content to be written
+ */
+ if( rc==SQLITE_OK && p->bHasStat
+ && p->bAutoincrmerge==0xff && p->nLeafAdd>0
+ ){
+ sqlite3_stmt *pStmt = 0;
+ rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
+ rc = sqlite3_step(pStmt);
+ p->bAutoincrmerge = (rc==SQLITE_ROW && sqlite3_column_int(pStmt, 0));
+ rc = sqlite3_reset(pStmt);
+ }
+ }
return rc;
}
@@ -125878,12 +128914,13 @@ static void fts3UpdateDocTotals(
return;
}
pBlob = (char*)&a[nStat];
- rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
+ rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0);
if( rc ){
sqlite3_free(a);
*pRC = rc;
return;
}
+ sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL);
if( sqlite3_step(pStmt)==SQLITE_ROW ){
fts3DecodeIntArray(nStat, a,
sqlite3_column_blob(pStmt, 0),
@@ -125907,29 +128944,47 @@ static void fts3UpdateDocTotals(
a[i+1] = x;
}
fts3EncodeIntArray(nStat, a, pBlob, &nBlob);
- rc = fts3SqlStmt(p, SQL_REPLACE_DOCTOTAL, &pStmt, 0);
+ rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0);
if( rc ){
sqlite3_free(a);
*pRC = rc;
return;
}
- sqlite3_bind_blob(pStmt, 1, pBlob, nBlob, SQLITE_STATIC);
+ sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL);
+ sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, SQLITE_STATIC);
sqlite3_step(pStmt);
*pRC = sqlite3_reset(pStmt);
sqlite3_free(a);
}
+/*
+** Merge the entire database so that there is one segment for each
+** iIndex/iLangid combination.
+*/
static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
- int i;
int bSeenDone = 0;
- int rc = SQLITE_OK;
- for(i=0; rc==SQLITE_OK && i<p->nIndex; i++){
- rc = fts3SegmentMerge(p, i, FTS3_SEGCURSOR_ALL);
- if( rc==SQLITE_DONE ){
- bSeenDone = 1;
- rc = SQLITE_OK;
+ int rc;
+ sqlite3_stmt *pAllLangid = 0;
+
+ rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
+ if( rc==SQLITE_OK ){
+ int rc2;
+ sqlite3_bind_int(pAllLangid, 1, p->nIndex);
+ while( sqlite3_step(pAllLangid)==SQLITE_ROW ){
+ int i;
+ int iLangid = sqlite3_column_int(pAllLangid, 0);
+ for(i=0; rc==SQLITE_OK && i<p->nIndex; i++){
+ rc = fts3SegmentMerge(p, iLangid, i, FTS3_SEGCURSOR_ALL);
+ if( rc==SQLITE_DONE ){
+ bSeenDone = 1;
+ rc = SQLITE_OK;
+ }
+ }
}
+ rc2 = sqlite3_reset(pAllLangid);
+ if( rc==SQLITE_OK ) rc = rc2;
}
+
sqlite3Fts3SegmentsClose(p);
sqlite3Fts3PendingTermsClear(p);
@@ -125980,11 +129035,12 @@ static int fts3DoRebuild(Fts3Table *p){
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
int iCol;
- rc = fts3PendingTermsDocid(p, sqlite3_column_int64(pStmt, 0));
+ int iLangid = langidFromSelect(p, pStmt);
+ rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pStmt, 0));
aSz[p->nColumn] = 0;
for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1);
- rc = fts3PendingTermsAdd(p, z, iCol, &aSz[iCol]);
+ rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]);
aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1);
}
if( p->bHasDocsize ){
@@ -126000,7 +129056,7 @@ static int fts3DoRebuild(Fts3Table *p){
}
}
}
- if( p->bHasStat ){
+ if( p->bFts4 ){
fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry);
}
sqlite3_free(aSz);
@@ -126016,6 +129072,1687 @@ static int fts3DoRebuild(Fts3Table *p){
return rc;
}
+
+/*
+** This function opens a cursor used to read the input data for an
+** incremental merge operation. Specifically, it opens a cursor to scan
+** the oldest nSeg segments (idx=0 through idx=(nSeg-1)) in absolute
+** level iAbsLevel.
+*/
+static int fts3IncrmergeCsr(
+ Fts3Table *p, /* FTS3 table handle */
+ sqlite3_int64 iAbsLevel, /* Absolute level to open */
+ int nSeg, /* Number of segments to merge */
+ Fts3MultiSegReader *pCsr /* Cursor object to populate */
+){
+ int rc; /* Return Code */
+ sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */
+ int nByte; /* Bytes allocated at pCsr->apSegment[] */
+
+ /* Allocate space for the Fts3MultiSegReader.aCsr[] array */
+ memset(pCsr, 0, sizeof(*pCsr));
+ nByte = sizeof(Fts3SegReader *) * nSeg;
+ pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc(nByte);
+
+ if( pCsr->apSegment==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pCsr->apSegment, 0, nByte);
+ rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0);
+ }
+ if( rc==SQLITE_OK ){
+ int i;
+ int rc2;
+ sqlite3_bind_int64(pStmt, 1, iAbsLevel);
+ assert( pCsr->nSegment==0 );
+ for(i=0; rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW && i<nSeg; i++){
+ rc = sqlite3Fts3SegReaderNew(i, 0,
+ sqlite3_column_int64(pStmt, 1), /* segdir.start_block */
+ sqlite3_column_int64(pStmt, 2), /* segdir.leaves_end_block */
+ sqlite3_column_int64(pStmt, 3), /* segdir.end_block */
+ sqlite3_column_blob(pStmt, 4), /* segdir.root */
+ sqlite3_column_bytes(pStmt, 4), /* segdir.root */
+ &pCsr->apSegment[i]
+ );
+ pCsr->nSegment++;
+ }
+ rc2 = sqlite3_reset(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+
+ return rc;
+}
+
+typedef struct IncrmergeWriter IncrmergeWriter;
+typedef struct NodeWriter NodeWriter;
+typedef struct Blob Blob;
+typedef struct NodeReader NodeReader;
+
+/*
+** An instance of the following structure is used as a dynamic buffer
+** to build up nodes or other blobs of data in.
+**
+** The function blobGrowBuffer() is used to extend the allocation.
+*/
+struct Blob {
+ char *a; /* Pointer to allocation */
+ int n; /* Number of valid bytes of data in a[] */
+ int nAlloc; /* Allocated size of a[] (nAlloc>=n) */
+};
+
+/*
+** This structure is used to build up buffers containing segment b-tree
+** nodes (blocks).
+*/
+struct NodeWriter {
+ sqlite3_int64 iBlock; /* Current block id */
+ Blob key; /* Last key written to the current block */
+ Blob block; /* Current block image */
+};
+
+/*
+** An object of this type contains the state required to create or append
+** to an appendable b-tree segment.
+*/
+struct IncrmergeWriter {
+ int nLeafEst; /* Space allocated for leaf blocks */
+ int nWork; /* Number of leaf pages flushed */
+ sqlite3_int64 iAbsLevel; /* Absolute level of input segments */
+ int iIdx; /* Index of *output* segment in iAbsLevel+1 */
+ sqlite3_int64 iStart; /* Block number of first allocated block */
+ sqlite3_int64 iEnd; /* Block number of last allocated block */
+ NodeWriter aNodeWriter[FTS_MAX_APPENDABLE_HEIGHT];
+};
+
+/*
+** An object of the following type is used to read data from a single
+** FTS segment node. See the following functions:
+**
+** nodeReaderInit()
+** nodeReaderNext()
+** nodeReaderRelease()
+*/
+struct NodeReader {
+ const char *aNode;
+ int nNode;
+ int iOff; /* Current offset within aNode[] */
+
+ /* Output variables. Containing the current node entry. */
+ sqlite3_int64 iChild; /* Pointer to child node */
+ Blob term; /* Current term */
+ const char *aDoclist; /* Pointer to doclist */
+ int nDoclist; /* Size of doclist in bytes */
+};
+
+/*
+** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
+** Otherwise, if the allocation at pBlob->a is not already at least nMin
+** bytes in size, extend (realloc) it to be so.
+**
+** If an OOM error occurs, set *pRc to SQLITE_NOMEM and leave pBlob->a
+** unmodified. Otherwise, if the allocation succeeds, update pBlob->nAlloc
+** to reflect the new size of the pBlob->a[] buffer.
+*/
+static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
+ if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){
+ int nAlloc = nMin;
+ char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc);
+ if( a ){
+ pBlob->nAlloc = nAlloc;
+ pBlob->a = a;
+ }else{
+ *pRc = SQLITE_NOMEM;
+ }
+ }
+}
+
+/*
+** Attempt to advance the node-reader object passed as the first argument to
+** the next entry on the node.
+**
+** Return an error code if an error occurs (SQLITE_NOMEM is possible).
+** Otherwise return SQLITE_OK. If there is no next entry on the node
+** (e.g. because the current entry is the last) set NodeReader->aNode to
+** NULL to indicate EOF. Otherwise, populate the NodeReader structure output
+** variables for the new entry.
+*/
+static int nodeReaderNext(NodeReader *p){
+ int bFirst = (p->term.n==0); /* True for first term on the node */
+ int nPrefix = 0; /* Bytes to copy from previous term */
+ int nSuffix = 0; /* Bytes to append to the prefix */
+ int rc = SQLITE_OK; /* Return code */
+
+ assert( p->aNode );
+ if( p->iChild && bFirst==0 ) p->iChild++;
+ if( p->iOff>=p->nNode ){
+ /* EOF */
+ p->aNode = 0;
+ }else{
+ if( bFirst==0 ){
+ p->iOff += sqlite3Fts3GetVarint32(&p->aNode[p->iOff], &nPrefix);
+ }
+ p->iOff += sqlite3Fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);
+
+ blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
+ if( rc==SQLITE_OK ){
+ memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
+ p->term.n = nPrefix+nSuffix;
+ p->iOff += nSuffix;
+ if( p->iChild==0 ){
+ p->iOff += sqlite3Fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
+ p->aDoclist = &p->aNode[p->iOff];
+ p->iOff += p->nDoclist;
+ }
+ }
+ }
+
+ assert( p->iOff<=p->nNode );
+
+ return rc;
+}
+
+/*
+** Release all dynamic resources held by node-reader object *p.
+*/
+static void nodeReaderRelease(NodeReader *p){
+ sqlite3_free(p->term.a);
+}
+
+/*
+** Initialize a node-reader object to read the node in buffer aNode/nNode.
+**
+** If successful, SQLITE_OK is returned and the NodeReader object set to
+** point to the first entry on the node (if any). Otherwise, an SQLite
+** error code is returned.
+*/
+static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){
+ memset(p, 0, sizeof(NodeReader));
+ p->aNode = aNode;
+ p->nNode = nNode;
+
+ /* Figure out if this is a leaf or an internal node. */
+ if( p->aNode[0] ){
+ /* An internal node. */
+ p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild);
+ }else{
+ p->iOff = 1;
+ }
+
+ return nodeReaderNext(p);
+}
+
+/*
+** This function is called while writing an FTS segment each time a leaf o
+** node is finished and written to disk. The key (zTerm/nTerm) is guaranteed
+** to be greater than the largest key on the node just written, but smaller
+** than or equal to the first key that will be written to the next leaf
+** node.
+**
+** The block id of the leaf node just written to disk may be found in
+** (pWriter->aNodeWriter[0].iBlock) when this function is called.
+*/
+static int fts3IncrmergePush(
+ Fts3Table *p, /* Fts3 table handle */
+ IncrmergeWriter *pWriter, /* Writer object */
+ const char *zTerm, /* Term to write to internal node */
+ int nTerm /* Bytes at zTerm */
+){
+ sqlite3_int64 iPtr = pWriter->aNodeWriter[0].iBlock;
+ int iLayer;
+
+ assert( nTerm>0 );
+ for(iLayer=1; ALWAYS(iLayer<FTS_MAX_APPENDABLE_HEIGHT); iLayer++){
+ sqlite3_int64 iNextPtr = 0;
+ NodeWriter *pNode = &pWriter->aNodeWriter[iLayer];
+ int rc = SQLITE_OK;
+ int nPrefix;
+ int nSuffix;
+ int nSpace;
+
+ /* Figure out how much space the key will consume if it is written to
+ ** the current node of layer iLayer. Due to the prefix compression,
+ ** the space required changes depending on which node the key is to
+ ** be added to. */
+ nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm);
+ nSuffix = nTerm - nPrefix;
+ nSpace = sqlite3Fts3VarintLen(nPrefix);
+ nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
+
+ if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){
+ /* If the current node of layer iLayer contains zero keys, or if adding
+ ** the key to it will not cause it to grow to larger than nNodeSize
+ ** bytes in size, write the key here. */
+
+ Blob *pBlk = &pNode->block;
+ if( pBlk->n==0 ){
+ blobGrowBuffer(pBlk, p->nNodeSize, &rc);
+ if( rc==SQLITE_OK ){
+ pBlk->a[0] = (char)iLayer;
+ pBlk->n = 1 + sqlite3Fts3PutVarint(&pBlk->a[1], iPtr);
+ }
+ }
+ blobGrowBuffer(pBlk, pBlk->n + nSpace, &rc);
+ blobGrowBuffer(&pNode->key, nTerm, &rc);
+
+ if( rc==SQLITE_OK ){
+ if( pNode->key.n ){
+ pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix);
+ }
+ pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix);
+ memcpy(&pBlk->a[pBlk->n], &zTerm[nPrefix], nSuffix);
+ pBlk->n += nSuffix;
+
+ memcpy(pNode->key.a, zTerm, nTerm);
+ pNode->key.n = nTerm;
+ }
+ }else{
+ /* Otherwise, flush the the current node of layer iLayer to disk.
+ ** Then allocate a new, empty sibling node. The key will be written
+ ** into the parent of this node. */
+ rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n);
+
+ assert( pNode->block.nAlloc>=p->nNodeSize );
+ pNode->block.a[0] = (char)iLayer;
+ pNode->block.n = 1 + sqlite3Fts3PutVarint(&pNode->block.a[1], iPtr+1);
+
+ iNextPtr = pNode->iBlock;
+ pNode->iBlock++;
+ pNode->key.n = 0;
+ }
+
+ if( rc!=SQLITE_OK || iNextPtr==0 ) return rc;
+ iPtr = iNextPtr;
+ }
+
+ assert( 0 );
+ return 0;
+}
+
+/*
+** Append a term and (optionally) doclist to the FTS segment node currently
+** stored in blob *pNode. The node need not contain any terms, but the
+** header must be written before this function is called.
+**
+** A node header is a single 0x00 byte for a leaf node, or a height varint
+** followed by the left-hand-child varint for an internal node.
+**
+** The term to be appended is passed via arguments zTerm/nTerm. For a
+** leaf node, the doclist is passed as aDoclist/nDoclist. For an internal
+** node, both aDoclist and nDoclist must be passed 0.
+**
+** If the size of the value in blob pPrev is zero, then this is the first
+** term written to the node. Otherwise, pPrev contains a copy of the
+** previous term. Before this function returns, it is updated to contain a
+** copy of zTerm/nTerm.
+**
+** It is assumed that the buffer associated with pNode is already large
+** enough to accommodate the new entry. The buffer associated with pPrev
+** is extended by this function if requrired.
+**
+** If an error (i.e. OOM condition) occurs, an SQLite error code is
+** returned. Otherwise, SQLITE_OK.
+*/
+static int fts3AppendToNode(
+ Blob *pNode, /* Current node image to append to */
+ Blob *pPrev, /* Buffer containing previous term written */
+ const char *zTerm, /* New term to write */
+ int nTerm, /* Size of zTerm in bytes */
+ const char *aDoclist, /* Doclist (or NULL) to write */
+ int nDoclist /* Size of aDoclist in bytes */
+){
+ int rc = SQLITE_OK; /* Return code */
+ int bFirst = (pPrev->n==0); /* True if this is the first term written */
+ int nPrefix; /* Size of term prefix in bytes */
+ int nSuffix; /* Size of term suffix in bytes */
+
+ /* Node must have already been started. There must be a doclist for a
+ ** leaf node, and there must not be a doclist for an internal node. */
+ assert( pNode->n>0 );
+ assert( (pNode->a[0]=='\0')==(aDoclist!=0) );
+
+ blobGrowBuffer(pPrev, nTerm, &rc);
+ if( rc!=SQLITE_OK ) return rc;
+
+ nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm);
+ nSuffix = nTerm - nPrefix;
+ memcpy(pPrev->a, zTerm, nTerm);
+ pPrev->n = nTerm;
+
+ if( bFirst==0 ){
+ pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nPrefix);
+ }
+ pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nSuffix);
+ memcpy(&pNode->a[pNode->n], &zTerm[nPrefix], nSuffix);
+ pNode->n += nSuffix;
+
+ if( aDoclist ){
+ pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nDoclist);
+ memcpy(&pNode->a[pNode->n], aDoclist, nDoclist);
+ pNode->n += nDoclist;
+ }
+
+ assert( pNode->n<=pNode->nAlloc );
+
+ return SQLITE_OK;
+}
+
+/*
+** Append the current term and doclist pointed to by cursor pCsr to the
+** appendable b-tree segment opened for writing by pWriter.
+**
+** Return SQLITE_OK if successful, or an SQLite error code otherwise.
+*/
+static int fts3IncrmergeAppend(
+ Fts3Table *p, /* Fts3 table handle */
+ IncrmergeWriter *pWriter, /* Writer object */
+ Fts3MultiSegReader *pCsr /* Cursor containing term and doclist */
+){
+ const char *zTerm = pCsr->zTerm;
+ int nTerm = pCsr->nTerm;
+ const char *aDoclist = pCsr->aDoclist;
+ int nDoclist = pCsr->nDoclist;
+ int rc = SQLITE_OK; /* Return code */
+ int nSpace; /* Total space in bytes required on leaf */
+ int nPrefix; /* Size of prefix shared with previous term */
+ int nSuffix; /* Size of suffix (nTerm - nPrefix) */
+ NodeWriter *pLeaf; /* Object used to write leaf nodes */
+
+ pLeaf = &pWriter->aNodeWriter[0];
+ nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm);
+ nSuffix = nTerm - nPrefix;
+
+ nSpace = sqlite3Fts3VarintLen(nPrefix);
+ nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
+ nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist;
+
+ /* If the current block is not empty, and if adding this term/doclist
+ ** to the current block would make it larger than Fts3Table.nNodeSize
+ ** bytes, write this block out to the database. */
+ if( pLeaf->block.n>0 && (pLeaf->block.n + nSpace)>p->nNodeSize ){
+ rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n);
+ pWriter->nWork++;
+
+ /* Add the current term to the parent node. The term added to the
+ ** parent must:
+ **
+ ** a) be greater than the largest term on the leaf node just written
+ ** to the database (still available in pLeaf->key), and
+ **
+ ** b) be less than or equal to the term about to be added to the new
+ ** leaf node (zTerm/nTerm).
+ **
+ ** In other words, it must be the prefix of zTerm 1 byte longer than
+ ** the common prefix (if any) of zTerm and pWriter->zTerm.
+ */
+ if( rc==SQLITE_OK ){
+ rc = fts3IncrmergePush(p, pWriter, zTerm, nPrefix+1);
+ }
+
+ /* Advance to the next output block */
+ pLeaf->iBlock++;
+ pLeaf->key.n = 0;
+ pLeaf->block.n = 0;
+
+ nSuffix = nTerm;
+ nSpace = 1;
+ nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
+ nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist;
+ }
+
+ blobGrowBuffer(&pLeaf->block, pLeaf->block.n + nSpace, &rc);
+
+ if( rc==SQLITE_OK ){
+ if( pLeaf->block.n==0 ){
+ pLeaf->block.n = 1;
+ pLeaf->block.a[0] = '\0';
+ }
+ rc = fts3AppendToNode(
+ &pLeaf->block, &pLeaf->key, zTerm, nTerm, aDoclist, nDoclist
+ );
+ }
+
+ return rc;
+}
+
+/*
+** This function is called to release all dynamic resources held by the
+** merge-writer object pWriter, and if no error has occurred, to flush
+** all outstanding node buffers held by pWriter to disk.
+**
+** If *pRc is not SQLITE_OK when this function is called, then no attempt
+** is made to write any data to disk. Instead, this function serves only
+** to release outstanding resources.
+**
+** Otherwise, if *pRc is initially SQLITE_OK and an error occurs while
+** flushing buffers to disk, *pRc is set to an SQLite error code before
+** returning.
+*/
+static void fts3IncrmergeRelease(
+ Fts3Table *p, /* FTS3 table handle */
+ IncrmergeWriter *pWriter, /* Merge-writer object */
+ int *pRc /* IN/OUT: Error code */
+){
+ int i; /* Used to iterate through non-root layers */
+ int iRoot; /* Index of root in pWriter->aNodeWriter */
+ NodeWriter *pRoot; /* NodeWriter for root node */
+ int rc = *pRc; /* Error code */
+
+ /* Set iRoot to the index in pWriter->aNodeWriter[] of the output segment
+ ** root node. If the segment fits entirely on a single leaf node, iRoot
+ ** will be set to 0. If the root node is the parent of the leaves, iRoot
+ ** will be 1. And so on. */
+ for(iRoot=FTS_MAX_APPENDABLE_HEIGHT-1; iRoot>=0; iRoot--){
+ NodeWriter *pNode = &pWriter->aNodeWriter[iRoot];
+ if( pNode->block.n>0 ) break;
+ assert( *pRc || pNode->block.nAlloc==0 );
+ assert( *pRc || pNode->key.nAlloc==0 );
+ sqlite3_free(pNode->block.a);
+ sqlite3_free(pNode->key.a);
+ }
+
+ /* Empty output segment. This is a no-op. */
+ if( iRoot<0 ) return;
+
+ /* The entire output segment fits on a single node. Normally, this means
+ ** the node would be stored as a blob in the "root" column of the %_segdir
+ ** table. However, this is not permitted in this case. The problem is that
+ ** space has already been reserved in the %_segments table, and so the
+ ** start_block and end_block fields of the %_segdir table must be populated.
+ ** And, by design or by accident, released versions of FTS cannot handle
+ ** segments that fit entirely on the root node with start_block!=0.
+ **
+ ** Instead, create a synthetic root node that contains nothing but a
+ ** pointer to the single content node. So that the segment consists of a
+ ** single leaf and a single interior (root) node.
+ **
+ ** Todo: Better might be to defer allocating space in the %_segments
+ ** table until we are sure it is needed.
+ */
+ if( iRoot==0 ){
+ Blob *pBlock = &pWriter->aNodeWriter[1].block;
+ blobGrowBuffer(pBlock, 1 + FTS3_VARINT_MAX, &rc);
+ if( rc==SQLITE_OK ){
+ pBlock->a[0] = 0x01;
+ pBlock->n = 1 + sqlite3Fts3PutVarint(
+ &pBlock->a[1], pWriter->aNodeWriter[0].iBlock
+ );
+ }
+ iRoot = 1;
+ }
+ pRoot = &pWriter->aNodeWriter[iRoot];
+
+ /* Flush all currently outstanding nodes to disk. */
+ for(i=0; i<iRoot; i++){
+ NodeWriter *pNode = &pWriter->aNodeWriter[i];
+ if( pNode->block.n>0 && rc==SQLITE_OK ){
+ rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n);
+ }
+ sqlite3_free(pNode->block.a);
+ sqlite3_free(pNode->key.a);
+ }
+
+ /* Write the %_segdir record. */
+ if( rc==SQLITE_OK ){
+ rc = fts3WriteSegdir(p,
+ pWriter->iAbsLevel+1, /* level */
+ pWriter->iIdx, /* idx */
+ pWriter->iStart, /* start_block */
+ pWriter->aNodeWriter[0].iBlock, /* leaves_end_block */
+ pWriter->iEnd, /* end_block */
+ pRoot->block.a, pRoot->block.n /* root */
+ );
+ }
+ sqlite3_free(pRoot->block.a);
+ sqlite3_free(pRoot->key.a);
+
+ *pRc = rc;
+}
+
+/*
+** Compare the term in buffer zLhs (size in bytes nLhs) with that in
+** zRhs (size in bytes nRhs) using memcmp. If one term is a prefix of
+** the other, it is considered to be smaller than the other.
+**
+** Return -ve if zLhs is smaller than zRhs, 0 if it is equal, or +ve
+** if it is greater.
+*/
+static int fts3TermCmp(
+ const char *zLhs, int nLhs, /* LHS of comparison */
+ const char *zRhs, int nRhs /* RHS of comparison */
+){
+ int nCmp = MIN(nLhs, nRhs);
+ int res;
+
+ res = memcmp(zLhs, zRhs, nCmp);
+ if( res==0 ) res = nLhs - nRhs;
+
+ return res;
+}
+
+
+/*
+** Query to see if the entry in the %_segments table with blockid iEnd is
+** NULL. If no error occurs and the entry is NULL, set *pbRes 1 before
+** returning. Otherwise, set *pbRes to 0.
+**
+** Or, if an error occurs while querying the database, return an SQLite
+** error code. The final value of *pbRes is undefined in this case.
+**
+** This is used to test if a segment is an "appendable" segment. If it
+** is, then a NULL entry has been inserted into the %_segments table
+** with blockid %_segdir.end_block.
+*/
+static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){
+ int bRes = 0; /* Result to set *pbRes to */
+ sqlite3_stmt *pCheck = 0; /* Statement to query database with */
+ int rc; /* Return code */
+
+ rc = fts3SqlStmt(p, SQL_SEGMENT_IS_APPENDABLE, &pCheck, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int64(pCheck, 1, iEnd);
+ if( SQLITE_ROW==sqlite3_step(pCheck) ) bRes = 1;
+ rc = sqlite3_reset(pCheck);
+ }
+
+ *pbRes = bRes;
+ return rc;
+}
+
+/*
+** This function is called when initializing an incremental-merge operation.
+** It checks if the existing segment with index value iIdx at absolute level
+** (iAbsLevel+1) can be appended to by the incremental merge. If it can, the
+** merge-writer object *pWriter is initialized to write to it.
+**
+** An existing segment can be appended to by an incremental merge if:
+**
+** * It was initially created as an appendable segment (with all required
+** space pre-allocated), and
+**
+** * The first key read from the input (arguments zKey and nKey) is
+** greater than the largest key currently stored in the potential
+** output segment.
+*/
+static int fts3IncrmergeLoad(
+ Fts3Table *p, /* Fts3 table handle */
+ sqlite3_int64 iAbsLevel, /* Absolute level of input segments */
+ int iIdx, /* Index of candidate output segment */
+ const char *zKey, /* First key to write */
+ int nKey, /* Number of bytes in nKey */
+ IncrmergeWriter *pWriter /* Populate this object */
+){
+ int rc; /* Return code */
+ sqlite3_stmt *pSelect = 0; /* SELECT to read %_segdir entry */
+
+ rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pSelect, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_int64 iStart = 0; /* Value of %_segdir.start_block */
+ sqlite3_int64 iLeafEnd = 0; /* Value of %_segdir.leaves_end_block */
+ sqlite3_int64 iEnd = 0; /* Value of %_segdir.end_block */
+ const char *aRoot = 0; /* Pointer to %_segdir.root buffer */
+ int nRoot = 0; /* Size of aRoot[] in bytes */
+ int rc2; /* Return code from sqlite3_reset() */
+ int bAppendable = 0; /* Set to true if segment is appendable */
+
+ /* Read the %_segdir entry for index iIdx absolute level (iAbsLevel+1) */
+ sqlite3_bind_int64(pSelect, 1, iAbsLevel+1);
+ sqlite3_bind_int(pSelect, 2, iIdx);
+ if( sqlite3_step(pSelect)==SQLITE_ROW ){
+ iStart = sqlite3_column_int64(pSelect, 1);
+ iLeafEnd = sqlite3_column_int64(pSelect, 2);
+ iEnd = sqlite3_column_int64(pSelect, 3);
+ nRoot = sqlite3_column_bytes(pSelect, 4);
+ aRoot = sqlite3_column_blob(pSelect, 4);
+ }else{
+ return sqlite3_reset(pSelect);
+ }
+
+ /* Check for the zero-length marker in the %_segments table */
+ rc = fts3IsAppendable(p, iEnd, &bAppendable);
+
+ /* Check that zKey/nKey is larger than the largest key the candidate */
+ if( rc==SQLITE_OK && bAppendable ){
+ char *aLeaf = 0;
+ int nLeaf = 0;
+
+ rc = sqlite3Fts3ReadBlock(p, iLeafEnd, &aLeaf, &nLeaf, 0);
+ if( rc==SQLITE_OK ){
+ NodeReader reader;
+ for(rc = nodeReaderInit(&reader, aLeaf, nLeaf);
+ rc==SQLITE_OK && reader.aNode;
+ rc = nodeReaderNext(&reader)
+ ){
+ assert( reader.aNode );
+ }
+ if( fts3TermCmp(zKey, nKey, reader.term.a, reader.term.n)<=0 ){
+ bAppendable = 0;
+ }
+ nodeReaderRelease(&reader);
+ }
+ sqlite3_free(aLeaf);
+ }
+
+ if( rc==SQLITE_OK && bAppendable ){
+ /* It is possible to append to this segment. Set up the IncrmergeWriter
+ ** object to do so. */
+ int i;
+ int nHeight = (int)aRoot[0];
+ NodeWriter *pNode;
+
+ pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT;
+ pWriter->iStart = iStart;
+ pWriter->iEnd = iEnd;
+ pWriter->iAbsLevel = iAbsLevel;
+ pWriter->iIdx = iIdx;
+
+ for(i=nHeight+1; i<FTS_MAX_APPENDABLE_HEIGHT; i++){
+ pWriter->aNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst;
+ }
+
+ pNode = &pWriter->aNodeWriter[nHeight];
+ pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight;
+ blobGrowBuffer(&pNode->block, MAX(nRoot, p->nNodeSize), &rc);
+ if( rc==SQLITE_OK ){
+ memcpy(pNode->block.a, aRoot, nRoot);
+ pNode->block.n = nRoot;
+ }
+
+ for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){
+ NodeReader reader;
+ pNode = &pWriter->aNodeWriter[i];
+
+ rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
+ while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader);
+ blobGrowBuffer(&pNode->key, reader.term.n, &rc);
+ if( rc==SQLITE_OK ){
+ memcpy(pNode->key.a, reader.term.a, reader.term.n);
+ pNode->key.n = reader.term.n;
+ if( i>0 ){
+ char *aBlock = 0;
+ int nBlock = 0;
+ pNode = &pWriter->aNodeWriter[i-1];
+ pNode->iBlock = reader.iChild;
+ rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0);
+ blobGrowBuffer(&pNode->block, MAX(nBlock, p->nNodeSize), &rc);
+ if( rc==SQLITE_OK ){
+ memcpy(pNode->block.a, aBlock, nBlock);
+ pNode->block.n = nBlock;
+ }
+ sqlite3_free(aBlock);
+ }
+ }
+ nodeReaderRelease(&reader);
+ }
+ }
+
+ rc2 = sqlite3_reset(pSelect);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+
+ return rc;
+}
+
+/*
+** Determine the largest segment index value that exists within absolute
+** level iAbsLevel+1. If no error occurs, set *piIdx to this value plus
+** one before returning SQLITE_OK. Or, if there are no segments at all
+** within level iAbsLevel, set *piIdx to zero.
+**
+** If an error occurs, return an SQLite error code. The final value of
+** *piIdx is undefined in this case.
+*/
+static int fts3IncrmergeOutputIdx(
+ Fts3Table *p, /* FTS Table handle */
+ sqlite3_int64 iAbsLevel, /* Absolute index of input segments */
+ int *piIdx /* OUT: Next free index at iAbsLevel+1 */
+){
+ int rc;
+ sqlite3_stmt *pOutputIdx = 0; /* SQL used to find output index */
+
+ rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pOutputIdx, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int64(pOutputIdx, 1, iAbsLevel+1);
+ sqlite3_step(pOutputIdx);
+ *piIdx = sqlite3_column_int(pOutputIdx, 0);
+ rc = sqlite3_reset(pOutputIdx);
+ }
+
+ return rc;
+}
+
+/*
+** Allocate an appendable output segment on absolute level iAbsLevel+1
+** with idx value iIdx.
+**
+** In the %_segdir table, a segment is defined by the values in three
+** columns:
+**
+** start_block
+** leaves_end_block
+** end_block
+**
+** When an appendable segment is allocated, it is estimated that the
+** maximum number of leaf blocks that may be required is the sum of the
+** number of leaf blocks consumed by the input segments, plus the number
+** of input segments, multiplied by two. This value is stored in stack
+** variable nLeafEst.
+**
+** A total of 16*nLeafEst blocks are allocated when an appendable segment
+** is created ((1 + end_block - start_block)==16*nLeafEst). The contiguous
+** array of leaf nodes starts at the first block allocated. The array
+** of interior nodes that are parents of the leaf nodes start at block
+** (start_block + (1 + end_block - start_block) / 16). And so on.
+**
+** In the actual code below, the value "16" is replaced with the
+** pre-processor macro FTS_MAX_APPENDABLE_HEIGHT.
+*/
+static int fts3IncrmergeWriter(
+ Fts3Table *p, /* Fts3 table handle */
+ sqlite3_int64 iAbsLevel, /* Absolute level of input segments */
+ int iIdx, /* Index of new output segment */
+ Fts3MultiSegReader *pCsr, /* Cursor that data will be read from */
+ IncrmergeWriter *pWriter /* Populate this object */
+){
+ int rc; /* Return Code */
+ int i; /* Iterator variable */
+ int nLeafEst = 0; /* Blocks allocated for leaf nodes */
+ sqlite3_stmt *pLeafEst = 0; /* SQL used to determine nLeafEst */
+ sqlite3_stmt *pFirstBlock = 0; /* SQL used to determine first block */
+
+ /* Calculate nLeafEst. */
+ rc = fts3SqlStmt(p, SQL_MAX_LEAF_NODE_ESTIMATE, &pLeafEst, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int64(pLeafEst, 1, iAbsLevel);
+ sqlite3_bind_int64(pLeafEst, 2, pCsr->nSegment);
+ if( SQLITE_ROW==sqlite3_step(pLeafEst) ){
+ nLeafEst = sqlite3_column_int(pLeafEst, 0);
+ }
+ rc = sqlite3_reset(pLeafEst);
+ }
+ if( rc!=SQLITE_OK ) return rc;
+
+ /* Calculate the first block to use in the output segment */
+ rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pFirstBlock, 0);
+ if( rc==SQLITE_OK ){
+ if( SQLITE_ROW==sqlite3_step(pFirstBlock) ){
+ pWriter->iStart = sqlite3_column_int64(pFirstBlock, 0);
+ pWriter->iEnd = pWriter->iStart - 1;
+ pWriter->iEnd += nLeafEst * FTS_MAX_APPENDABLE_HEIGHT;
+ }
+ rc = sqlite3_reset(pFirstBlock);
+ }
+ if( rc!=SQLITE_OK ) return rc;
+
+ /* Insert the marker in the %_segments table to make sure nobody tries
+ ** to steal the space just allocated. This is also used to identify
+ ** appendable segments. */
+ rc = fts3WriteSegment(p, pWriter->iEnd, 0, 0);
+ if( rc!=SQLITE_OK ) return rc;
+
+ pWriter->iAbsLevel = iAbsLevel;
+ pWriter->nLeafEst = nLeafEst;
+ pWriter->iIdx = iIdx;
+
+ /* Set up the array of NodeWriter objects */
+ for(i=0; i<FTS_MAX_APPENDABLE_HEIGHT; i++){
+ pWriter->aNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Remove an entry from the %_segdir table. This involves running the
+** following two statements:
+**
+** DELETE FROM %_segdir WHERE level = :iAbsLevel AND idx = :iIdx
+** UPDATE %_segdir SET idx = idx - 1 WHERE level = :iAbsLevel AND idx > :iIdx
+**
+** The DELETE statement removes the specific %_segdir level. The UPDATE
+** statement ensures that the remaining segments have contiguously allocated
+** idx values.
+*/
+static int fts3RemoveSegdirEntry(
+ Fts3Table *p, /* FTS3 table handle */
+ sqlite3_int64 iAbsLevel, /* Absolute level to delete from */
+ int iIdx /* Index of %_segdir entry to delete */
+){
+ int rc; /* Return code */
+ sqlite3_stmt *pDelete = 0; /* DELETE statement */
+
+ rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_ENTRY, &pDelete, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int64(pDelete, 1, iAbsLevel);
+ sqlite3_bind_int(pDelete, 2, iIdx);
+ sqlite3_step(pDelete);
+ rc = sqlite3_reset(pDelete);
+ }
+
+ return rc;
+}
+
+/*
+** One or more segments have just been removed from absolute level iAbsLevel.
+** Update the 'idx' values of the remaining segments in the level so that
+** the idx values are a contiguous sequence starting from 0.
+*/
+static int fts3RepackSegdirLevel(
+ Fts3Table *p, /* FTS3 table handle */
+ sqlite3_int64 iAbsLevel /* Absolute level to repack */
+){
+ int rc; /* Return code */
+ int *aIdx = 0; /* Array of remaining idx values */
+ int nIdx = 0; /* Valid entries in aIdx[] */
+ int nAlloc = 0; /* Allocated size of aIdx[] */
+ int i; /* Iterator variable */
+ sqlite3_stmt *pSelect = 0; /* Select statement to read idx values */
+ sqlite3_stmt *pUpdate = 0; /* Update statement to modify idx values */
+
+ rc = fts3SqlStmt(p, SQL_SELECT_INDEXES, &pSelect, 0);
+ if( rc==SQLITE_OK ){
+ int rc2;
+ sqlite3_bind_int64(pSelect, 1, iAbsLevel);
+ while( SQLITE_ROW==sqlite3_step(pSelect) ){
+ if( nIdx>=nAlloc ){
+ int *aNew;
+ nAlloc += 16;
+ aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int));
+ if( !aNew ){
+ rc = SQLITE_NOMEM;
+ break;
+ }
+ aIdx = aNew;
+ }
+ aIdx[nIdx++] = sqlite3_column_int(pSelect, 0);
+ }
+ rc2 = sqlite3_reset(pSelect);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = fts3SqlStmt(p, SQL_SHIFT_SEGDIR_ENTRY, &pUpdate, 0);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int64(pUpdate, 2, iAbsLevel);
+ }
+
+ assert( p->bIgnoreSavepoint==0 );
+ p->bIgnoreSavepoint = 1;
+ for(i=0; rc==SQLITE_OK && i<nIdx; i++){
+ if( aIdx[i]!=i ){
+ sqlite3_bind_int(pUpdate, 3, aIdx[i]);
+ sqlite3_bind_int(pUpdate, 1, i);
+ sqlite3_step(pUpdate);
+ rc = sqlite3_reset(pUpdate);
+ }
+ }
+ p->bIgnoreSavepoint = 0;
+
+ sqlite3_free(aIdx);
+ return rc;
+}
+
+static void fts3StartNode(Blob *pNode, int iHeight, sqlite3_int64 iChild){
+ pNode->a[0] = (char)iHeight;
+ if( iChild ){
+ assert( pNode->nAlloc>=1+sqlite3Fts3VarintLen(iChild) );
+ pNode->n = 1 + sqlite3Fts3PutVarint(&pNode->a[1], iChild);
+ }else{
+ assert( pNode->nAlloc>=1 );
+ pNode->n = 1;
+ }
+}
+
+/*
+** The first two arguments are a pointer to and the size of a segment b-tree
+** node. The node may be a leaf or an internal node.
+**
+** This function creates a new node image in blob object *pNew by copying
+** all terms that are greater than or equal to zTerm/nTerm (for leaf nodes)
+** or greater than zTerm/nTerm (for internal nodes) from aNode/nNode.
+*/
+static int fts3TruncateNode(
+ const char *aNode, /* Current node image */
+ int nNode, /* Size of aNode in bytes */
+ Blob *pNew, /* OUT: Write new node image here */
+ const char *zTerm, /* Omit all terms smaller than this */
+ int nTerm, /* Size of zTerm in bytes */
+ sqlite3_int64 *piBlock /* OUT: Block number in next layer down */
+){
+ NodeReader reader; /* Reader object */
+ Blob prev = {0, 0, 0}; /* Previous term written to new node */
+ int rc = SQLITE_OK; /* Return code */
+ int bLeaf = aNode[0]=='\0'; /* True for a leaf node */
+
+ /* Allocate required output space */
+ blobGrowBuffer(pNew, nNode, &rc);
+ if( rc!=SQLITE_OK ) return rc;
+ pNew->n = 0;
+
+ /* Populate new node buffer */
+ for(rc = nodeReaderInit(&reader, aNode, nNode);
+ rc==SQLITE_OK && reader.aNode;
+ rc = nodeReaderNext(&reader)
+ ){
+ if( pNew->n==0 ){
+ int res = fts3TermCmp(reader.term.a, reader.term.n, zTerm, nTerm);
+ if( res<0 || (bLeaf==0 && res==0) ) continue;
+ fts3StartNode(pNew, (int)aNode[0], reader.iChild);
+ *piBlock = reader.iChild;
+ }
+ rc = fts3AppendToNode(
+ pNew, &prev, reader.term.a, reader.term.n,
+ reader.aDoclist, reader.nDoclist
+ );
+ if( rc!=SQLITE_OK ) break;
+ }
+ if( pNew->n==0 ){
+ fts3StartNode(pNew, (int)aNode[0], reader.iChild);
+ *piBlock = reader.iChild;
+ }
+ assert( pNew->n<=pNew->nAlloc );
+
+ nodeReaderRelease(&reader);
+ sqlite3_free(prev.a);
+ return rc;
+}
+
+/*
+** Remove all terms smaller than zTerm/nTerm from segment iIdx in absolute
+** level iAbsLevel. This may involve deleting entries from the %_segments
+** table, and modifying existing entries in both the %_segments and %_segdir
+** tables.
+**
+** SQLITE_OK is returned if the segment is updated successfully. Or an
+** SQLite error code otherwise.
+*/
+static int fts3TruncateSegment(
+ Fts3Table *p, /* FTS3 table handle */
+ sqlite3_int64 iAbsLevel, /* Absolute level of segment to modify */
+ int iIdx, /* Index within level of segment to modify */
+ const char *zTerm, /* Remove terms smaller than this */
+ int nTerm /* Number of bytes in buffer zTerm */
+){
+ int rc = SQLITE_OK; /* Return code */
+ Blob root = {0,0,0}; /* New root page image */
+ Blob block = {0,0,0}; /* Buffer used for any other block */
+ sqlite3_int64 iBlock = 0; /* Block id */
+ sqlite3_int64 iNewStart = 0; /* New value for iStartBlock */
+ sqlite3_int64 iOldStart = 0; /* Old value for iStartBlock */
+ sqlite3_stmt *pFetch = 0; /* Statement used to fetch segdir */
+
+ rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pFetch, 0);
+ if( rc==SQLITE_OK ){
+ int rc2; /* sqlite3_reset() return code */
+ sqlite3_bind_int64(pFetch, 1, iAbsLevel);
+ sqlite3_bind_int(pFetch, 2, iIdx);
+ if( SQLITE_ROW==sqlite3_step(pFetch) ){
+ const char *aRoot = sqlite3_column_blob(pFetch, 4);
+ int nRoot = sqlite3_column_bytes(pFetch, 4);
+ iOldStart = sqlite3_column_int64(pFetch, 1);
+ rc = fts3TruncateNode(aRoot, nRoot, &root, zTerm, nTerm, &iBlock);
+ }
+ rc2 = sqlite3_reset(pFetch);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+
+ while( rc==SQLITE_OK && iBlock ){
+ char *aBlock = 0;
+ int nBlock = 0;
+ iNewStart = iBlock;
+
+ rc = sqlite3Fts3ReadBlock(p, iBlock, &aBlock, &nBlock, 0);
+ if( rc==SQLITE_OK ){
+ rc = fts3TruncateNode(aBlock, nBlock, &block, zTerm, nTerm, &iBlock);
+ }
+ if( rc==SQLITE_OK ){
+ rc = fts3WriteSegment(p, iNewStart, block.a, block.n);
+ }
+ sqlite3_free(aBlock);
+ }
+
+ /* Variable iNewStart now contains the first valid leaf node. */
+ if( rc==SQLITE_OK && iNewStart ){
+ sqlite3_stmt *pDel = 0;
+ rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDel, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int64(pDel, 1, iOldStart);
+ sqlite3_bind_int64(pDel, 2, iNewStart-1);
+ sqlite3_step(pDel);
+ rc = sqlite3_reset(pDel);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3_stmt *pChomp = 0;
+ rc = fts3SqlStmt(p, SQL_CHOMP_SEGDIR, &pChomp, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int64(pChomp, 1, iNewStart);
+ sqlite3_bind_blob(pChomp, 2, root.a, root.n, SQLITE_STATIC);
+ sqlite3_bind_int64(pChomp, 3, iAbsLevel);
+ sqlite3_bind_int(pChomp, 4, iIdx);
+ sqlite3_step(pChomp);
+ rc = sqlite3_reset(pChomp);
+ }
+ }
+
+ sqlite3_free(root.a);
+ sqlite3_free(block.a);
+ return rc;
+}
+
+/*
+** This function is called after an incrmental-merge operation has run to
+** merge (or partially merge) two or more segments from absolute level
+** iAbsLevel.
+**
+** Each input segment is either removed from the db completely (if all of
+** its data was copied to the output segment by the incrmerge operation)
+** or modified in place so that it no longer contains those entries that
+** have been duplicated in the output segment.
+*/
+static int fts3IncrmergeChomp(
+ Fts3Table *p, /* FTS table handle */
+ sqlite3_int64 iAbsLevel, /* Absolute level containing segments */
+ Fts3MultiSegReader *pCsr, /* Chomp all segments opened by this cursor */
+ int *pnRem /* Number of segments not deleted */
+){
+ int i;
+ int nRem = 0;
+ int rc = SQLITE_OK;
+
+ for(i=pCsr->nSegment-1; i>=0 && rc==SQLITE_OK; i--){
+ Fts3SegReader *pSeg = 0;
+ int j;
+
+ /* Find the Fts3SegReader object with Fts3SegReader.iIdx==i. It is hiding
+ ** somewhere in the pCsr->apSegment[] array. */
+ for(j=0; ALWAYS(j<pCsr->nSegment); j++){
+ pSeg = pCsr->apSegment[j];
+ if( pSeg->iIdx==i ) break;
+ }
+ assert( j<pCsr->nSegment && pSeg->iIdx==i );
+
+ if( pSeg->aNode==0 ){
+ /* Seg-reader is at EOF. Remove the entire input segment. */
+ rc = fts3DeleteSegment(p, pSeg);
+ if( rc==SQLITE_OK ){
+ rc = fts3RemoveSegdirEntry(p, iAbsLevel, pSeg->iIdx);
+ }
+ *pnRem = 0;
+ }else{
+ /* The incremental merge did not copy all the data from this
+ ** segment to the upper level. The segment is modified in place
+ ** so that it contains no keys smaller than zTerm/nTerm. */
+ const char *zTerm = pSeg->zTerm;
+ int nTerm = pSeg->nTerm;
+ rc = fts3TruncateSegment(p, iAbsLevel, pSeg->iIdx, zTerm, nTerm);
+ nRem++;
+ }
+ }
+
+ if( rc==SQLITE_OK && nRem!=pCsr->nSegment ){
+ rc = fts3RepackSegdirLevel(p, iAbsLevel);
+ }
+
+ *pnRem = nRem;
+ return rc;
+}
+
+/*
+** Store an incr-merge hint in the database.
+*/
+static int fts3IncrmergeHintStore(Fts3Table *p, Blob *pHint){
+ sqlite3_stmt *pReplace = 0;
+ int rc; /* Return code */
+
+ rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pReplace, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int(pReplace, 1, FTS_STAT_INCRMERGEHINT);
+ sqlite3_bind_blob(pReplace, 2, pHint->a, pHint->n, SQLITE_STATIC);
+ sqlite3_step(pReplace);
+ rc = sqlite3_reset(pReplace);
+ }
+
+ return rc;
+}
+
+/*
+** Load an incr-merge hint from the database. The incr-merge hint, if one
+** exists, is stored in the rowid==1 row of the %_stat table.
+**
+** If successful, populate blob *pHint with the value read from the %_stat
+** table and return SQLITE_OK. Otherwise, if an error occurs, return an
+** SQLite error code.
+*/
+static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){
+ sqlite3_stmt *pSelect = 0;
+ int rc;
+
+ pHint->n = 0;
+ rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pSelect, 0);
+ if( rc==SQLITE_OK ){
+ int rc2;
+ sqlite3_bind_int(pSelect, 1, FTS_STAT_INCRMERGEHINT);
+ if( SQLITE_ROW==sqlite3_step(pSelect) ){
+ const char *aHint = sqlite3_column_blob(pSelect, 0);
+ int nHint = sqlite3_column_bytes(pSelect, 0);
+ if( aHint ){
+ blobGrowBuffer(pHint, nHint, &rc);
+ if( rc==SQLITE_OK ){
+ memcpy(pHint->a, aHint, nHint);
+ pHint->n = nHint;
+ }
+ }
+ }
+ rc2 = sqlite3_reset(pSelect);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+
+ return rc;
+}
+
+/*
+** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
+** Otherwise, append an entry to the hint stored in blob *pHint. Each entry
+** consists of two varints, the absolute level number of the input segments
+** and the number of input segments.
+**
+** If successful, leave *pRc set to SQLITE_OK and return. If an error occurs,
+** set *pRc to an SQLite error code before returning.
+*/
+static void fts3IncrmergeHintPush(
+ Blob *pHint, /* Hint blob to append to */
+ i64 iAbsLevel, /* First varint to store in hint */
+ int nInput, /* Second varint to store in hint */
+ int *pRc /* IN/OUT: Error code */
+){
+ blobGrowBuffer(pHint, pHint->n + 2*FTS3_VARINT_MAX, pRc);
+ if( *pRc==SQLITE_OK ){
+ pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], iAbsLevel);
+ pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], (i64)nInput);
+ }
+}
+
+/*
+** Read the last entry (most recently pushed) from the hint blob *pHint
+** and then remove the entry. Write the two values read to *piAbsLevel and
+** *pnInput before returning.
+**
+** If no error occurs, return SQLITE_OK. If the hint blob in *pHint does
+** not contain at least two valid varints, return SQLITE_CORRUPT_VTAB.
+*/
+static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
+ const int nHint = pHint->n;
+ int i;
+
+ i = pHint->n-2;
+ while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
+ while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
+
+ pHint->n = i;
+ i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel);
+ i += sqlite3Fts3GetVarint32(&pHint->a[i], pnInput);
+ if( i!=nHint ) return SQLITE_CORRUPT_VTAB;
+
+ return SQLITE_OK;
+}
+
+
+/*
+** Attempt an incremental merge that writes nMerge leaf blocks.
+**
+** Incremental merges happen nMin segments at a time. The two
+** segments to be merged are the nMin oldest segments (the ones with
+** the smallest indexes) in the highest level that contains at least
+** nMin segments. Multiple merges might occur in an attempt to write the
+** quota of nMerge leaf blocks.
+*/
+SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
+ int rc; /* Return code */
+ int nRem = nMerge; /* Number of leaf pages yet to be written */
+ Fts3MultiSegReader *pCsr; /* Cursor used to read input data */
+ Fts3SegFilter *pFilter; /* Filter used with cursor pCsr */
+ IncrmergeWriter *pWriter; /* Writer object */
+ int nSeg = 0; /* Number of input segments */
+ sqlite3_int64 iAbsLevel = 0; /* Absolute level number to work on */
+ Blob hint = {0, 0, 0}; /* Hint read from %_stat table */
+ int bDirtyHint = 0; /* True if blob 'hint' has been modified */
+
+ /* Allocate space for the cursor, filter and writer objects */
+ const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter);
+ pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc);
+ if( !pWriter ) return SQLITE_NOMEM;
+ pFilter = (Fts3SegFilter *)&pWriter[1];
+ pCsr = (Fts3MultiSegReader *)&pFilter[1];
+
+ rc = fts3IncrmergeHintLoad(p, &hint);
+ while( rc==SQLITE_OK && nRem>0 ){
+ const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex;
+ sqlite3_stmt *pFindLevel = 0; /* SQL used to determine iAbsLevel */
+ int bUseHint = 0; /* True if attempting to append */
+
+ /* Search the %_segdir table for the absolute level with the smallest
+ ** relative level number that contains at least nMin segments, if any.
+ ** If one is found, set iAbsLevel to the absolute level number and
+ ** nSeg to nMin. If no level with at least nMin segments can be found,
+ ** set nSeg to -1.
+ */
+ rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0);
+ sqlite3_bind_int(pFindLevel, 1, nMin);
+ if( sqlite3_step(pFindLevel)==SQLITE_ROW ){
+ iAbsLevel = sqlite3_column_int64(pFindLevel, 0);
+ nSeg = nMin;
+ }else{
+ nSeg = -1;
+ }
+ rc = sqlite3_reset(pFindLevel);
+
+ /* If the hint read from the %_stat table is not empty, check if the
+ ** last entry in it specifies a relative level smaller than or equal
+ ** to the level identified by the block above (if any). If so, this
+ ** iteration of the loop will work on merging at the hinted level.
+ */
+ if( rc==SQLITE_OK && hint.n ){
+ int nHint = hint.n;
+ sqlite3_int64 iHintAbsLevel = 0; /* Hint level */
+ int nHintSeg = 0; /* Hint number of segments */
+
+ rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg);
+ if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){
+ iAbsLevel = iHintAbsLevel;
+ nSeg = nHintSeg;
+ bUseHint = 1;
+ bDirtyHint = 1;
+ }else{
+ /* This undoes the effect of the HintPop() above - so that no entry
+ ** is removed from the hint blob. */
+ hint.n = nHint;
+ }
+ }
+
+ /* If nSeg is less that zero, then there is no level with at least
+ ** nMin segments and no hint in the %_stat table. No work to do.
+ ** Exit early in this case. */
+ if( nSeg<0 ) break;
+
+ /* Open a cursor to iterate through the contents of the oldest nSeg
+ ** indexes of absolute level iAbsLevel. If this cursor is opened using
+ ** the 'hint' parameters, it is possible that there are less than nSeg
+ ** segments available in level iAbsLevel. In this case, no work is
+ ** done on iAbsLevel - fall through to the next iteration of the loop
+ ** to start work on some other level. */
+ memset(pWriter, 0, nAlloc);
+ pFilter->flags = FTS3_SEGMENT_REQUIRE_POS;
+ if( rc==SQLITE_OK ){
+ rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr);
+ }
+ if( SQLITE_OK==rc && pCsr->nSegment==nSeg
+ && SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter))
+ && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr))
+ ){
+ int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */
+ rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx);
+ if( rc==SQLITE_OK ){
+ if( bUseHint && iIdx>0 ){
+ const char *zKey = pCsr->zTerm;
+ int nKey = pCsr->nTerm;
+ rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter);
+ }else{
+ rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter);
+ }
+ }
+
+ if( rc==SQLITE_OK && pWriter->nLeafEst ){
+ fts3LogMerge(nSeg, iAbsLevel);
+ do {
+ rc = fts3IncrmergeAppend(p, pWriter, pCsr);
+ if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr);
+ if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK;
+ }while( rc==SQLITE_ROW );
+
+ /* Update or delete the input segments */
+ if( rc==SQLITE_OK ){
+ nRem -= (1 + pWriter->nWork);
+ rc = fts3IncrmergeChomp(p, iAbsLevel, pCsr, &nSeg);
+ if( nSeg!=0 ){
+ bDirtyHint = 1;
+ fts3IncrmergeHintPush(&hint, iAbsLevel, nSeg, &rc);
+ }
+ }
+ }
+
+ fts3IncrmergeRelease(p, pWriter, &rc);
+ }
+
+ sqlite3Fts3SegReaderFinish(pCsr);
+ }
+
+ /* Write the hint values into the %_stat table for the next incr-merger */
+ if( bDirtyHint && rc==SQLITE_OK ){
+ rc = fts3IncrmergeHintStore(p, &hint);
+ }
+
+ sqlite3_free(pWriter);
+ sqlite3_free(hint.a);
+ return rc;
+}
+
+/*
+** Convert the text beginning at *pz into an integer and return
+** its value. Advance *pz to point to the first character past
+** the integer.
+*/
+static int fts3Getint(const char **pz){
+ const char *z = *pz;
+ int i = 0;
+ while( (*z)>='0' && (*z)<='9' ) i = 10*i + *(z++) - '0';
+ *pz = z;
+ return i;
+}
+
+/*
+** Process statements of the form:
+**
+** INSERT INTO table(table) VALUES('merge=A,B');
+**
+** A and B are integers that decode to be the number of leaf pages
+** written for the merge, and the minimum number of segments on a level
+** before it will be selected for a merge, respectively.
+*/
+static int fts3DoIncrmerge(
+ Fts3Table *p, /* FTS3 table handle */
+ const char *zParam /* Nul-terminated string containing "A,B" */
+){
+ int rc;
+ int nMin = (FTS3_MERGE_COUNT / 2);
+ int nMerge = 0;
+ const char *z = zParam;
+
+ /* Read the first integer value */
+ nMerge = fts3Getint(&z);
+
+ /* If the first integer value is followed by a ',', read the second
+ ** integer value. */
+ if( z[0]==',' && z[1]!='\0' ){
+ z++;
+ nMin = fts3Getint(&z);
+ }
+
+ if( z[0]!='\0' || nMin<2 ){
+ rc = SQLITE_ERROR;
+ }else{
+ rc = SQLITE_OK;
+ if( !p->bHasStat ){
+ assert( p->bFts4==0 );
+ sqlite3Fts3CreateStatTable(&rc, p);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts3Incrmerge(p, nMerge, nMin);
+ }
+ sqlite3Fts3SegmentsClose(p);
+ }
+ return rc;
+}
+
+/*
+** Process statements of the form:
+**
+** INSERT INTO table(table) VALUES('automerge=X');
+**
+** where X is an integer. X==0 means to turn automerge off. X!=0 means
+** turn it on. The setting is persistent.
+*/
+static int fts3DoAutoincrmerge(
+ Fts3Table *p, /* FTS3 table handle */
+ const char *zParam /* Nul-terminated string containing boolean */
+){
+ int rc = SQLITE_OK;
+ sqlite3_stmt *pStmt = 0;
+ p->bAutoincrmerge = fts3Getint(&zParam)!=0;
+ if( !p->bHasStat ){
+ assert( p->bFts4==0 );
+ sqlite3Fts3CreateStatTable(&rc, p);
+ if( rc ) return rc;
+ }
+ rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0);
+ if( rc ) return rc;;
+ sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
+ sqlite3_bind_int(pStmt, 2, p->bAutoincrmerge);
+ sqlite3_step(pStmt);
+ rc = sqlite3_reset(pStmt);
+ return rc;
+}
+
+/*
+** Return a 64-bit checksum for the FTS index entry specified by the
+** arguments to this function.
+*/
+static u64 fts3ChecksumEntry(
+ const char *zTerm, /* Pointer to buffer containing term */
+ int nTerm, /* Size of zTerm in bytes */
+ int iLangid, /* Language id for current row */
+ int iIndex, /* Index (0..Fts3Table.nIndex-1) */
+ i64 iDocid, /* Docid for current row. */
+ int iCol, /* Column number */
+ int iPos /* Position */
+){
+ int i;
+ u64 ret = (u64)iDocid;
+
+ ret += (ret<<3) + iLangid;
+ ret += (ret<<3) + iIndex;
+ ret += (ret<<3) + iCol;
+ ret += (ret<<3) + iPos;
+ for(i=0; i<nTerm; i++) ret += (ret<<3) + zTerm[i];
+
+ return ret;
+}
+
+/*
+** Return a checksum of all entries in the FTS index that correspond to
+** language id iLangid. The checksum is calculated by XORing the checksums
+** of each individual entry (see fts3ChecksumEntry()) together.
+**
+** If successful, the checksum value is returned and *pRc set to SQLITE_OK.
+** Otherwise, if an error occurs, *pRc is set to an SQLite error code. The
+** return value is undefined in this case.
+*/
+static u64 fts3ChecksumIndex(
+ Fts3Table *p, /* FTS3 table handle */
+ int iLangid, /* Language id to return cksum for */
+ int iIndex, /* Index to cksum (0..p->nIndex-1) */
+ int *pRc /* OUT: Return code */
+){
+ Fts3SegFilter filter;
+ Fts3MultiSegReader csr;
+ int rc;
+ u64 cksum = 0;
+
+ assert( *pRc==SQLITE_OK );
+
+ memset(&filter, 0, sizeof(filter));
+ memset(&csr, 0, sizeof(csr));
+ filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY;
+ filter.flags |= FTS3_SEGMENT_SCAN;
+
+ rc = sqlite3Fts3SegReaderCursor(
+ p, iLangid, iIndex, FTS3_SEGCURSOR_ALL, 0, 0, 0, 1,&csr
+ );
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts3SegReaderStart(p, &csr, &filter);
+ }
+
+ if( rc==SQLITE_OK ){
+ while( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, &csr)) ){
+ char *pCsr = csr.aDoclist;
+ char *pEnd = &pCsr[csr.nDoclist];
+
+ i64 iDocid = 0;
+ i64 iCol = 0;
+ i64 iPos = 0;
+
+ pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid);
+ while( pCsr<pEnd ){
+ i64 iVal = 0;
+ pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
+ if( pCsr<pEnd ){
+ if( iVal==0 || iVal==1 ){
+ iCol = 0;
+ iPos = 0;
+ if( iVal ){
+ pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
+ }else{
+ pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
+ iDocid += iVal;
+ }
+ }else{
+ iPos += (iVal - 2);
+ cksum = cksum ^ fts3ChecksumEntry(
+ csr.zTerm, csr.nTerm, iLangid, iIndex, iDocid,
+ (int)iCol, (int)iPos
+ );
+ }
+ }
+ }
+ }
+ }
+ sqlite3Fts3SegReaderFinish(&csr);
+
+ *pRc = rc;
+ return cksum;
+}
+
+/*
+** Check if the contents of the FTS index match the current contents of the
+** content table. If no error occurs and the contents do match, set *pbOk
+** to true and return SQLITE_OK. Or if the contents do not match, set *pbOk
+** to false before returning.
+**
+** If an error occurs (e.g. an OOM or IO error), return an SQLite error
+** code. The final value of *pbOk is undefined in this case.
+*/
+static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
+ int rc = SQLITE_OK; /* Return code */
+ u64 cksum1 = 0; /* Checksum based on FTS index contents */
+ u64 cksum2 = 0; /* Checksum based on %_content contents */
+ sqlite3_stmt *pAllLangid = 0; /* Statement to return all language-ids */
+
+ /* This block calculates the checksum according to the FTS index. */
+ rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
+ if( rc==SQLITE_OK ){
+ int rc2;
+ sqlite3_bind_int(pAllLangid, 1, p->nIndex);
+ while( rc==SQLITE_OK && sqlite3_step(pAllLangid)==SQLITE_ROW ){
+ int iLangid = sqlite3_column_int(pAllLangid, 0);
+ int i;
+ for(i=0; i<p->nIndex; i++){
+ cksum1 = cksum1 ^ fts3ChecksumIndex(p, iLangid, i, &rc);
+ }
+ }
+ rc2 = sqlite3_reset(pAllLangid);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+
+ /* This block calculates the checksum according to the %_content table */
+ rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule;
+ sqlite3_stmt *pStmt = 0;
+ char *zSql;
+
+ zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist);
+ if( !zSql ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ }
+
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ i64 iDocid = sqlite3_column_int64(pStmt, 0);
+ int iLang = langidFromSelect(p, pStmt);
+ int iCol;
+
+ for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
+ const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1);
+ int nText = sqlite3_column_bytes(pStmt, iCol+1);
+ sqlite3_tokenizer_cursor *pT = 0;
+
+ rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText, &pT);
+ while( rc==SQLITE_OK ){
+ char const *zToken; /* Buffer containing token */
+ int nToken; /* Number of bytes in token */
+ int iDum1, iDum2; /* Dummy variables */
+ int iPos; /* Position of token in zText */
+
+ rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos);
+ if( rc==SQLITE_OK ){
+ int i;
+ cksum2 = cksum2 ^ fts3ChecksumEntry(
+ zToken, nToken, iLang, 0, iDocid, iCol, iPos
+ );
+ for(i=1; i<p->nIndex; i++){
+ if( p->aIndex[i].nPrefix<=nToken ){
+ cksum2 = cksum2 ^ fts3ChecksumEntry(
+ zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos
+ );
+ }
+ }
+ }
+ }
+ if( pT ) pModule->xClose(pT);
+ if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+ }
+ }
+
+ sqlite3_finalize(pStmt);
+ }
+
+ *pbOk = (cksum1==cksum2);
+ return rc;
+}
+
+/*
+** Run the integrity-check. If no error occurs and the current contents of
+** the FTS index are correct, return SQLITE_OK. Or, if the contents of the
+** FTS index are incorrect, return SQLITE_CORRUPT_VTAB.
+**
+** Or, if an error (e.g. an OOM or IO error) occurs, return an SQLite
+** error code.
+**
+** The integrity-check works as follows. For each token and indexed token
+** prefix in the document set, a 64-bit checksum is calculated (by code
+** in fts3ChecksumEntry()) based on the following:
+**
+** + The index number (0 for the main index, 1 for the first prefix
+** index etc.),
+** + The token (or token prefix) text itself,
+** + The language-id of the row it appears in,
+** + The docid of the row it appears in,
+** + The column it appears in, and
+** + The tokens position within that column.
+**
+** The checksums for all entries in the index are XORed together to create
+** a single checksum for the entire index.
+**
+** The integrity-check code calculates the same checksum in two ways:
+**
+** 1. By scanning the contents of the FTS index, and
+** 2. By scanning and tokenizing the content table.
+**
+** If the two checksums are identical, the integrity-check is deemed to have
+** passed.
+*/
+static int fts3DoIntegrityCheck(
+ Fts3Table *p /* FTS3 table handle */
+){
+ int rc;
+ int bOk = 0;
+ rc = fts3IntegrityCheck(p, &bOk);
+ if( rc==SQLITE_OK && bOk==0 ) rc = SQLITE_CORRUPT_VTAB;
+ return rc;
+}
+
/*
** Handle a 'special' INSERT of the form:
**
@@ -126035,6 +130772,12 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
rc = fts3DoOptimize(p, 0);
}else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){
rc = fts3DoRebuild(p);
+ }else if( nVal==15 && 0==sqlite3_strnicmp(zVal, "integrity-check", 15) ){
+ rc = fts3DoIntegrityCheck(p);
+ }else if( nVal>6 && 0==sqlite3_strnicmp(zVal, "merge=", 6) ){
+ rc = fts3DoIncrmerge(p, &zVal[6]);
+ }else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){
+ rc = fts3DoAutoincrmerge(p, &zVal[10]);
#ifdef SQLITE_TEST
}else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
p->nNodeSize = atoi(&zVal[9]);
@@ -126103,14 +130846,13 @@ SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1);
sqlite3_tokenizer_cursor *pTC = 0;
- rc = pModule->xOpen(pT, zText, -1, &pTC);
+ rc = sqlite3Fts3OpenTokenizer(pT, pCsr->iLangid, zText, -1, &pTC);
while( rc==SQLITE_OK ){
char const *zToken; /* Buffer containing token */
int nToken; /* Number of bytes in token */
int iDum1, iDum2; /* Dummy variables */
int iPos; /* Position of token in zText */
- pTC->pTokenizer = pT;
rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos);
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
Fts3PhraseToken *pPT = pDef->pToken;
@@ -126210,8 +130952,6 @@ static int fts3DeleteByRowid(
rc = fts3DeleteAll(p, 1);
*pnDoc = *pnDoc - 1;
}else{
- sqlite3_int64 iRemove = sqlite3_value_int64(pRowid);
- rc = fts3PendingTermsDocid(p, iRemove);
fts3DeleteTerms(&rc, p, pRowid, aSzDel);
if( p->zContentTbl==0 ){
fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
@@ -126230,7 +130970,16 @@ static int fts3DeleteByRowid(
/*
** This function does the work for the xUpdate method of FTS3 virtual
-** tables.
+** tables. The schema of the virtual table being:
+**
+** CREATE TABLE <table name>(
+** <user columns>,
+** <table name> HIDDEN,
+** docid HIDDEN,
+** <langid> HIDDEN
+** );
+**
+**
*/
SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
sqlite3_vtab *pVtab, /* FTS3 vtab object */
@@ -126247,6 +130996,10 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
int bInsertDone = 0;
assert( p->pSegments==0 );
+ assert(
+ nArg==1 /* DELETE operations */
+ || nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */
+ );
/* Check for a "special" INSERT operation. One of the form:
**
@@ -126260,6 +131013,11 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
goto update_out;
}
+ if( nArg>1 && sqlite3_value_int(apVal[2 + p->nColumn + 2])<0 ){
+ rc = SQLITE_CONSTRAINT;
+ goto update_out;
+ }
+
/* Allocate space to hold the change in document sizes */
aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 );
if( aSzIns==0 ){
@@ -126327,6 +131085,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
/* If this is an INSERT or UPDATE operation, insert the new record. */
if( nArg>1 && rc==SQLITE_OK ){
+ int iLangid = sqlite3_value_int(apVal[2 + p->nColumn + 2]);
if( bInsertDone==0 ){
rc = fts3InsertData(p, apVal, pRowid);
if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){
@@ -126334,11 +131093,11 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
}
}
if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){
- rc = fts3PendingTermsDocid(p, *pRowid);
+ rc = fts3PendingTermsDocid(p, iLangid, *pRowid);
}
if( rc==SQLITE_OK ){
assert( p->iPrevDocid==*pRowid );
- rc = fts3InsertTerms(p, apVal, aSzIns);
+ rc = fts3InsertTerms(p, iLangid, apVal, aSzIns);
}
if( p->bHasDocsize ){
fts3InsertDocsize(&rc, p, aSzIns);
@@ -126346,7 +131105,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
nChng++;
}
- if( p->bHasStat ){
+ if( p->bFts4 ){
fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng);
}
@@ -126743,10 +131502,11 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
SnippetIter *p = (SnippetIter *)ctx;
SnippetPhrase *pPhrase = &p->aPhrase[iPhrase];
char *pCsr;
+ int rc;
pPhrase->nToken = pExpr->pPhrase->nToken;
-
- pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol);
+ rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr);
+ assert( rc==SQLITE_OK || pCsr==0 );
if( pCsr ){
int iFirst = 0;
pPhrase->pList = pCsr;
@@ -126757,10 +131517,12 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
pPhrase->iHead = iFirst;
pPhrase->iTail = iFirst;
}else{
- assert( pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 );
+ assert( rc!=SQLITE_OK || (
+ pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0
+ ));
}
- return SQLITE_OK;
+ return rc;
}
/*
@@ -126915,6 +131677,7 @@ static int fts3StringAppend(
*/
static int fts3SnippetShift(
Fts3Table *pTab, /* FTS3 table snippet comes from */
+ int iLangid, /* Language id to use in tokenizing */
int nSnippet, /* Number of tokens desired for snippet */
const char *zDoc, /* Document text to extract snippet from */
int nDoc, /* Size of buffer zDoc in bytes */
@@ -126950,11 +131713,10 @@ static int fts3SnippetShift(
/* Open a cursor on zDoc/nDoc. Check if there are (nSnippet+nDesired)
** or more tokens in zDoc/nDoc.
*/
- rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
+ rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, iLangid, zDoc, nDoc, &pC);
if( rc!=SQLITE_OK ){
return rc;
}
- pC->pTokenizer = pTab->pTokenizer;
while( rc==SQLITE_OK && iCurrent<(nSnippet+nDesired) ){
const char *ZDUMMY; int DUMMY1, DUMMY2, DUMMY3;
rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent);
@@ -127014,11 +131776,10 @@ static int fts3SnippetText(
/* Open a token cursor on the document. */
pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule;
- rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
+ rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid, zDoc,nDoc,&pC);
if( rc!=SQLITE_OK ){
return rc;
}
- pC->pTokenizer = pTab->pTokenizer;
while( rc==SQLITE_OK ){
int iBegin; /* Offset in zDoc of start of token */
@@ -127040,7 +131801,9 @@ static int fts3SnippetText(
if( !isShiftDone ){
int n = nDoc - iBegin;
- rc = fts3SnippetShift(pTab, nSnippet, &zDoc[iBegin], n, &iPos, &hlmask);
+ rc = fts3SnippetShift(
+ pTab, pCsr->iLangid, nSnippet, &zDoc[iBegin], n, &iPos, &hlmask
+ );
isShiftDone = 1;
/* Now that the shift has been done, check if the initial "..." are
@@ -127152,13 +131915,14 @@ static int fts3ExprLocalHitsCb(
int iPhrase, /* Phrase number */
void *pCtx /* Pointer to MatchInfo structure */
){
+ int rc = SQLITE_OK;
MatchInfo *p = (MatchInfo *)pCtx;
int iStart = iPhrase * p->nCol * 3;
int i;
- for(i=0; i<p->nCol; i++){
+ for(i=0; i<p->nCol && rc==SQLITE_OK; i++){
char *pCsr;
- pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCursor, pExpr, i);
+ rc = sqlite3Fts3EvalPhrasePoslist(p->pCursor, pExpr, i, &pCsr);
if( pCsr ){
p->aMatchinfo[iStart+i*3] = fts3ColumnlistCount(&pCsr);
}else{
@@ -127166,7 +131930,7 @@ static int fts3ExprLocalHitsCb(
}
}
- return SQLITE_OK;
+ return rc;
}
static int fts3MatchinfoCheck(
@@ -127176,8 +131940,8 @@ static int fts3MatchinfoCheck(
){
if( (cArg==FTS3_MATCHINFO_NPHRASE)
|| (cArg==FTS3_MATCHINFO_NCOL)
- || (cArg==FTS3_MATCHINFO_NDOC && pTab->bHasStat)
- || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bHasStat)
+ || (cArg==FTS3_MATCHINFO_NDOC && pTab->bFts4)
+ || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bFts4)
|| (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize)
|| (cArg==FTS3_MATCHINFO_LCS)
|| (cArg==FTS3_MATCHINFO_HITS)
@@ -127327,8 +132091,10 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
int nLive = 0; /* Number of iterators in aIter not at EOF */
for(i=0; i<pInfo->nPhrase; i++){
+ int rc;
LcsIterator *pIt = &aIter[i];
- pIt->pRead = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol);
+ rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead);
+ if( rc!=SQLITE_OK ) return rc;
if( pIt->pRead ){
pIt->iPos = pIt->iPosOffset;
fts3LcsIteratorAdvance(&aIter[i]);
@@ -127680,9 +132446,10 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
int iTerm; /* For looping through nTerm phrase terms */
char *pList; /* Pointer to position list for phrase */
int iPos = 0; /* First position in position-list */
+ int rc;
UNUSED_PARAMETER(iPhrase);
- pList = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol);
+ rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pList);
nTerm = pExpr->pPhrase->nToken;
if( pList ){
fts3GetDeltaPosition(&pList, &iPos);
@@ -127696,7 +132463,7 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
pT->iPos = iPos;
}
- return SQLITE_OK;
+ return rc;
}
/*
@@ -127773,9 +132540,10 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
}
/* Initialize a tokenizer iterator to iterate through column iCol. */
- rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
+ rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid,
+ zDoc, nDoc, &pC
+ );
if( rc!=SQLITE_OK ) goto offsets_out;
- pC->pTokenizer = pTab->pTokenizer;
rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent);
while( rc==SQLITE_OK ){
@@ -128067,6 +132835,19 @@ struct Rtree {
#define RTREE_COORD_INT32 1
/*
+** If SQLITE_RTREE_INT_ONLY is defined, then this virtual table will
+** only deal with integer coordinates. No floating point operations
+** will be done.
+*/
+#ifdef SQLITE_RTREE_INT_ONLY
+ typedef sqlite3_int64 RtreeDValue; /* High accuracy coordinate */
+ typedef int RtreeValue; /* Low accuracy coordinate */
+#else
+ typedef double RtreeDValue; /* High accuracy coordinate */
+ typedef float RtreeValue; /* Low accuracy coordinate */
+#endif
+
+/*
** The minimum number of cells allowed for a node is a third of the
** maximum. In Gutman's notation:
**
@@ -128101,20 +132882,25 @@ struct RtreeCursor {
};
union RtreeCoord {
- float f;
+ RtreeValue f;
int i;
};
/*
** The argument is an RtreeCoord. Return the value stored within the RtreeCoord
-** formatted as a double. This macro assumes that local variable pRtree points
-** to the Rtree structure associated with the RtreeCoord.
+** formatted as a RtreeDValue (double or int64). This macro assumes that local
+** variable pRtree points to the Rtree structure associated with the
+** RtreeCoord.
*/
-#define DCOORD(coord) ( \
- (pRtree->eCoordType==RTREE_COORD_REAL32) ? \
- ((double)coord.f) : \
- ((double)coord.i) \
-)
+#ifdef SQLITE_RTREE_INT_ONLY
+# define DCOORD(coord) ((RtreeDValue)coord.i)
+#else
+# define DCOORD(coord) ( \
+ (pRtree->eCoordType==RTREE_COORD_REAL32) ? \
+ ((double)coord.f) : \
+ ((double)coord.i) \
+ )
+#endif
/*
** A search constraint.
@@ -128122,8 +132908,8 @@ union RtreeCoord {
struct RtreeConstraint {
int iCoord; /* Index of constrained coordinate */
int op; /* Constraining operation */
- double rValue; /* Constraint value. */
- int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
+ RtreeDValue rValue; /* Constraint value. */
+ int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);
sqlite3_rtree_geometry *pGeom; /* Constraint callback argument for a MATCH */
};
@@ -128171,10 +132957,10 @@ struct RtreeCell {
*/
struct RtreeMatchArg {
u32 magic; /* Always RTREE_GEOMETRY_MAGIC */
- int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
+ int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue*, int *);
void *pContext;
int nParam;
- double aParam[1];
+ RtreeDValue aParam[1];
};
/*
@@ -128186,7 +132972,7 @@ struct RtreeMatchArg {
** the geometry callback function).
*/
struct RtreeGeomCallback {
- int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
+ int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);
void *pContext;
};
@@ -128752,7 +133538,7 @@ static int testRtreeGeom(
int *pbRes /* OUT: Test result */
){
int i;
- double aCoord[RTREE_MAX_DIMENSIONS*2];
+ RtreeDValue aCoord[RTREE_MAX_DIMENSIONS*2];
int nCoord = pRtree->nDim*2;
assert( pConstraint->op==RTREE_MATCH );
@@ -128782,8 +133568,8 @@ static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){
RtreeConstraint *p = &pCursor->aConstraint[ii];
- double cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]);
- double cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);
+ RtreeDValue cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]);
+ RtreeDValue cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
@@ -128835,7 +133621,7 @@ static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
for(ii=0; ii<pCursor->nConstraint; ii++){
RtreeConstraint *p = &pCursor->aConstraint[ii];
- double coord = DCOORD(cell.aCoord[p->iCoord]);
+ RtreeDValue coord = DCOORD(cell.aCoord[p->iCoord]);
int res;
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
@@ -129033,9 +133819,12 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
}else{
RtreeCoord c;
nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c);
+#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
sqlite3_result_double(ctx, c.f);
- }else{
+ }else
+#endif
+ {
assert( pRtree->eCoordType==RTREE_COORD_INT32 );
sqlite3_result_int(ctx, c.i);
}
@@ -129077,12 +133866,12 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
int nBlob;
/* Check that value is actually a blob. */
- if( !sqlite3_value_type(pValue)==SQLITE_BLOB ) return SQLITE_ERROR;
+ if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR;
/* Check that the blob is roughly the right size. */
nBlob = sqlite3_value_bytes(pValue);
if( nBlob<(int)sizeof(RtreeMatchArg)
- || ((nBlob-sizeof(RtreeMatchArg))%sizeof(double))!=0
+ || ((nBlob-sizeof(RtreeMatchArg))%sizeof(RtreeDValue))!=0
){
return SQLITE_ERROR;
}
@@ -129096,7 +133885,7 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
memcpy(p, sqlite3_value_blob(pValue), nBlob);
if( p->magic!=RTREE_GEOMETRY_MAGIC
- || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(double))
+ || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(RtreeDValue))
){
sqlite3_free(pGeom);
return SQLITE_ERROR;
@@ -129168,7 +133957,11 @@ static int rtreeFilter(
break;
}
}else{
+#ifdef SQLITE_RTREE_INT_ONLY
+ p->rValue = sqlite3_value_int64(argv[ii]);
+#else
p->rValue = sqlite3_value_double(argv[ii]);
+#endif
}
}
}
@@ -129302,11 +134095,11 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
/*
** Return the N-dimensional volumn of the cell stored in *p.
*/
-static float cellArea(Rtree *pRtree, RtreeCell *p){
- float area = 1.0;
+static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
+ RtreeDValue area = (RtreeDValue)1;
int ii;
for(ii=0; ii<(pRtree->nDim*2); ii+=2){
- area = (float)(area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])));
+ area = (area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])));
}
return area;
}
@@ -129315,11 +134108,11 @@ static float cellArea(Rtree *pRtree, RtreeCell *p){
** Return the margin length of cell p. The margin length is the sum
** of the objects size in each dimension.
*/
-static float cellMargin(Rtree *pRtree, RtreeCell *p){
- float margin = 0.0;
+static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
+ RtreeDValue margin = (RtreeDValue)0;
int ii;
for(ii=0; ii<(pRtree->nDim*2); ii+=2){
- margin += (float)(DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
+ margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
}
return margin;
}
@@ -129364,8 +134157,8 @@ static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
/*
** Return the amount cell p would grow by if it were unioned with pCell.
*/
-static float cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
- float area;
+static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
+ RtreeDValue area;
RtreeCell cell;
memcpy(&cell, p, sizeof(RtreeCell));
area = cellArea(pRtree, &cell);
@@ -129374,7 +134167,7 @@ static float cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
}
#if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLIT
-static float cellOverlap(
+static RtreeDValue cellOverlap(
Rtree *pRtree,
RtreeCell *p,
RtreeCell *aCell,
@@ -129382,7 +134175,7 @@ static float cellOverlap(
int iExclude
){
int ii;
- float overlap = 0.0;
+ RtreeDValue overlap = 0.0;
for(ii=0; ii<nCell; ii++){
#if VARIANT_RSTARTREE_CHOOSESUBTREE
if( ii!=iExclude )
@@ -129392,10 +134185,9 @@ static float cellOverlap(
#endif
{
int jj;
- float o = 1.0;
+ RtreeDValue o = (RtreeDValue)1;
for(jj=0; jj<(pRtree->nDim*2); jj+=2){
- double x1;
- double x2;
+ RtreeDValue x1, x2;
x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj]));
x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1]));
@@ -129404,7 +134196,7 @@ static float cellOverlap(
o = 0.0;
break;
}else{
- o = o * (float)(x2-x1);
+ o = o * (x2-x1);
}
}
overlap += o;
@@ -129415,7 +134207,7 @@ static float cellOverlap(
#endif
#if VARIANT_RSTARTREE_CHOOSESUBTREE
-static float cellOverlapEnlargement(
+static RtreeDValue cellOverlapEnlargement(
Rtree *pRtree,
RtreeCell *p,
RtreeCell *pInsert,
@@ -129423,12 +134215,11 @@ static float cellOverlapEnlargement(
int nCell,
int iExclude
){
- double before;
- double after;
+ RtreeDValue before, after;
before = cellOverlap(pRtree, p, aCell, nCell, iExclude);
cellUnion(pRtree, p, pInsert);
after = cellOverlap(pRtree, p, aCell, nCell, iExclude);
- return (float)(after-before);
+ return (after-before);
}
#endif
@@ -129452,11 +134243,11 @@ static int ChooseLeaf(
int iCell;
sqlite3_int64 iBest = 0;
- float fMinGrowth = 0.0;
- float fMinArea = 0.0;
+ RtreeDValue fMinGrowth = 0.0;
+ RtreeDValue fMinArea = 0.0;
#if VARIANT_RSTARTREE_CHOOSESUBTREE
- float fMinOverlap = 0.0;
- float overlap;
+ RtreeDValue fMinOverlap = 0.0;
+ RtreeDValue overlap;
#endif
int nCell = NCELL(pNode);
@@ -129487,8 +134278,8 @@ static int ChooseLeaf(
*/
for(iCell=0; iCell<nCell; iCell++){
int bBest = 0;
- float growth;
- float area;
+ RtreeDValue growth;
+ RtreeDValue area;
nodeGetCell(pRtree, pNode, iCell, &cell);
growth = cellGrowth(pRtree, &cell, pCell);
area = cellArea(pRtree, &cell);
@@ -129615,7 +134406,7 @@ static void LinearPickSeeds(
int i;
int iLeftSeed = 0;
int iRightSeed = 1;
- float maxNormalInnerWidth = 0.0;
+ RtreeDValue maxNormalInnerWidth = (RtreeDValue)0;
/* Pick two "seed" cells from the array of cells. The algorithm used
** here is the LinearPickSeeds algorithm from Gutman[1984]. The
@@ -129623,18 +134414,18 @@ static void LinearPickSeeds(
** variables iLeftSeek and iRightSeed.
*/
for(i=0; i<pRtree->nDim; i++){
- float x1 = DCOORD(aCell[0].aCoord[i*2]);
- float x2 = DCOORD(aCell[0].aCoord[i*2+1]);
- float x3 = x1;
- float x4 = x2;
+ RtreeDValue x1 = DCOORD(aCell[0].aCoord[i*2]);
+ RtreeDValue x2 = DCOORD(aCell[0].aCoord[i*2+1]);
+ RtreeDValue x3 = x1;
+ RtreeDValue x4 = x2;
int jj;
int iCellLeft = 0;
int iCellRight = 0;
for(jj=1; jj<nCell; jj++){
- float left = DCOORD(aCell[jj].aCoord[i*2]);
- float right = DCOORD(aCell[jj].aCoord[i*2+1]);
+ RtreeDValue left = DCOORD(aCell[jj].aCoord[i*2]);
+ RtreeDValue right = DCOORD(aCell[jj].aCoord[i*2+1]);
if( left<x1 ) x1 = left;
if( right>x4 ) x4 = right;
@@ -129649,7 +134440,7 @@ static void LinearPickSeeds(
}
if( x4!=x1 ){
- float normalwidth = (x3 - x2) / (x4 - x1);
+ RtreeDValue normalwidth = (x3 - x2) / (x4 - x1);
if( normalwidth>maxNormalInnerWidth ){
iLeftSeed = iCellLeft;
iRightSeed = iCellRight;
@@ -129678,13 +134469,13 @@ static RtreeCell *QuadraticPickNext(
#define FABS(a) ((a)<0.0?-1.0*(a):(a))
int iSelect = -1;
- float fDiff;
+ RtreeDValue fDiff;
int ii;
for(ii=0; ii<nCell; ii++){
if( aiUsed[ii]==0 ){
- float left = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
- float right = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
- float diff = FABS(right-left);
+ RtreeDValue left = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
+ RtreeDValue right = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
+ RtreeDValue diff = FABS(right-left);
if( iSelect<0 || diff>fDiff ){
fDiff = diff;
iSelect = ii;
@@ -129711,13 +134502,13 @@ static void QuadraticPickSeeds(
int iLeftSeed = 0;
int iRightSeed = 1;
- float fWaste = 0.0;
+ RtreeDValue fWaste = 0.0;
for(ii=0; ii<nCell; ii++){
for(jj=ii+1; jj<nCell; jj++){
- float right = cellArea(pRtree, &aCell[jj]);
- float growth = cellGrowth(pRtree, &aCell[ii], &aCell[jj]);
- float waste = growth - right;
+ RtreeDValue right = cellArea(pRtree, &aCell[jj]);
+ RtreeDValue growth = cellGrowth(pRtree, &aCell[ii], &aCell[jj]);
+ RtreeDValue waste = growth - right;
if( waste>fWaste ){
iLeftSeed = ii;
@@ -129752,7 +134543,7 @@ static void QuadraticPickSeeds(
static void SortByDistance(
int *aIdx,
int nIdx,
- float *aDistance,
+ RtreeDValue *aDistance,
int *aSpare
){
if( nIdx>1 ){
@@ -129778,8 +134569,8 @@ static void SortByDistance(
aIdx[iLeft+iRight] = aLeft[iLeft];
iLeft++;
}else{
- float fLeft = aDistance[aLeft[iLeft]];
- float fRight = aDistance[aRight[iRight]];
+ RtreeDValue fLeft = aDistance[aLeft[iLeft]];
+ RtreeDValue fRight = aDistance[aRight[iRight]];
if( fLeft<fRight ){
aIdx[iLeft+iRight] = aLeft[iLeft];
iLeft++;
@@ -129795,8 +134586,8 @@ static void SortByDistance(
{
int jj;
for(jj=1; jj<nIdx; jj++){
- float left = aDistance[aIdx[jj-1]];
- float right = aDistance[aIdx[jj]];
+ RtreeDValue left = aDistance[aIdx[jj-1]];
+ RtreeDValue right = aDistance[aIdx[jj]];
assert( left<=right );
}
}
@@ -129839,10 +134630,10 @@ static void SortByDimension(
memcpy(aSpare, aLeft, sizeof(int)*nLeft);
aLeft = aSpare;
while( iLeft<nLeft || iRight<nRight ){
- double xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]);
- double xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]);
- double xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]);
- double xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]);
+ RtreeDValue xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]);
+ RtreeDValue xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]);
+ RtreeDValue xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]);
+ RtreeDValue xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]);
if( (iLeft!=nLeft) && ((iRight==nRight)
|| (xleft1<xright1)
|| (xleft1==xright1 && xleft2<xright2)
@@ -129860,10 +134651,10 @@ static void SortByDimension(
{
int jj;
for(jj=1; jj<nIdx; jj++){
- float xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2];
- float xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1];
- float xright1 = aCell[aIdx[jj]].aCoord[iDim*2];
- float xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1];
+ RtreeDValue xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2];
+ RtreeDValue xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1];
+ RtreeDValue xright1 = aCell[aIdx[jj]].aCoord[iDim*2];
+ RtreeDValue xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1];
assert( xleft1<=xright1 && (xleft1<xright1 || xleft2<=xright2) );
}
}
@@ -129890,7 +134681,7 @@ static int splitNodeStartree(
int iBestDim = 0;
int iBestSplit = 0;
- float fBestMargin = 0.0;
+ RtreeDValue fBestMargin = 0.0;
int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
@@ -129911,9 +134702,9 @@ static int splitNodeStartree(
}
for(ii=0; ii<pRtree->nDim; ii++){
- float margin = 0.0;
- float fBestOverlap = 0.0;
- float fBestArea = 0.0;
+ RtreeDValue margin = 0.0;
+ RtreeDValue fBestOverlap = 0.0;
+ RtreeDValue fBestArea = 0.0;
int iBestLeft = 0;
int nLeft;
@@ -129925,8 +134716,8 @@ static int splitNodeStartree(
RtreeCell left;
RtreeCell right;
int kk;
- float overlap;
- float area;
+ RtreeDValue overlap;
+ RtreeDValue area;
memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell));
memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell));
@@ -130009,7 +134800,7 @@ static int splitNodeGuttman(
for(i=nCell-2; i>0; i--){
RtreeCell *pNext;
pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed);
- float diff =
+ RtreeDValue diff =
cellGrowth(pRtree, pBboxLeft, pNext) -
cellGrowth(pRtree, pBboxRight, pNext)
;
@@ -130342,32 +135133,34 @@ static int Reinsert(
int *aOrder;
int *aSpare;
RtreeCell *aCell;
- float *aDistance;
+ RtreeDValue *aDistance;
int nCell;
- float aCenterCoord[RTREE_MAX_DIMENSIONS];
+ RtreeDValue aCenterCoord[RTREE_MAX_DIMENSIONS];
int iDim;
int ii;
int rc = SQLITE_OK;
+ int n;
- memset(aCenterCoord, 0, sizeof(float)*RTREE_MAX_DIMENSIONS);
+ memset(aCenterCoord, 0, sizeof(RtreeDValue)*RTREE_MAX_DIMENSIONS);
nCell = NCELL(pNode)+1;
+ n = (nCell+1)&(~1);
/* Allocate the buffers used by this operation. The allocation is
** relinquished before this function returns.
*/
- aCell = (RtreeCell *)sqlite3_malloc(nCell * (
- sizeof(RtreeCell) + /* aCell array */
- sizeof(int) + /* aOrder array */
- sizeof(int) + /* aSpare array */
- sizeof(float) /* aDistance array */
+ aCell = (RtreeCell *)sqlite3_malloc(n * (
+ sizeof(RtreeCell) + /* aCell array */
+ sizeof(int) + /* aOrder array */
+ sizeof(int) + /* aSpare array */
+ sizeof(RtreeDValue) /* aDistance array */
));
if( !aCell ){
return SQLITE_NOMEM;
}
- aOrder = (int *)&aCell[nCell];
- aSpare = (int *)&aOrder[nCell];
- aDistance = (float *)&aSpare[nCell];
+ aOrder = (int *)&aCell[n];
+ aSpare = (int *)&aOrder[n];
+ aDistance = (RtreeDValue *)&aSpare[n];
for(ii=0; ii<nCell; ii++){
if( ii==(nCell-1) ){
@@ -130377,19 +135170,19 @@ static int Reinsert(
}
aOrder[ii] = ii;
for(iDim=0; iDim<pRtree->nDim; iDim++){
- aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2]);
- aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2+1]);
+ aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]);
+ aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]);
}
}
for(iDim=0; iDim<pRtree->nDim; iDim++){
- aCenterCoord[iDim] = (float)(aCenterCoord[iDim]/((float)nCell*2.0));
+ aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2));
}
for(ii=0; ii<nCell; ii++){
aDistance[ii] = 0.0;
for(iDim=0; iDim<pRtree->nDim; iDim++){
- float coord = (float)(DCOORD(aCell[ii].aCoord[iDim*2+1]) -
- DCOORD(aCell[ii].aCoord[iDim*2]));
+ RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) -
+ DCOORD(aCell[ii].aCoord[iDim*2]));
aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
}
}
@@ -130631,16 +135424,19 @@ static int rtreeUpdate(
/* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */
assert( nData==(pRtree->nDim*2 + 3) );
+#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
for(ii=0; ii<(pRtree->nDim*2); ii+=2){
- cell.aCoord[ii].f = (float)sqlite3_value_double(azData[ii+3]);
- cell.aCoord[ii+1].f = (float)sqlite3_value_double(azData[ii+4]);
+ cell.aCoord[ii].f = (RtreeValue)sqlite3_value_double(azData[ii+3]);
+ cell.aCoord[ii+1].f = (RtreeValue)sqlite3_value_double(azData[ii+4]);
if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
rc = SQLITE_CONSTRAINT;
goto constraint;
}
}
- }else{
+ }else
+#endif
+ {
for(ii=0; ii<(pRtree->nDim*2); ii+=2){
cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]);
@@ -130940,8 +135736,8 @@ static int rtreeInit(
sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
/* Allocate the sqlite3_vtab structure */
- nDb = strlen(argv[1]);
- nName = strlen(argv[2]);
+ nDb = (int)strlen(argv[1]);
+ nName = (int)strlen(argv[2]);
pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2);
if( !pRtree ){
return SQLITE_NOMEM;
@@ -131036,10 +135832,16 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
nodeGetCell(&tree, &node, ii, &cell);
sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
- nCell = strlen(zCell);
+ nCell = (int)strlen(zCell);
for(jj=0; jj<tree.nDim*2; jj++){
- sqlite3_snprintf(512-nCell,&zCell[nCell]," %f",(double)cell.aCoord[jj].f);
- nCell = strlen(zCell);
+#ifndef SQLITE_RTREE_INT_ONLY
+ sqlite3_snprintf(512-nCell,&zCell[nCell], " %f",
+ (double)cell.aCoord[jj].f);
+#else
+ sqlite3_snprintf(512-nCell,&zCell[nCell], " %d",
+ cell.aCoord[jj].i);
+#endif
+ nCell = (int)strlen(zCell);
}
if( zText ){
@@ -131080,7 +135882,11 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
}
if( rc==SQLITE_OK ){
+#ifdef SQLITE_RTREE_INT_ONLY
+ void *c = (void *)RTREE_COORD_INT32;
+#else
void *c = (void *)RTREE_COORD_REAL32;
+#endif
rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0);
}
if( rc==SQLITE_OK ){
@@ -131114,7 +135920,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
RtreeMatchArg *pBlob;
int nBlob;
- nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(double);
+ nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue);
pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob);
if( !pBlob ){
sqlite3_result_error_nomem(ctx);
@@ -131125,7 +135931,11 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
pBlob->pContext = pGeomCtx->pContext;
pBlob->nParam = nArg;
for(i=0; i<nArg; i++){
+#ifdef SQLITE_RTREE_INT_ONLY
+ pBlob->aParam[i] = sqlite3_value_int64(aArg[i]);
+#else
pBlob->aParam[i] = sqlite3_value_double(aArg[i]);
+#endif
}
sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free);
}
@@ -131137,7 +135947,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
SQLITE_API int sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
- int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *),
+ int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue *, int *),
void *pContext
){
RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */
@@ -131782,7 +136592,10 @@ static int icuOpen(
*ppCursor = 0;
- if( nInput<0 ){
+ if( zInput==0 ){
+ nInput = 0;
+ zInput = "";
+ }else if( nInput<0 ){
nInput = strlen(zInput);
}
nChar = nInput+1;
diff --git a/libgda/sqlite/sqlite-src/sqlite3.h b/libgda/sqlite/sqlite-src/sqlite3.h
index efaf3c8..a198489 100644
--- a/libgda/sqlite/sqlite-src/sqlite3.h
+++ b/libgda/sqlite/sqlite-src/sqlite3.h
@@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.7.9"
-#define SQLITE_VERSION_NUMBER 3007009
-#define SQLITE_SOURCE_ID "2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e"
+#define SQLITE_VERSION "3.7.12.1"
+#define SQLITE_VERSION_NUMBER 3007012
+#define SQLITE_SOURCE_ID "2012-05-22 02:45:53 6d326d44fd1d626aae0e8456e5fa2049f1ce0789"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -177,7 +177,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
** CAPI3REF: Test To See If The Library Is Threadsafe
**
** ^The sqlite3_threadsafe() function returns zero if and only if
-** SQLite was compiled mutexing code omitted due to the
+** SQLite was compiled with mutexing code omitted due to the
** [SQLITE_THREADSAFE] compile-time option being set to 0.
**
** SQLite can be compiled with or without mutexes. When
@@ -371,7 +371,7 @@ SQLITE_API int sqlite3_exec(
** KEYWORDS: {result code} {result codes}
**
** Many SQLite functions return an integer result code from the set shown
-** here in order to indicates success or failure.
+** here in order to indicate success or failure.
**
** New error codes may be added in future versions of SQLite.
**
@@ -458,9 +458,11 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
+#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
+#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -509,7 +511,11 @@ SQLITE_API int sqlite3_exec(
** first then the size of the file is extended, never the other
** way around. The SQLITE_IOCAP_SEQUENTIAL property means that
** information is written to disk in the same order as calls
-** to xWrite().
+** to xWrite(). The SQLITE_IOCAP_POWERSAFE_OVERWRITE property means that
+** after reboot following a crash or power loss, the only bytes in a
+** file that were written at the application level might have changed
+** and that adjacent bytes, even bytes within the same sector are
+** guaranteed to be unchanged.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -523,6 +529,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
+#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
/*
** CAPI3REF: File Locking Levels
@@ -711,7 +718,8 @@ struct sqlite3_io_methods {
** into an integer that the pArg argument points to. This capability
** is used during testing and only needs to be supported when SQLITE_TEST
** is defined.
-**
+** <ul>
+** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
** layer a hint of how large the database file will grow to be during the
** current transaction. This hint is not guaranteed to be accurate but it
@@ -719,6 +727,7 @@ struct sqlite3_io_methods {
** file space based on this hint in order to help writes to the database
** file run faster.
**
+** <li>[[SQLITE_FCNTL_CHUNK_SIZE]]
** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
** extends and truncates the database file in chunks of a size specified
** by the user. The fourth argument to [sqlite3_file_control()] should
@@ -727,11 +736,13 @@ struct sqlite3_io_methods {
** chunks (say 1MB at a time), may reduce file-system fragmentation and
** improve performance on some systems.
**
+** <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 the [sqlite3_file_control()] documentation for
** additional information.
**
+** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by
** SQLite and sent to all VFSes in place of a call to the xSync method
** when the database connection has [PRAGMA synchronous] set to OFF.)^
@@ -742,14 +753,15 @@ struct sqlite3_io_methods {
** opcode as doing so may disrupt the operation of the specialized VFSes
** that do require it.
**
+** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]]
** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
** retry counts and intervals for certain disk I/O operations for the
-** windows [VFS] in order to work to provide robustness against
+** windows [VFS] in order to provide robustness in the presence of
** anti-virus programs. By default, the windows VFS will retry file read,
** file write, and file delete operations up to 10 times, with a delay
** of 25 milliseconds before the first retry and with the delay increasing
** by an additional 25 milliseconds with each subsequent retry. This
-** opcode allows those to values (10 retries and 25 milliseconds of delay)
+** opcode allows these two values (10 retries and 25 milliseconds of delay)
** to be adjusted. The values are changed for all database connections
** within the same process. The argument is a pointer to an array of two
** integers where the first integer i the new retry count and the second
@@ -758,8 +770,9 @@ struct sqlite3_io_methods {
** into the array entry, allowing the current retry settings to be
** interrogated. The zDbName parameter is ignored.
**
+** <li>[[SQLITE_FCNTL_PERSIST_WAL]]
** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the
-** persistent [WAL | Write AHead Log] setting. By default, the auxiliary
+** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary
** write ahead log and shared memory files used for transaction control
** are automatically deleted when the latest connection to the database
** closes. Setting persistent WAL mode causes those files to persist after
@@ -772,22 +785,72 @@ struct sqlite3_io_methods {
** WAL mode. If the integer is -1, then it is overwritten with the current
** WAL persistence setting.
**
+** <li>[[SQLITE_FCNTL_POWERSAFE_OVERWRITE]]
+** ^The [SQLITE_FCNTL_POWERSAFE_OVERWRITE] opcode is used to set or query the
+** persistent "powersafe-overwrite" or "PSOW" setting. The PSOW setting
+** determines the [SQLITE_IOCAP_POWERSAFE_OVERWRITE] bit of the
+** xDeviceCharacteristics methods. The fourth parameter to
+** [sqlite3_file_control()] for this opcode should be a pointer to an integer.
+** That integer is 0 to disable zero-damage mode or 1 to enable zero-damage
+** mode. If the integer is -1, then it is overwritten with the current
+** zero-damage mode setting.
+**
+** <li>[[SQLITE_FCNTL_OVERWRITE]]
** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening
** a write transaction to indicate that, unless it is rolled back for some
** reason, the entire database file will be overwritten by the current
** transaction. This is used by VACUUM operations.
+**
+** <li>[[SQLITE_FCNTL_VFSNAME]]
+** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of
+** all [VFSes] in the VFS stack. The names are of all VFS shims and the
+** final bottom-level VFS are written into memory obtained from
+** [sqlite3_malloc()] and the result is stored in the char* variable
+** that the fourth parameter of [sqlite3_file_control()] points to.
+** The caller is responsible for freeing the memory when done. As with
+** all file-control actions, there is no guarantee that this will actually
+** do anything. Callers should initialize the char* variable to a NULL
+** pointer in case this file-control is not implemented. This file-control
+** is intended for diagnostic use 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
+** to the database file to which the pragma statement refers. ^The argument
+** to the [SQLITE_FCNTL_PRAGMA] file control is an array of
+** pointers to strings (char**) in which the second element of the array
+** is the name of the pragma and the third element is the argument to the
+** pragma or NULL if the pragma has no argument. ^The handler for an
+** [SQLITE_FCNTL_PRAGMA] file control can optionally make the first element
+** of the char** argument point to a string obtained from [sqlite3_mprintf()]
+** or the equivalent and that string will become the result of the pragma or
+** the error message if the pragma fails. ^If the
+** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal
+** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA]
+** file control returns [SQLITE_OK], then the parser assumes that the
+** VFS has handled the PRAGMA itself and the parser generates a no-op
+** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns
+** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means
+** that the VFS encountered an error while handling the [PRAGMA] and the
+** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
+** file control occurs at the beginning of pragma statement analysis and so
+** it is able to override built-in [PRAGMA] statements.
+** </ul>
*/
-#define SQLITE_FCNTL_LOCKSTATE 1
-#define SQLITE_GET_LOCKPROXYFILE 2
-#define SQLITE_SET_LOCKPROXYFILE 3
-#define SQLITE_LAST_ERRNO 4
-#define SQLITE_FCNTL_SIZE_HINT 5
-#define SQLITE_FCNTL_CHUNK_SIZE 6
-#define SQLITE_FCNTL_FILE_POINTER 7
-#define SQLITE_FCNTL_SYNC_OMITTED 8
-#define SQLITE_FCNTL_WIN32_AV_RETRY 9
-#define SQLITE_FCNTL_PERSIST_WAL 10
-#define SQLITE_FCNTL_OVERWRITE 11
+#define SQLITE_FCNTL_LOCKSTATE 1
+#define SQLITE_GET_LOCKPROXYFILE 2
+#define SQLITE_SET_LOCKPROXYFILE 3
+#define SQLITE_LAST_ERRNO 4
+#define SQLITE_FCNTL_SIZE_HINT 5
+#define SQLITE_FCNTL_CHUNK_SIZE 6
+#define SQLITE_FCNTL_FILE_POINTER 7
+#define SQLITE_FCNTL_SYNC_OMITTED 8
+#define SQLITE_FCNTL_WIN32_AV_RETRY 9
+#define SQLITE_FCNTL_PERSIST_WAL 10
+#define SQLITE_FCNTL_OVERWRITE 11
+#define SQLITE_FCNTL_VFSNAME 12
+#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13
+#define SQLITE_FCNTL_PRAGMA 14
/*
** CAPI3REF: Mutex Handle
@@ -842,7 +905,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** from xFullPathname() with an optional suffix added.
** ^If a suffix is added to the zFilename parameter, it will
** consist of a single "-" character followed by no more than
-** 10 alphanumeric and/or "-" characters.
+** 11 alphanumeric and/or "-" characters.
** ^SQLite further guarantees that
** the string will be valid and unchanged until xClose() is
** called. Because of the previous sentence,
@@ -1373,7 +1436,7 @@ struct sqlite3_mem_methods {
** <dd> ^This option specifies a static memory buffer that SQLite can use for
** the database page cache with the default page cache implementation.
** This configuration should not be used if an application-define page
-** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
+** cache implementation is loaded using the SQLITE_CONFIG_PCACHE2 option.
** There are three arguments to this option: A pointer to 8-byte aligned
** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument should be the size of the largest database page
@@ -1442,15 +1505,15 @@ struct sqlite3_mem_methods {
** verb to [sqlite3_db_config()] can be used to change the lookaside
** configuration on individual connections.)^ </dd>
**
-** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt>
+** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
** <dd> ^(This option takes a single argument which is a pointer to
-** an [sqlite3_pcache_methods] object. This object specifies the interface
+** an [sqlite3_pcache_methods2] object. This object specifies the interface
** to a custom page cache implementation.)^ ^SQLite makes a copy of the
** object and uses it for page cache memory allocations.</dd>
**
-** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt>
+** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt>
** <dd> ^(This option takes a single argument which is a pointer to an
-** [sqlite3_pcache_methods] object. SQLite copies of the current
+** [sqlite3_pcache_methods2] object. SQLite copies of the current
** page cache implementation into that object.)^ </dd>
**
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
@@ -1483,6 +1546,11 @@ struct sqlite3_mem_methods {
** database connection is opened. By default, URI handling is globally
** disabled. The default value may be changed by compiling with the
** [SQLITE_USE_URI] symbol defined.
+**
+** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]]
+** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
+** <dd> These options are obsolete and should not be used by new code.
+** They are retained for backwards compatibility but are now no-ops.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1498,10 +1566,12 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */
-#define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */
+#define SQLITE_CONFIG_PCACHE 14 /* no-op */
+#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
#define SQLITE_CONFIG_URI 17 /* int */
+#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -1986,7 +2056,7 @@ SQLITE_API void sqlite3_free_table(char **result);
** All of the usual printf() formatting options apply. In addition, there
** is are "%q", "%Q", and "%z" options.
**
-** ^(The %q option works like %s in that it substitutes a null-terminated
+** ^(The %q option works like %s in that it substitutes a nul-terminated
** string from the argument list. But %q also doubles every '\'' character.
** %q is designed for use inside a string literal.)^ By doubling each '\''
** character it escapes that character and allows it to be inserted into
@@ -2594,21 +2664,45 @@ SQLITE_API int sqlite3_open_v2(
/*
** CAPI3REF: Obtain Values For URI Parameters
**
-** This is a utility routine, useful to VFS implementations, that checks
+** These are utility routines, useful to VFS implementations, that check
** to see if a database file was a URI that contained a specific query
-** parameter, and if so obtains the value of the query parameter.
-**
-** The zFilename argument is the filename pointer passed into the xOpen()
-** method of a VFS implementation. The zParam argument is the name of the
-** query parameter we seek. This routine returns the value of the zParam
-** parameter if it exists. If the parameter does not exist, this routine
-** returns a NULL pointer.
-**
-** If the zFilename argument to this function is not a pointer that SQLite
-** passed into the xOpen VFS method, then the behavior of this routine
-** is undefined and probably undesirable.
+** parameter, and if so obtains the value of that query parameter.
+**
+** If F is the database filename pointer passed into the xOpen() method of
+** a VFS implementation when the flags parameter to xOpen() has one or
+** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and
+** P is the name of the query parameter, then
+** sqlite3_uri_parameter(F,P) returns the value of the P
+** parameter if it exists or a NULL pointer if P does not appear as a
+** query parameter on F. If P is a query parameter of F
+** has no explicit value, then sqlite3_uri_parameter(F,P) returns
+** a pointer to an empty string.
+**
+** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean
+** parameter and returns true (1) or false (0) according to the value
+** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the
+** value of query parameter P is one of "yes", "true", or "on" in any
+** case or if the value begins with a non-zero number. The
+** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of
+** query parameter P is one of "no", "false", or "off" in any case or
+** if the value begins with a numeric zero. If P is not a query
+** parameter on F or if the value of P is does not match any of the
+** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0).
+**
+** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a
+** 64-bit signed integer and returns that integer, or D if P does not
+** exist. If the value of P is something other than an integer, then
+** zero is returned.
+**
+** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
+** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and
+** is not a database file pathname pointer that SQLite passed into the xOpen
+** VFS method, then the behavior of this routine is undefined and probably
+** undesirable.
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
+SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
/*
@@ -2931,6 +3025,25 @@ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Determine If A Prepared Statement Has Been Reset
+**
+** ^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 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]
+** object, then the behavior is undefined and probably undesirable.
+**
+** This interface can be used in combination [sqlite3_next_stmt()]
+** to locate all prepared statements associated with a database
+** connection that are in need of being reset. This can be used,
+** for example, in diagnostic routines to search for prepared
+** statements that are holding a transaction open.
+*/
+SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
+
+/*
** CAPI3REF: Dynamically Typed Value Object
** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value}
**
@@ -3471,7 +3584,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** bytes in the string, not the number of characters.
**
** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(),
-** even empty strings, are always zero terminated. ^The return
+** even empty strings, are always zero-terminated. ^The return
** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
**
** ^The object returned by [sqlite3_column_value()] is an
@@ -4372,6 +4485,31 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3*);
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
/*
+** CAPI3REF: Return The Filename For A Database Connection
+**
+** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
+** associated with database N of connection D. ^The main database file
+** has the name "main". If there is no attached database N on the database
+** connection D, or if database N is a temporary or in-memory database, then
+** a NULL pointer is returned.
+**
+** ^The filename returned by this function is the output of the
+** xFullPathname method of the [VFS]. ^In other words, the filename
+** will be an absolute pathname, even if the filename used
+** to open the database originally was a URI or relative pathname.
+*/
+SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+
+/*
+** CAPI3REF: Determine if a database is read-only
+**
+** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N
+** of connection D is read-only, 0 if it is read/write, or -1 if N is not
+** the name of a database on connection D.
+*/
+SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
+
+/*
** CAPI3REF: Find the next prepared statement
**
** ^This interface returns a pointer to the next [prepared statement] after
@@ -4406,13 +4544,15 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
** on the same [database connection] D, or NULL for
** the first call for each function on D.
**
+** The commit and rollback hook callbacks are not reentrant.
** The callback implementation must not do anything that will modify
** the database connection that invoked the callback. Any actions
** to modify the database connection must be deferred until after the
** completion of the [sqlite3_step()] call that triggered the commit
** or rollback hook in the first place.
-** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
-** database connections for the meaning of "modify" in this paragraph.
+** Note that running any other SQL statements, including SELECT statements,
+** or merely calling [sqlite3_prepare_v2()] and [sqlite3_step()] will modify
+** the database connections for the meaning of "modify" in this paragraph.
**
** ^Registering a NULL function disables the callback.
**
@@ -4525,10 +4665,25 @@ SQLITE_API int sqlite3_enable_shared_cache(int);
** which might be more or less than the amount requested.
** ^The sqlite3_release_memory() routine is a no-op returning zero
** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT].
+**
+** See also: [sqlite3_db_release_memory()]
*/
SQLITE_API int sqlite3_release_memory(int);
/*
+** CAPI3REF: Free Memory Used By A Database Connection
+**
+** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap
+** memory as possible from database connection D. Unlike the
+** [sqlite3_release_memory()] interface, this interface is effect even
+** when then [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is
+** omitted.
+**
+** See also: [sqlite3_release_memory()]
+*/
+SQLITE_API int sqlite3_db_release_memory(sqlite3*);
+
+/*
** CAPI3REF: Impose A Limit On Heap Size
**
** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
@@ -4542,7 +4697,8 @@ SQLITE_API int sqlite3_release_memory(int);
** is advisory only.
**
** ^The return value from sqlite3_soft_heap_limit64() is the size of
-** the soft heap limit prior to the call. ^If the argument N is negative
+** the soft heap limit prior to the call, or negative in the case of an
+** error. ^If the argument N is negative
** then no change is made to the soft heap limit. Hence, the current
** size of the soft heap limit can be determined by invoking
** sqlite3_soft_heap_limit64() with a negative argument.
@@ -4558,7 +4714,7 @@ SQLITE_API int sqlite3_release_memory(int);
** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and
** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option.
** <li> An alternative page cache implementation is specified using
-** [sqlite3_config]([SQLITE_CONFIG_PCACHE],...).
+** [sqlite3_config]([SQLITE_CONFIG_PCACHE2],...).
** <li> The page cache allocates from its own memory pool supplied
** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than
** from the heap.
@@ -5300,7 +5456,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** <ul>
** <li> SQLITE_MUTEX_OS2
-** <li> SQLITE_MUTEX_PTHREAD
+** <li> SQLITE_MUTEX_PTHREADS
** <li> SQLITE_MUTEX_W32
** <li> SQLITE_MUTEX_NOOP
** </ul>)^
@@ -5308,7 +5464,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** ^The SQLITE_MUTEX_NOOP implementation is a set of routines
** that does no real locking and is appropriate for use in
** a single-threaded application. ^The SQLITE_MUTEX_OS2,
-** SQLITE_MUTEX_PTHREAD, and SQLITE_MUTEX_W32 implementations
+** SQLITE_MUTEX_PTHREADS, and SQLITE_MUTEX_W32 implementations
** are appropriate for use on OS/2, Unix, and Windows.
**
** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
@@ -5498,7 +5654,7 @@ struct sqlite3_mutex_methods {
** ^These routines should return true if the mutex in their argument
** is held or not held, respectively, by the calling thread.
**
-** ^The implementation is not required to provided versions of these
+** ^The implementation is not required to provide versions of these
** routines that actually work. If the implementation does not provide working
** versions of these routines, it should at least provide stubs that always
** return true so that one does not get spurious assertion failures.
@@ -5626,9 +5782,9 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_RESERVE 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_PGHDRSZ 17
-#define SQLITE_TESTCTRL_SCRATCHMALLOC 18
-#define SQLITE_TESTCTRL_LOCALTIME_FAULT 19
+#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
+#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
+#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
#define SQLITE_TESTCTRL_LAST 19
/*
@@ -5851,6 +6007,17 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS
** is always 0.
** </dd>
+**
+** [[SQLITE_DBSTATUS_CACHE_WRITE]] ^(<dt>SQLITE_DBSTATUS_CACHE_WRITE</dt>
+** <dd>This parameter returns the number of dirty cache entries that have
+** been written to disk. Specifically, the number of pages written to the
+** wal file in wal mode databases, or the number of pages written to the
+** database file in rollback mode databases. Any pages written as part of
+** transaction rollback or database recovery operations are not included.
+** If an IO or other error occurs while writing a page to disk, the effect
+** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The
+** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
+** </dd>
** </dl>
*/
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
@@ -5862,7 +6029,8 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6
#define SQLITE_DBSTATUS_CACHE_HIT 7
#define SQLITE_DBSTATUS_CACHE_MISS 8
-#define SQLITE_DBSTATUS_MAX 8 /* Largest defined DBSTATUS */
+#define SQLITE_DBSTATUS_CACHE_WRITE 9
+#define SQLITE_DBSTATUS_MAX 9 /* Largest defined DBSTATUS */
/*
@@ -5931,17 +6099,33 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
** sqlite3_pcache object except by holding and passing pointers
** to the object.
**
-** See [sqlite3_pcache_methods] for additional information.
+** See [sqlite3_pcache_methods2] for additional information.
*/
typedef struct sqlite3_pcache sqlite3_pcache;
/*
+** CAPI3REF: Custom Page Cache Object
+**
+** The sqlite3_pcache_page object represents a single page in the
+** page cache. The page cache will allocate instances of this
+** object. Various methods of the page cache use pointers to instances
+** of this object as parameters or as their return value.
+**
+** See [sqlite3_pcache_methods2] for additional information.
+*/
+typedef struct sqlite3_pcache_page sqlite3_pcache_page;
+struct sqlite3_pcache_page {
+ void *pBuf; /* The content of the page */
+ void *pExtra; /* Extra information associated with the page */
+};
+
+/*
** CAPI3REF: Application Defined Page Cache.
** KEYWORDS: {page cache}
**
-** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
+** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can
** register an alternative page cache implementation by passing in an
-** instance of the sqlite3_pcache_methods structure.)^
+** instance of the sqlite3_pcache_methods2 structure.)^
** In many applications, most of the heap memory allocated by
** SQLite is used for the page cache.
** By implementing a
@@ -5955,7 +6139,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** extreme measure that is only needed by the most demanding applications.
** The built-in page cache is recommended for most uses.
**
-** ^(The contents of the sqlite3_pcache_methods structure are copied to an
+** ^(The contents of the sqlite3_pcache_methods2 structure are copied to an
** internal buffer by SQLite within the call to [sqlite3_config]. Hence
** the application may discard the parameter after the call to
** [sqlite3_config()] returns.)^
@@ -5964,7 +6148,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** ^(The xInit() method is called once for each effective
** call to [sqlite3_initialize()])^
** (usually only once during the lifetime of the process). ^(The xInit()
-** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^
+** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^
** The intent of the xInit() method is to set up global data structures
** required by the custom page cache implementation.
** ^(If the xInit() method is NULL, then the
@@ -5991,17 +6175,15 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** SQLite will typically create one cache instance for each open database file,
** though this is not guaranteed. ^The
** first parameter, szPage, is the size in bytes of the pages that must
-** be allocated by the cache. ^szPage will not be a power of two. ^szPage
-** will the page size of the database file that is to be cached plus an
-** increment (here called "R") of less than 250. SQLite will use the
-** extra R bytes on each page to store metadata about the underlying
-** database page on disk. The value of R depends
+** be allocated by the cache. ^szPage will always a power of two. ^The
+** second parameter szExtra is a number of bytes of extra storage
+** associated with each page cache entry. ^The szExtra parameter will
+** a number less than 250. SQLite will use the
+** extra szExtra bytes on each page to store metadata about the underlying
+** database page on disk. The value passed into szExtra depends
** on the SQLite version, the target platform, and how SQLite was compiled.
-** ^(R is constant for a particular build of SQLite. Except, there are two
-** distinct values of R when SQLite is compiled with the proprietary
-** ZIPVFS extension.)^ ^The second argument to
-** xCreate(), bPurgeable, is true if the cache being created will
-** be used to cache database pages of a file stored on disk, or
+** ^The third argument to xCreate(), bPurgeable, is true if the cache being
+** created will be used to cache database pages of a file stored on disk, or
** false if it is used for an in-memory database. The cache implementation
** does not have to do anything special based with the value of bPurgeable;
** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
@@ -6025,11 +6207,16 @@ typedef struct sqlite3_pcache sqlite3_pcache;
**
** [[the xFetch() page cache methods]]
** The xFetch() method locates a page in the cache and returns a pointer to
-** the page, or a NULL pointer.
-** A "page", in this context, means a buffer of szPage bytes aligned at an
-** 8-byte boundary. The page to be fetched is determined by the key. ^The
-** minimum key value is 1. After it has been retrieved using xFetch, the page
-** is considered to be "pinned".
+** an sqlite3_pcache_page object associated with that page, or a NULL pointer.
+** The pBuf element of the returned sqlite3_pcache_page object will be a
+** pointer to a buffer of szPage bytes used to store the content of a
+** single database page. The pExtra element of sqlite3_pcache_page will be
+** a pointer to the szExtra bytes of extra storage that SQLite has requested
+** for each entry in the page cache.
+**
+** The page to be fetched is determined by the key. ^The minimum key value
+** is 1. After it has been retrieved using xFetch, the page is considered
+** to be "pinned".
**
** If the requested page is already in the page cache, then the page cache
** implementation must return a pointer to the page buffer with its content
@@ -6082,8 +6269,37 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** ^The xDestroy() method is used to delete a cache allocated by xCreate().
** All resources associated with the specified cache should be freed. ^After
** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
-** handle invalid, and will not use it with any other sqlite3_pcache_methods
+** handle invalid, and will not use it with any other sqlite3_pcache_methods2
** functions.
+**
+** [[the xShrink() page cache method]]
+** ^SQLite invokes the xShrink() method when it wants the page cache to
+** free up as much of heap memory as possible. The page cache implementation
+** is not obligated to free any memory, but well-behaved implementations should
+** do their best.
+*/
+typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2;
+struct sqlite3_pcache_methods2 {
+ int iVersion;
+ void *pArg;
+ int (*xInit)(void*);
+ void (*xShutdown)(void*);
+ sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable);
+ void (*xCachesize)(sqlite3_pcache*, int nCachesize);
+ int (*xPagecount)(sqlite3_pcache*);
+ sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
+ void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard);
+ void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
+ unsigned oldKey, unsigned newKey);
+ void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
+ void (*xDestroy)(sqlite3_pcache*);
+ void (*xShrink)(sqlite3_pcache*);
+};
+
+/*
+** This is the obsolete pcache_methods object that has now been replaced
+** by sqlite3_pcache_methods2. This object is not used by SQLite. It is
+** retained in the header file for backwards compatibility only.
*/
typedef struct sqlite3_pcache_methods sqlite3_pcache_methods;
struct sqlite3_pcache_methods {
@@ -6100,6 +6316,7 @@ struct sqlite3_pcache_methods {
void (*xDestroy)(sqlite3_pcache*);
};
+
/*
** CAPI3REF: Online Backup Object
**
@@ -6429,11 +6646,12 @@ SQLITE_API int sqlite3_unlock_notify(
/*
** CAPI3REF: String Comparison
**
-** ^The [sqlite3_strnicmp()] API allows applications and extensions to
-** compare the contents of two buffers containing UTF-8 strings in a
-** case-independent fashion, using the same definition of case independence
-** that SQLite uses internally when comparing identifiers.
+** ^The [sqlite3_stricmp()] and [sqlite3_strnicmp()] APIs allow applications
+** and extensions to compare the contents of two buffers containing UTF-8
+** strings in a case-independent fashion, using the same definition of "case
+** independence" that SQLite uses internally when comparing identifiers.
*/
+SQLITE_API int sqlite3_stricmp(const char *, const char *);
SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
/*
@@ -6768,7 +6986,11 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
SQLITE_API int sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
- int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes),
+#ifdef SQLITE_RTREE_INT_ONLY
+ int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes),
+#else
+ int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes),
+#endif
void *pContext
);
diff --git a/providers/sqlcipher/sqlcipher.patch b/providers/sqlcipher/sqlcipher.patch
index 332b6a9..5452e53 100644
--- a/providers/sqlcipher/sqlcipher.patch
+++ b/providers/sqlcipher/sqlcipher.patch
@@ -1,6 +1,6 @@
---- sqlite3.c.sqlite 2012-01-31 11:12:59.360849603 +0100
-+++ sqlite3.c 2012-01-31 11:08:52.510576554 +0100
-@@ -11952,9 +11952,47 @@
+--- sqlite3.c.sqlite 2012-08-27 14:56:39.000000000 +0200
++++ sqlite3.c 2012-08-27 14:56:17.000000000 +0200
+@@ -12218,9 +12218,47 @@
#endif /* _SQLITEINT_H_ */
/************** End of sqliteInt.h *******************************************/
@@ -50,7 +50,7 @@
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
-@@ -11964,313 +12002,2262 @@
+@@ -12230,220 +12268,2261 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
@@ -415,7 +415,7 @@
- 500, /* nLookaside */
- {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}, /* pcache */
+- {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
- (void*)0, /* pHeap */
- 0, /* nHeap */
- 0, 0, /* mnHeap, mxHeap */
@@ -465,18 +465,20 @@
+ u8 hasData; /* True if this page stores data */
+ u8 hdrOffset; /* 100 for page 1. 0 otherwise */
+ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
++ u8 max1bytePayload; /* min(maxLocal,127) */
+ u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
+ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
+ u16 cellOffset; /* Index in aData of first cell pointer */
+ u16 nFree; /* Number of free bytes on the page */
+ u16 nCell; /* Number of cells on this page, local and ovfl */
+ u16 maskPage; /* Mask for page offset */
-+ struct _OvflCell { /* Cells that will not fit on aData[] */
-+ u8 *pCell; /* Pointers to the body of the overflow cell */
-+ u16 idx; /* Insert this cell before idx-th non-overflow cell */
-+ } aOvfl[5];
++ u16 aiOvfl[5]; /* Insert the i-th overflow cell before the aiOvfl-th
++ ** non-overflow cell */
++ u8 *apOvfl[5]; /* Pointers to the body of overflow cells */
+ BtShared *pBt; /* Pointer to BtShared that this page is part of */
+ 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 */
+ DbPage *pDbPage; /* Pager page handle */
+ Pgno pgno; /* Page number for this page */
+};
@@ -588,32 +590,24 @@
/*
-** 2010 February 23
-**
--** The author disclaims copyright to this source code. In place of
--** a legal notice, here is a blessing:
+** An instance of this object represents a single database file.
+**
-+** A single database file can be in use as the same time by two
++** A single database file can be in use at the same time by two
+** or more database connections. When two or more connections are
+** sharing the same database file, each connection has it own
+** private Btree object for the file and each of those Btrees points
+** to this one BtShared object. BtShared.nRef is the number of
+** connections currently sharing this database file.
- **
--** 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.
++**
+** Fields in this structure are accessed under the BtShared.mutex
+** mutex, except for nRef and pNext which are accessed under the
+** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field
+** may not be modified once it is initially set as long as nRef>0.
+** The pSchema field may be set once under BtShared.mutex and
+** thereafter is unchanged as long as nRef>0.
- **
--*************************************************************************
++**
+** isPending:
- **
--** This file implements routines used to report what compile-time options
--** SQLite was built with.
++**
+** If a BtShared client fails to obtain a write-lock on a database
+** table (because there exists one or more read-locks on the table),
+** the shared-cache enters 'pending-lock' state and isPending is
@@ -629,23 +623,20 @@
+** transaction.
+**
+** This feature is included to help prevent writer-starvation.
- */
++*/
+struct BtShared {
+ Pager *pPager; /* The page cache */
+ sqlite3 *db; /* Database connection currently using this Btree */
+ BtCursor *pCursor; /* A list of all open cursors */
+ MemPage *pPage1; /* First page of the database */
-+ u8 readOnly; /* True if the underlying file is readonly */
-+ u8 pageSizeFixed; /* True if the page size can no longer be changed */
-+ u8 secureDelete; /* True if secure_delete is enabled */
-+ u8 initiallyEmpty; /* Database is empty at start of transaction */
+ u8 openFlags; /* Flags to sqlite3BtreeOpen() */
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ u8 autoVacuum; /* True if auto-vacuum is enabled */
+ u8 incrVacuum; /* True if incr-vacuum is enabled */
+#endif
+ u8 inTransaction; /* Transaction state */
-+ u8 doNotUseWAL; /* If true, do not open write-ahead-log file */
++ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
++ u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
+ u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
+ u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
+ u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
@@ -663,13 +654,21 @@
+ BtShared *pNext; /* Next on a list of sharable BtShared structs */
+ BtLock *pLock; /* List of locks held on this shared-btree struct */
+ Btree *pWriter; /* Btree with currently open write transaction */
-+ u8 isExclusive; /* True if pWriter has an EXCLUSIVE lock on the db */
-+ u8 isPending; /* If waiting for read-locks to clear */
+#endif
+ u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
+};
-
--#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
++
++/*
++** Allowed values for BtShared.btsFlags
++*/
++#define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */
++#define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */
++#define BTS_SECURE_DELETE 0x0004 /* PRAGMA secure_delete is enabled */
++#define BTS_INITIALLY_EMPTY 0x0008 /* Database was empty at trans start */
++#define BTS_NO_WAL 0x0010 /* Do not open write-ahead-log files */
++#define BTS_EXCLUSIVE 0x0020 /* pWriter has an exclusive lock */
++#define BTS_PENDING 0x0040 /* Waiting for read-locks to clear */
++
+/*
+** An instance of the following structure is used to hold information
+** about a cell. The parseCellPtr() function fills in this structure
@@ -686,7 +685,7 @@
+ u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
+ u16 nSize; /* Size of the cell content on the main b-tree page */
+};
-
++
+/*
+** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
+** this will be declared corrupt. This value is calculated based on a
@@ -697,32 +696,29 @@
+** assumed that the database is corrupt.
+*/
+#define BTCURSOR_MAX_DEPTH 20
-
- /*
--** An array of names of all compile-time options. This array should
--** be sorted A-Z.
++
++/*
+** A cursor is a pointer to a particular entry within a particular
+** b-tree within a database file.
- **
--** This array looks large, but in a typical installation actually uses
--** only a handful of compile-time options, so most times this array is usually
--** rather short and uses little memory space.
++**
+** The entry is identified by its MemPage and the index in
+** MemPage.aCell[] of the entry.
+**
-+** A single database file can shared by two more database connections,
++** A single database file can be shared by two more database connections,
+** but cursors cannot be shared. Each cursor is associated with a
+** particular database connection identified BtCursor.pBtree.db.
+**
+** Fields in this structure are accessed under the BtShared.mutex
+** found at self->pBt->mutex.
- */
--static const char * const azCompileOpt[] = {
++*/
+struct BtCursor {
+ Btree *pBtree; /* The Btree to which this cursor belongs */
+ BtShared *pBt; /* The BtShared this cursor points to */
+ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
+ struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
++#ifndef SQLITE_OMIT_INCRBLOB
++ Pgno *aOverflow; /* Cache of overflow page locations */
++#endif
+ Pgno pgnoRoot; /* The root page of this tree */
+ sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */
+ CellInfo info; /* A parse of the cell we are pointing at */
@@ -734,18 +730,13 @@
+ u8 validNKey; /* True if info.nKey is valid */
+ u8 eState; /* One of the CURSOR_XXX constants (see below) */
+#ifndef SQLITE_OMIT_INCRBLOB
-+ Pgno *aOverflow; /* Cache of overflow page locations */
+ u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
+#endif
+ i16 iPage; /* Index of current page in apPage */
+ u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
+ MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
+};
-
--/* These macros are provided to "stringify" the value of the define
--** for those options in which the value is meaningful. */
--#define CTIMEOPT_VAL_(opt) #opt
--#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
++
+/*
+** Potential values for BtCursor.eState.
+**
@@ -775,24 +766,7 @@
+#define CURSOR_VALID 1
+#define CURSOR_REQUIRESEEK 2
+#define CURSOR_FAULT 3
-
--#ifdef SQLITE_32BIT_ROWID
-- "32BIT_ROWID",
--#endif
--#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
-- "4_BYTE_ALIGNED_MALLOC",
--#endif
--#ifdef SQLITE_CASE_SENSITIVE_LIKE
-- "CASE_SENSITIVE_LIKE",
--#endif
--#ifdef SQLITE_CHECK_PAGES
-- "CHECK_PAGES",
--#endif
--#ifdef SQLITE_COVERAGE_TEST
-- "COVERAGE_TEST",
--#endif
--#ifdef SQLITE_DEBUG
-- "DEBUG",
++
+/*
+** The database page the PENDING_BYTE occupies. This page is never used.
+*/
@@ -873,21 +847,25 @@
+#define ISAUTOVACUUM (pBt->autoVacuum)
+#else
+#define ISAUTOVACUUM 0
- #endif
--#ifdef SQLITE_DEFAULT_LOCKING_MODE
-- "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
++#endif
+
+
+/*
+** This structure is passed around through all the sanity checking routines
+** in order to keep track of some global state information.
++**
++** The aRef[] array is allocated so that there is 1 bit for each page in
++** the database. As the integrity-check proceeds, for each page used in
++** the database the corresponding bit is set. This allows integrity-check to
++** detect pages that are used twice and orphaned pages (both of which
++** indicate corruption).
+*/
+typedef struct IntegrityCk IntegrityCk;
+struct IntegrityCk {
+ BtShared *pBt; /* The tree being checked out */
+ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
++ u8 *aPgRef; /* 1 bit per page in the db (see above) */
+ Pgno nPage; /* Number of pages in the database */
-+ int *anRef; /* Number of times each page is referenced */
+ int mxErr; /* Stop accumulating errors when this reaches zero */
+ int nErr; /* Number of messages written to zErrMsg so far */
+ int mallocFailed; /* A memory allocation error has occurred */
@@ -895,7 +873,7 @@
+};
+
+/*
-+** Read or write a two- and four-byte big-endian integer values.
++** Routines to read or write a two- and four-byte big-endian integer values.
+*/
+#define get2byte(x) ((x)[0]<<8 | (x)[1])
+#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
@@ -945,11 +923,13 @@
+
+#define FILE_HEADER_SZ 16
+
++#ifndef CIPHER_VERSION
++#define CIPHER_VERSION "2.0.6"
++#endif
++
+#ifndef CIPHER
+#define CIPHER "aes-256-cbc"
- #endif
--#ifdef SQLITE_DISABLE_DIRSYNC
-- "DISABLE_DIRSYNC",
++#endif
+
+#define CIPHER_DECRYPT 0
+#define CIPHER_ENCRYPT 1
@@ -960,24 +940,18 @@
+
+#ifndef PBKDF2_ITER
+#define PBKDF2_ITER 4000
- #endif
--#ifdef SQLITE_DISABLE_LFS
-- "DISABLE_LFS",
++#endif
+
+#ifndef DEFAULT_USE_HMAC
+#define DEFAULT_USE_HMAC 1
- #endif
--#ifdef SQLITE_ENABLE_ATOMIC_WRITE
-- "ENABLE_ATOMIC_WRITE",
++#endif
+
+/* by default, sqlcipher will use a reduced number of iterations to generate
+ the HMAC key / or transform a raw cipher key
+ */
+#ifndef FAST_PBKDF2_ITER
+#define FAST_PBKDF2_ITER 2
- #endif
--#ifdef SQLITE_ENABLE_CEROD
-- "ENABLE_CEROD",
++#endif
+
+/* this if a fixed random array that will be xor'd with the database salt to ensure that the
+ salt passed to the HMAC key derivation function is not the same as that used to derive
@@ -986,21 +960,31 @@
+ will likely allow this to be defined at runtime via pragma */
+#ifndef HMAC_SALT_MASK
+#define HMAC_SALT_MASK 0x3a
- #endif
--#ifdef SQLITE_ENABLE_COLUMN_METADATA
-- "ENABLE_COLUMN_METADATA",
++#endif
+
+#ifdef CODEC_DEBUG
+#define CODEC_TRACE(X) {printf X;fflush(stdout);}
+#else
+#define CODEC_TRACE(X)
- #endif
--#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
-- "ENABLE_EXPENSIVE_ASSERT",
++#endif
+
++#ifdef CODEC_DEBUG_PAGEDATA
++#define CODEC_HEXDUMP(DESC,BUFFER,LEN) \
++ { \
++ int __pctr; \
++ printf(DESC); \
++ for(__pctr=0; __pctr < LEN; __pctr++) { \
++ if(__pctr % 16 == 0) printf("\n%05x: ",__pctr); \
++ printf("%02x ",((unsigned char*) BUFFER)[__pctr]); \
++ } \
++ printf("\n"); \
++ fflush(stdout); \
++ }
++#else
++#define CODEC_HEXDUMP(DESC,BUFFER,LEN)
++#endif
+
-+/* extensions defined in pragma.c */
-+
++/* extensions defined in pager.c */
+SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx);
+SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno);
+SQLITE_PRIVATE sqlite3_file *sqlite3Pager_get_fd(Pager *pPager);
@@ -1011,7 +995,8 @@
+ void (*xCodecFree)(void*),
+ void *pCodec
+);
-+/* end extensions defined in pragma.c */
++SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetError(Pager *pPager, int error);
++/* end extensions defined in pager.c */
+
+/*
+** Simple shared routines for converting hex char strings to binary data
@@ -1034,6 +1019,7 @@
+typedef struct codec_ctx codec_ctx;
+
+/* utility functions */
++int sqlcipher_ismemset(const unsigned char *a0, unsigned char value, int len);
+int sqlcipher_memcmp(const unsigned char *a0, const unsigned char *a1, int len);
+int sqlcipher_pseudorandom(void *, int);
+void sqlcipher_free(void *, int);
@@ -1069,23 +1055,30 @@
+
+void sqlcipher_exportFunc(sqlite3_context *, int, sqlite3_value **);
+
++void sqlcipher_set_default_use_hmac(int use);
++
+int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use);
+/* end extensions defined in crypto_impl.c */
+
- #endif
--#ifdef SQLITE_ENABLE_FTS1
-- "ENABLE_FTS1",
- #endif
--#ifdef SQLITE_ENABLE_FTS2
-- "ENABLE_FTS2",
++#endif
++#endif
+/* END CRYPTO */
+
+/************** End of crypto.h **********************************************/
+/************** Continuing where we left off in crypto.c *********************/
+
++/* Generate code to return a string value */
++void codec_vdbe_return_static_string(Parse *pParse, const char *zLabel, const char *value){
++ Vdbe *v = sqlite3GetVdbe(pParse);
++ sqlite3VdbeSetNumCols(v, 1);
++ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC);
++ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, value, 0);
++ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
++}
++
+int codec_set_kdf_iter(sqlite3* db, int nDb, int kdf_iter, int for_ctx) {
+ struct Db *pDb = &db->aDb[nDb];
-+ CODEC_TRACE(("codec_set_kdf_iter: entered db=%d nDb=%d kdf_iter=%d for_ctx=%d\n", db, nDb, kdf_iter, for_ctx));
++ CODEC_TRACE(("codec_set_kdf_iter: entered db=%p nDb=%d kdf_iter=%d for_ctx=%d\n", db, nDb, kdf_iter, for_ctx));
+
+ if(pDb->pBt) {
+ codec_ctx *ctx;
@@ -1097,7 +1090,7 @@
+
+int codec_set_fast_kdf_iter(sqlite3* db, int nDb, int kdf_iter, int for_ctx) {
+ struct Db *pDb = &db->aDb[nDb];
-+ CODEC_TRACE(("codec_set_kdf_iter: entered db=%d nDb=%d kdf_iter=%d for_ctx=%d\n", db, nDb, kdf_iter, for_ctx));
++ CODEC_TRACE(("codec_set_kdf_iter: entered db=%p nDb=%d kdf_iter=%d for_ctx=%d\n", db, nDb, kdf_iter, for_ctx));
+
+ if(pDb->pBt) {
+ codec_ctx *ctx;
@@ -1115,17 +1108,24 @@
+
+ sqlite3_mutex_enter(db->mutex);
+ db->nextPagesize = page_sz;
-+ pDb->pBt->pBt->pageSizeFixed = 0;
++
++ /* before forcing the page size we need to unset the BTS_PAGESIZE_FIXED flag, else
++ sqliteBtreeSetPageSize will block the change */
++ pDb->pBt->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
+ CODEC_TRACE(("codec_set_btree_to_codec_pagesize: sqlite3BtreeSetPageSize() size=%d reserve=%d\n", page_sz, reserve_sz));
+ rc = sqlite3BtreeSetPageSize(pDb->pBt, page_sz, reserve_sz, 0);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
+
++void codec_set_default_use_hmac(int use) {
++ sqlcipher_set_default_use_hmac(use);
++}
++
+int codec_set_use_hmac(sqlite3* db, int nDb, int use) {
+ struct Db *pDb = &db->aDb[nDb];
+
-+ CODEC_TRACE(("codec_set_use_hmac: entered db=%d nDb=%d use=%d\n", db, nDb, use));
++ CODEC_TRACE(("codec_set_use_hmac: entered db=%p nDb=%d use=%d\n", db, nDb, use));
+
+ if(pDb->pBt) {
+ int rc;
@@ -1135,8 +1135,6 @@
+ rc = sqlcipher_codec_ctx_set_use_hmac(ctx, use);
+ if(rc != SQLITE_OK) return rc;
+ /* since the use of hmac has changed, the page size may also change */
-+ /* Note: before forcing the page size we need to force pageSizeFixed to 0, else
-+ sqliteBtreeSetPageSize will block the change */
+ return codec_set_btree_to_codec_pagesize(db, pDb, ctx);
+ }
+ }
@@ -1145,7 +1143,7 @@
+
+int codec_set_page_size(sqlite3* db, int nDb, int size) {
+ struct Db *pDb = &db->aDb[nDb];
-+ CODEC_TRACE(("codec_set_page_size: entered db=%d nDb=%d size=%d\n", db, nDb, size));
++ CODEC_TRACE(("codec_set_page_size: entered db=%p nDb=%d size=%d\n", db, nDb, size));
+
+ if(pDb->pBt) {
+ int rc;
@@ -1169,7 +1167,7 @@
+ */
+int codec_set_cipher_name(sqlite3* db, int nDb, const char *cipher_name, int for_ctx) {
+ struct Db *pDb = &db->aDb[nDb];
-+ CODEC_TRACE(("codec_set_cipher_name: entered db=%d nDb=%d cipher_name=%s for_ctx=%d\n", db, nDb, cipher_name, for_ctx));
++ CODEC_TRACE(("codec_set_cipher_name: entered db=%p nDb=%d cipher_name=%s for_ctx=%d\n", db, nDb, cipher_name, for_ctx));
+
+ if(pDb->pBt) {
+ codec_ctx *ctx;
@@ -1181,7 +1179,7 @@
+
+int codec_set_pass_key(sqlite3* db, int nDb, const void *zKey, int nKey, int for_ctx) {
+ struct Db *pDb = &db->aDb[nDb];
-+ CODEC_TRACE(("codec_set_pass_key: entered db=%d nDb=%d cipher_name=%s nKey=%d for_ctx=%d\n", db, nDb, zKey, nKey, for_ctx));
++ CODEC_TRACE(("codec_set_pass_key: entered db=%p nDb=%d zKey=%s nKey=%d for_ctx=%d\n", db, nDb, (char *)zKey, nKey, for_ctx));
+ if(pDb->pBt) {
+ codec_ctx *ctx;
+ sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
@@ -1252,7 +1250,7 @@
+SQLITE_PRIVATE int sqlite3CodecAttach(sqlite3* db, int nDb, const void *zKey, int nKey) {
+ struct Db *pDb = &db->aDb[nDb];
+
-+ CODEC_TRACE(("sqlite3CodecAttach: entered nDb=%d zKey=%s, nKey=%d\n", nDb, zKey, nKey));
++ CODEC_TRACE(("sqlite3CodecAttach: entered nDb=%d zKey=%s, nKey=%d\n", nDb, (char *)zKey, nKey));
+
+ sqlcipher_activate();
+
@@ -1269,6 +1267,11 @@
+
+ codec_set_btree_to_codec_pagesize(db, pDb, ctx);
+
++ /* force secure delete. This has the benefit of wiping internal data when deleted
++ and also ensures that all pages are written to disk (i.e. not skipped by
++ sqlite3PagerDontWrite optimizations) */
++ sqlite3BtreeSecureDelete(pDb->pBt, 1);
++
+ /* if fd is null, then this is an in-memory database and
+ we dont' want to overwrite the AutoVacuum settings
+ if not null, then set to the default */
@@ -1286,7 +1289,7 @@
+}
+
+SQLITE_API int sqlite3_key(sqlite3 *db, const void *pKey, int nKey) {
-+ CODEC_TRACE(("sqlite3_key: entered db=%d pKey=%s nKey=%d\n", db, pKey, nKey));
++ CODEC_TRACE(("sqlite3_key: entered db=%p pKey=%s nKey=%d\n", db, (char *)pKey, nKey));
+ /* attach key if db and pKey are not null and nKey is > 0 */
+ if(db && pKey && nKey) {
+ sqlite3CodecAttach(db, 0, pKey, nKey); // operate only on the main db
@@ -1306,11 +1309,11 @@
+** 3. If there is a key present, re-encrypt the database with the new key
+*/
+SQLITE_API int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) {
-+ CODEC_TRACE(("sqlite3_rekey: entered db=%d pKey=%s, nKey=%d\n", db, pKey, nKey));
++ CODEC_TRACE(("sqlite3_rekey: entered db=%p pKey=%s, nKey=%d\n", db, (char *)pKey, nKey));
+ sqlcipher_activate();
+ if(db && pKey && nKey) {
+ struct Db *pDb = &db->aDb[0];
-+ CODEC_TRACE(("sqlite3_rekey: database pDb=%d\n", pDb));
++ CODEC_TRACE(("sqlite3_rekey: database pDb=%p\n", pDb));
+ if(pDb->pBt) {
+ codec_ctx *ctx;
+ int rc, page_count;
@@ -1343,11 +1346,14 @@
+ rc = sqlite3PagerGet(pPager, pgno, &page);
+ if(rc == SQLITE_OK) { /* write page see pager_incr_changecounter for example */
+ rc = sqlite3PagerWrite(page);
-+ //printf("sqlite3PagerWrite(%d)\n", pgno);
+ if(rc == SQLITE_OK) {
+ sqlite3PagerUnref(page);
-+ }
-+ }
++ } else {
++ CODEC_TRACE(("sqlite3_rekey: error %d occurred writing page %d\n", rc, pgno));
++ }
++ } else {
++ CODEC_TRACE(("sqlite3_rekey: error %d occurred getting page %d\n", rc, pgno));
++ }
+ }
+ }
+
@@ -1358,7 +1364,7 @@
+ sqlcipher_codec_key_copy(ctx, CIPHER_WRITE_CTX);
+ } else {
+ CODEC_TRACE(("sqlite3_rekey: rollback\n"));
-+ sqlite3BtreeRollback(pDb->pBt);
++ sqlite3BtreeRollback(pDb->pBt, SQLITE_ABORT_ROLLBACK);
+ }
+
+ sqlite3_mutex_leave(db->mutex);
@@ -1370,7 +1376,7 @@
+
+SQLITE_PRIVATE void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) {
+ struct Db *pDb = &db->aDb[nDb];
-+ CODEC_TRACE(("sqlite3CodecGetKey: entered db=%d, nDb=%d\n", db, nDb));
++ CODEC_TRACE(("sqlite3CodecGetKey: entered db=%p, nDb=%d\n", db, nDb));
+
+ if( pDb->pBt ) {
+ codec_ctx *ctx;
@@ -1387,9 +1393,7 @@
+
+
+/* END CRYPTO */
- #endif
--#ifdef SQLITE_ENABLE_FTS3
-- "ENABLE_FTS3",
++#endif
+
+/************** End of crypto.c **********************************************/
+/************** Begin file crypto_impl.c *************************************/
@@ -1436,12 +1440,8 @@
+#include <sys/mman.h>
+#elif defined(_WIN32)
+/* # include <windows.h> */
- #endif
--#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
-- "ENABLE_FTS3_PARENTHESIS",
- #endif
--#ifdef SQLITE_ENABLE_FTS4
-- "ENABLE_FTS4",
++#endif
++#endif
+
+/* the default implementation of SQLCipher uses a cipher_ctx
+ to keep track of read / write state separately. The following
@@ -1475,6 +1475,8 @@
+/* prototype for pager HMAC function */
+int sqlcipher_page_hmac(cipher_ctx *, Pgno, unsigned char *, int, unsigned char *);
+
++static int default_use_hmac = DEFAULT_USE_HMAC;
++
+struct codec_ctx {
+ int kdf_salt_sz;
+ int page_sz;
@@ -1494,6 +1496,14 @@
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+
++/* fixed time zero memory check tests every position of a memory segement
++ matches a single value (i.e. the memory is all zeros)*/
++int sqlcipher_ismemset(const unsigned char *a0, unsigned char value, int len) {
++ int i = 0, noMatch = 0;
++ for(i = 0; i < len; i++) noMatch = (noMatch || (a0[i] != value));
++ return noMatch;
++}
++
+/* fixed time memory comparison routine */
+int sqlcipher_memcmp(const unsigned char *a0, const unsigned char *a1, int len) {
+ int i = 0, noMatch = 0;
@@ -1527,12 +1537,8 @@
+ munlock(ptr, sz);
+#elif defined(_WIN32)
+ VirtualUnlock(ptr, sz);
- #endif
--#ifdef SQLITE_ENABLE_ICU
-- "ENABLE_ICU",
- #endif
--#ifdef SQLITE_ENABLE_IOTRACE
-- "ENABLE_IOTRACE",
++#endif
++#endif
+ }
+ sqlite3_free(ptr);
+ }
@@ -1551,9 +1557,7 @@
+ mlock(ptr, sz);
+#elif defined(_WIN32)
+ VirtualLock(ptr, sz);
- #endif
--#ifdef SQLITE_ENABLE_LOAD_EXTENSION
-- "ENABLE_LOAD_EXTENSION",
++#endif
+ }
+#endif
+ return ptr;
@@ -1585,7 +1589,7 @@
+ */
+void sqlcipher_cipher_ctx_free(cipher_ctx **iCtx) {
+ cipher_ctx *ctx = *iCtx;
-+ CODEC_TRACE(("cipher_ctx_free: entered iCtx=%d\n", iCtx));
++ CODEC_TRACE(("cipher_ctx_free: entered iCtx=%p\n", iCtx));
+ sqlcipher_free(ctx->key, ctx->key_sz);
+ sqlcipher_free(ctx->hmac_key, ctx->key_sz);
+ sqlcipher_free(ctx->pass, ctx->pass_sz);
@@ -1599,7 +1603,7 @@
+ * returns 1 otherwise
+ */
+int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
-+ CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered c1=%d c2=%d\n", c1, c2));
++ CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered c1=%p c2=%p\n", c1, c2));
+
+ if(
+ c1->evp_cipher == c2->evp_cipher
@@ -1608,6 +1612,8 @@
+ && c1->fast_kdf_iter == c2->fast_kdf_iter
+ && c1->key_sz == c2->key_sz
+ && c1->pass_sz == c2->pass_sz
++ && c1->use_hmac == c2->use_hmac
++ && c1->hmac_sz == c2->hmac_sz
+ && (
+ c1->pass == c2->pass
+ || !sqlcipher_memcmp((const unsigned char*)c1->pass,
@@ -1630,7 +1636,7 @@
+ void *key = target->key;
+ void *hmac_key = target->hmac_key;
+
-+ CODEC_TRACE(("sqlcipher_cipher_ctx_copy: entered target=%d, source=%d\n", target, source));
++ CODEC_TRACE(("sqlcipher_cipher_ctx_copy: entered target=%p, source=%p\n", target, source));
+ sqlcipher_free(target->pass, target->pass_sz);
+ memcpy(target, source, sizeof(cipher_ctx));
+
@@ -1727,7 +1733,12 @@
+ return SQLITE_OK;
+}
+
++/* set the global default flag for HMAC */
++void sqlcipher_set_default_use_hmac(int use) {
++ default_use_hmac = use;
++}
+
++/* set the codec flag for whether this individual database should be using hmac */
+int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use) {
+ int reserve = EVP_MAX_IV_LENGTH; /* base reserve size will be IV only */
+
@@ -1748,7 +1759,9 @@
+}
+
+void sqlcipher_codec_ctx_set_error(codec_ctx *ctx, int error) {
-+ ctx->pBt->db->errCode = error;
++ CODEC_TRACE(("sqlcipher_codec_ctx_set_error: ctx=%p, error=%d\n", ctx, error));
++ sqlite3pager_sqlite3PagerSetError(ctx->pBt->pBt->pPager, error);
++ ctx->pBt->pBt->db->errCode = error;
+}
+
+int sqlcipher_codec_ctx_get_pagesize(codec_ctx *ctx) {
@@ -1834,7 +1847,7 @@
+
+ /* Use HMAC signatures by default. Note that codec_set_use_hmac will implicity call
+ codec_set_page_size to set the default */
-+ if((rc = sqlcipher_codec_ctx_set_use_hmac(ctx, DEFAULT_USE_HMAC)) != SQLITE_OK) return rc;
++ if((rc = sqlcipher_codec_ctx_set_use_hmac(ctx, default_use_hmac)) != SQLITE_OK) return rc;
+
+ if((rc = sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx)) != SQLITE_OK) return rc;
+
@@ -1847,7 +1860,7 @@
+ */
+void sqlcipher_codec_ctx_free(codec_ctx **iCtx) {
+ codec_ctx *ctx = *iCtx;
-+ CODEC_TRACE(("codec_ctx_free: entered iCtx=%d\n", iCtx));
++ CODEC_TRACE(("codec_ctx_free: entered iCtx=%p\n", iCtx));
+ sqlcipher_free(ctx->kdf_salt, ctx->kdf_salt_sz);
+ sqlcipher_free(ctx->hmac_kdf_salt, ctx->kdf_salt_sz);
+ sqlcipher_free(ctx->buffer, 0);
@@ -1896,12 +1909,13 @@
+ out_start = out; /* note the original position of the output buffer pointer, as out will be rewritten during encryption */
+
+ CODEC_TRACE(("codec_cipher:entered pgno=%d, mode=%d, size=%d\n", pgno, mode, size));
++ CODEC_HEXDUMP("codec_cipher: input page data", in, page_sz);
+
-+ /* just copy raw data from in to out when key size is 0
-+ * i.e. during a rekey of a plaintext database */
++ /* the key size should never be zero. If it is, error out. */
+ if(c_ctx->key_sz == 0) {
-+ memcpy(out, in, size);
-+ return SQLITE_OK;
++ CODEC_TRACE(("codec_cipher: error possible context corruption, key_sz is zero for pgno=%d\n", pgno));
++ memset(out, 0, page_sz);
++ return SQLITE_ERROR;
+ }
+
+ if(mode == CIPHER_ENCRYPT) {
@@ -1918,14 +1932,24 @@
+ return SQLITE_ERROR;
+ }
+
-+ CODEC_TRACE(("codec_cipher: comparing hmac on in=%d out=%d hmac_sz=%d\n", hmac_in, hmac_out, c_ctx->hmac_sz));
-+ if(sqlcipher_memcmp(hmac_in, hmac_out, c_ctx->hmac_sz) != 0) {
-+ /* the hmac check failed, which means the data was tampered with or
-+ corrupted in some way. we will return an error, and zero out the page data
-+ to force an error */
-+ memset(out, 0, page_sz);
-+ CODEC_TRACE(("codec_cipher: hmac check failed for pgno=%d\n", pgno));
-+ return SQLITE_ERROR;
++ CODEC_TRACE(("codec_cipher: comparing hmac on in=%p out=%p hmac_sz=%d\n", hmac_in, hmac_out, c_ctx->hmac_sz));
++ if(sqlcipher_memcmp(hmac_in, hmac_out, c_ctx->hmac_sz) != 0) { /* the hmac check failed */
++ if(sqlcipher_ismemset(in, 0, page_sz) == 0) {
++ /* first check if the entire contents of the page is zeros. If so, this page
++ resulted from a short read (i.e. sqlite attempted to pull a page after the end of the file. these
++ short read failures must be ignored for autovaccum mode to work so wipe the output buffer
++ and return SQLITE_OK to skip the decryption step. */
++ CODEC_TRACE(("codec_cipher: zeroed page (short read) for pgno %d, encryption but returning SQLITE_OK\n", pgno));
++ memset(out, 0, page_sz);
++ return SQLITE_OK;
++ } else {
++ /* if the page memory is not all zeros, it means the there was data and a hmac on the page.
++ since the check failed, the page was either tampered with or corrupted. wipe the output buffer,
++ and return SQLITE_ERROR to the caller */
++ CODEC_TRACE(("codec_cipher: hmac check failed for pgno=%d returning SQLITE_ERROR\n", pgno));
++ memset(out, 0, page_sz);
++ return SQLITE_ERROR;
++ }
+ }
+ }
+
@@ -1944,6 +1968,8 @@
+ sqlcipher_page_hmac(c_ctx, pgno, out_start, size + c_ctx->iv_sz, hmac_out);
+ }
+
++ CODEC_HEXDUMP("codec_cipher: output page data", out_start, page_sz);
++
+ return SQLITE_OK;
+}
+
@@ -1960,8 +1986,8 @@
+ */
+int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
+ CODEC_TRACE(("codec_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d \
-+ ctx->kdf_salt=%d ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d \
-+ ctx->hmac_kdf_salt=%d, c_ctx->fast_kdf_iter=%d c_ctx->key_sz=%d\n",
++ ctx->kdf_salt=%p ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d \
++ ctx->hmac_kdf_salt=%p, c_ctx->fast_kdf_iter=%d c_ctx->key_sz=%d\n",
+ c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter,
+ ctx->hmac_kdf_salt, c_ctx->fast_kdf_iter, c_ctx->key_sz));
+
@@ -2384,7 +2410,7 @@
+ 500, /* nLookaside */
+ {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}, /* pcache */
++ {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
+ (void*)0, /* pHeap */
+ 0, /* nHeap */
+ 0, 0, /* mnHeap, mxHeap */
@@ -2461,103 +2487,10 @@
+/*
+** 2010 February 23
+**
-+** The author disclaims copyright to this source code. In place of
-+** a legal notice, here is a blessing:
-+**
-+** May you do good and not evil.
-+** May you find forgiveness for yourself and forgive others.
-+** May you share freely, never taking more than you give.
-+**
-+*************************************************************************
-+**
-+** This file implements routines used to report what compile-time options
-+** SQLite was built with.
-+*/
-+
-+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-+
-+
-+/*
-+** An array of names of all compile-time options. This array should
-+** be sorted A-Z.
-+**
-+** This array looks large, but in a typical installation actually uses
-+** only a handful of compile-time options, so most times this array is usually
-+** rather short and uses little memory space.
-+*/
-+static const char * const azCompileOpt[] = {
-+
-+/* These macros are provided to "stringify" the value of the define
-+** for those options in which the value is meaningful. */
-+#define CTIMEOPT_VAL_(opt) #opt
-+#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
-+
-+#ifdef SQLITE_32BIT_ROWID
-+ "32BIT_ROWID",
-+#endif
-+#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
-+ "4_BYTE_ALIGNED_MALLOC",
-+#endif
-+#ifdef SQLITE_CASE_SENSITIVE_LIKE
-+ "CASE_SENSITIVE_LIKE",
-+#endif
-+#ifdef SQLITE_CHECK_PAGES
-+ "CHECK_PAGES",
-+#endif
-+#ifdef SQLITE_COVERAGE_TEST
-+ "COVERAGE_TEST",
-+#endif
-+#ifdef SQLITE_DEBUG
-+ "DEBUG",
-+#endif
-+#ifdef SQLITE_DEFAULT_LOCKING_MODE
-+ "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
-+#endif
-+#ifdef SQLITE_DISABLE_DIRSYNC
-+ "DISABLE_DIRSYNC",
-+#endif
-+#ifdef SQLITE_DISABLE_LFS
-+ "DISABLE_LFS",
-+#endif
-+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
-+ "ENABLE_ATOMIC_WRITE",
-+#endif
-+#ifdef SQLITE_ENABLE_CEROD
-+ "ENABLE_CEROD",
-+#endif
-+#ifdef SQLITE_ENABLE_COLUMN_METADATA
-+ "ENABLE_COLUMN_METADATA",
-+#endif
-+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
-+ "ENABLE_EXPENSIVE_ASSERT",
-+#endif
-+#ifdef SQLITE_ENABLE_FTS1
-+ "ENABLE_FTS1",
-+#endif
-+#ifdef SQLITE_ENABLE_FTS2
-+ "ENABLE_FTS2",
-+#endif
-+#ifdef SQLITE_ENABLE_FTS3
-+ "ENABLE_FTS3",
-+#endif
-+#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
-+ "ENABLE_FTS3_PARENTHESIS",
-+#endif
-+#ifdef SQLITE_ENABLE_FTS4
-+ "ENABLE_FTS4",
-+#endif
-+#ifdef SQLITE_ENABLE_ICU
-+ "ENABLE_ICU",
-+#endif
-+#ifdef SQLITE_ENABLE_IOTRACE
-+ "ENABLE_IOTRACE",
-+#endif
-+#ifdef SQLITE_ENABLE_LOAD_EXTENSION
-+ "ENABLE_LOAD_EXTENSION",
- #endif
- #ifdef SQLITE_ENABLE_LOCKING_STYLE
- "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
-@@ -24516,7 +26503,7 @@
+ ** The author disclaims copyright to this source code. In place of
+ ** a legal notice, here is a blessing:
+ **
+@@ -24967,7 +27046,7 @@
#include <sys/time.h>
#include <errno.h>
#ifndef SQLITE_OMIT_WAL
@@ -2565,17 +2498,42 @@
+/* #include <sys/mman.h> */
#endif
- #if SQLITE_ENABLE_LOCKING_STYLE
-@@ -44185,12 +46172,41 @@
- #endif /* SQLITE_OMIT_DISKIO */
+@@ -45561,24 +47640,56 @@
+ }
+ #endif
--/************** End of pager.c ***********************************************/
--/************** Begin file wal.c *********************************************/
+-#ifdef SQLITE_HAS_CODEC
-/*
--** 2010 February 1
+-** This function is called by the wal module when writing page content
+-** into the log file.
-**
--** The author disclaims copyright to this source code. In place of
+-** This function returns a pointer to a buffer containing the encrypted
+-** page content. If a malloc fails, this function may return NULL.
+-*/
+-SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
+- void *aData = 0;
+- CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
+- return aData;
++#ifdef SQLITE_HAS_CODEC
++/*
++** This function is called by the wal module when writing page content
++** into the log file.
++**
++** This function returns a pointer to a buffer containing the encrypted
++** page content. If a malloc fails, this function may return NULL.
++*/
++SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
++ void *aData = 0;
++ CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
++ return aData;
++}
++#endif /* SQLITE_HAS_CODEC */
++
++#endif /* !SQLITE_OMIT_WAL */
++
++#endif /* SQLITE_OMIT_DISKIO */
++
+/* BEGIN CRYPTO */
+#ifdef SQLITE_HAS_CODEC
+SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx) {
@@ -2600,118 +2558,4040 @@
+ sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec);
+}
+
-+
++SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetError( Pager *pPager, int error) {
++ pPager->errCode = error;
+ }
+-#endif /* SQLITE_HAS_CODEC */
+
+-#endif /* !SQLITE_OMIT_WAL */
+#endif
+/* END CRYPTO */
-+
-+
-+/************** End of pager.c ***********************************************/
-+/************** Begin file wal.c *********************************************/
-+/*
-+** 2010 February 1
-+**
-+** The author disclaims copyright to this source code. In place of
- ** a legal notice, here is a blessing:
- **
- ** May you do good and not evil.
-@@ -46941,870 +48957,223 @@
- pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
- testcase( szPage<=32768 );
- testcase( szPage>=65536 );
-- pWal->hdr.mxFrame = iFrame;
-- if( isCommit ){
-- pWal->hdr.iChange++;
-- pWal->hdr.nPage = nTruncate;
+
+-#endif /* SQLITE_OMIT_DISKIO */
+
+ /************** End of pager.c ***********************************************/
+ /************** Begin file wal.c *********************************************/
+@@ -46100,3253 +48211,2590 @@
+ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
+ int rc = SQLITE_OK;
+
+- /* Enlarge the pWal->apWiData[] array if required */
+- if( pWal->nWiData<=iPage ){
+- int nByte = sizeof(u32*)*(iPage+1);
+- volatile u32 **apNew;
+- apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte);
+- if( !apNew ){
+- *ppPage = 0;
+- return SQLITE_NOMEM;
- }
-- /* If this is a commit, update the wal-index header too. */
-- if( isCommit ){
-- walIndexWriteHdr(pWal);
-- pWal->iCallback = iFrame;
+- memset((void*)&apNew[pWal->nWiData], 0,
+- sizeof(u32*)*(iPage+1-pWal->nWiData));
+- pWal->apWiData = apNew;
+- pWal->nWiData = iPage+1;
+- }
+-
+- /* Request a pointer to the required page from the VFS */
+- if( pWal->apWiData[iPage]==0 ){
+- if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+- pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
+- if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
+- }else{
+- rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
+- pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
+- );
+- if( rc==SQLITE_READONLY ){
+- pWal->readOnly |= WAL_SHM_RDONLY;
+- rc = SQLITE_OK;
+- }
- }
- }
-
-- WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
+- *ppPage = pWal->apWiData[iPage];
+- assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
- return rc;
-}
-
--/*
--** This routine is called to implement sqlite3_wal_checkpoint() and
--** related interfaces.
+-/*
+-** Return a pointer to the WalCkptInfo structure in the wal-index.
+-*/
+-static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
+- assert( pWal->nWiData>0 && pWal->apWiData[0] );
+- return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
+-}
+-
+-/*
+-** Return a pointer to the WalIndexHdr structure in the wal-index.
+-*/
+-static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
+- assert( pWal->nWiData>0 && pWal->apWiData[0] );
+- return (volatile WalIndexHdr*)pWal->apWiData[0];
+-}
+-
+-/*
+-** The argument to this macro must be of type u32. On a little-endian
+-** architecture, it returns the u32 value that results from interpreting
+-** the 4 bytes as a big-endian value. On a big-endian architecture, it
+-** returns the value that would be produced by intepreting the 4 bytes
+-** of the input value as a little-endian integer.
+-*/
+-#define BYTESWAP32(x) ( \
+- (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \
+- + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \
+-)
+-
+-/*
+-** Generate or extend an 8 byte checksum based on the data in
+-** array aByte[] and the initial values of aIn[0] and aIn[1] (or
+-** initial values of 0 and 0 if aIn==NULL).
-**
--** Obtain a CHECKPOINT lock and then backfill as much information as
--** we can from WAL into the database.
+-** The checksum is written back into aOut[] before returning.
-**
--** If parameter xBusy is not NULL, it is a pointer to a busy-handler
--** callback. In this case this function runs a blocking checkpoint.
+-** nByte must be a positive multiple of 8.
-*/
--SQLITE_PRIVATE int sqlite3WalCheckpoint(
-- Wal *pWal, /* Wal connection */
-- int eMode, /* PASSIVE, FULL or RESTART */
-- int (*xBusy)(void*), /* Function to call when busy */
-- void *pBusyArg, /* Context argument for xBusyHandler */
-- int sync_flags, /* Flags to sync db file with (or 0) */
-- int nBuf, /* Size of temporary buffer */
-- u8 *zBuf, /* Temporary buffer to use */
-- int *pnLog, /* OUT: Number of frames in WAL */
-- int *pnCkpt /* OUT: Number of backfilled frames in WAL */
+-static void walChecksumBytes(
+- int nativeCksum, /* True for native byte-order, false for non-native */
+- u8 *a, /* Content to be checksummed */
+- int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
+- const u32 *aIn, /* Initial checksum value input */
+- u32 *aOut /* OUT: Final checksum value output */
-){
-- int rc; /* Return code */
-- int isChanged = 0; /* True if a new wal-index header is loaded */
-- int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
--
-- assert( pWal->ckptLock==0 );
-- assert( pWal->writeLock==0 );
+- u32 s1, s2;
+- u32 *aData = (u32 *)a;
+- u32 *aEnd = (u32 *)&a[nByte];
-
-- if( pWal->readOnly ) return SQLITE_READONLY;
-- WALTRACE(("WAL%p: checkpoint begins\n", pWal));
-- rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
-- if( rc ){
-- /* Usually this is SQLITE_BUSY meaning that another thread or process
-- ** is already running a checkpoint, or maybe a recovery. But it might
-- ** also be SQLITE_IOERR. */
-- return rc;
+- if( aIn ){
+- s1 = aIn[0];
+- s2 = aIn[1];
+- }else{
+- s1 = s2 = 0;
- }
-- pWal->ckptLock = 1;
-
-- /* If this is a blocking-checkpoint, then obtain the write-lock as well
-- ** to prevent any writers from running while the checkpoint is underway.
-- ** This has to be done before the call to walIndexReadHdr() below.
-- **
-- ** If the writer lock cannot be obtained, then a passive checkpoint is
-- ** run instead. Since the checkpointer is not holding the writer lock,
-- ** there is no point in blocking waiting for any readers. Assuming no
-- ** other error occurs, this function will return SQLITE_BUSY to the caller.
-- */
-- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
-- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
-- if( rc==SQLITE_OK ){
-- pWal->writeLock = 1;
-- }else if( rc==SQLITE_BUSY ){
-- eMode2 = SQLITE_CHECKPOINT_PASSIVE;
-- rc = SQLITE_OK;
-- }
-- }
+- assert( nByte>=8 );
+- assert( (nByte&0x00000007)==0 );
-
-- /* Read the wal-index header. */
-- if( rc==SQLITE_OK ){
-- rc = walIndexReadHdr(pWal, &isChanged);
+- if( nativeCksum ){
+- do {
+- s1 += *aData++ + s2;
+- s2 += *aData++ + s1;
+- }while( aData<aEnd );
+- }else{
+- do {
+- s1 += BYTESWAP32(aData[0]) + s2;
+- s2 += BYTESWAP32(aData[1]) + s1;
+- aData += 2;
+- }while( aData<aEnd );
- }
-
-- /* Copy data from the log to the database file. */
-- if( rc==SQLITE_OK ){
-- if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
-- rc = SQLITE_CORRUPT_BKPT;
-- }else{
-- rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
-- }
+- aOut[0] = s1;
+- aOut[1] = s2;
+-}
-
+-static void walShmBarrier(Wal *pWal){
+- if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
+- sqlite3OsShmBarrier(pWal->pDbFd);
+- }
+-}
+-
+-/*
+-** Write the header information in pWal->hdr into the wal-index.
+-**
+-** The checksum on pWal->hdr is updated before it is written.
+-*/
+-static void walIndexWriteHdr(Wal *pWal){
+- volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
+- const int nCksum = offsetof(WalIndexHdr, aCksum);
+-
+- assert( pWal->writeLock );
+- pWal->hdr.isInit = 1;
+- pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
+- walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
+- memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
+- walShmBarrier(pWal);
+- memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
+-}
+-
+-/*
+-** This function encodes a single frame header and writes it to a buffer
+-** supplied by the caller. A frame-header is made up of a series of
+-** 4-byte big-endian integers, as follows:
+-**
+-** 0: Page number.
+-** 4: For commit records, the size of the database image in pages
+-** after the commit. For all other records, zero.
+-** 8: Salt-1 (copied from the wal-header)
+-** 12: Salt-2 (copied from the wal-header)
+-** 16: Checksum-1.
+-** 20: Checksum-2.
+-*/
+-static void walEncodeFrame(
+- Wal *pWal, /* The write-ahead log */
+- u32 iPage, /* Database page number for frame */
+- u32 nTruncate, /* New db size (or 0 for non-commit frames) */
+- u8 *aData, /* Pointer to page data */
+- u8 *aFrame /* OUT: Write encoded frame here */
+-){
+- int nativeCksum; /* True for native byte-order checksums */
+- u32 *aCksum = pWal->hdr.aFrameCksum;
+- assert( WAL_FRAME_HDRSIZE==24 );
+- sqlite3Put4byte(&aFrame[0], iPage);
+- sqlite3Put4byte(&aFrame[4], nTruncate);
+- memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
+-
+- nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
+- walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
+- walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
+-
+- sqlite3Put4byte(&aFrame[16], aCksum[0]);
+- sqlite3Put4byte(&aFrame[20], aCksum[1]);
+-}
+-
+-/*
+-** Check to see if the frame with header in aFrame[] and content
+-** in aData[] is valid. If it is a valid frame, fill *piPage and
+-** *pnTruncate and return true. Return if the frame is not valid.
+-*/
+-static int walDecodeFrame(
+- Wal *pWal, /* The write-ahead log */
+- u32 *piPage, /* OUT: Database page number for frame */
+- u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */
+- u8 *aData, /* Pointer to page data (for checksum) */
+- u8 *aFrame /* Frame data */
+-){
+- int nativeCksum; /* True for native byte-order checksums */
+- u32 *aCksum = pWal->hdr.aFrameCksum;
+- u32 pgno; /* Page number of the frame */
+- assert( WAL_FRAME_HDRSIZE==24 );
+-
+- /* A frame is only valid if the salt values in the frame-header
+- ** match the salt values in the wal-header.
+- */
+- if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
+- return 0;
+- }
+-
+- /* A frame is only valid if the page number is creater than zero.
+- */
+- pgno = sqlite3Get4byte(&aFrame[0]);
+- if( pgno==0 ){
+- return 0;
+- }
+-
+- /* A frame is only valid if a checksum of the WAL header,
+- ** all prior frams, the first 16 bytes of this frame-header,
+- ** and the frame-data matches the checksum in the last 8
+- ** bytes of this frame-header.
+- */
+- nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
+- walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
+- walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
+- if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
+- || aCksum[1]!=sqlite3Get4byte(&aFrame[20])
+- ){
+- /* Checksum failed. */
+- return 0;
+- }
+-
+- /* If we reach this point, the frame is valid. Return the page number
+- ** and the new database size.
+- */
+- *piPage = pgno;
+- *pnTruncate = sqlite3Get4byte(&aFrame[4]);
+- return 1;
+-}
+-
+-
+-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+-/*
+-** Names of locks. This routine is used to provide debugging output and is not
+-** a part of an ordinary build.
+-*/
+-static const char *walLockName(int lockIdx){
+- if( lockIdx==WAL_WRITE_LOCK ){
+- return "WRITE-LOCK";
+- }else if( lockIdx==WAL_CKPT_LOCK ){
+- return "CKPT-LOCK";
+- }else if( lockIdx==WAL_RECOVER_LOCK ){
+- return "RECOVER-LOCK";
+- }else{
+- static char zName[15];
+- sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]",
+- lockIdx-WAL_READ_LOCK(0));
+- return zName;
+- }
+-}
+-#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
+-
+-
+-/*
+-** Set or release locks on the WAL. Locks are either shared or exclusive.
+-** A lock cannot be moved directly between shared and exclusive - it must go
+-** through the unlocked state first.
+-**
+-** In locking_mode=EXCLUSIVE, all of these routines become no-ops.
+-*/
+-static int walLockShared(Wal *pWal, int lockIdx){
+- int rc;
+- if( pWal->exclusiveMode ) return SQLITE_OK;
+- rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
+- SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
+- WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
+- walLockName(lockIdx), rc ? "failed" : "ok"));
+- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+- return rc;
+-}
+-static void walUnlockShared(Wal *pWal, int lockIdx){
+- if( pWal->exclusiveMode ) return;
+- (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
+- SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
+- WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
+-}
+-static int walLockExclusive(Wal *pWal, int lockIdx, int n){
+- int rc;
+- if( pWal->exclusiveMode ) return SQLITE_OK;
+- rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
+- SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
+- WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
+- walLockName(lockIdx), n, rc ? "failed" : "ok"));
+- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+- return rc;
+-}
+-static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
+- if( pWal->exclusiveMode ) return;
+- (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
+- SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
+- WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
+- walLockName(lockIdx), n));
+-}
+-
+-/*
+-** Compute a hash on a page number. The resulting hash value must land
+-** between 0 and (HASHTABLE_NSLOT-1). The walHashNext() function advances
+-** the hash to the next value in the event of a collision.
+-*/
+-static int walHash(u32 iPage){
+- assert( iPage>0 );
+- assert( (HASHTABLE_NSLOT & (HASHTABLE_NSLOT-1))==0 );
+- return (iPage*HASHTABLE_HASH_1) & (HASHTABLE_NSLOT-1);
+-}
+-static int walNextHash(int iPriorHash){
+- return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
+-}
+-
+-/*
+-** Return pointers to the hash table and page number array stored on
+-** page iHash of the wal-index. The wal-index is broken into 32KB pages
+-** numbered starting from 0.
+-**
+-** Set output variable *paHash to point to the start of the hash table
+-** in the wal-index file. Set *piZero to one less than the frame
+-** number of the first frame indexed by this hash table. If a
+-** slot in the hash table is set to N, it refers to frame number
+-** (*piZero+N) in the log.
+-**
+-** Finally, set *paPgno so that *paPgno[1] is the page number of the
+-** first frame indexed by the hash table, frame (*piZero+1).
+-*/
+-static int walHashGet(
+- Wal *pWal, /* WAL handle */
+- int iHash, /* Find the iHash'th table */
+- volatile ht_slot **paHash, /* OUT: Pointer to hash index */
+- volatile u32 **paPgno, /* OUT: Pointer to page number array */
+- u32 *piZero /* OUT: Frame associated with *paPgno[0] */
+-){
+- int rc; /* Return code */
+- volatile u32 *aPgno;
+-
+- rc = walIndexPage(pWal, iHash, &aPgno);
+- assert( rc==SQLITE_OK || iHash>0 );
+-
+- if( rc==SQLITE_OK ){
+- u32 iZero;
+- volatile ht_slot *aHash;
+-
+- aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
+- if( iHash==0 ){
+- aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
+- iZero = 0;
+- }else{
+- iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
+- }
+-
+- *paPgno = &aPgno[-1];
+- *paHash = aHash;
+- *piZero = iZero;
+- }
+- return rc;
+-}
+-
+-/*
+-** Return the number of the wal-index page that contains the hash-table
+-** and page-number array that contain entries corresponding to WAL frame
+-** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
+-** are numbered starting from 0.
+-*/
+-static int walFramePage(u32 iFrame){
+- int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE;
+- assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE)
+- && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
+- && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
+- && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
+- && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
+- );
+- return iHash;
+-}
+-
+-/*
+-** Return the page number associated with frame iFrame in this WAL.
+-*/
+-static u32 walFramePgno(Wal *pWal, u32 iFrame){
+- int iHash = walFramePage(iFrame);
+- if( iHash==0 ){
+- return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
+- }
+- return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
+-}
+-
+-/*
+-** Remove entries from the hash table that point to WAL slots greater
+-** than pWal->hdr.mxFrame.
+-**
+-** This function is called whenever pWal->hdr.mxFrame is decreased due
+-** to a rollback or savepoint.
+-**
+-** At most only the hash table containing pWal->hdr.mxFrame needs to be
+-** updated. Any later hash tables will be automatically cleared when
+-** pWal->hdr.mxFrame advances to the point where those hash tables are
+-** actually needed.
+-*/
+-static void walCleanupHash(Wal *pWal){
+- volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */
+- volatile u32 *aPgno = 0; /* Page number array for hash table */
+- u32 iZero = 0; /* frame == (aHash[x]+iZero) */
+- int iLimit = 0; /* Zero values greater than this */
+- int nByte; /* Number of bytes to zero in aPgno[] */
+- int i; /* Used to iterate through aHash[] */
+-
+- assert( pWal->writeLock );
+- testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
+- testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE );
+- testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 );
+-
+- if( pWal->hdr.mxFrame==0 ) return;
+-
+- /* Obtain pointers to the hash-table and page-number array containing
+- ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
+- ** that the page said hash-table and array reside on is already mapped.
+- */
+- assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
+- assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
+- walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
+-
+- /* Zero all hash-table entries that correspond to frame numbers greater
+- ** than pWal->hdr.mxFrame.
+- */
+- iLimit = pWal->hdr.mxFrame - iZero;
+- assert( iLimit>0 );
+- for(i=0; i<HASHTABLE_NSLOT; i++){
+- if( aHash[i]>iLimit ){
+- aHash[i] = 0;
+- }
+- }
+-
+- /* Zero the entries in the aPgno array that correspond to frames with
+- ** frame numbers greater than pWal->hdr.mxFrame.
+- */
+- nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
+- memset((void *)&aPgno[iLimit+1], 0, nByte);
+-
+-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+- /* Verify that the every entry in the mapping region is still reachable
+- ** via the hash table even after the cleanup.
+- */
+- if( iLimit ){
+- int i; /* Loop counter */
+- int iKey; /* Hash key */
+- for(i=1; i<=iLimit; i++){
+- for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
+- if( aHash[iKey]==i ) break;
+- }
+- assert( aHash[iKey]==i );
+- }
+- }
+-#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
+-}
+-
+-
+-/*
+-** Set an entry in the wal-index that will map database page number
+-** pPage into WAL frame iFrame.
+-*/
+-static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
+- int rc; /* Return code */
+- u32 iZero = 0; /* One less than frame number of aPgno[1] */
+- volatile u32 *aPgno = 0; /* Page number array */
+- volatile ht_slot *aHash = 0; /* Hash table */
+-
+- rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
+-
+- /* Assuming the wal-index file was successfully mapped, populate the
+- ** page number array and hash table entry.
+- */
+- if( rc==SQLITE_OK ){
+- int iKey; /* Hash table key */
+- int idx; /* Value to write to hash-table slot */
+- int nCollide; /* Number of hash collisions */
+-
+- idx = iFrame - iZero;
+- assert( idx <= HASHTABLE_NSLOT/2 + 1 );
+-
+- /* If this is the first entry to be added to this hash-table, zero the
+- ** entire hash table and aPgno[] array before proceding.
+- */
+- if( idx==1 ){
+- int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
+- memset((void*)&aPgno[1], 0, nByte);
+- }
+-
+- /* If the entry in aPgno[] is already set, then the previous writer
+- ** must have exited unexpectedly in the middle of a transaction (after
+- ** writing one or more dirty pages to the WAL to free up memory).
+- ** Remove the remnants of that writers uncommitted transaction from
+- ** the hash-table before writing any new entries.
+- */
+- if( aPgno[idx] ){
+- walCleanupHash(pWal);
+- assert( !aPgno[idx] );
+- }
+-
+- /* Write the aPgno[] array entry and the hash-table slot. */
+- nCollide = idx;
+- for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
+- if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
+- }
+- aPgno[idx] = iPage;
+- aHash[iKey] = (ht_slot)idx;
+-
+-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+- /* Verify that the number of entries in the hash table exactly equals
+- ** the number of entries in the mapping region.
+- */
+- {
+- int i; /* Loop counter */
+- int nEntry = 0; /* Number of entries in the hash table */
+- for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
+- assert( nEntry==idx );
++ /* Enlarge the pWal->apWiData[] array if required */
++ if( pWal->nWiData<=iPage ){
++ int nByte = sizeof(u32*)*(iPage+1);
++ volatile u32 **apNew;
++ apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte);
++ if( !apNew ){
++ *ppPage = 0;
++ return SQLITE_NOMEM;
+ }
++ memset((void*)&apNew[pWal->nWiData], 0,
++ sizeof(u32*)*(iPage+1-pWal->nWiData));
++ pWal->apWiData = apNew;
++ pWal->nWiData = iPage+1;
++ }
+
+- /* Verify that the every entry in the mapping region is reachable
+- ** via the hash table. This turns out to be a really, really expensive
+- ** thing to check, so only do this occasionally - not on every
+- ** iteration.
+- */
+- if( (idx&0x3ff)==0 ){
+- int i; /* Loop counter */
+- for(i=1; i<=idx; i++){
+- for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
+- if( aHash[iKey]==i ) break;
+- }
+- assert( aHash[iKey]==i );
++ /* Request a pointer to the required page from the VFS */
++ if( pWal->apWiData[iPage]==0 ){
++ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
++ pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
++ if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
++ }else{
++ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
++ pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
++ );
++ if( rc==SQLITE_READONLY ){
++ pWal->readOnly |= WAL_SHM_RDONLY;
++ rc = SQLITE_OK;
+ }
+ }
+-#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
+ }
+
+-
++ *ppPage = pWal->apWiData[iPage];
++ assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
+ return rc;
+ }
+
++/*
++** Return a pointer to the WalCkptInfo structure in the wal-index.
++*/
++static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
++ assert( pWal->nWiData>0 && pWal->apWiData[0] );
++ return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
++}
+
+ /*
+-** Recover the wal-index by reading the write-ahead log file.
+-**
+-** This routine first tries to establish an exclusive lock on the
+-** wal-index to prevent other threads/processes from doing anything
+-** with the WAL or wal-index while recovery is running. The
+-** WAL_RECOVER_LOCK is also held so that other threads will know
+-** that this thread is running recovery. If unable to establish
+-** the necessary locks, this routine returns SQLITE_BUSY.
++** Return a pointer to the WalIndexHdr structure in the wal-index.
+ */
+-static int walIndexRecover(Wal *pWal){
+- int rc; /* Return Code */
+- i64 nSize; /* Size of log file */
+- u32 aFrameCksum[2] = {0, 0};
+- int iLock; /* Lock offset to lock for checkpoint */
+- int nLock; /* Number of locks to hold */
++static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
++ assert( pWal->nWiData>0 && pWal->apWiData[0] );
++ return (volatile WalIndexHdr*)pWal->apWiData[0];
++}
+
+- /* Obtain an exclusive lock on all byte in the locking range not already
+- ** locked by the caller. The caller is guaranteed to have locked the
+- ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
+- ** If successful, the same bytes that are locked here are unlocked before
+- ** this function returns.
+- */
+- assert( pWal->ckptLock==1 || pWal->ckptLock==0 );
+- assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
+- assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
+- assert( pWal->writeLock );
+- iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
+- nLock = SQLITE_SHM_NLOCK - iLock;
+- rc = walLockExclusive(pWal, iLock, nLock);
+- if( rc ){
+- return rc;
+- }
+- WALTRACE(("WAL%p: recovery begin...\n", pWal));
++/*
++** The argument to this macro must be of type u32. On a little-endian
++** architecture, it returns the u32 value that results from interpreting
++** the 4 bytes as a big-endian value. On a big-endian architecture, it
++** returns the value that would be produced by intepreting the 4 bytes
++** of the input value as a little-endian integer.
++*/
++#define BYTESWAP32(x) ( \
++ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \
++ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \
++)
+
+- memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
++/*
++** Generate or extend an 8 byte checksum based on the data in
++** array aByte[] and the initial values of aIn[0] and aIn[1] (or
++** initial values of 0 and 0 if aIn==NULL).
++**
++** The checksum is written back into aOut[] before returning.
++**
++** nByte must be a positive multiple of 8.
++*/
++static void walChecksumBytes(
++ int nativeCksum, /* True for native byte-order, false for non-native */
++ u8 *a, /* Content to be checksummed */
++ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
++ const u32 *aIn, /* Initial checksum value input */
++ u32 *aOut /* OUT: Final checksum value output */
++){
++ u32 s1, s2;
++ u32 *aData = (u32 *)a;
++ u32 *aEnd = (u32 *)&a[nByte];
+
+- rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
+- if( rc!=SQLITE_OK ){
+- goto recovery_error;
++ if( aIn ){
++ s1 = aIn[0];
++ s2 = aIn[1];
++ }else{
++ s1 = s2 = 0;
+ }
+
+- if( nSize>WAL_HDRSIZE ){
+- u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
+- u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
+- int szFrame; /* Number of bytes in buffer aFrame[] */
+- u8 *aData; /* Pointer to data part of aFrame buffer */
+- int iFrame; /* Index of last frame read */
+- i64 iOffset; /* Next offset to read from log file */
+- int szPage; /* Page size according to the log */
+- u32 magic; /* Magic value read from WAL header */
+- u32 version; /* Magic value read from WAL header */
+- int isValid; /* True if this frame is valid */
+-
+- /* Read in the WAL header. */
+- rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
+- if( rc!=SQLITE_OK ){
+- goto recovery_error;
+- }
+-
+- /* If the database page size is not a power of two, or is greater than
+- ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
+- ** data. Similarly, if the 'magic' value is invalid, ignore the whole
+- ** WAL file.
+- */
+- magic = sqlite3Get4byte(&aBuf[0]);
+- szPage = sqlite3Get4byte(&aBuf[8]);
+- if( (magic&0xFFFFFFFE)!=WAL_MAGIC
+- || szPage&(szPage-1)
+- || szPage>SQLITE_MAX_PAGE_SIZE
+- || szPage<512
+- ){
+- goto finished;
+- }
+- pWal->hdr.bigEndCksum = (u8)(magic&0x00000001);
+- pWal->szPage = szPage;
+- pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
+- memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
+-
+- /* Verify that the WAL header checksum is correct */
+- walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
+- aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
+- );
+- if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
+- || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28])
+- ){
+- goto finished;
+- }
+-
+- /* Verify that the version number on the WAL format is one that
+- ** are able to understand */
+- version = sqlite3Get4byte(&aBuf[4]);
+- if( version!=WAL_MAX_VERSION ){
+- rc = SQLITE_CANTOPEN_BKPT;
+- goto finished;
+- }
+-
+- /* Malloc a buffer to read frames into. */
+- szFrame = szPage + WAL_FRAME_HDRSIZE;
+- aFrame = (u8 *)sqlite3_malloc(szFrame);
+- if( !aFrame ){
+- rc = SQLITE_NOMEM;
+- goto recovery_error;
+- }
+- aData = &aFrame[WAL_FRAME_HDRSIZE];
+-
+- /* Read all frames from the log file. */
+- iFrame = 0;
+- for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
+- u32 pgno; /* Database page number for frame */
+- u32 nTruncate; /* dbsize field from frame header */
+-
+- /* Read and decode the next log frame. */
+- iFrame++;
+- rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
+- if( rc!=SQLITE_OK ) break;
+- isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
+- if( !isValid ) break;
+- rc = walIndexAppend(pWal, iFrame, pgno);
+- if( rc!=SQLITE_OK ) break;
+-
+- /* If nTruncate is non-zero, this is a commit record. */
+- if( nTruncate ){
+- pWal->hdr.mxFrame = iFrame;
+- pWal->hdr.nPage = nTruncate;
+- pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
+- testcase( szPage<=32768 );
+- testcase( szPage>=65536 );
+- aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
+- aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
+- }
+- }
++ assert( nByte>=8 );
++ assert( (nByte&0x00000007)==0 );
+
+- sqlite3_free(aFrame);
++ if( nativeCksum ){
++ do {
++ s1 += *aData++ + s2;
++ s2 += *aData++ + s1;
++ }while( aData<aEnd );
++ }else{
++ do {
++ s1 += BYTESWAP32(aData[0]) + s2;
++ s2 += BYTESWAP32(aData[1]) + s1;
++ aData += 2;
++ }while( aData<aEnd );
+ }
+
+-finished:
+- if( rc==SQLITE_OK ){
+- volatile WalCkptInfo *pInfo;
+- int i;
+- pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
+- pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
+- walIndexWriteHdr(pWal);
+-
+- /* Reset the checkpoint-header. This is safe because this thread is
+- ** currently holding locks that exclude all other readers, writers and
+- ** checkpointers.
+- */
+- pInfo = walCkptInfo(pWal);
+- pInfo->nBackfill = 0;
+- pInfo->aReadMark[0] = 0;
+- for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
++ aOut[0] = s1;
++ aOut[1] = s2;
++}
+
+- /* If more than one frame was recovered from the log file, report an
+- ** event via sqlite3_log(). This is to help with identifying performance
+- ** problems caused by applications routinely shutting down without
+- ** checkpointing the log file.
+- */
+- if( pWal->hdr.nPage ){
+- sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
+- pWal->hdr.nPage, pWal->zWalName
+- );
+- }
++static void walShmBarrier(Wal *pWal){
++ if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
++ sqlite3OsShmBarrier(pWal->pDbFd);
+ }
+-
+-recovery_error:
+- WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
+- walUnlockExclusive(pWal, iLock, nLock);
+- return rc;
+ }
+
+ /*
+-** Close an open wal-index.
++** Write the header information in pWal->hdr into the wal-index.
++**
++** The checksum on pWal->hdr is updated before it is written.
+ */
+-static void walIndexClose(Wal *pWal, int isDelete){
+- if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+- int i;
+- for(i=0; i<pWal->nWiData; i++){
+- sqlite3_free((void *)pWal->apWiData[i]);
+- pWal->apWiData[i] = 0;
+- }
+- }else{
+- sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
+- }
++static void walIndexWriteHdr(Wal *pWal){
++ volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
++ const int nCksum = offsetof(WalIndexHdr, aCksum);
++
++ assert( pWal->writeLock );
++ pWal->hdr.isInit = 1;
++ pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
++ walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
++ memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
++ walShmBarrier(pWal);
++ memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
+ }
+
+-/*
+-** Open a connection to the WAL file zWalName. The database file must
+-** already be opened on connection pDbFd. The buffer that zWalName points
+-** to must remain valid for the lifetime of the returned Wal* handle.
+-**
+-** A SHARED lock should be held on the database file when this function
+-** is called. The purpose of this SHARED lock is to prevent any other
+-** client from unlinking the WAL or wal-index file. If another process
+-** were to do this just after this client opened one of these files, the
+-** system would be badly broken.
++/*
++** This function encodes a single frame header and writes it to a buffer
++** supplied by the caller. A frame-header is made up of a series of
++** 4-byte big-endian integers, as follows:
+ **
+-** If the log file is successfully opened, SQLITE_OK is returned and
+-** *ppWal is set to point to a new WAL handle. If an error occurs,
+-** an SQLite error code is returned and *ppWal is left unmodified.
++** 0: Page number.
++** 4: For commit records, the size of the database image in pages
++** after the commit. For all other records, zero.
++** 8: Salt-1 (copied from the wal-header)
++** 12: Salt-2 (copied from the wal-header)
++** 16: Checksum-1.
++** 20: Checksum-2.
+ */
+-SQLITE_PRIVATE int sqlite3WalOpen(
+- sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */
+- sqlite3_file *pDbFd, /* The open database file */
+- const char *zWalName, /* Name of the WAL file */
+- int bNoShm, /* True to run in heap-memory mode */
+- i64 mxWalSize, /* Truncate WAL to this size on reset */
+- Wal **ppWal /* OUT: Allocated Wal handle */
++static void walEncodeFrame(
++ Wal *pWal, /* The write-ahead log */
++ u32 iPage, /* Database page number for frame */
++ u32 nTruncate, /* New db size (or 0 for non-commit frames) */
++ u8 *aData, /* Pointer to page data */
++ u8 *aFrame /* OUT: Write encoded frame here */
+ ){
+- int rc; /* Return Code */
+- Wal *pRet; /* Object to allocate and return */
+- int flags; /* Flags passed to OsOpen() */
++ int nativeCksum; /* True for native byte-order checksums */
++ u32 *aCksum = pWal->hdr.aFrameCksum;
++ assert( WAL_FRAME_HDRSIZE==24 );
++ sqlite3Put4byte(&aFrame[0], iPage);
++ sqlite3Put4byte(&aFrame[4], nTruncate);
++ memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
+
+- assert( zWalName && zWalName[0] );
+- assert( pDbFd );
++ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
++ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
++ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
+
+- /* In the amalgamation, the os_unix.c and os_win.c source files come before
+- ** this source file. Verify that the #defines of the locking byte offsets
+- ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
+- */
+-#ifdef WIN_SHM_BASE
+- assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
+-#endif
+-#ifdef UNIX_SHM_BASE
+- assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
+-#endif
++ sqlite3Put4byte(&aFrame[16], aCksum[0]);
++ sqlite3Put4byte(&aFrame[20], aCksum[1]);
++}
+
++/*
++** Check to see if the frame with header in aFrame[] and content
++** in aData[] is valid. If it is a valid frame, fill *piPage and
++** *pnTruncate and return true. Return if the frame is not valid.
++*/
++static int walDecodeFrame(
++ Wal *pWal, /* The write-ahead log */
++ u32 *piPage, /* OUT: Database page number for frame */
++ u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */
++ u8 *aData, /* Pointer to page data (for checksum) */
++ u8 *aFrame /* Frame data */
++){
++ int nativeCksum; /* True for native byte-order checksums */
++ u32 *aCksum = pWal->hdr.aFrameCksum;
++ u32 pgno; /* Page number of the frame */
++ assert( WAL_FRAME_HDRSIZE==24 );
+
+- /* Allocate an instance of struct Wal to return. */
+- *ppWal = 0;
+- pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
+- if( !pRet ){
+- return SQLITE_NOMEM;
++ /* A frame is only valid if the salt values in the frame-header
++ ** match the salt values in the wal-header.
++ */
++ if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
++ return 0;
+ }
+
+- pRet->pVfs = pVfs;
+- pRet->pWalFd = (sqlite3_file *)&pRet[1];
+- pRet->pDbFd = pDbFd;
+- pRet->readLock = -1;
+- pRet->mxWalSize = mxWalSize;
+- pRet->zWalName = zWalName;
+- pRet->syncHeader = 1;
+- pRet->padToSectorBoundary = 1;
+- pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
+-
+- /* Open file handle on the write-ahead log file. */
+- flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
+- rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
+- if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
+- pRet->readOnly = WAL_RDONLY;
++ /* A frame is only valid if the page number is creater than zero.
++ */
++ pgno = sqlite3Get4byte(&aFrame[0]);
++ if( pgno==0 ){
++ return 0;
+ }
+
+- if( rc!=SQLITE_OK ){
+- walIndexClose(pRet, 0);
+- sqlite3OsClose(pRet->pWalFd);
+- sqlite3_free(pRet);
+- }else{
+- int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
+- if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
+- if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
+- pRet->padToSectorBoundary = 0;
+- }
+- *ppWal = pRet;
+- WALTRACE(("WAL%d: opened\n", pRet));
++ /* A frame is only valid if a checksum of the WAL header,
++ ** all prior frams, the first 16 bytes of this frame-header,
++ ** and the frame-data matches the checksum in the last 8
++ ** bytes of this frame-header.
++ */
++ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
++ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
++ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
++ if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
++ || aCksum[1]!=sqlite3Get4byte(&aFrame[20])
++ ){
++ /* Checksum failed. */
++ return 0;
+ }
+- return rc;
++
++ /* If we reach this point, the frame is valid. Return the page number
++ ** and the new database size.
++ */
++ *piPage = pgno;
++ *pnTruncate = sqlite3Get4byte(&aFrame[4]);
++ return 1;
+ }
+
++
++#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+ /*
+-** Change the size to which the WAL file is trucated on each reset.
++** Names of locks. This routine is used to provide debugging output and is not
++** a part of an ordinary build.
+ */
+-SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){
+- if( pWal ) pWal->mxWalSize = iLimit;
++static const char *walLockName(int lockIdx){
++ if( lockIdx==WAL_WRITE_LOCK ){
++ return "WRITE-LOCK";
++ }else if( lockIdx==WAL_CKPT_LOCK ){
++ return "CKPT-LOCK";
++ }else if( lockIdx==WAL_RECOVER_LOCK ){
++ return "RECOVER-LOCK";
++ }else{
++ static char zName[15];
++ sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]",
++ lockIdx-WAL_READ_LOCK(0));
++ return zName;
++ }
+ }
++#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
++
+
+ /*
+-** Find the smallest page number out of all pages held in the WAL that
+-** has not been returned by any prior invocation of this method on the
+-** same WalIterator object. Write into *piFrame the frame index where
+-** that page was last written into the WAL. Write into *piPage the page
+-** number.
++** Set or release locks on the WAL. Locks are either shared or exclusive.
++** A lock cannot be moved directly between shared and exclusive - it must go
++** through the unlocked state first.
+ **
+-** Return 0 on success. If there are no pages in the WAL with a page
+-** number larger than *piPage, then return 1.
++** In locking_mode=EXCLUSIVE, all of these routines become no-ops.
+ */
+-static int walIteratorNext(
+- WalIterator *p, /* Iterator */
+- u32 *piPage, /* OUT: The page number of the next page */
+- u32 *piFrame /* OUT: Wal frame index of next page */
+-){
+- u32 iMin; /* Result pgno must be greater than iMin */
+- u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */
+- int i; /* For looping through segments */
+-
+- iMin = p->iPrior;
+- assert( iMin<0xffffffff );
+- for(i=p->nSegment-1; i>=0; i--){
+- struct WalSegment *pSegment = &p->aSegment[i];
+- while( pSegment->iNext<pSegment->nEntry ){
+- u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]];
+- if( iPg>iMin ){
+- if( iPg<iRet ){
+- iRet = iPg;
+- *piFrame = pSegment->iZero + pSegment->aIndex[pSegment->iNext];
+- }
+- break;
+- }
+- pSegment->iNext++;
+- }
+- }
+-
+- *piPage = p->iPrior = iRet;
+- return (iRet==0xFFFFFFFF);
++static int walLockShared(Wal *pWal, int lockIdx){
++ int rc;
++ if( pWal->exclusiveMode ) return SQLITE_OK;
++ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
++ SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
++ WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
++ walLockName(lockIdx), rc ? "failed" : "ok"));
++ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
++ return rc;
++}
++static void walUnlockShared(Wal *pWal, int lockIdx){
++ if( pWal->exclusiveMode ) return;
++ (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
++ SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
++ WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
++}
++static int walLockExclusive(Wal *pWal, int lockIdx, int n){
++ int rc;
++ if( pWal->exclusiveMode ) return SQLITE_OK;
++ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
++ SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
++ WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
++ walLockName(lockIdx), n, rc ? "failed" : "ok"));
++ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
++ return rc;
++}
++static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
++ if( pWal->exclusiveMode ) return;
++ (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
++ SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
++ WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
++ walLockName(lockIdx), n));
+ }
+
+ /*
+-** This function merges two sorted lists into a single sorted list.
+-**
+-** aLeft[] and aRight[] are arrays of indices. The sort key is
+-** aContent[aLeft[]] and aContent[aRight[]]. Upon entry, the following
+-** is guaranteed for all J<K:
+-**
+-** aContent[aLeft[J]] < aContent[aLeft[K]]
+-** aContent[aRight[J]] < aContent[aRight[K]]
+-**
+-** This routine overwrites aRight[] with a new (probably longer) sequence
+-** of indices such that the aRight[] contains every index that appears in
+-** either aLeft[] or the old aRight[] and such that the second condition
+-** above is still met.
+-**
+-** The aContent[aLeft[X]] values will be unique for all X. And the
+-** aContent[aRight[X]] values will be unique too. But there might be
+-** one or more combinations of X and Y such that
++** Compute a hash on a page number. The resulting hash value must land
++** between 0 and (HASHTABLE_NSLOT-1). The walHashNext() function advances
++** the hash to the next value in the event of a collision.
++*/
++static int walHash(u32 iPage){
++ assert( iPage>0 );
++ assert( (HASHTABLE_NSLOT & (HASHTABLE_NSLOT-1))==0 );
++ return (iPage*HASHTABLE_HASH_1) & (HASHTABLE_NSLOT-1);
++}
++static int walNextHash(int iPriorHash){
++ return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
++}
++
++/*
++** Return pointers to the hash table and page number array stored on
++** page iHash of the wal-index. The wal-index is broken into 32KB pages
++** numbered starting from 0.
+ **
+-** aLeft[X]!=aRight[Y] && aContent[aLeft[X]] == aContent[aRight[Y]]
++** Set output variable *paHash to point to the start of the hash table
++** in the wal-index file. Set *piZero to one less than the frame
++** number of the first frame indexed by this hash table. If a
++** slot in the hash table is set to N, it refers to frame number
++** (*piZero+N) in the log.
+ **
+-** When that happens, omit the aLeft[X] and use the aRight[Y] index.
++** Finally, set *paPgno so that *paPgno[1] is the page number of the
++** first frame indexed by the hash table, frame (*piZero+1).
+ */
+-static void walMerge(
+- const u32 *aContent, /* Pages in wal - keys for the sort */
+- ht_slot *aLeft, /* IN: Left hand input list */
+- int nLeft, /* IN: Elements in array *paLeft */
+- ht_slot **paRight, /* IN/OUT: Right hand input list */
+- int *pnRight, /* IN/OUT: Elements in *paRight */
+- ht_slot *aTmp /* Temporary buffer */
++static int walHashGet(
++ Wal *pWal, /* WAL handle */
++ int iHash, /* Find the iHash'th table */
++ volatile ht_slot **paHash, /* OUT: Pointer to hash index */
++ volatile u32 **paPgno, /* OUT: Pointer to page number array */
++ u32 *piZero /* OUT: Frame associated with *paPgno[0] */
+ ){
+- int iLeft = 0; /* Current index in aLeft */
+- int iRight = 0; /* Current index in aRight */
+- int iOut = 0; /* Current index in output buffer */
+- int nRight = *pnRight;
+- ht_slot *aRight = *paRight;
++ int rc; /* Return code */
++ volatile u32 *aPgno;
+
+- assert( nLeft>0 && nRight>0 );
+- while( iRight<nRight || iLeft<nLeft ){
+- ht_slot logpage;
+- Pgno dbpage;
++ rc = walIndexPage(pWal, iHash, &aPgno);
++ assert( rc==SQLITE_OK || iHash>0 );
+
+- if( (iLeft<nLeft)
+- && (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
+- ){
+- logpage = aLeft[iLeft++];
++ if( rc==SQLITE_OK ){
++ u32 iZero;
++ volatile ht_slot *aHash;
++
++ aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
++ if( iHash==0 ){
++ aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
++ iZero = 0;
+ }else{
+- logpage = aRight[iRight++];
++ iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
+ }
+- dbpage = aContent[logpage];
++
++ *paPgno = &aPgno[-1];
++ *paHash = aHash;
++ *piZero = iZero;
++ }
++ return rc;
++}
+
+- aTmp[iOut++] = logpage;
+- if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
++/*
++** Return the number of the wal-index page that contains the hash-table
++** and page-number array that contain entries corresponding to WAL frame
++** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
++** are numbered starting from 0.
++*/
++static int walFramePage(u32 iFrame){
++ int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE;
++ assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE)
++ && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
++ && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
++ && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
++ && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
++ );
++ return iHash;
++}
+
+- assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
+- assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
++/*
++** Return the page number associated with frame iFrame in this WAL.
++*/
++static u32 walFramePgno(Wal *pWal, u32 iFrame){
++ int iHash = walFramePage(iFrame);
++ if( iHash==0 ){
++ return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
+ }
+-
+- *paRight = aLeft;
+- *pnRight = iOut;
+- memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut);
++ return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
+ }
+
+ /*
+-** Sort the elements in list aList using aContent[] as the sort key.
+-** Remove elements with duplicate keys, preferring to keep the
+-** larger aList[] values.
+-**
+-** The aList[] entries are indices into aContent[]. The values in
+-** aList[] are to be sorted so that for all J<K:
+-**
+-** aContent[aList[J]] < aContent[aList[K]]
+-**
+-** For any X and Y such that
++** Remove entries from the hash table that point to WAL slots greater
++** than pWal->hdr.mxFrame.
+ **
+-** aContent[aList[X]] == aContent[aList[Y]]
++** This function is called whenever pWal->hdr.mxFrame is decreased due
++** to a rollback or savepoint.
+ **
+-** Keep the larger of the two values aList[X] and aList[Y] and discard
+-** the smaller.
++** At most only the hash table containing pWal->hdr.mxFrame needs to be
++** updated. Any later hash tables will be automatically cleared when
++** pWal->hdr.mxFrame advances to the point where those hash tables are
++** actually needed.
+ */
+-static void walMergesort(
+- const u32 *aContent, /* Pages in wal */
+- ht_slot *aBuffer, /* Buffer of at least *pnList items to use */
+- ht_slot *aList, /* IN/OUT: List to sort */
+- int *pnList /* IN/OUT: Number of elements in aList[] */
+-){
+- struct Sublist {
+- int nList; /* Number of elements in aList */
+- ht_slot *aList; /* Pointer to sub-list content */
+- };
++static void walCleanupHash(Wal *pWal){
++ volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */
++ volatile u32 *aPgno = 0; /* Page number array for hash table */
++ u32 iZero = 0; /* frame == (aHash[x]+iZero) */
++ int iLimit = 0; /* Zero values greater than this */
++ int nByte; /* Number of bytes to zero in aPgno[] */
++ int i; /* Used to iterate through aHash[] */
+
+- const int nList = *pnList; /* Size of input list */
+- int nMerge = 0; /* Number of elements in list aMerge */
+- ht_slot *aMerge = 0; /* List to be merged */
+- int iList; /* Index into input list */
+- int iSub = 0; /* Index into aSub array */
+- struct Sublist aSub[13]; /* Array of sub-lists */
++ assert( pWal->writeLock );
++ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
++ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE );
++ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 );
+
+- memset(aSub, 0, sizeof(aSub));
+- assert( nList<=HASHTABLE_NPAGE && nList>0 );
+- assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) );
++ if( pWal->hdr.mxFrame==0 ) return;
+
+- for(iList=0; iList<nList; iList++){
+- nMerge = 1;
+- aMerge = &aList[iList];
+- for(iSub=0; iList & (1<<iSub); iSub++){
+- struct Sublist *p = &aSub[iSub];
+- assert( p->aList && p->nList<=(1<<iSub) );
+- assert( p->aList==&aList[iList&~((2<<iSub)-1)] );
+- walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
+- }
+- aSub[iSub].aList = aMerge;
+- aSub[iSub].nList = nMerge;
+- }
++ /* Obtain pointers to the hash-table and page-number array containing
++ ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
++ ** that the page said hash-table and array reside on is already mapped.
++ */
++ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
++ assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
++ walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
+
+- for(iSub++; iSub<ArraySize(aSub); iSub++){
+- if( nList & (1<<iSub) ){
+- struct Sublist *p = &aSub[iSub];
+- assert( p->nList<=(1<<iSub) );
+- assert( p->aList==&aList[nList&~((2<<iSub)-1)] );
+- walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
++ /* Zero all hash-table entries that correspond to frame numbers greater
++ ** than pWal->hdr.mxFrame.
++ */
++ iLimit = pWal->hdr.mxFrame - iZero;
++ assert( iLimit>0 );
++ for(i=0; i<HASHTABLE_NSLOT; i++){
++ if( aHash[i]>iLimit ){
++ aHash[i] = 0;
+ }
+ }
+- assert( aMerge==aList );
+- *pnList = nMerge;
++
++ /* Zero the entries in the aPgno array that correspond to frames with
++ ** frame numbers greater than pWal->hdr.mxFrame.
++ */
++ nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
++ memset((void *)&aPgno[iLimit+1], 0, nByte);
+
+-#ifdef SQLITE_DEBUG
+- {
+- int i;
+- for(i=1; i<*pnList; i++){
+- assert( aContent[aList[i]] > aContent[aList[i-1]] );
++#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
++ /* Verify that the every entry in the mapping region is still reachable
++ ** via the hash table even after the cleanup.
++ */
++ if( iLimit ){
++ int i; /* Loop counter */
++ int iKey; /* Hash key */
++ for(i=1; i<=iLimit; i++){
++ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
++ if( aHash[iKey]==i ) break;
++ }
++ assert( aHash[iKey]==i );
+ }
+ }
+-#endif
++#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
+ }
+
+-/*
+-** Free an iterator allocated by walIteratorInit().
+-*/
+-static void walIteratorFree(WalIterator *p){
+- sqlite3ScratchFree(p);
+-}
+
+ /*
+-** Construct a WalInterator object that can be used to loop over all
+-** pages in the WAL in ascending order. The caller must hold the checkpoint
+-** lock.
+-**
+-** On success, make *pp point to the newly allocated WalInterator object
+-** return SQLITE_OK. Otherwise, return an error code. If this routine
+-** returns an error, the value of *pp is undefined.
+-**
+-** The calling routine should invoke walIteratorFree() to destroy the
+-** WalIterator object when it has finished with it.
++** Set an entry in the wal-index that will map database page number
++** pPage into WAL frame iFrame.
+ */
+-static int walIteratorInit(Wal *pWal, WalIterator **pp){
+- WalIterator *p; /* Return value */
+- int nSegment; /* Number of segments to merge */
+- u32 iLast; /* Last frame in log */
+- int nByte; /* Number of bytes to allocate */
+- int i; /* Iterator variable */
+- ht_slot *aTmp; /* Temp space used by merge-sort */
+- int rc = SQLITE_OK; /* Return Code */
++static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
++ int rc; /* Return code */
++ u32 iZero = 0; /* One less than frame number of aPgno[1] */
++ volatile u32 *aPgno = 0; /* Page number array */
++ volatile ht_slot *aHash = 0; /* Hash table */
+
+- /* This routine only runs while holding the checkpoint lock. And
+- ** it only runs if there is actually content in the log (mxFrame>0).
++ rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
++
++ /* Assuming the wal-index file was successfully mapped, populate the
++ ** page number array and hash table entry.
+ */
+- assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
+- iLast = pWal->hdr.mxFrame;
++ if( rc==SQLITE_OK ){
++ int iKey; /* Hash table key */
++ int idx; /* Value to write to hash-table slot */
++ int nCollide; /* Number of hash collisions */
+
+- /* Allocate space for the WalIterator object. */
+- nSegment = walFramePage(iLast) + 1;
+- nByte = sizeof(WalIterator)
+- + (nSegment-1)*sizeof(struct WalSegment)
+- + iLast*sizeof(ht_slot);
+- p = (WalIterator *)sqlite3ScratchMalloc(nByte);
+- if( !p ){
+- return SQLITE_NOMEM;
+- }
+- memset(p, 0, nByte);
+- p->nSegment = nSegment;
++ idx = iFrame - iZero;
++ assert( idx <= HASHTABLE_NSLOT/2 + 1 );
++
++ /* If this is the first entry to be added to this hash-table, zero the
++ ** entire hash table and aPgno[] array before proceding.
++ */
++ if( idx==1 ){
++ int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
++ memset((void*)&aPgno[1], 0, nByte);
++ }
+
+- /* Allocate temporary space used by the merge-sort routine. This block
+- ** of memory will be freed before this function returns.
+- */
+- aTmp = (ht_slot *)sqlite3ScratchMalloc(
+- sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
+- );
+- if( !aTmp ){
+- rc = SQLITE_NOMEM;
+- }
++ /* If the entry in aPgno[] is already set, then the previous writer
++ ** must have exited unexpectedly in the middle of a transaction (after
++ ** writing one or more dirty pages to the WAL to free up memory).
++ ** Remove the remnants of that writers uncommitted transaction from
++ ** the hash-table before writing any new entries.
++ */
++ if( aPgno[idx] ){
++ walCleanupHash(pWal);
++ assert( !aPgno[idx] );
++ }
+
+- for(i=0; rc==SQLITE_OK && i<nSegment; i++){
+- volatile ht_slot *aHash;
+- u32 iZero;
+- volatile u32 *aPgno;
++ /* Write the aPgno[] array entry and the hash-table slot. */
++ nCollide = idx;
++ for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
++ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
++ }
++ aPgno[idx] = iPage;
++ aHash[iKey] = (ht_slot)idx;
+
+- rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
+- if( rc==SQLITE_OK ){
+- int j; /* Counter variable */
+- int nEntry; /* Number of entries in this segment */
+- ht_slot *aIndex; /* Sorted index for this segment */
++#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
++ /* Verify that the number of entries in the hash table exactly equals
++ ** the number of entries in the mapping region.
++ */
++ {
++ int i; /* Loop counter */
++ int nEntry = 0; /* Number of entries in the hash table */
++ for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
++ assert( nEntry==idx );
++ }
+
+- aPgno++;
+- if( (i+1)==nSegment ){
+- nEntry = (int)(iLast - iZero);
+- }else{
+- nEntry = (int)((u32*)aHash - (u32*)aPgno);
+- }
+- aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
+- iZero++;
+-
+- for(j=0; j<nEntry; j++){
+- aIndex[j] = (ht_slot)j;
++ /* Verify that the every entry in the mapping region is reachable
++ ** via the hash table. This turns out to be a really, really expensive
++ ** thing to check, so only do this occasionally - not on every
++ ** iteration.
++ */
++ if( (idx&0x3ff)==0 ){
++ int i; /* Loop counter */
++ for(i=1; i<=idx; i++){
++ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
++ if( aHash[iKey]==i ) break;
++ }
++ assert( aHash[iKey]==i );
+ }
+- walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
+- p->aSegment[i].iZero = iZero;
+- p->aSegment[i].nEntry = nEntry;
+- p->aSegment[i].aIndex = aIndex;
+- p->aSegment[i].aPgno = (u32 *)aPgno;
+ }
++#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
+ }
+- sqlite3ScratchFree(aTmp);
+
+- if( rc!=SQLITE_OK ){
+- walIteratorFree(p);
+- }
+- *pp = p;
+- return rc;
+-}
+
+-/*
+-** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
+-** n. If the attempt fails and parameter xBusy is not NULL, then it is a
+-** busy-handler function. Invoke it and retry the lock until either the
+-** lock is successfully obtained or the busy-handler returns 0.
+-*/
+-static int walBusyLock(
+- Wal *pWal, /* WAL connection */
+- int (*xBusy)(void*), /* Function to call when busy */
+- void *pBusyArg, /* Context argument for xBusyHandler */
+- int lockIdx, /* Offset of first byte to lock */
+- int n /* Number of bytes to lock */
+-){
+- int rc;
+- do {
+- rc = walLockExclusive(pWal, lockIdx, n);
+- }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
+ return rc;
+ }
+
+-/*
+-** The cache of the wal-index header must be valid to call this function.
+-** Return the page-size in bytes used by the database.
+-*/
+-static int walPagesize(Wal *pWal){
+- return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
+-}
+
+ /*
+-** Copy as much content as we can from the WAL back into the database file
+-** in response to an sqlite3_wal_checkpoint() request or the equivalent.
+-**
+-** The amount of information copies from WAL to database might be limited
+-** by active readers. This routine will never overwrite a database page
+-** that a concurrent reader might be using.
+-**
+-** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
+-** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
+-** checkpoints are always run by a background thread or background
+-** process, foreground threads will never block on a lengthy fsync call.
+-**
+-** Fsync is called on the WAL before writing content out of the WAL and
+-** into the database. This ensures that if the new content is persistent
+-** in the WAL and can be recovered following a power-loss or hard reset.
+-**
+-** Fsync is also called on the database file if (and only if) the entire
+-** WAL content is copied into the database file. This second fsync makes
+-** it safe to delete the WAL since the new content will persist in the
+-** database file.
+-**
+-** This routine uses and updates the nBackfill field of the wal-index header.
+-** This is the only routine tha will increase the value of nBackfill.
+-** (A WAL reset or recovery will revert nBackfill to zero, but not increase
+-** its value.)
++** Recover the wal-index by reading the write-ahead log file.
+ **
+-** The caller must be holding sufficient locks to ensure that no other
+-** checkpoint is running (in any other thread or process) at the same
+-** time.
++** This routine first tries to establish an exclusive lock on the
++** wal-index to prevent other threads/processes from doing anything
++** with the WAL or wal-index while recovery is running. The
++** WAL_RECOVER_LOCK is also held so that other threads will know
++** that this thread is running recovery. If unable to establish
++** the necessary locks, this routine returns SQLITE_BUSY.
+ */
+-static int walCheckpoint(
+- Wal *pWal, /* Wal connection */
+- int eMode, /* One of PASSIVE, FULL or RESTART */
+- int (*xBusyCall)(void*), /* Function to call when busy */
+- void *pBusyArg, /* Context argument for xBusyHandler */
+- int sync_flags, /* Flags for OsSync() (or 0) */
+- u8 *zBuf /* Temporary buffer to use */
+-){
+- int rc; /* Return code */
+- int szPage; /* Database page-size */
+- WalIterator *pIter = 0; /* Wal iterator context */
+- u32 iDbpage = 0; /* Next database page to write */
+- u32 iFrame = 0; /* Wal frame containing data for iDbpage */
+- u32 mxSafeFrame; /* Max frame that can be backfilled */
+- u32 mxPage; /* Max database page to write */
+- int i; /* Loop counter */
+- volatile WalCkptInfo *pInfo; /* The checkpoint status information */
+- int (*xBusy)(void*) = 0; /* Function to call when waiting for locks */
++static int walIndexRecover(Wal *pWal){
++ int rc; /* Return Code */
++ i64 nSize; /* Size of log file */
++ u32 aFrameCksum[2] = {0, 0};
++ int iLock; /* Lock offset to lock for checkpoint */
++ int nLock; /* Number of locks to hold */
+
+- szPage = walPagesize(pWal);
+- testcase( szPage<=32768 );
+- testcase( szPage>=65536 );
+- pInfo = walCkptInfo(pWal);
+- if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
++ /* Obtain an exclusive lock on all byte in the locking range not already
++ ** locked by the caller. The caller is guaranteed to have locked the
++ ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
++ ** If successful, the same bytes that are locked here are unlocked before
++ ** this function returns.
++ */
++ assert( pWal->ckptLock==1 || pWal->ckptLock==0 );
++ assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
++ assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
++ assert( pWal->writeLock );
++ iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
++ nLock = SQLITE_SHM_NLOCK - iLock;
++ rc = walLockExclusive(pWal, iLock, nLock);
++ if( rc ){
++ return rc;
++ }
++ WALTRACE(("WAL%p: recovery begin...\n", pWal));
+
+- /* Allocate the iterator */
+- rc = walIteratorInit(pWal, &pIter);
++ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
++
++ rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
+ if( rc!=SQLITE_OK ){
+- return rc;
++ goto recovery_error;
+ }
+- assert( pIter );
+
+- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall;
++ if( nSize>WAL_HDRSIZE ){
++ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
++ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
++ int szFrame; /* Number of bytes in buffer aFrame[] */
++ u8 *aData; /* Pointer to data part of aFrame buffer */
++ int iFrame; /* Index of last frame read */
++ i64 iOffset; /* Next offset to read from log file */
++ int szPage; /* Page size according to the log */
++ u32 magic; /* Magic value read from WAL header */
++ u32 version; /* Magic value read from WAL header */
++ int isValid; /* True if this frame is valid */
+
+- /* Compute in mxSafeFrame the index of the last frame of the WAL that is
+- ** safe to write into the database. Frames beyond mxSafeFrame might
+- ** overwrite database pages that are in use by active readers and thus
+- ** cannot be backfilled from the WAL.
+- */
+- mxSafeFrame = pWal->hdr.mxFrame;
+- mxPage = pWal->hdr.nPage;
+- for(i=1; i<WAL_NREADER; i++){
+- u32 y = pInfo->aReadMark[i];
+- if( mxSafeFrame>y ){
+- assert( y<=pWal->hdr.mxFrame );
+- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
+- if( rc==SQLITE_OK ){
+- pInfo->aReadMark[i] = READMARK_NOT_USED;
+- walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+- }else if( rc==SQLITE_BUSY ){
+- mxSafeFrame = y;
+- xBusy = 0;
+- }else{
+- goto walcheckpoint_out;
+- }
++ /* Read in the WAL header. */
++ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
++ if( rc!=SQLITE_OK ){
++ goto recovery_error;
+ }
+- }
+
+- if( pInfo->nBackfill<mxSafeFrame
+- && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
+- ){
+- i64 nSize; /* Current size of database file */
+- u32 nBackfill = pInfo->nBackfill;
++ /* If the database page size is not a power of two, or is greater than
++ ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
++ ** data. Similarly, if the 'magic' value is invalid, ignore the whole
++ ** WAL file.
++ */
++ magic = sqlite3Get4byte(&aBuf[0]);
++ szPage = sqlite3Get4byte(&aBuf[8]);
++ if( (magic&0xFFFFFFFE)!=WAL_MAGIC
++ || szPage&(szPage-1)
++ || szPage>SQLITE_MAX_PAGE_SIZE
++ || szPage<512
++ ){
++ goto finished;
++ }
++ pWal->hdr.bigEndCksum = (u8)(magic&0x00000001);
++ pWal->szPage = szPage;
++ pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
++ memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
+
+- /* Sync the WAL to disk */
+- if( sync_flags ){
+- rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
++ /* Verify that the WAL header checksum is correct */
++ walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
++ aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
++ );
++ if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
++ || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28])
++ ){
++ goto finished;
+ }
+
+- /* If the database file may grow as a result of this checkpoint, hint
+- ** about the eventual size of the db file to the VFS layer.
+- */
+- if( rc==SQLITE_OK ){
+- i64 nReq = ((i64)mxPage * szPage);
+- rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
+- if( rc==SQLITE_OK && nSize<nReq ){
+- sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+- }
++ /* Verify that the version number on the WAL format is one that
++ ** are able to understand */
++ version = sqlite3Get4byte(&aBuf[4]);
++ if( version!=WAL_MAX_VERSION ){
++ rc = SQLITE_CANTOPEN_BKPT;
++ goto finished;
+ }
+
+- /* Iterate through the contents of the WAL, copying data to the db file. */
+- while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
+- i64 iOffset;
+- assert( walFramePgno(pWal, iFrame)==iDbpage );
+- if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
+- iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
+- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
+- rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
++ /* Malloc a buffer to read frames into. */
++ szFrame = szPage + WAL_FRAME_HDRSIZE;
++ aFrame = (u8 *)sqlite3_malloc(szFrame);
++ if( !aFrame ){
++ rc = SQLITE_NOMEM;
++ goto recovery_error;
++ }
++ aData = &aFrame[WAL_FRAME_HDRSIZE];
++
++ /* Read all frames from the log file. */
++ iFrame = 0;
++ for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
++ u32 pgno; /* Database page number for frame */
++ u32 nTruncate; /* dbsize field from frame header */
++
++ /* Read and decode the next log frame. */
++ iFrame++;
++ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
+ if( rc!=SQLITE_OK ) break;
+- iOffset = (iDbpage-1)*(i64)szPage;
+- testcase( IS_BIG_INT(iOffset) );
+- rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
++ isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
++ if( !isValid ) break;
++ rc = walIndexAppend(pWal, iFrame, pgno);
+ if( rc!=SQLITE_OK ) break;
+- }
+
+- /* If work was actually accomplished... */
+- if( rc==SQLITE_OK ){
+- if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
+- i64 szDb = pWal->hdr.nPage*(i64)szPage;
+- testcase( IS_BIG_INT(szDb) );
+- rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
+- if( rc==SQLITE_OK && sync_flags ){
+- rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+- }
+- }
+- if( rc==SQLITE_OK ){
+- pInfo->nBackfill = mxSafeFrame;
++ /* If nTruncate is non-zero, this is a commit record. */
++ if( nTruncate ){
++ pWal->hdr.mxFrame = iFrame;
++ pWal->hdr.nPage = nTruncate;
++ pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
++ testcase( szPage<=32768 );
++ testcase( szPage>=65536 );
++ aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
++ aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
+ }
+ }
+
+- /* Release the reader lock held while backfilling */
+- walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
++ sqlite3_free(aFrame);
+ }
+
+- if( rc==SQLITE_BUSY ){
+- /* Reset the return code so as not to report a checkpoint failure
+- ** just because there are active readers. */
+- rc = SQLITE_OK;
+- }
++finished:
++ if( rc==SQLITE_OK ){
++ volatile WalCkptInfo *pInfo;
++ int i;
++ pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
++ pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
++ walIndexWriteHdr(pWal);
+
+- /* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal
+- ** file has been copied into the database file, then block until all
+- ** readers have finished using the wal file. This ensures that the next
+- ** process to write to the database restarts the wal file.
+- */
+- if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
+- assert( pWal->writeLock );
+- if( pInfo->nBackfill<pWal->hdr.mxFrame ){
+- rc = SQLITE_BUSY;
+- }else if( eMode==SQLITE_CHECKPOINT_RESTART ){
+- assert( mxSafeFrame==pWal->hdr.mxFrame );
+- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
+- if( rc==SQLITE_OK ){
+- walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+- }
++ /* Reset the checkpoint-header. This is safe because this thread is
++ ** currently holding locks that exclude all other readers, writers and
++ ** checkpointers.
++ */
++ pInfo = walCkptInfo(pWal);
++ pInfo->nBackfill = 0;
++ pInfo->aReadMark[0] = 0;
++ for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
++
++ /* If more than one frame was recovered from the log file, report an
++ ** event via sqlite3_log(). This is to help with identifying performance
++ ** problems caused by applications routinely shutting down without
++ ** checkpointing the log file.
++ */
++ if( pWal->hdr.nPage ){
++ sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
++ pWal->hdr.nPage, pWal->zWalName
++ );
+ }
+ }
+
+- walcheckpoint_out:
+- walIteratorFree(pIter);
++recovery_error:
++ WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
++ walUnlockExclusive(pWal, iLock, nLock);
+ return rc;
+ }
+
+ /*
+-** If the WAL file is currently larger than nMax bytes in size, truncate
+-** it to exactly nMax bytes. If an error occurs while doing so, ignore it.
+-*/
+-static void walLimitSize(Wal *pWal, i64 nMax){
+- i64 sz;
+- int rx;
+- sqlite3BeginBenignMalloc();
+- rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
+- if( rx==SQLITE_OK && (sz > nMax ) ){
+- rx = sqlite3OsTruncate(pWal->pWalFd, nMax);
+- }
+- sqlite3EndBenignMalloc();
+- if( rx ){
+- sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
+- }
+-}
+-
+-/*
+-** Close a connection to a log file.
++** Close an open wal-index.
+ */
+-SQLITE_PRIVATE int sqlite3WalClose(
+- Wal *pWal, /* Wal to close */
+- int sync_flags, /* Flags to pass to OsSync() (or 0) */
+- int nBuf,
+- u8 *zBuf /* Buffer of at least nBuf bytes */
+-){
+- int rc = SQLITE_OK;
+- if( pWal ){
+- int isDelete = 0; /* True to unlink wal and wal-index files */
+-
+- /* If an EXCLUSIVE lock can be obtained on the database file (using the
+- ** ordinary, rollback-mode locking methods, this guarantees that the
+- ** connection associated with this log file is the only connection to
+- ** the database. In this case checkpoint the database and unlink both
+- ** the wal and wal-index files.
+- **
+- ** The EXCLUSIVE lock is not released before returning.
+- */
+- rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
+- if( rc==SQLITE_OK ){
+- if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
+- pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
+- }
+- rc = sqlite3WalCheckpoint(
+- pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
+- );
+- if( rc==SQLITE_OK ){
+- int bPersist = -1;
+- sqlite3OsFileControlHint(
+- pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist
+- );
+- if( bPersist!=1 ){
+- /* Try to delete the WAL file if the checkpoint completed and
+- ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
+- ** mode (!bPersist) */
+- isDelete = 1;
+- }else if( pWal->mxWalSize>=0 ){
+- /* Try to truncate the WAL file to zero bytes if the checkpoint
+- ** completed and fsynced (rc==SQLITE_OK) and we are in persistent
+- ** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a
+- ** non-negative value (pWal->mxWalSize>=0). Note that we truncate
+- ** to zero bytes as truncating to the journal_size_limit might
+- ** leave a corrupt WAL file on disk. */
+- walLimitSize(pWal, 0);
+- }
+- }
+- }
+-
+- walIndexClose(pWal, isDelete);
+- sqlite3OsClose(pWal->pWalFd);
+- if( isDelete ){
+- sqlite3BeginBenignMalloc();
+- sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
+- sqlite3EndBenignMalloc();
++static void walIndexClose(Wal *pWal, int isDelete){
++ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
++ int i;
++ for(i=0; i<pWal->nWiData; i++){
++ sqlite3_free((void *)pWal->apWiData[i]);
++ pWal->apWiData[i] = 0;
+ }
+- WALTRACE(("WAL%p: closed\n", pWal));
+- sqlite3_free((void *)pWal->apWiData);
+- sqlite3_free(pWal);
++ }else{
++ sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
+ }
+- return rc;
+ }
+
+-/*
+-** Try to read the wal-index header. Return 0 on success and 1 if
+-** there is a problem.
+-**
+-** The wal-index is in shared memory. Another thread or process might
+-** be writing the header at the same time this procedure is trying to
+-** read it, which might result in inconsistency. A dirty read is detected
+-** by verifying that both copies of the header are the same and also by
+-** a checksum on the header.
++/*
++** Open a connection to the WAL file zWalName. The database file must
++** already be opened on connection pDbFd. The buffer that zWalName points
++** to must remain valid for the lifetime of the returned Wal* handle.
+ **
+-** If and only if the read is consistent and the header is different from
+-** pWal->hdr, then pWal->hdr is updated to the content of the new header
+-** and *pChanged is set to 1.
++** A SHARED lock should be held on the database file when this function
++** is called. The purpose of this SHARED lock is to prevent any other
++** client from unlinking the WAL or wal-index file. If another process
++** were to do this just after this client opened one of these files, the
++** system would be badly broken.
+ **
+-** If the checksum cannot be verified return non-zero. If the header
+-** is read successfully and the checksum verified, return zero.
++** If the log file is successfully opened, SQLITE_OK is returned and
++** *ppWal is set to point to a new WAL handle. If an error occurs,
++** an SQLite error code is returned and *ppWal is left unmodified.
+ */
+-static int walIndexTryHdr(Wal *pWal, int *pChanged){
+- u32 aCksum[2]; /* Checksum on the header content */
+- WalIndexHdr h1, h2; /* Two copies of the header content */
+- WalIndexHdr volatile *aHdr; /* Header in shared memory */
++SQLITE_PRIVATE int sqlite3WalOpen(
++ sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */
++ sqlite3_file *pDbFd, /* The open database file */
++ const char *zWalName, /* Name of the WAL file */
++ int bNoShm, /* True to run in heap-memory mode */
++ i64 mxWalSize, /* Truncate WAL to this size on reset */
++ Wal **ppWal /* OUT: Allocated Wal handle */
++){
++ int rc; /* Return Code */
++ Wal *pRet; /* Object to allocate and return */
++ int flags; /* Flags passed to OsOpen() */
+
+- /* The first page of the wal-index must be mapped at this point. */
+- assert( pWal->nWiData>0 && pWal->apWiData[0] );
++ assert( zWalName && zWalName[0] );
++ assert( pDbFd );
+
+- /* Read the header. This might happen concurrently with a write to the
+- ** same area of shared memory on a different CPU in a SMP,
+- ** meaning it is possible that an inconsistent snapshot is read
+- ** from the file. If this happens, return non-zero.
+- **
+- ** There are two copies of the header at the beginning of the wal-index.
+- ** When reading, read [0] first then [1]. Writes are in the reverse order.
+- ** Memory barriers are used to prevent the compiler or the hardware from
+- ** reordering the reads and writes.
++ /* In the amalgamation, the os_unix.c and os_win.c source files come before
++ ** this source file. Verify that the #defines of the locking byte offsets
++ ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
+ */
+- aHdr = walIndexHdr(pWal);
+- memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
+- walShmBarrier(pWal);
+- memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
++#ifdef WIN_SHM_BASE
++ assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
++#endif
++#ifdef UNIX_SHM_BASE
++ assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
++#endif
+
+- if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
+- return 1; /* Dirty read */
+- }
+- if( h1.isInit==0 ){
+- return 1; /* Malformed header - probably all zeros */
++
++ /* Allocate an instance of struct Wal to return. */
++ *ppWal = 0;
++ pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
++ if( !pRet ){
++ return SQLITE_NOMEM;
+ }
+- walChecksumBytes(1, (u8*)&h1, sizeof(h1)-sizeof(h1.aCksum), 0, aCksum);
+- if( aCksum[0]!=h1.aCksum[0] || aCksum[1]!=h1.aCksum[1] ){
+- return 1; /* Checksum does not match */
++
++ pRet->pVfs = pVfs;
++ pRet->pWalFd = (sqlite3_file *)&pRet[1];
++ pRet->pDbFd = pDbFd;
++ pRet->readLock = -1;
++ pRet->mxWalSize = mxWalSize;
++ pRet->zWalName = zWalName;
++ pRet->syncHeader = 1;
++ pRet->padToSectorBoundary = 1;
++ pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
++
++ /* Open file handle on the write-ahead log file. */
++ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
++ rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
++ if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
++ pRet->readOnly = WAL_RDONLY;
+ }
+
+- if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
+- *pChanged = 1;
+- memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr));
+- pWal->szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
+- testcase( pWal->szPage<=32768 );
+- testcase( pWal->szPage>=65536 );
++ if( rc!=SQLITE_OK ){
++ walIndexClose(pRet, 0);
++ sqlite3OsClose(pRet->pWalFd);
++ sqlite3_free(pRet);
++ }else{
++ int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
++ if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
++ if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
++ pRet->padToSectorBoundary = 0;
++ }
++ *ppWal = pRet;
++ WALTRACE(("WAL%d: opened\n", pRet));
+ }
++ return rc;
++}
+
+- /* The header was successfully read. Return zero. */
+- return 0;
++/*
++** Change the size to which the WAL file is trucated on each reset.
++*/
++SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){
++ if( pWal ) pWal->mxWalSize = iLimit;
+ }
+
+ /*
+-** Read the wal-index header from the wal-index and into pWal->hdr.
+-** If the wal-header appears to be corrupt, try to reconstruct the
+-** wal-index from the WAL before returning.
+-**
+-** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
+-** changed by this opertion. If pWal->hdr is unchanged, set *pChanged
+-** to 0.
++** Find the smallest page number out of all pages held in the WAL that
++** has not been returned by any prior invocation of this method on the
++** same WalIterator object. Write into *piFrame the frame index where
++** that page was last written into the WAL. Write into *piPage the page
++** number.
+ **
+-** If the wal-index header is successfully read, return SQLITE_OK.
+-** Otherwise an SQLite error code.
++** Return 0 on success. If there are no pages in the WAL with a page
++** number larger than *piPage, then return 1.
+ */
+-static int walIndexReadHdr(Wal *pWal, int *pChanged){
+- int rc; /* Return code */
+- int badHdr; /* True if a header read failed */
+- volatile u32 *page0; /* Chunk of wal-index containing header */
+-
+- /* Ensure that page 0 of the wal-index (the page that contains the
+- ** wal-index header) is mapped. Return early if an error occurs here.
+- */
+- assert( pChanged );
+- rc = walIndexPage(pWal, 0, &page0);
+- if( rc!=SQLITE_OK ){
+- return rc;
+- };
+- assert( page0 || pWal->writeLock==0 );
+-
+- /* If the first page of the wal-index has been mapped, try to read the
+- ** wal-index header immediately, without holding any lock. This usually
+- ** works, but may fail if the wal-index header is corrupt or currently
+- ** being modified by another thread or process.
+- */
+- badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
++static int walIteratorNext(
++ WalIterator *p, /* Iterator */
++ u32 *piPage, /* OUT: The page number of the next page */
++ u32 *piFrame /* OUT: Wal frame index of next page */
++){
++ u32 iMin; /* Result pgno must be greater than iMin */
++ u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */
++ int i; /* For looping through segments */
+
+- /* If the first attempt failed, it might have been due to a race
+- ** with a writer. So get a WRITE lock and try again.
+- */
+- assert( badHdr==0 || pWal->writeLock==0 );
+- if( badHdr ){
+- if( pWal->readOnly & WAL_SHM_RDONLY ){
+- if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
+- walUnlockShared(pWal, WAL_WRITE_LOCK);
+- rc = SQLITE_READONLY_RECOVERY;
+- }
+- }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
+- pWal->writeLock = 1;
+- if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
+- badHdr = walIndexTryHdr(pWal, pChanged);
+- if( badHdr ){
+- /* If the wal-index header is still malformed even while holding
+- ** a WRITE lock, it can only mean that the header is corrupted and
+- ** needs to be reconstructed. So run recovery to do exactly that.
+- */
+- rc = walIndexRecover(pWal);
+- *pChanged = 1;
++ iMin = p->iPrior;
++ assert( iMin<0xffffffff );
++ for(i=p->nSegment-1; i>=0; i--){
++ struct WalSegment *pSegment = &p->aSegment[i];
++ while( pSegment->iNext<pSegment->nEntry ){
++ u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]];
++ if( iPg>iMin ){
++ if( iPg<iRet ){
++ iRet = iPg;
++ *piFrame = pSegment->iZero + pSegment->aIndex[pSegment->iNext];
+ }
++ break;
+ }
+- pWal->writeLock = 0;
+- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
++ pSegment->iNext++;
++ }
++ }
++
++ *piPage = p->iPrior = iRet;
++ return (iRet==0xFFFFFFFF);
++}
++
++/*
++** This function merges two sorted lists into a single sorted list.
++**
++** aLeft[] and aRight[] are arrays of indices. The sort key is
++** aContent[aLeft[]] and aContent[aRight[]]. Upon entry, the following
++** is guaranteed for all J<K:
++**
++** aContent[aLeft[J]] < aContent[aLeft[K]]
++** aContent[aRight[J]] < aContent[aRight[K]]
++**
++** This routine overwrites aRight[] with a new (probably longer) sequence
++** of indices such that the aRight[] contains every index that appears in
++** either aLeft[] or the old aRight[] and such that the second condition
++** above is still met.
++**
++** The aContent[aLeft[X]] values will be unique for all X. And the
++** aContent[aRight[X]] values will be unique too. But there might be
++** one or more combinations of X and Y such that
++**
++** aLeft[X]!=aRight[Y] && aContent[aLeft[X]] == aContent[aRight[Y]]
++**
++** When that happens, omit the aLeft[X] and use the aRight[Y] index.
++*/
++static void walMerge(
++ const u32 *aContent, /* Pages in wal - keys for the sort */
++ ht_slot *aLeft, /* IN: Left hand input list */
++ int nLeft, /* IN: Elements in array *paLeft */
++ ht_slot **paRight, /* IN/OUT: Right hand input list */
++ int *pnRight, /* IN/OUT: Elements in *paRight */
++ ht_slot *aTmp /* Temporary buffer */
++){
++ int iLeft = 0; /* Current index in aLeft */
++ int iRight = 0; /* Current index in aRight */
++ int iOut = 0; /* Current index in output buffer */
++ int nRight = *pnRight;
++ ht_slot *aRight = *paRight;
++
++ assert( nLeft>0 && nRight>0 );
++ while( iRight<nRight || iLeft<nLeft ){
++ ht_slot logpage;
++ Pgno dbpage;
++
++ if( (iLeft<nLeft)
++ && (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
++ ){
++ logpage = aLeft[iLeft++];
++ }else{
++ logpage = aRight[iRight++];
+ }
+- }
++ dbpage = aContent[logpage];
+
+- /* If the header is read successfully, check the version number to make
+- ** sure the wal-index was not constructed with some future format that
+- ** this version of SQLite cannot understand.
+- */
+- if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
+- rc = SQLITE_CANTOPEN_BKPT;
++ aTmp[iOut++] = logpage;
++ if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
++
++ assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
++ assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
+ }
+
+- return rc;
++ *paRight = aLeft;
++ *pnRight = iOut;
++ memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut);
+ }
+
+ /*
+-** This is the value that walTryBeginRead returns when it needs to
+-** be retried.
+-*/
+-#define WAL_RETRY (-1)
+-
+-/*
+-** Attempt to start a read transaction. This might fail due to a race or
+-** other transient condition. When that happens, it returns WAL_RETRY to
+-** indicate to the caller that it is safe to retry immediately.
++** Sort the elements in list aList using aContent[] as the sort key.
++** Remove elements with duplicate keys, preferring to keep the
++** larger aList[] values.
+ **
+-** On success return SQLITE_OK. On a permanent failure (such an
+-** I/O error or an SQLITE_BUSY because another process is running
+-** recovery) return a positive error code.
++** The aList[] entries are indices into aContent[]. The values in
++** aList[] are to be sorted so that for all J<K:
+ **
+-** The useWal parameter is true to force the use of the WAL and disable
+-** the case where the WAL is bypassed because it has been completely
+-** checkpointed. If useWal==0 then this routine calls walIndexReadHdr()
+-** to make a copy of the wal-index header into pWal->hdr. If the
+-** wal-index header has changed, *pChanged is set to 1 (as an indication
+-** to the caller that the local paget cache is obsolete and needs to be
+-** flushed.) When useWal==1, the wal-index header is assumed to already
+-** be loaded and the pChanged parameter is unused.
++** aContent[aList[J]] < aContent[aList[K]]
+ **
+-** The caller must set the cnt parameter to the number of prior calls to
+-** this routine during the current read attempt that returned WAL_RETRY.
+-** This routine will start taking more aggressive measures to clear the
+-** race conditions after multiple WAL_RETRY returns, and after an excessive
+-** number of errors will ultimately return SQLITE_PROTOCOL. The
+-** SQLITE_PROTOCOL return indicates that some other process has gone rogue
+-** and is not honoring the locking protocol. There is a vanishingly small
+-** chance that SQLITE_PROTOCOL could be returned because of a run of really
+-** bad luck when there is lots of contention for the wal-index, but that
+-** possibility is so small that it can be safely neglected, we believe.
++** For any X and Y such that
+ **
+-** On success, this routine obtains a read lock on
+-** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is
+-** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1)
+-** that means the Wal does not hold any read lock. The reader must not
+-** access any database page that is modified by a WAL frame up to and
+-** including frame number aReadMark[pWal->readLock]. The reader will
+-** use WAL frames up to and including pWal->hdr.mxFrame if pWal->readLock>0
+-** Or if pWal->readLock==0, then the reader will ignore the WAL
+-** completely and get all content directly from the database file.
+-** If the useWal parameter is 1 then the WAL will never be ignored and
+-** this routine will always set pWal->readLock>0 on success.
+-** When the read transaction is completed, the caller must release the
+-** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1.
++** aContent[aList[X]] == aContent[aList[Y]]
+ **
+-** This routine uses the nBackfill and aReadMark[] fields of the header
+-** to select a particular WAL_READ_LOCK() that strives to let the
+-** checkpoint process do as much work as possible. This routine might
+-** update values of the aReadMark[] array in the header, but if it does
+-** so it takes care to hold an exclusive lock on the corresponding
+-** WAL_READ_LOCK() while changing values.
++** Keep the larger of the two values aList[X] and aList[Y] and discard
++** the smaller.
+ */
+-static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
+- volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
+- u32 mxReadMark; /* Largest aReadMark[] value */
+- int mxI; /* Index of largest aReadMark[] value */
+- int i; /* Loop counter */
+- int rc = SQLITE_OK; /* Return code */
++static void walMergesort(
++ const u32 *aContent, /* Pages in wal */
++ ht_slot *aBuffer, /* Buffer of at least *pnList items to use */
++ ht_slot *aList, /* IN/OUT: List to sort */
++ int *pnList /* IN/OUT: Number of elements in aList[] */
++){
++ struct Sublist {
++ int nList; /* Number of elements in aList */
++ ht_slot *aList; /* Pointer to sub-list content */
++ };
+
+- assert( pWal->readLock<0 ); /* Not currently locked */
++ const int nList = *pnList; /* Size of input list */
++ int nMerge = 0; /* Number of elements in list aMerge */
++ ht_slot *aMerge = 0; /* List to be merged */
++ int iList; /* Index into input list */
++ int iSub = 0; /* Index into aSub array */
++ struct Sublist aSub[13]; /* Array of sub-lists */
+
+- /* Take steps to avoid spinning forever if there is a protocol error.
+- **
+- ** Circumstances that cause a RETRY should only last for the briefest
+- ** instances of time. No I/O or other system calls are done while the
+- ** locks are held, so the locks should not be held for very long. But
+- ** if we are unlucky, another process that is holding a lock might get
+- ** paged out or take a page-fault that is time-consuming to resolve,
+- ** during the few nanoseconds that it is holding the lock. In that case,
+- ** it might take longer than normal for the lock to free.
+- **
+- ** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few
+- ** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this
+- ** is more of a scheduler yield than an actual delay. But on the 10th
+- ** an subsequent retries, the delays start becoming longer and longer,
+- ** so that on the 100th (and last) RETRY we delay for 21 milliseconds.
+- ** The total delay time before giving up is less than 1 second.
+- */
+- if( cnt>5 ){
+- int nDelay = 1; /* Pause time in microseconds */
+- if( cnt>100 ){
+- VVA_ONLY( pWal->lockError = 1; )
+- return SQLITE_PROTOCOL;
+- }
+- if( cnt>=10 ) nDelay = (cnt-9)*238; /* Max delay 21ms. Total delay 996ms */
+- sqlite3OsSleep(pWal->pVfs, nDelay);
+- }
++ memset(aSub, 0, sizeof(aSub));
++ assert( nList<=HASHTABLE_NPAGE && nList>0 );
++ assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) );
+
+- if( !useWal ){
+- rc = walIndexReadHdr(pWal, pChanged);
+- if( rc==SQLITE_BUSY ){
+- /* If there is not a recovery running in another thread or process
+- ** then convert BUSY errors to WAL_RETRY. If recovery is known to
+- ** be running, convert BUSY to BUSY_RECOVERY. There is a race here
+- ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY
+- ** would be technically correct. But the race is benign since with
+- ** WAL_RETRY this routine will be called again and will probably be
+- ** right on the second iteration.
+- */
+- if( pWal->apWiData[0]==0 ){
+- /* This branch is taken when the xShmMap() method returns SQLITE_BUSY.
+- ** We assume this is a transient condition, so return WAL_RETRY. The
+- ** xShmMap() implementation used by the default unix and win32 VFS
+- ** modules may return SQLITE_BUSY due to a race condition in the
+- ** code that determines whether or not the shared-memory region
+- ** must be zeroed before the requested page is returned.
+- */
+- rc = WAL_RETRY;
+- }else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){
+- walUnlockShared(pWal, WAL_RECOVER_LOCK);
+- rc = WAL_RETRY;
+- }else if( rc==SQLITE_BUSY ){
+- rc = SQLITE_BUSY_RECOVERY;
+- }
+- }
+- if( rc!=SQLITE_OK ){
+- return rc;
++ for(iList=0; iList<nList; iList++){
++ nMerge = 1;
++ aMerge = &aList[iList];
++ for(iSub=0; iList & (1<<iSub); iSub++){
++ struct Sublist *p = &aSub[iSub];
++ assert( p->aList && p->nList<=(1<<iSub) );
++ assert( p->aList==&aList[iList&~((2<<iSub)-1)] );
++ walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
+ }
++ aSub[iSub].aList = aMerge;
++ aSub[iSub].nList = nMerge;
+ }
+
+- pInfo = walCkptInfo(pWal);
+- if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
+- /* The WAL has been completely backfilled (or it is empty).
+- ** and can be safely ignored.
+- */
+- rc = walLockShared(pWal, WAL_READ_LOCK(0));
+- walShmBarrier(pWal);
+- if( rc==SQLITE_OK ){
+- if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
+- /* It is not safe to allow the reader to continue here if frames
+- ** may have been appended to the log before READ_LOCK(0) was obtained.
+- ** When holding READ_LOCK(0), the reader ignores the entire log file,
+- ** which implies that the database file contains a trustworthy
+- ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from
+- ** happening, this is usually correct.
+- **
+- ** However, if frames have been appended to the log (or if the log
+- ** is wrapped and written for that matter) before the READ_LOCK(0)
+- ** is obtained, that is not necessarily true. A checkpointer may
+- ** have started to backfill the appended frames but crashed before
+- ** it finished. Leaving a corrupt image in the database file.
+- */
+- walUnlockShared(pWal, WAL_READ_LOCK(0));
+- return WAL_RETRY;
+- }
+- pWal->readLock = 0;
+- return SQLITE_OK;
+- }else if( rc!=SQLITE_BUSY ){
+- return rc;
++ for(iSub++; iSub<ArraySize(aSub); iSub++){
++ if( nList & (1<<iSub) ){
++ struct Sublist *p = &aSub[iSub];
++ assert( p->nList<=(1<<iSub) );
++ assert( p->aList==&aList[nList&~((2<<iSub)-1)] );
++ walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
+ }
+ }
++ assert( aMerge==aList );
++ *pnList = nMerge;
+
+- /* If we get this far, it means that the reader will want to use
+- ** the WAL to get at content from recent commits. The job now is
+- ** to select one of the aReadMark[] entries that is closest to
+- ** but not exceeding pWal->hdr.mxFrame and lock that entry.
+- */
+- mxReadMark = 0;
+- mxI = 0;
+- for(i=1; i<WAL_NREADER; i++){
+- u32 thisMark = pInfo->aReadMark[i];
+- if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){
+- assert( thisMark!=READMARK_NOT_USED );
+- mxReadMark = thisMark;
+- mxI = i;
+- }
+- }
+- /* There was once an "if" here. The extra "{" is to preserve indentation. */
++#ifdef SQLITE_DEBUG
+ {
+- if( (pWal->readOnly & WAL_SHM_RDONLY)==0
+- && (mxReadMark<pWal->hdr.mxFrame || mxI==0)
+- ){
+- for(i=1; i<WAL_NREADER; i++){
+- rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+- 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;
+- }
+-
+- 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;
++ int i;
++ for(i=1; i<*pnList; i++){
++ assert( aContent[aList[i]] > aContent[aList[i-1]] );
+ }
+ }
+- return rc;
+-}
+-
+-/*
+-** Begin a read transaction on the database.
+-**
+-** This routine used to be called sqlite3OpenSnapshot() and with good reason:
+-** it takes a snapshot of the state of the WAL and wal-index for the current
+-** instant in time. The current thread will continue to use this snapshot.
+-** Other threads might append new content to the WAL and wal-index but
+-** that extra content is ignored by the current thread.
+-**
+-** If the database contents have changes since the previous read
+-** transaction, then *pChanged is set to 1 before returning. The
+-** Pager layer will use this to know that is cache is stale and
+-** needs to be flushed.
+-*/
+-SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+- int rc; /* Return code */
+- int cnt = 0; /* Number of TryBeginRead attempts */
+-
+- do{
+- rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
+- }while( rc==WAL_RETRY );
+- testcase( (rc&0xff)==SQLITE_BUSY );
+- testcase( (rc&0xff)==SQLITE_IOERR );
+- testcase( rc==SQLITE_PROTOCOL );
+- testcase( rc==SQLITE_OK );
+- return rc;
++#endif
+ }
+
+-/*
+-** Finish with a read transaction. All this does is release the
+-** read-lock.
++/*
++** Free an iterator allocated by walIteratorInit().
+ */
+-SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
+- sqlite3WalEndWriteTransaction(pWal);
+- if( pWal->readLock>=0 ){
+- walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+- pWal->readLock = -1;
+- }
++static void walIteratorFree(WalIterator *p){
++ sqlite3ScratchFree(p);
+ }
+
+ /*
+-** Read a page from the WAL, if it is present in the WAL and if the
+-** current read transaction is configured to use the WAL.
++** Construct a WalInterator object that can be used to loop over all
++** pages in the WAL in ascending order. The caller must hold the checkpoint
++** lock.
+ **
+-** The *pInWal is set to 1 if the requested page is in the WAL and
+-** has been loaded. Or *pInWal is set to 0 if the page was not in
+-** the WAL and needs to be read out of the database.
++** On success, make *pp point to the newly allocated WalInterator object
++** return SQLITE_OK. Otherwise, return an error code. If this routine
++** returns an error, the value of *pp is undefined.
++**
++** The calling routine should invoke walIteratorFree() to destroy the
++** WalIterator object when it has finished with it.
+ */
+-SQLITE_PRIVATE int sqlite3WalRead(
+- Wal *pWal, /* WAL handle */
+- Pgno pgno, /* Database page number to read data for */
+- int *pInWal, /* OUT: True if data is read from WAL */
+- int nOut, /* Size of buffer pOut in bytes */
+- u8 *pOut /* Buffer to write page data to */
+-){
+- u32 iRead = 0; /* If !=0, WAL frame to return data from */
+- u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
+- int iHash; /* Used to loop through N hash tables */
+-
+- /* This routine is only be called from within a read transaction. */
+- assert( pWal->readLock>=0 || pWal->lockError );
++static int walIteratorInit(Wal *pWal, WalIterator **pp){
++ WalIterator *p; /* Return value */
++ int nSegment; /* Number of segments to merge */
++ u32 iLast; /* Last frame in log */
++ int nByte; /* Number of bytes to allocate */
++ int i; /* Iterator variable */
++ ht_slot *aTmp; /* Temp space used by merge-sort */
++ int rc = SQLITE_OK; /* Return Code */
+
+- /* If the "last page" field of the wal-index header snapshot is 0, then
+- ** no data will be read from the wal under any circumstances. Return early
+- ** in this case as an optimization. Likewise, if pWal->readLock==0,
+- ** then the WAL is ignored by the reader so return early, as if the
+- ** WAL were empty.
++ /* This routine only runs while holding the checkpoint lock. And
++ ** it only runs if there is actually content in the log (mxFrame>0).
+ */
+- if( iLast==0 || pWal->readLock==0 ){
+- *pInWal = 0;
+- return SQLITE_OK;
++ assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
++ iLast = pWal->hdr.mxFrame;
++
++ /* Allocate space for the WalIterator object. */
++ nSegment = walFramePage(iLast) + 1;
++ nByte = sizeof(WalIterator)
++ + (nSegment-1)*sizeof(struct WalSegment)
++ + iLast*sizeof(ht_slot);
++ p = (WalIterator *)sqlite3ScratchMalloc(nByte);
++ if( !p ){
++ return SQLITE_NOMEM;
+ }
++ memset(p, 0, nByte);
++ p->nSegment = nSegment;
+
+- /* Search the hash table or tables for an entry matching page number
+- ** pgno. Each iteration of the following for() loop searches one
+- ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames).
+- **
+- ** This code might run concurrently to the code in walIndexAppend()
+- ** that adds entries to the wal-index (and possibly to this hash
+- ** table). This means the value just read from the hash
+- ** slot (aHash[iKey]) may have been added before or after the
+- ** current read transaction was opened. Values added after the
+- ** read transaction was opened may have been written incorrectly -
+- ** i.e. these slots may contain garbage data. However, we assume
+- ** that any slots written before the current read transaction was
+- ** opened remain unmodified.
+- **
+- ** For the reasons above, the if(...) condition featured in the inner
+- ** loop of the following block is more stringent that would be required
+- ** if we had exclusive access to the hash-table:
+- **
+- ** (aPgno[iFrame]==pgno):
+- ** This condition filters out normal hash-table collisions.
+- **
+- ** (iFrame<=iLast):
+- ** This condition filters out entries that were added to the hash
+- ** table after the current read-transaction had started.
++ /* Allocate temporary space used by the merge-sort routine. This block
++ ** of memory will be freed before this function returns.
+ */
+- for(iHash=walFramePage(iLast); iHash>=0 && iRead==0; iHash--){
+- volatile ht_slot *aHash; /* Pointer to hash table */
+- volatile u32 *aPgno; /* Pointer to array of page numbers */
+- u32 iZero; /* Frame number corresponding to aPgno[0] */
+- int iKey; /* Hash slot index */
+- int nCollide; /* Number of hash collisions remaining */
+- int rc; /* Error code */
+-
+- rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
+- if( rc!=SQLITE_OK ){
+- return rc;
+- }
+- nCollide = HASHTABLE_NSLOT;
+- for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
+- u32 iFrame = aHash[iKey] + iZero;
+- if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
+- /* assert( iFrame>iRead ); -- not true if there is corruption */
+- iRead = iFrame;
+- }
+- if( (nCollide--)==0 ){
+- return SQLITE_CORRUPT_BKPT;
+- }
+- }
++ aTmp = (ht_slot *)sqlite3ScratchMalloc(
++ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
++ );
++ if( !aTmp ){
++ rc = SQLITE_NOMEM;
+ }
+
+-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+- /* If expensive assert() statements are available, do a linear search
+- ** of the wal-index file content. Make sure the results agree with the
+- ** result obtained using the hash indexes above. */
+- {
+- u32 iRead2 = 0;
+- u32 iTest;
+- for(iTest=iLast; iTest>0; iTest--){
+- if( walFramePgno(pWal, iTest)==pgno ){
+- iRead2 = iTest;
+- break;
+- }
+- }
+- assert( iRead==iRead2 );
+- }
+-#endif
++ for(i=0; rc==SQLITE_OK && i<nSegment; i++){
++ volatile ht_slot *aHash;
++ u32 iZero;
++ volatile u32 *aPgno;
+
+- /* If iRead is non-zero, then it is the log frame number that contains the
+- ** required page. Read and return data from the log file.
+- */
+- if( iRead ){
+- int sz;
+- i64 iOffset;
+- sz = pWal->hdr.szPage;
+- sz = (sz&0xfe00) + ((sz&0x0001)<<16);
+- testcase( sz<=32768 );
+- testcase( sz>=65536 );
+- iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
+- *pInWal = 1;
+- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+- return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
++ rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
++ if( rc==SQLITE_OK ){
++ int j; /* Counter variable */
++ int nEntry; /* Number of entries in this segment */
++ ht_slot *aIndex; /* Sorted index for this segment */
++
++ aPgno++;
++ if( (i+1)==nSegment ){
++ nEntry = (int)(iLast - iZero);
++ }else{
++ nEntry = (int)((u32*)aHash - (u32*)aPgno);
++ }
++ aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
++ iZero++;
++
++ for(j=0; j<nEntry; j++){
++ aIndex[j] = (ht_slot)j;
++ }
++ walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
++ p->aSegment[i].iZero = iZero;
++ p->aSegment[i].nEntry = nEntry;
++ p->aSegment[i].aIndex = aIndex;
++ p->aSegment[i].aPgno = (u32 *)aPgno;
++ }
+ }
++ sqlite3ScratchFree(aTmp);
+
+- *pInWal = 0;
+- return SQLITE_OK;
++ if( rc!=SQLITE_OK ){
++ walIteratorFree(p);
++ }
++ *pp = p;
++ return rc;
+ }
+
+-
+-/*
+-** Return the size of the database in pages (or zero, if unknown).
++/*
++** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
++** n. If the attempt fails and parameter xBusy is not NULL, then it is a
++** busy-handler function. Invoke it and retry the lock until either the
++** lock is successfully obtained or the busy-handler returns 0.
+ */
+-SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
+- if( pWal && ALWAYS(pWal->readLock>=0) ){
+- return pWal->hdr.nPage;
+- }
+- return 0;
++static int walBusyLock(
++ Wal *pWal, /* WAL connection */
++ int (*xBusy)(void*), /* Function to call when busy */
++ void *pBusyArg, /* Context argument for xBusyHandler */
++ int lockIdx, /* Offset of first byte to lock */
++ int n /* Number of bytes to lock */
++){
++ int rc;
++ do {
++ rc = walLockExclusive(pWal, lockIdx, n);
++ }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
++ return rc;
+ }
+
++/*
++** The cache of the wal-index header must be valid to call this function.
++** Return the page-size in bytes used by the database.
++*/
++static int walPagesize(Wal *pWal){
++ return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
++}
+
+-/*
+-** This function starts a write transaction on the WAL.
++/*
++** Copy as much content as we can from the WAL back into the database file
++** in response to an sqlite3_wal_checkpoint() request or the equivalent.
+ **
+-** A read transaction must have already been started by a prior call
+-** to sqlite3WalBeginReadTransaction().
++** The amount of information copies from WAL to database might be limited
++** by active readers. This routine will never overwrite a database page
++** that a concurrent reader might be using.
+ **
+-** If another thread or process has written into the database since
+-** the read transaction was started, then it is not possible for this
+-** thread to write as doing so would cause a fork. So this routine
+-** returns SQLITE_BUSY in that case and no write transaction is started.
++** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
++** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
++** checkpoints are always run by a background thread or background
++** process, foreground threads will never block on a lengthy fsync call.
+ **
+-** There can only be a single writer active at a time.
++** Fsync is called on the WAL before writing content out of the WAL and
++** into the database. This ensures that if the new content is persistent
++** in the WAL and can be recovered following a power-loss or hard reset.
++**
++** Fsync is also called on the database file if (and only if) the entire
++** WAL content is copied into the database file. This second fsync makes
++** it safe to delete the WAL since the new content will persist in the
++** database file.
++**
++** This routine uses and updates the nBackfill field of the wal-index header.
++** This is the only routine tha will increase the value of nBackfill.
++** (A WAL reset or recovery will revert nBackfill to zero, but not increase
++** its value.)
++**
++** The caller must be holding sufficient locks to ensure that no other
++** checkpoint is running (in any other thread or process) at the same
++** time.
+ */
+-SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
+- int rc;
+-
+- /* Cannot start a write transaction without first holding a read
+- ** transaction. */
+- assert( pWal->readLock>=0 );
++static int walCheckpoint(
++ Wal *pWal, /* Wal connection */
++ int eMode, /* One of PASSIVE, FULL or RESTART */
++ int (*xBusyCall)(void*), /* Function to call when busy */
++ void *pBusyArg, /* Context argument for xBusyHandler */
++ int sync_flags, /* Flags for OsSync() (or 0) */
++ u8 *zBuf /* Temporary buffer to use */
++){
++ int rc; /* Return code */
++ int szPage; /* Database page-size */
++ WalIterator *pIter = 0; /* Wal iterator context */
++ u32 iDbpage = 0; /* Next database page to write */
++ u32 iFrame = 0; /* Wal frame containing data for iDbpage */
++ u32 mxSafeFrame; /* Max frame that can be backfilled */
++ u32 mxPage; /* Max database page to write */
++ int i; /* Loop counter */
++ volatile WalCkptInfo *pInfo; /* The checkpoint status information */
++ int (*xBusy)(void*) = 0; /* Function to call when waiting for locks */
+
+- if( pWal->readOnly ){
+- return SQLITE_READONLY;
+- }
++ szPage = walPagesize(pWal);
++ testcase( szPage<=32768 );
++ testcase( szPage>=65536 );
++ pInfo = walCkptInfo(pWal);
++ if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
+
+- /* Only one writer allowed at a time. Get the write lock. Return
+- ** SQLITE_BUSY if unable.
+- */
+- rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+- if( rc ){
++ /* Allocate the iterator */
++ rc = walIteratorInit(pWal, &pIter);
++ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+- pWal->writeLock = 1;
++ assert( pIter );
+
+- /* If another connection has written to the database file since the
+- ** time the read transaction on this connection was started, then
+- ** the write is disallowed.
++ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall;
++
++ /* Compute in mxSafeFrame the index of the last frame of the WAL that is
++ ** safe to write into the database. Frames beyond mxSafeFrame might
++ ** overwrite database pages that are in use by active readers and thus
++ ** cannot be backfilled from the WAL.
+ */
+- if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+- pWal->writeLock = 0;
+- rc = SQLITE_BUSY;
++ mxSafeFrame = pWal->hdr.mxFrame;
++ mxPage = pWal->hdr.nPage;
++ for(i=1; i<WAL_NREADER; i++){
++ u32 y = pInfo->aReadMark[i];
++ if( mxSafeFrame>y ){
++ assert( y<=pWal->hdr.mxFrame );
++ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
++ if( rc==SQLITE_OK ){
++ pInfo->aReadMark[i] = READMARK_NOT_USED;
++ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
++ }else if( rc==SQLITE_BUSY ){
++ mxSafeFrame = y;
++ xBusy = 0;
++ }else{
++ goto walcheckpoint_out;
++ }
++ }
+ }
+
+- return rc;
+-}
++ if( pInfo->nBackfill<mxSafeFrame
++ && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
++ ){
++ i64 nSize; /* Current size of database file */
++ u32 nBackfill = pInfo->nBackfill;
+
+-/*
+-** End a write transaction. The commit has already been done. This
+-** routine merely releases the lock.
+-*/
+-SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
+- if( pWal->writeLock ){
+- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+- pWal->writeLock = 0;
+- pWal->truncateOnCommit = 0;
+- }
+- return SQLITE_OK;
+-}
++ /* Sync the WAL to disk */
++ if( sync_flags ){
++ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
++ }
+
+-/*
+-** If any data has been written (but not committed) to the log file, this
+-** function moves the write-pointer back to the start of the transaction.
+-**
+-** Additionally, the callback function is invoked for each frame written
+-** to the WAL since the start of the transaction. If the callback returns
+-** other than SQLITE_OK, it is not invoked again and the error code is
+-** returned to the caller.
+-**
+-** Otherwise, if the callback function does not return an error, this
+-** function returns SQLITE_OK.
+-*/
+-SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
+- int rc = SQLITE_OK;
+- if( ALWAYS(pWal->writeLock) ){
+- Pgno iMax = pWal->hdr.mxFrame;
+- Pgno iFrame;
+-
+- /* Restore the clients cache of the wal-index header to the state it
+- ** was in before the client began writing to the database.
++ /* If the database file may grow as a result of this checkpoint, hint
++ ** about the eventual size of the db file to the VFS layer.
+ */
+- memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
+-
+- for(iFrame=pWal->hdr.mxFrame+1;
+- ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
+- iFrame++
+- ){
+- /* This call cannot fail. Unless the page for which the page number
+- ** is passed as the second argument is (a) in the cache and
+- ** (b) has an outstanding reference, then xUndo is either a no-op
+- ** (if (a) is false) or simply expels the page from the cache (if (b)
+- ** is false).
+- **
+- ** If the upper layer is doing a rollback, it is guaranteed that there
+- ** are no outstanding references to any page other than page 1. And
+- ** page 1 is never written to the log until the transaction is
+- ** committed. As a result, the call to xUndo may not fail.
+- */
+- assert( walFramePgno(pWal, iFrame)!=1 );
+- rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
++ if( rc==SQLITE_OK ){
++ i64 nReq = ((i64)mxPage * szPage);
++ rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
++ if( rc==SQLITE_OK && nSize<nReq ){
++ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
++ }
+ }
+- walCleanupHash(pWal);
+- }
+- assert( rc==SQLITE_OK );
+- return rc;
+-}
+-
+-/*
+-** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32
+-** values. This function populates the array with values required to
+-** "rollback" the write position of the WAL handle back to the current
+-** point in the event of a savepoint rollback (via WalSavepointUndo()).
+-*/
+-SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
+- assert( pWal->writeLock );
+- aWalData[0] = pWal->hdr.mxFrame;
+- aWalData[1] = pWal->hdr.aFrameCksum[0];
+- aWalData[2] = pWal->hdr.aFrameCksum[1];
+- aWalData[3] = pWal->nCkpt;
+-}
+
+-/*
+-** Move the write position of the WAL back to the point identified by
+-** the values in the aWalData[] array. aWalData must point to an array
+-** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated
+-** by a call to WalSavepoint().
+-*/
+-SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
+- int rc = SQLITE_OK;
++ /* Iterate through the contents of the WAL, copying data to the db file. */
++ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
++ i64 iOffset;
++ assert( walFramePgno(pWal, iFrame)==iDbpage );
++ if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
++ iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
++ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
++ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
++ if( rc!=SQLITE_OK ) break;
++ iOffset = (iDbpage-1)*(i64)szPage;
++ testcase( IS_BIG_INT(iOffset) );
++ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
++ if( rc!=SQLITE_OK ) break;
++ }
+
+- assert( pWal->writeLock );
+- assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame );
++ /* If work was actually accomplished... */
++ if( rc==SQLITE_OK ){
++ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
++ i64 szDb = pWal->hdr.nPage*(i64)szPage;
++ testcase( IS_BIG_INT(szDb) );
++ rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
++ if( rc==SQLITE_OK && sync_flags ){
++ rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
++ }
++ }
++ if( rc==SQLITE_OK ){
++ pInfo->nBackfill = mxSafeFrame;
++ }
++ }
+
+- if( aWalData[3]!=pWal->nCkpt ){
+- /* This savepoint was opened immediately after the write-transaction
+- ** was started. Right after that, the writer decided to wrap around
+- ** to the start of the log. Update the savepoint values to match.
+- */
+- aWalData[0] = 0;
+- aWalData[3] = pWal->nCkpt;
++ /* Release the reader lock held while backfilling */
++ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
+ }
+
+- if( aWalData[0]<pWal->hdr.mxFrame ){
+- pWal->hdr.mxFrame = aWalData[0];
+- pWal->hdr.aFrameCksum[0] = aWalData[1];
+- pWal->hdr.aFrameCksum[1] = aWalData[2];
+- walCleanupHash(pWal);
++ if( rc==SQLITE_BUSY ){
++ /* Reset the return code so as not to report a checkpoint failure
++ ** just because there are active readers. */
++ rc = SQLITE_OK;
+ }
+
+- return rc;
+-}
+-
+-
+-/*
+-** This function is called just before writing a set of frames to the log
+-** file (see sqlite3WalFrames()). It checks to see if, instead of appending
+-** to the current log file, it is possible to overwrite the start of the
+-** existing log file with the new frames (i.e. "reset" the log). If so,
+-** it sets pWal->hdr.mxFrame to 0. Otherwise, pWal->hdr.mxFrame is left
+-** unchanged.
+-**
+-** SQLITE_OK is returned if no error is encountered (regardless of whether
+-** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned
+-** if an error occurs.
+-*/
+-static int walRestartLog(Wal *pWal){
+- int rc = SQLITE_OK;
+- int cnt;
+-
+- if( pWal->readLock==0 ){
+- volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+- assert( pInfo->nBackfill==pWal->hdr.mxFrame );
+- if( pInfo->nBackfill>0 ){
+- u32 salt1;
+- sqlite3_randomness(4, &salt1);
+- rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
++ /* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal
++ ** file has been copied into the database file, then block until all
++ ** readers have finished using the wal file. This ensures that the next
++ ** process to write to the database restarts the wal file.
++ */
++ if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
++ assert( pWal->writeLock );
++ if( pInfo->nBackfill<pWal->hdr.mxFrame ){
++ rc = SQLITE_BUSY;
++ }else if( eMode==SQLITE_CHECKPOINT_RESTART ){
++ assert( mxSafeFrame==pWal->hdr.mxFrame );
++ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
+ if( rc==SQLITE_OK ){
+- /* If all readers are using WAL_READ_LOCK(0) (in other words if no
+- ** readers are currently using the WAL), then the transactions
+- ** frames will overwrite the start of the existing log. Update the
+- ** wal-index header to reflect this.
+- **
+- ** In theory it would be Ok to update the cache of the header only
+- ** at this point. But updating the actual wal-index header is also
+- ** safe and means there is no special case for sqlite3WalUndo()
+- ** to handle if this transaction is rolled back.
+- */
+- int i; /* Loop counter */
+- u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
+-
+- pWal->nCkpt++;
+- pWal->hdr.mxFrame = 0;
+- sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
+- aSalt[1] = salt1;
+- walIndexWriteHdr(pWal);
+- pInfo->nBackfill = 0;
+- for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
+- assert( pInfo->aReadMark[0]==0 );
+ walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+- }else if( rc!=SQLITE_BUSY ){
+- return rc;
+ }
+ }
+- walUnlockShared(pWal, WAL_READ_LOCK(0));
+- pWal->readLock = -1;
+- cnt = 0;
+- do{
+- int notUsed;
+- rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt);
+- }while( rc==WAL_RETRY );
+- assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
+- testcase( (rc&0xff)==SQLITE_IOERR );
+- testcase( rc==SQLITE_PROTOCOL );
+- testcase( rc==SQLITE_OK );
+ }
++
++ walcheckpoint_out:
++ walIteratorFree(pIter);
+ return rc;
+ }
+
+ /*
+-** Information about the current state of the WAL file and where
+-** the next fsync should occur - passed from sqlite3WalFrames() into
+-** walWriteToLog().
+-*/
+-typedef struct WalWriter {
+- Wal *pWal; /* The complete WAL information */
+- sqlite3_file *pFd; /* The WAL file to which we write */
+- sqlite3_int64 iSyncPoint; /* Fsync at this offset */
+- int syncFlags; /* Flags for the fsync */
+- int szPage; /* Size of one page */
+-} WalWriter;
+-
+-/*
+-** Write iAmt bytes of content into the WAL file beginning at iOffset.
+-** Do a sync when crossing the p->iSyncPoint boundary.
+-**
+-** In other words, if iSyncPoint is in between iOffset and iOffset+iAmt,
+-** first write the part before iSyncPoint, then sync, then write the
+-** rest.
++** If the WAL file is currently larger than nMax bytes in size, truncate
++** it to exactly nMax bytes. If an error occurs while doing so, ignore it.
+ */
+-static int walWriteToLog(
+- WalWriter *p, /* WAL to write to */
+- void *pContent, /* Content to be written */
+- int iAmt, /* Number of bytes to write */
+- sqlite3_int64 iOffset /* Start writing at this offset */
+-){
+- int rc;
+- if( iOffset<p->iSyncPoint && iOffset+iAmt>=p->iSyncPoint ){
+- int iFirstAmt = (int)(p->iSyncPoint - iOffset);
+- rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset);
+- if( rc ) return rc;
+- iOffset += iFirstAmt;
+- iAmt -= iFirstAmt;
+- pContent = (void*)(iFirstAmt + (char*)pContent);
+- assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
+- rc = sqlite3OsSync(p->pFd, p->syncFlags);
+- if( iAmt==0 || rc ) return rc;
++static void walLimitSize(Wal *pWal, i64 nMax){
++ i64 sz;
++ int rx;
++ sqlite3BeginBenignMalloc();
++ rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
++ if( rx==SQLITE_OK && (sz > nMax ) ){
++ rx = sqlite3OsTruncate(pWal->pWalFd, nMax);
++ }
++ sqlite3EndBenignMalloc();
++ if( rx ){
++ sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
+ }
+- rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
+- return rc;
+ }
+
+ /*
+-** Write out a single frame of the WAL
++** Close a connection to a log file.
+ */
+-static int walWriteOneFrame(
+- WalWriter *p, /* Where to write the frame */
+- PgHdr *pPage, /* The page of the frame to be written */
+- int nTruncate, /* The commit flag. Usually 0. >0 for commit */
+- sqlite3_int64 iOffset /* Byte offset at which to write */
++SQLITE_PRIVATE int sqlite3WalClose(
++ Wal *pWal, /* Wal to close */
++ int sync_flags, /* Flags to pass to OsSync() (or 0) */
++ int nBuf,
++ u8 *zBuf /* Buffer of at least nBuf bytes */
+ ){
+- int rc; /* Result code from subfunctions */
+- void *pData; /* Data actually written */
+- u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
+-#if defined(SQLITE_HAS_CODEC)
+- if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
+-#else
+- pData = pPage->pData;
+-#endif
+- walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
+- rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
+- if( rc ) return rc;
+- /* Write the page data */
+- rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
++ int rc = SQLITE_OK;
++ if( pWal ){
++ int isDelete = 0; /* True to unlink wal and wal-index files */
++
++ /* If an EXCLUSIVE lock can be obtained on the database file (using the
++ ** ordinary, rollback-mode locking methods, this guarantees that the
++ ** connection associated with this log file is the only connection to
++ ** the database. In this case checkpoint the database and unlink both
++ ** the wal and wal-index files.
++ **
++ ** The EXCLUSIVE lock is not released before returning.
++ */
++ rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
++ if( rc==SQLITE_OK ){
++ if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
++ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
++ }
++ rc = sqlite3WalCheckpoint(
++ pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
++ );
++ if( rc==SQLITE_OK ){
++ int bPersist = -1;
++ sqlite3OsFileControlHint(
++ pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist
++ );
++ if( bPersist!=1 ){
++ /* Try to delete the WAL file if the checkpoint completed and
++ ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
++ ** mode (!bPersist) */
++ isDelete = 1;
++ }else if( pWal->mxWalSize>=0 ){
++ /* Try to truncate the WAL file to zero bytes if the checkpoint
++ ** completed and fsynced (rc==SQLITE_OK) and we are in persistent
++ ** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a
++ ** non-negative value (pWal->mxWalSize>=0). Note that we truncate
++ ** to zero bytes as truncating to the journal_size_limit might
++ ** leave a corrupt WAL file on disk. */
++ walLimitSize(pWal, 0);
++ }
++ }
++ }
++
++ walIndexClose(pWal, isDelete);
++ sqlite3OsClose(pWal->pWalFd);
++ if( isDelete ){
++ sqlite3BeginBenignMalloc();
++ sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
++ sqlite3EndBenignMalloc();
++ }
++ WALTRACE(("WAL%p: closed\n", pWal));
++ sqlite3_free((void *)pWal->apWiData);
++ sqlite3_free(pWal);
++ }
+ return rc;
+ }
+
+-/*
+-** Write a set of frames to the log. The caller must hold the write-lock
+-** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
++/*
++** Try to read the wal-index header. Return 0 on success and 1 if
++** there is a problem.
++**
++** The wal-index is in shared memory. Another thread or process might
++** be writing the header at the same time this procedure is trying to
++** read it, which might result in inconsistency. A dirty read is detected
++** by verifying that both copies of the header are the same and also by
++** a checksum on the header.
++**
++** If and only if the read is consistent and the header is different from
++** pWal->hdr, then pWal->hdr is updated to the content of the new header
++** and *pChanged is set to 1.
++**
++** If the checksum cannot be verified return non-zero. If the header
++** is read successfully and the checksum verified, return zero.
+ */
+-SQLITE_PRIVATE int sqlite3WalFrames(
+- Wal *pWal, /* Wal handle to write to */
+- int szPage, /* Database page-size in bytes */
+- PgHdr *pList, /* List of dirty pages to write */
+- Pgno nTruncate, /* Database size after this commit */
+- int isCommit, /* True if this is a commit */
+- int sync_flags /* Flags to pass to OsSync() (or 0) */
+-){
+- int rc; /* Used to catch return codes */
+- u32 iFrame; /* Next frame address */
+- PgHdr *p; /* Iterator to run through pList with. */
+- PgHdr *pLast = 0; /* Last frame in list */
+- int nExtra = 0; /* Number of extra copies of last page */
+- int szFrame; /* The size of a single frame */
+- i64 iOffset; /* Next byte to write in WAL file */
+- WalWriter w; /* The writer */
++static int walIndexTryHdr(Wal *pWal, int *pChanged){
++ u32 aCksum[2]; /* Checksum on the header content */
++ WalIndexHdr h1, h2; /* Two copies of the header content */
++ WalIndexHdr volatile *aHdr; /* Header in shared memory */
+
+- assert( pList );
+- assert( pWal->writeLock );
++ /* The first page of the wal-index must be mapped at this point. */
++ assert( pWal->nWiData>0 && pWal->apWiData[0] );
+
+- /* If this frame set completes a transaction, then nTruncate>0. If
+- ** nTruncate==0 then this frame set does not complete the transaction. */
+- assert( (isCommit!=0)==(nTruncate!=0) );
++ /* Read the header. This might happen concurrently with a write to the
++ ** same area of shared memory on a different CPU in a SMP,
++ ** meaning it is possible that an inconsistent snapshot is read
++ ** from the file. If this happens, return non-zero.
++ **
++ ** There are two copies of the header at the beginning of the wal-index.
++ ** When reading, read [0] first then [1]. Writes are in the reverse order.
++ ** Memory barriers are used to prevent the compiler or the hardware from
++ ** reordering the reads and writes.
++ */
++ aHdr = walIndexHdr(pWal);
++ memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
++ walShmBarrier(pWal);
++ memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
+
+-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+- { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
+- WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
+- pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
++ if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
++ return 1; /* Dirty read */
++ }
++ if( h1.isInit==0 ){
++ return 1; /* Malformed header - probably all zeros */
++ }
++ walChecksumBytes(1, (u8*)&h1, sizeof(h1)-sizeof(h1.aCksum), 0, aCksum);
++ if( aCksum[0]!=h1.aCksum[0] || aCksum[1]!=h1.aCksum[1] ){
++ return 1; /* Checksum does not match */
+ }
+-#endif
+
+- /* See if it is possible to write these frames into the start of the
+- ** log file, instead of appending to it at pWal->hdr.mxFrame.
+- */
+- if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
+- return rc;
++ if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
++ *pChanged = 1;
++ memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr));
++ pWal->szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
++ testcase( pWal->szPage<=32768 );
++ testcase( pWal->szPage>=65536 );
+ }
+
+- /* If this is the first frame written into the log, write the WAL
+- ** header to the start of the WAL file. See comments at the top of
+- ** this source file for a description of the WAL header format.
++ /* The header was successfully read. Return zero. */
++ return 0;
++}
++
++/*
++** Read the wal-index header from the wal-index and into pWal->hdr.
++** If the wal-header appears to be corrupt, try to reconstruct the
++** wal-index from the WAL before returning.
++**
++** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
++** changed by this opertion. If pWal->hdr is unchanged, set *pChanged
++** to 0.
++**
++** If the wal-index header is successfully read, return SQLITE_OK.
++** Otherwise an SQLite error code.
++*/
++static int walIndexReadHdr(Wal *pWal, int *pChanged){
++ int rc; /* Return code */
++ int badHdr; /* True if a header read failed */
++ volatile u32 *page0; /* Chunk of wal-index containing header */
++
++ /* Ensure that page 0 of the wal-index (the page that contains the
++ ** wal-index header) is mapped. Return early if an error occurs here.
+ */
+- iFrame = pWal->hdr.mxFrame;
+- if( iFrame==0 ){
+- u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */
+- u32 aCksum[2]; /* Checksum for wal-header */
++ assert( pChanged );
++ rc = walIndexPage(pWal, 0, &page0);
++ if( rc!=SQLITE_OK ){
++ return rc;
++ };
++ assert( page0 || pWal->writeLock==0 );
+
+- sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN));
+- sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
+- sqlite3Put4byte(&aWalHdr[8], szPage);
+- sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
+- if( pWal->nCkpt==0 ) sqlite3_randomness(8, pWal->hdr.aSalt);
+- memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
+- walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
+- sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
+- sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
+-
+- pWal->szPage = szPage;
+- pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
+- pWal->hdr.aFrameCksum[0] = aCksum[0];
+- pWal->hdr.aFrameCksum[1] = aCksum[1];
+- pWal->truncateOnCommit = 1;
++ /* If the first page of the wal-index has been mapped, try to read the
++ ** wal-index header immediately, without holding any lock. This usually
++ ** works, but may fail if the wal-index header is corrupt or currently
++ ** being modified by another thread or process.
++ */
++ badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
+
+- rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
+- WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok"));
+- if( rc!=SQLITE_OK ){
+- return rc;
++ /* If the first attempt failed, it might have been due to a race
++ ** with a writer. So get a WRITE lock and try again.
++ */
++ assert( badHdr==0 || pWal->writeLock==0 );
++ if( badHdr ){
++ if( pWal->readOnly & WAL_SHM_RDONLY ){
++ if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
++ walUnlockShared(pWal, WAL_WRITE_LOCK);
++ rc = SQLITE_READONLY_RECOVERY;
++ }
++ }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
++ pWal->writeLock = 1;
++ if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
++ badHdr = walIndexTryHdr(pWal, pChanged);
++ if( badHdr ){
++ /* If the wal-index header is still malformed even while holding
++ ** a WRITE lock, it can only mean that the header is corrupted and
++ ** needs to be reconstructed. So run recovery to do exactly that.
++ */
++ rc = walIndexRecover(pWal);
++ *pChanged = 1;
++ }
++ }
++ pWal->writeLock = 0;
++ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ }
++ }
+
+- /* Sync the header (unless SQLITE_IOCAP_SEQUENTIAL is true or unless
+- ** all syncing is turned off by PRAGMA synchronous=OFF). Otherwise
+- ** an out-of-order write following a WAL restart could result in
+- ** database corruption. See the ticket:
+- **
+- ** http://localhost:591/sqlite/info/ff5be73dee
+- */
+- if( pWal->syncHeader && sync_flags ){
+- rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
+- if( rc ) return rc;
+- }
++ /* If the header is read successfully, check the version number to make
++ ** sure the wal-index was not constructed with some future format that
++ ** this version of SQLite cannot understand.
++ */
++ if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
++ rc = SQLITE_CANTOPEN_BKPT;
+ }
+- assert( (int)pWal->szPage==szPage );
+
+- /* Setup information needed to write frames into the WAL */
+- w.pWal = pWal;
+- w.pFd = pWal->pWalFd;
+- w.iSyncPoint = 0;
+- w.syncFlags = sync_flags;
+- w.szPage = szPage;
+- iOffset = walFrameOffset(iFrame+1, szPage);
+- szFrame = szPage + WAL_FRAME_HDRSIZE;
++ return rc;
++}
+
+- /* Write all frames into the log file exactly once */
+- for(p=pList; p; p=p->pDirty){
+- int nDbSize; /* 0 normally. Positive == commit flag */
+- iFrame++;
+- assert( iOffset==walFrameOffset(iFrame, szPage) );
+- nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
+- rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
+- if( rc ) return rc;
+- pLast = p;
+- iOffset += szFrame;
+- }
++/*
++** This is the value that walTryBeginRead returns when it needs to
++** be retried.
++*/
++#define WAL_RETRY (-1)
+
+- /* If this is the end of a transaction, then we might need to pad
+- ** the transaction and/or sync the WAL file.
++/*
++** Attempt to start a read transaction. This might fail due to a race or
++** other transient condition. When that happens, it returns WAL_RETRY to
++** indicate to the caller that it is safe to retry immediately.
++**
++** On success return SQLITE_OK. On a permanent failure (such an
++** I/O error or an SQLITE_BUSY because another process is running
++** recovery) return a positive error code.
++**
++** The useWal parameter is true to force the use of the WAL and disable
++** the case where the WAL is bypassed because it has been completely
++** checkpointed. If useWal==0 then this routine calls walIndexReadHdr()
++** to make a copy of the wal-index header into pWal->hdr. If the
++** wal-index header has changed, *pChanged is set to 1 (as an indication
++** to the caller that the local paget cache is obsolete and needs to be
++** flushed.) When useWal==1, the wal-index header is assumed to already
++** be loaded and the pChanged parameter is unused.
++**
++** The caller must set the cnt parameter to the number of prior calls to
++** this routine during the current read attempt that returned WAL_RETRY.
++** This routine will start taking more aggressive measures to clear the
++** race conditions after multiple WAL_RETRY returns, and after an excessive
++** number of errors will ultimately return SQLITE_PROTOCOL. The
++** SQLITE_PROTOCOL return indicates that some other process has gone rogue
++** and is not honoring the locking protocol. There is a vanishingly small
++** chance that SQLITE_PROTOCOL could be returned because of a run of really
++** bad luck when there is lots of contention for the wal-index, but that
++** possibility is so small that it can be safely neglected, we believe.
++**
++** On success, this routine obtains a read lock on
++** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is
++** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1)
++** that means the Wal does not hold any read lock. The reader must not
++** access any database page that is modified by a WAL frame up to and
++** including frame number aReadMark[pWal->readLock]. The reader will
++** use WAL frames up to and including pWal->hdr.mxFrame if pWal->readLock>0
++** Or if pWal->readLock==0, then the reader will ignore the WAL
++** completely and get all content directly from the database file.
++** If the useWal parameter is 1 then the WAL will never be ignored and
++** this routine will always set pWal->readLock>0 on success.
++** When the read transaction is completed, the caller must release the
++** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1.
++**
++** This routine uses the nBackfill and aReadMark[] fields of the header
++** to select a particular WAL_READ_LOCK() that strives to let the
++** checkpoint process do as much work as possible. This routine might
++** update values of the aReadMark[] array in the header, but if it does
++** so it takes care to hold an exclusive lock on the corresponding
++** WAL_READ_LOCK() while changing values.
++*/
++static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
++ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
++ u32 mxReadMark; /* Largest aReadMark[] value */
++ int mxI; /* Index of largest aReadMark[] value */
++ int i; /* Loop counter */
++ int rc = SQLITE_OK; /* Return code */
++
++ assert( pWal->readLock<0 ); /* Not currently locked */
++
++ /* Take steps to avoid spinning forever if there is a protocol error.
+ **
+- ** Padding and syncing only occur if this set of frames complete a
+- ** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL
+- ** or synchonous==OFF, then no padding or syncing are needed.
++ ** Circumstances that cause a RETRY should only last for the briefest
++ ** instances of time. No I/O or other system calls are done while the
++ ** locks are held, so the locks should not be held for very long. But
++ ** if we are unlucky, another process that is holding a lock might get
++ ** paged out or take a page-fault that is time-consuming to resolve,
++ ** during the few nanoseconds that it is holding the lock. In that case,
++ ** it might take longer than normal for the lock to free.
+ **
+- ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not
+- ** needed and only the sync is done. If padding is needed, then the
+- ** final frame is repeated (with its commit mark) until the next sector
+- ** boundary is crossed. Only the part of the WAL prior to the last
+- ** sector boundary is synced; the part of the last frame that extends
+- ** past the sector boundary is written after the sync.
++ ** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few
++ ** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this
++ ** is more of a scheduler yield than an actual delay. But on the 10th
++ ** an subsequent retries, the delays start becoming longer and longer,
++ ** so that on the 100th (and last) RETRY we delay for 21 milliseconds.
++ ** The total delay time before giving up is less than 1 second.
+ */
+- if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
+- if( pWal->padToSectorBoundary ){
+- int sectorSize = sqlite3OsSectorSize(pWal->pWalFd);
+- w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
+- while( iOffset<w.iSyncPoint ){
+- rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
+- if( rc ) return rc;
+- iOffset += szFrame;
+- nExtra++;
++ if( cnt>5 ){
++ int nDelay = 1; /* Pause time in microseconds */
++ if( cnt>100 ){
++ VVA_ONLY( pWal->lockError = 1; )
++ return SQLITE_PROTOCOL;
++ }
++ if( cnt>=10 ) nDelay = (cnt-9)*238; /* Max delay 21ms. Total delay 996ms */
++ sqlite3OsSleep(pWal->pVfs, nDelay);
++ }
++
++ if( !useWal ){
++ rc = walIndexReadHdr(pWal, pChanged);
++ if( rc==SQLITE_BUSY ){
++ /* If there is not a recovery running in another thread or process
++ ** then convert BUSY errors to WAL_RETRY. If recovery is known to
++ ** be running, convert BUSY to BUSY_RECOVERY. There is a race here
++ ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY
++ ** would be technically correct. But the race is benign since with
++ ** WAL_RETRY this routine will be called again and will probably be
++ ** right on the second iteration.
++ */
++ if( pWal->apWiData[0]==0 ){
++ /* This branch is taken when the xShmMap() method returns SQLITE_BUSY.
++ ** We assume this is a transient condition, so return WAL_RETRY. The
++ ** xShmMap() implementation used by the default unix and win32 VFS
++ ** modules may return SQLITE_BUSY due to a race condition in the
++ ** code that determines whether or not the shared-memory region
++ ** must be zeroed before the requested page is returned.
++ */
++ rc = WAL_RETRY;
++ }else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){
++ walUnlockShared(pWal, WAL_RECOVER_LOCK);
++ rc = WAL_RETRY;
++ }else if( rc==SQLITE_BUSY ){
++ rc = SQLITE_BUSY_RECOVERY;
+ }
+- }else{
+- rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
++ }
++ if( rc!=SQLITE_OK ){
++ return rc;
+ }
+ }
+
+- /* If this frame set completes the first transaction in the WAL and
+- ** if PRAGMA journal_size_limit is set, then truncate the WAL to the
+- ** journal size limit, if possible.
+- */
+- if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){
+- i64 sz = pWal->mxWalSize;
+- if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){
+- sz = walFrameOffset(iFrame+nExtra+1, szPage);
++ pInfo = walCkptInfo(pWal);
++ if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
++ /* The WAL has been completely backfilled (or it is empty).
++ ** and can be safely ignored.
++ */
++ rc = walLockShared(pWal, WAL_READ_LOCK(0));
++ walShmBarrier(pWal);
++ if( rc==SQLITE_OK ){
++ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
++ /* It is not safe to allow the reader to continue here if frames
++ ** may have been appended to the log before READ_LOCK(0) was obtained.
++ ** When holding READ_LOCK(0), the reader ignores the entire log file,
++ ** which implies that the database file contains a trustworthy
++ ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from
++ ** happening, this is usually correct.
++ **
++ ** However, if frames have been appended to the log (or if the log
++ ** is wrapped and written for that matter) before the READ_LOCK(0)
++ ** is obtained, that is not necessarily true. A checkpointer may
++ ** have started to backfill the appended frames but crashed before
++ ** it finished. Leaving a corrupt image in the database file.
++ */
++ walUnlockShared(pWal, WAL_READ_LOCK(0));
++ return WAL_RETRY;
++ }
++ pWal->readLock = 0;
++ return SQLITE_OK;
++ }else if( rc!=SQLITE_BUSY ){
++ return rc;
+ }
+- walLimitSize(pWal, sz);
+- pWal->truncateOnCommit = 0;
+ }
+
+- /* Append data to the wal-index. It is not necessary to lock the
+- ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
+- ** guarantees that there are no other writers, and no data that may
+- ** be in use by existing readers is being overwritten.
++ /* If we get this far, it means that the reader will want to use
++ ** the WAL to get at content from recent commits. The job now is
++ ** to select one of the aReadMark[] entries that is closest to
++ ** but not exceeding pWal->hdr.mxFrame and lock that entry.
+ */
+- iFrame = pWal->hdr.mxFrame;
+- for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
+- iFrame++;
+- rc = walIndexAppend(pWal, iFrame, p->pgno);
+- }
+- while( rc==SQLITE_OK && nExtra>0 ){
+- iFrame++;
+- nExtra--;
+- rc = walIndexAppend(pWal, iFrame, pLast->pgno);
++ mxReadMark = 0;
++ mxI = 0;
++ for(i=1; i<WAL_NREADER; i++){
++ u32 thisMark = pInfo->aReadMark[i];
++ if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){
++ assert( thisMark!=READMARK_NOT_USED );
++ mxReadMark = thisMark;
++ mxI = i;
++ }
+ }
++ /* There was once an "if" here. The extra "{" is to preserve indentation. */
++ {
++ if( (pWal->readOnly & WAL_SHM_RDONLY)==0
++ && (mxReadMark<pWal->hdr.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] = 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( rc==SQLITE_OK ){
+- /* Update the private copy of the header. */
+- pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
+- testcase( szPage<=32768 );
+- testcase( szPage>=65536 );
+- pWal->hdr.mxFrame = iFrame;
+- if( isCommit ){
+- pWal->hdr.iChange++;
+- pWal->hdr.nPage = nTruncate;
++ rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
++ if( rc ){
++ return rc==SQLITE_BUSY ? WAL_RETRY : rc;
+ }
+- /* If this is a commit, update the wal-index header too. */
+- if( isCommit ){
+- walIndexWriteHdr(pWal);
+- pWal->iCallback = iFrame;
++ /* Now that the read-lock has been obtained, check that neither the
++ ** value in the aReadMark[] array or the contents of the wal-index
++ ** header have changed.
++ **
++ ** 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;
++}
+
+- WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
++/*
++** Begin a read transaction on the database.
++**
++** This routine used to be called sqlite3OpenSnapshot() and with good reason:
++** it takes a snapshot of the state of the WAL and wal-index for the current
++** instant in time. The current thread will continue to use this snapshot.
++** Other threads might append new content to the WAL and wal-index but
++** that extra content is ignored by the current thread.
++**
++** If the database contents have changes since the previous read
++** transaction, then *pChanged is set to 1 before returning. The
++** Pager layer will use this to know that is cache is stale and
++** needs to be flushed.
++*/
++SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
++ int rc; /* Return code */
++ int cnt = 0; /* Number of TryBeginRead attempts */
++
++ do{
++ rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
++ }while( rc==WAL_RETRY );
++ testcase( (rc&0xff)==SQLITE_BUSY );
++ testcase( (rc&0xff)==SQLITE_IOERR );
++ testcase( rc==SQLITE_PROTOCOL );
++ testcase( rc==SQLITE_OK );
+ return rc;
+ }
+
+-/*
+-** This routine is called to implement sqlite3_wal_checkpoint() and
+-** related interfaces.
+-**
+-** Obtain a CHECKPOINT lock and then backfill as much information as
+-** we can from WAL into the database.
++/*
++** Finish with a read transaction. All this does is release the
++** read-lock.
++*/
++SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
++ sqlite3WalEndWriteTransaction(pWal);
++ if( pWal->readLock>=0 ){
++ walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
++ pWal->readLock = -1;
++ }
++}
++
++/*
++** Read a page from the WAL, if it is present in the WAL and if the
++** current read transaction is configured to use the WAL.
+ **
+-** If parameter xBusy is not NULL, it is a pointer to a busy-handler
+-** callback. In this case this function runs a blocking checkpoint.
++** The *pInWal is set to 1 if the requested page is in the WAL and
++** has been loaded. Or *pInWal is set to 0 if the page was not in
++** the WAL and needs to be read out of the database.
+ */
+-SQLITE_PRIVATE int sqlite3WalCheckpoint(
+- Wal *pWal, /* Wal connection */
+- int eMode, /* PASSIVE, FULL or RESTART */
+- int (*xBusy)(void*), /* Function to call when busy */
+- void *pBusyArg, /* Context argument for xBusyHandler */
+- int sync_flags, /* Flags to sync db file with (or 0) */
+- int nBuf, /* Size of temporary buffer */
+- u8 *zBuf, /* Temporary buffer to use */
+- int *pnLog, /* OUT: Number of frames in WAL */
+- int *pnCkpt /* OUT: Number of backfilled frames in WAL */
++SQLITE_PRIVATE int sqlite3WalRead(
++ Wal *pWal, /* WAL handle */
++ Pgno pgno, /* Database page number to read data for */
++ int *pInWal, /* OUT: True if data is read from WAL */
++ int nOut, /* Size of buffer pOut in bytes */
++ u8 *pOut /* Buffer to write page data to */
+ ){
+- int rc; /* Return code */
+- int isChanged = 0; /* True if a new wal-index header is loaded */
+- int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
++ u32 iRead = 0; /* If !=0, WAL frame to return data from */
++ u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
++ int iHash; /* Used to loop through N hash tables */
+
+- assert( pWal->ckptLock==0 );
+- assert( pWal->writeLock==0 );
++ /* This routine is only be called from within a read transaction. */
++ assert( pWal->readLock>=0 || pWal->lockError );
+
+- if( pWal->readOnly ) return SQLITE_READONLY;
+- WALTRACE(("WAL%p: checkpoint begins\n", pWal));
+- rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+- if( rc ){
+- /* Usually this is SQLITE_BUSY meaning that another thread or process
+- ** is already running a checkpoint, or maybe a recovery. But it might
+- ** also be SQLITE_IOERR. */
+- return rc;
++ /* If the "last page" field of the wal-index header snapshot is 0, then
++ ** no data will be read from the wal under any circumstances. Return early
++ ** in this case as an optimization. Likewise, if pWal->readLock==0,
++ ** then the WAL is ignored by the reader so return early, as if the
++ ** WAL were empty.
++ */
++ if( iLast==0 || pWal->readLock==0 ){
++ *pInWal = 0;
++ return SQLITE_OK;
+ }
+- pWal->ckptLock = 1;
+
+- /* If this is a blocking-checkpoint, then obtain the write-lock as well
+- ** to prevent any writers from running while the checkpoint is underway.
+- ** This has to be done before the call to walIndexReadHdr() below.
++ /* Search the hash table or tables for an entry matching page number
++ ** pgno. Each iteration of the following for() loop searches one
++ ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames).
+ **
+- ** If the writer lock cannot be obtained, then a passive checkpoint is
+- ** run instead. Since the checkpointer is not holding the writer lock,
+- ** there is no point in blocking waiting for any readers. Assuming no
+- ** other error occurs, this function will return SQLITE_BUSY to the caller.
++ ** This code might run concurrently to the code in walIndexAppend()
++ ** that adds entries to the wal-index (and possibly to this hash
++ ** table). This means the value just read from the hash
++ ** slot (aHash[iKey]) may have been added before or after the
++ ** current read transaction was opened. Values added after the
++ ** read transaction was opened may have been written incorrectly -
++ ** i.e. these slots may contain garbage data. However, we assume
++ ** that any slots written before the current read transaction was
++ ** opened remain unmodified.
++ **
++ ** For the reasons above, the if(...) condition featured in the inner
++ ** loop of the following block is more stringent that would be required
++ ** if we had exclusive access to the hash-table:
++ **
++ ** (aPgno[iFrame]==pgno):
++ ** This condition filters out normal hash-table collisions.
++ **
++ ** (iFrame<=iLast):
++ ** This condition filters out entries that were added to the hash
++ ** table after the current read-transaction had started.
+ */
+- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
+- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
+- if( rc==SQLITE_OK ){
+- pWal->writeLock = 1;
+- }else if( rc==SQLITE_BUSY ){
+- eMode2 = SQLITE_CHECKPOINT_PASSIVE;
+- rc = SQLITE_OK;
+- }
+- }
+-
+- /* Read the wal-index header. */
+- if( rc==SQLITE_OK ){
+- rc = walIndexReadHdr(pWal, &isChanged);
+- }
++ for(iHash=walFramePage(iLast); iHash>=0 && iRead==0; iHash--){
++ volatile ht_slot *aHash; /* Pointer to hash table */
++ volatile u32 *aPgno; /* Pointer to array of page numbers */
++ u32 iZero; /* Frame number corresponding to aPgno[0] */
++ int iKey; /* Hash slot index */
++ int nCollide; /* Number of hash collisions remaining */
++ int rc; /* Error code */
+
+- /* Copy data from the log to the database file. */
+- if( rc==SQLITE_OK ){
+- if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
+- rc = SQLITE_CORRUPT_BKPT;
+- }else{
+- rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
++ rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
++ if( rc!=SQLITE_OK ){
++ return rc;
++ }
++ nCollide = HASHTABLE_NSLOT;
++ for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
++ u32 iFrame = aHash[iKey] + iZero;
++ if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
++ /* assert( iFrame>iRead ); -- not true if there is corruption */
++ iRead = iFrame;
++ }
++ if( (nCollide--)==0 ){
++ return SQLITE_CORRUPT_BKPT;
++ }
+ }
++ }
+
- /* If no error occurred, set the output variables. */
- if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
- if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
- if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
-- }
-- }
--
++#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
++ /* If expensive assert() statements are available, do a linear search
++ ** of the wal-index file content. Make sure the results agree with the
++ ** result obtained using the hash indexes above. */
++ {
++ u32 iRead2 = 0;
++ u32 iTest;
++ for(iTest=iLast; iTest>0; iTest--){
++ if( walFramePgno(pWal, iTest)==pgno ){
++ iRead2 = iTest;
++ break;
++ }
+ }
++ assert( iRead==iRead2 );
+ }
++#endif
+
- if( isChanged ){
- /* If a new wal-index header was loaded before the checkpoint was
- ** performed, then the pager-cache associated with pWal is now
@@ -2720,34 +6600,60 @@
- ** the cache needs to be reset.
- */
- memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
-- }
--
++ /* If iRead is non-zero, then it is the log frame number that contains the
++ ** required page. Read and return data from the log file.
++ */
++ if( iRead ){
++ int sz;
++ i64 iOffset;
++ sz = pWal->hdr.szPage;
++ sz = (sz&0xfe00) + ((sz&0x0001)<<16);
++ testcase( sz<=32768 );
++ testcase( sz>=65536 );
++ iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
++ *pInWal = 1;
++ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
++ return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
+ }
+
- /* Release the locks. */
- sqlite3WalEndWriteTransaction(pWal);
- walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
- pWal->ckptLock = 0;
- WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
- return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
--}
--
++ *pInWal = 0;
++ return SQLITE_OK;
+ }
+
-/* Return the value to pass to a sqlite3_wal_hook callback, the
-** number of frames in the WAL at the point of the last commit since
-** sqlite3WalCallback() was called. If no commits have occurred since
-** the last call, then return 0.
--*/
++
++/*
++** Return the size of the database in pages (or zero, if unknown).
+ */
-SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
- u32 ret = 0;
- if( pWal ){
- ret = pWal->iCallback;
- pWal->iCallback = 0;
-- }
++SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
++ if( pWal && ALWAYS(pWal->readLock>=0) ){
++ return pWal->hdr.nPage;
+ }
- return (int)ret;
--}
--
++ return 0;
+ }
+
-/*
-** This function is called to change the WAL subsystem into or out
-** of locking_mode=EXCLUSIVE.
--**
++
++/*
++** This function starts a write transaction on the WAL.
+ **
-** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
-** into locking_mode=NORMAL. This means that we must acquire a lock
-** on the pWal->readLock byte. If the WAL is already in locking_mode=NORMAL
@@ -2755,24 +6661,32 @@
-** transition out of exclusive-mode is successful, return 1. This
-** operation must occur while the pager is still holding the exclusive
-** lock on the main database file.
--**
++** A read transaction must have already been started by a prior call
++** to sqlite3WalBeginReadTransaction().
+ **
-** If op is one, then change from locking_mode=NORMAL into
-** locking_mode=EXCLUSIVE. This means that the pWal->readLock must
-** be released. Return 1 if the transition is made and 0 if the
-** WAL is already in exclusive-locking mode - meaning that this
-** routine is a no-op. The pager must already hold the exclusive lock
-** on the main database file before invoking this operation.
--**
++** If another thread or process has written into the database since
++** the read transaction was started, then it is not possible for this
++** thread to write as doing so would cause a fork. So this routine
++** returns SQLITE_BUSY in that case and no write transaction is started.
+ **
-** If op is negative, then do a dry-run of the op==1 case but do
-** not actually change anything. The pager uses this to see if it
-** should acquire the database exclusive lock prior to invoking
-** the op==1 case.
--*/
++** There can only be a single writer active at a time.
+ */
-SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
-- int rc;
++SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
+ int rc;
- assert( pWal->writeLock==0 );
- assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 );
--
+
- /* pWal->readLock is usually set, but might be -1 if there was a
- ** prior error while attempting to acquire are read-lock. This cannot
- ** happen if the connection is actually in exclusive mode (as no xShmLock
@@ -2781,7 +6695,10 @@
- */
- assert( pWal->readLock>=0 || pWal->lockError );
- assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
--
++ /* Cannot start a write transaction without first holding a read
++ ** transaction. */
++ assert( pWal->readLock>=0 );
+
- if( op==0 ){
- if( pWal->exclusiveMode ){
- pWal->exclusiveMode = 0;
@@ -2801,7 +6718,9 @@
- rc = 1;
- }else{
- rc = pWal->exclusiveMode==0;
-- }
++ if( pWal->readOnly ){
++ return SQLITE_READONLY;
+ }
- return rc;
-}
-
@@ -2814,6 +6733,18 @@
- return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
-}
-
+-#ifdef SQLITE_ENABLE_ZIPVFS
+-/*
+-** If the argument is not NULL, it points to a Wal object that holds a
+-** read-lock. This function returns the database page-size if it is known,
+-** or zero if it is not (or if pWal is NULL).
+-*/
+-SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
+- assert( pWal==0 || pWal->readLock>=0 );
+- return (pWal ? pWal->szPage : 0);
+-}
+-#endif
+-
-#endif /* #ifndef SQLITE_OMIT_WAL */
-
-/************** End of wal.c *************************************************/
@@ -3040,39 +6971,164 @@
-** SIZE DESCRIPTION
-** 4 Page number of next overflow page
-** * Data
--**
++
++ /* Only one writer allowed at a time. Get the write lock. Return
++ ** SQLITE_BUSY if unable.
++ */
++ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
++ if( rc ){
++ return rc;
++ }
++ pWal->writeLock = 1;
++
++ /* If another connection has written to the database file since the
++ ** time the read transaction on this connection was started, then
++ ** the write is disallowed.
++ */
++ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
++ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
++ pWal->writeLock = 0;
++ rc = SQLITE_BUSY;
++ }
++
++ return rc;
++}
++
++/*
++** End a write transaction. The commit has already been done. This
++** routine merely releases the lock.
++*/
++SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
++ if( pWal->writeLock ){
++ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
++ pWal->writeLock = 0;
++ pWal->truncateOnCommit = 0;
++ }
++ return SQLITE_OK;
++}
++
++/*
++** If any data has been written (but not committed) to the log file, this
++** function moves the write-pointer back to the start of the transaction.
+ **
-** Freelist pages come in two subtypes: trunk pages and leaf pages. The
-** file header points to the first in a linked list of trunk page. Each trunk
-** page points to multiple leaf pages. The content of a leaf page is
-** unspecified. A trunk page looks like this:
--**
++** Additionally, the callback function is invoked for each frame written
++** to the WAL since the start of the transaction. If the callback returns
++** other than SQLITE_OK, it is not invoked again and the error code is
++** returned to the caller.
+ **
-** SIZE DESCRIPTION
-** 4 Page number of next trunk page
-** 4 Number of leaf pointers on this page
-** * zero or more pages numbers of leaves
--*/
--
--
++** Otherwise, if the callback function does not return an error, this
++** function returns SQLITE_OK.
+ */
++SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
++ int rc = SQLITE_OK;
++ if( ALWAYS(pWal->writeLock) ){
++ Pgno iMax = pWal->hdr.mxFrame;
++ Pgno iFrame;
++
++ /* Restore the clients cache of the wal-index header to the state it
++ ** was in before the client began writing to the database.
++ */
++ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
+
++ for(iFrame=pWal->hdr.mxFrame+1;
++ ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
++ iFrame++
++ ){
++ /* This call cannot fail. Unless the page for which the page number
++ ** is passed as the second argument is (a) in the cache and
++ ** (b) has an outstanding reference, then xUndo is either a no-op
++ ** (if (a) is false) or simply expels the page from the cache (if (b)
++ ** is false).
++ **
++ ** If the upper layer is doing a rollback, it is guaranteed that there
++ ** are no outstanding references to any page other than page 1. And
++ ** page 1 is never written to the log until the transaction is
++ ** committed. As a result, the call to xUndo may not fail.
++ */
++ assert( walFramePgno(pWal, iFrame)!=1 );
++ rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
++ }
++ walCleanupHash(pWal);
++ }
++ assert( rc==SQLITE_OK );
++ return rc;
++}
+
-/* The following value is the maximum cell size assuming a maximum page
-** size give above.
--*/
++/*
++** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32
++** values. This function populates the array with values required to
++** "rollback" the write position of the WAL handle back to the current
++** point in the event of a savepoint rollback (via WalSavepointUndo()).
+ */
-#define MX_CELL_SIZE(pBt) ((int)(pBt->pageSize-8))
--
++SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
++ assert( pWal->writeLock );
++ aWalData[0] = pWal->hdr.mxFrame;
++ aWalData[1] = pWal->hdr.aFrameCksum[0];
++ aWalData[2] = pWal->hdr.aFrameCksum[1];
++ aWalData[3] = pWal->nCkpt;
++}
+
-/* The maximum number of cells on a single page of the database. This
-** assumes a minimum cell size of 6 bytes (4 bytes for the cell itself
-** plus 2 bytes for the index to the cell in the page header). Such
-** small cells will be rare, but they are possible.
--*/
++/*
++** Move the write position of the WAL back to the point identified by
++** the values in the aWalData[] array. aWalData must point to an array
++** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated
++** by a call to WalSavepoint().
+ */
-#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
--
++SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
++ int rc = SQLITE_OK;
++
++ assert( pWal->writeLock );
++ assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame );
++
++ if( aWalData[3]!=pWal->nCkpt ){
++ /* This savepoint was opened immediately after the write-transaction
++ ** was started. Right after that, the writer decided to wrap around
++ ** to the start of the log. Update the savepoint values to match.
++ */
++ aWalData[0] = 0;
++ aWalData[3] = pWal->nCkpt;
++ }
++
++ if( aWalData[0]<pWal->hdr.mxFrame ){
++ pWal->hdr.mxFrame = aWalData[0];
++ pWal->hdr.aFrameCksum[0] = aWalData[1];
++ pWal->hdr.aFrameCksum[1] = aWalData[2];
++ walCleanupHash(pWal);
++ }
++
++ return rc;
++}
+
-/* Forward declarations */
-typedef struct MemPage MemPage;
-typedef struct BtLock BtLock;
--
--/*
+
+ /*
-** This is a magic string that appears at the beginning of every
-** SQLite database in order to identify the file as a real database.
--**
++** This function is called just before writing a set of frames to the log
++** file (see sqlite3WalFrames()). It checks to see if, instead of appending
++** to the current log file, it is possible to overwrite the start of the
++** existing log file with the new frames (i.e. "reset" the log). If so,
++** it sets pWal->hdr.mxFrame to 0. Otherwise, pWal->hdr.mxFrame is left
++** unchanged.
+ **
-** You can change this value at compile-time by specifying a
-** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
-** header must be exactly 16 bytes including the zero-terminator so
@@ -3080,21 +7136,86 @@
-** the header, then your custom library will not be able to read
-** databases generated by the standard tools and the standard tools
-** will not be able to read databases created by your custom library.
--*/
++** SQLITE_OK is returned if no error is encountered (regardless of whether
++** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned
++** if an error occurs.
+ */
-#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
-# define SQLITE_FILE_HEADER "SQLite format 3"
-#endif
--
--/*
++static int walRestartLog(Wal *pWal){
++ int rc = SQLITE_OK;
++ int cnt;
++
++ if( pWal->readLock==0 ){
++ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
++ assert( pInfo->nBackfill==pWal->hdr.mxFrame );
++ if( pInfo->nBackfill>0 ){
++ u32 salt1;
++ sqlite3_randomness(4, &salt1);
++ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
++ if( rc==SQLITE_OK ){
++ /* If all readers are using WAL_READ_LOCK(0) (in other words if no
++ ** readers are currently using the WAL), then the transactions
++ ** frames will overwrite the start of the existing log. Update the
++ ** wal-index header to reflect this.
++ **
++ ** In theory it would be Ok to update the cache of the header only
++ ** at this point. But updating the actual wal-index header is also
++ ** safe and means there is no special case for sqlite3WalUndo()
++ ** to handle if this transaction is rolled back.
++ */
++ int i; /* Loop counter */
++ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
++
++ pWal->nCkpt++;
++ pWal->hdr.mxFrame = 0;
++ sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
++ aSalt[1] = salt1;
++ walIndexWriteHdr(pWal);
++ pInfo->nBackfill = 0;
++ for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
++ assert( pInfo->aReadMark[0]==0 );
++ walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
++ }else if( rc!=SQLITE_BUSY ){
++ return rc;
++ }
++ }
++ walUnlockShared(pWal, WAL_READ_LOCK(0));
++ pWal->readLock = -1;
++ cnt = 0;
++ do{
++ int notUsed;
++ rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt);
++ }while( rc==WAL_RETRY );
++ assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
++ testcase( (rc&0xff)==SQLITE_IOERR );
++ testcase( rc==SQLITE_PROTOCOL );
++ testcase( rc==SQLITE_OK );
++ }
++ return rc;
++}
+
+ /*
-** Page type flags. An ORed combination of these flags appear as the
-** first byte of on-disk image of every BTree page.
--*/
++** Information about the current state of the WAL file and where
++** the next fsync should occur - passed from sqlite3WalFrames() into
++** walWriteToLog().
+ */
-#define PTF_INTKEY 0x01
-#define PTF_ZERODATA 0x02
-#define PTF_LEAFDATA 0x04
-#define PTF_LEAF 0x08
--
--/*
++typedef struct WalWriter {
++ Wal *pWal; /* The complete WAL information */
++ sqlite3_file *pFd; /* The WAL file to which we write */
++ sqlite3_int64 iSyncPoint; /* Fsync at this offset */
++ int syncFlags; /* Flags for the fsync */
++ int szPage; /* Size of one page */
++} WalWriter;
+
+ /*
-** As each page of the file is loaded into memory, an instance of the following
-** structure is appended and initialized to zero. This structure stores
-** information about the page that is decoded from the raw file page.
@@ -3103,10 +7224,15 @@
-** walk up the BTree from any leaf to the root. Care must be taken to
-** unref() the parent page pointer when this page is no longer referenced.
-** The pageDestructor() routine handles that chore.
--**
++** Write iAmt bytes of content into the WAL file beginning at iOffset.
++** Do a sync when crossing the p->iSyncPoint boundary.
+ **
-** Access to all fields of this structure is controlled by the mutex
-** stored in MemPage.pBt->mutex.
--*/
++** In other words, if iSyncPoint is in between iOffset and iOffset+iAmt,
++** first write the part before iSyncPoint, then sync, then write the
++** rest.
+ */
-struct MemPage {
- u8 isInit; /* True if previously initialized. MUST BE FIRST! */
- u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
@@ -3115,60 +7241,112 @@
- u8 hasData; /* True if this page stores data */
- u8 hdrOffset; /* 100 for page 1. 0 otherwise */
- u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
+- u8 max1bytePayload; /* min(maxLocal,127) */
- u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
- u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
- u16 cellOffset; /* Index in aData of first cell pointer */
- u16 nFree; /* Number of free bytes on the page */
- u16 nCell; /* Number of cells on this page, local and ovfl */
- u16 maskPage; /* Mask for page offset */
-- struct _OvflCell { /* Cells that will not fit on aData[] */
-- u8 *pCell; /* Pointers to the body of the overflow cell */
-- u16 idx; /* Insert this cell before idx-th non-overflow cell */
-- } aOvfl[5];
+- u16 aiOvfl[5]; /* Insert the i-th overflow cell before the aiOvfl-th
+- ** non-overflow cell */
+- u8 *apOvfl[5]; /* Pointers to the body of overflow cells */
- BtShared *pBt; /* Pointer to BtShared that this page is part of */
- 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 */
- DbPage *pDbPage; /* Pager page handle */
- Pgno pgno; /* Page number for this page */
-};
--
--/*
++static int walWriteToLog(
++ WalWriter *p, /* WAL to write to */
++ void *pContent, /* Content to be written */
++ int iAmt, /* Number of bytes to write */
++ sqlite3_int64 iOffset /* Start writing at this offset */
++){
++ int rc;
++ if( iOffset<p->iSyncPoint && iOffset+iAmt>=p->iSyncPoint ){
++ int iFirstAmt = (int)(p->iSyncPoint - iOffset);
++ rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset);
++ if( rc ) return rc;
++ iOffset += iFirstAmt;
++ iAmt -= iFirstAmt;
++ pContent = (void*)(iFirstAmt + (char*)pContent);
++ assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
++ rc = sqlite3OsSync(p->pFd, p->syncFlags);
++ if( iAmt==0 || rc ) return rc;
++ }
++ rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
++ return rc;
++}
+
+ /*
-** The in-memory image of a disk page has the auxiliary information appended
-** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
-** that extra information.
--*/
++** Write out a single frame of the WAL
+ */
-#define EXTRA_SIZE sizeof(MemPage)
--
++static int walWriteOneFrame(
++ WalWriter *p, /* Where to write the frame */
++ PgHdr *pPage, /* The page of the frame to be written */
++ int nTruncate, /* The commit flag. Usually 0. >0 for commit */
++ sqlite3_int64 iOffset /* Byte offset at which to write */
++){
++ int rc; /* Result code from subfunctions */
++ void *pData; /* Data actually written */
++ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
++#if defined(SQLITE_HAS_CODEC)
++ if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
++#else
++ pData = pPage->pData;
++#endif
++ walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
++ rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
++ if( rc ) return rc;
++ /* Write the page data */
++ rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
++ return rc;
++}
+
-/*
-** A linked list of the following structures is stored at BtShared.pLock.
-** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
-** is opened on the table with root page BtShared.iTable. Locks are removed
-** from this list when a transaction is committed or rolled back, or when
-** a btree handle is closed.
--*/
++/*
++** Write a set of frames to the log. The caller must hold the write-lock
++** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
+ */
-struct BtLock {
-- Btree *pBtree; /* Btree handle holding this lock */
-- Pgno iTable; /* Root page of table */
-- u8 eLock; /* READ_LOCK or WRITE_LOCK */
-- BtLock *pNext; /* Next in BtShared.pLock list */
--};
-+ pWal->hdr.mxFrame = iFrame;
-+ if( isCommit ){
-+ pWal->hdr.iChange++;
-+ pWal->hdr.nPage = nTruncate;
-+ }
-+ /* If this is a commit, update the wal-index header too. */
-+ if( isCommit ){
-+ walIndexWriteHdr(pWal);
-+ pWal->iCallback = iFrame;
-+ }
-+ }
+- Btree *pBtree; /* Btree handle holding this lock */
+- Pgno iTable; /* Root page of table */
+- u8 eLock; /* READ_LOCK or WRITE_LOCK */
+- BtLock *pNext; /* Next in BtShared.pLock list */
+-};
++SQLITE_PRIVATE int sqlite3WalFrames(
++ Wal *pWal, /* Wal handle to write to */
++ int szPage, /* Database page-size in bytes */
++ PgHdr *pList, /* List of dirty pages to write */
++ Pgno nTruncate, /* Database size after this commit */
++ int isCommit, /* True if this is a commit */
++ int sync_flags /* Flags to pass to OsSync() (or 0) */
++){
++ int rc; /* Used to catch return codes */
++ u32 iFrame; /* Next frame address */
++ PgHdr *p; /* Iterator to run through pList with. */
++ PgHdr *pLast = 0; /* Last frame in list */
++ int nExtra = 0; /* Number of extra copies of last page */
++ int szFrame; /* The size of a single frame */
++ i64 iOffset; /* Next byte to write in WAL file */
++ WalWriter w; /* The writer */
-/* Candidate values for BtLock.eLock */
-#define READ_LOCK 1
-#define WRITE_LOCK 2
-+ WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
-+ return rc;
-+}
++ assert( pList );
++ assert( pWal->writeLock );
-/* A Btree handle
-**
@@ -3177,27 +7355,20 @@
-** is opaque to the database connection. The database connection cannot
-** see the internals of this structure and only deals with pointers to
-** this structure.
-+/*
-+** This routine is called to implement sqlite3_wal_checkpoint() and
-+** related interfaces.
- **
+-**
-** For some database files, the same underlying database cache might be
-** shared between multiple connections. In that case, each connection
-** has it own instance of this object. But each instance of this object
-** points to the same BtShared object. The database cache and the
-** schema associated with the database file are all contained within
-** the BtShared object.
-+** Obtain a CHECKPOINT lock and then backfill as much information as
-+** we can from WAL into the database.
- **
+-**
-** All fields in this structure are accessed under sqlite3.mutex.
-** The pBt pointer itself may not be changed while there exists cursors
-** in the referenced BtShared that point back to this Btree since those
-** cursors have to go through this Btree to find their BtShared and
-** they often do so without holding sqlite3.mutex.
-+** If parameter xBusy is not NULL, it is a pointer to a busy-handler
-+** callback. In this case this function runs a blocking checkpoint.
- */
+-*/
-struct Btree {
- sqlite3 *db; /* The database connection holding this btree */
- BtShared *pBt; /* Sharable content of this btree */
@@ -3210,22 +7381,17 @@
- Btree *pPrev; /* Back pointer of the same list */
-#ifndef SQLITE_OMIT_SHARED_CACHE
- BtLock lock; /* Object used to lock page 1 */
--#endif
++ /* If this frame set completes a transaction, then nTruncate>0. If
++ ** nTruncate==0 then this frame set does not complete the transaction. */
++ assert( (isCommit!=0)==(nTruncate!=0) );
++
++#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
++ { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
++ WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
++ pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
++ }
+ #endif
-};
-+SQLITE_PRIVATE int sqlite3WalCheckpoint(
-+ Wal *pWal, /* Wal connection */
-+ int eMode, /* PASSIVE, FULL or RESTART */
-+ int (*xBusy)(void*), /* Function to call when busy */
-+ void *pBusyArg, /* Context argument for xBusyHandler */
-+ int sync_flags, /* Flags to sync db file with (or 0) */
-+ int nBuf, /* Size of temporary buffer */
-+ u8 *zBuf, /* Temporary buffer to use */
-+ int *pnLog, /* OUT: Number of frames in WAL */
-+ int *pnCkpt /* OUT: Number of backfilled frames in WAL */
-+){
-+ int rc; /* Return code */
-+ int isChanged = 0; /* True if a new wal-index header is loaded */
-+ int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
-/*
-** Btree.inTrans may take one of the following values.
@@ -3237,13 +7403,158 @@
-#define TRANS_NONE 0
-#define TRANS_READ 1
-#define TRANS_WRITE 2
-+ assert( pWal->ckptLock==0 );
-+ assert( pWal->writeLock==0 );
++ /* See if it is possible to write these frames into the start of the
++ ** log file, instead of appending to it at pWal->hdr.mxFrame.
++ */
++ if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
++ return rc;
++ }
++
++ /* If this is the first frame written into the log, write the WAL
++ ** header to the start of the WAL file. See comments at the top of
++ ** this source file for a description of the WAL header format.
++ */
++ iFrame = pWal->hdr.mxFrame;
++ if( iFrame==0 ){
++ u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */
++ u32 aCksum[2]; /* Checksum for wal-header */
++
++ sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN));
++ sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
++ sqlite3Put4byte(&aWalHdr[8], szPage);
++ sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
++ if( pWal->nCkpt==0 ) sqlite3_randomness(8, pWal->hdr.aSalt);
++ memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
++ walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
++ sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
++ sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
++
++ pWal->szPage = szPage;
++ pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
++ pWal->hdr.aFrameCksum[0] = aCksum[0];
++ pWal->hdr.aFrameCksum[1] = aCksum[1];
++ pWal->truncateOnCommit = 1;
++
++ rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
++ WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok"));
++ if( rc!=SQLITE_OK ){
++ return rc;
++ }
++
++ /* Sync the header (unless SQLITE_IOCAP_SEQUENTIAL is true or unless
++ ** all syncing is turned off by PRAGMA synchronous=OFF). Otherwise
++ ** an out-of-order write following a WAL restart could result in
++ ** database corruption. See the ticket:
++ **
++ ** http://localhost:591/sqlite/info/ff5be73dee
++ */
++ if( pWal->syncHeader && sync_flags ){
++ rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
++ if( rc ) return rc;
++ }
++ }
++ assert( (int)pWal->szPage==szPage );
++
++ /* Setup information needed to write frames into the WAL */
++ w.pWal = pWal;
++ w.pFd = pWal->pWalFd;
++ w.iSyncPoint = 0;
++ w.syncFlags = sync_flags;
++ w.szPage = szPage;
++ iOffset = walFrameOffset(iFrame+1, szPage);
++ szFrame = szPage + WAL_FRAME_HDRSIZE;
++
++ /* Write all frames into the log file exactly once */
++ for(p=pList; p; p=p->pDirty){
++ int nDbSize; /* 0 normally. Positive == commit flag */
++ iFrame++;
++ assert( iOffset==walFrameOffset(iFrame, szPage) );
++ nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
++ rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
++ if( rc ) return rc;
++ pLast = p;
++ iOffset += szFrame;
++ }
++
++ /* If this is the end of a transaction, then we might need to pad
++ ** the transaction and/or sync the WAL file.
++ **
++ ** Padding and syncing only occur if this set of frames complete a
++ ** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL
++ ** or synchonous==OFF, then no padding or syncing are needed.
++ **
++ ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not
++ ** needed and only the sync is done. If padding is needed, then the
++ ** final frame is repeated (with its commit mark) until the next sector
++ ** boundary is crossed. Only the part of the WAL prior to the last
++ ** sector boundary is synced; the part of the last frame that extends
++ ** past the sector boundary is written after the sync.
++ */
++ if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
++ if( pWal->padToSectorBoundary ){
++ int sectorSize = sqlite3OsSectorSize(pWal->pWalFd);
++ w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
++ while( iOffset<w.iSyncPoint ){
++ rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
++ if( rc ) return rc;
++ iOffset += szFrame;
++ nExtra++;
++ }
++ }else{
++ rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
++ }
++ }
++
++ /* If this frame set completes the first transaction in the WAL and
++ ** if PRAGMA journal_size_limit is set, then truncate the WAL to the
++ ** journal size limit, if possible.
++ */
++ if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){
++ i64 sz = pWal->mxWalSize;
++ if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){
++ sz = walFrameOffset(iFrame+nExtra+1, szPage);
++ }
++ walLimitSize(pWal, sz);
++ pWal->truncateOnCommit = 0;
++ }
++
++ /* Append data to the wal-index. It is not necessary to lock the
++ ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
++ ** guarantees that there are no other writers, and no data that may
++ ** be in use by existing readers is being overwritten.
++ */
++ iFrame = pWal->hdr.mxFrame;
++ for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
++ iFrame++;
++ rc = walIndexAppend(pWal, iFrame, p->pgno);
++ }
++ while( rc==SQLITE_OK && nExtra>0 ){
++ iFrame++;
++ nExtra--;
++ rc = walIndexAppend(pWal, iFrame, pLast->pgno);
++ }
++
++ if( rc==SQLITE_OK ){
++ /* Update the private copy of the header. */
++ pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
++ testcase( szPage<=32768 );
++ testcase( szPage>=65536 );
++ pWal->hdr.mxFrame = iFrame;
++ if( isCommit ){
++ pWal->hdr.iChange++;
++ pWal->hdr.nPage = nTruncate;
++ }
++ /* If this is a commit, update the wal-index header too. */
++ if( isCommit ){
++ walIndexWriteHdr(pWal);
++ pWal->iCallback = iFrame;
++ }
++ }
-/*
-** An instance of this object represents a single database file.
-**
--** A single database file can be in use as the same time by two
+-** A single database file can be in use at the same time by two
-** or more database connections. When two or more connections are
-** sharing the same database file, each connection has it own
-** private Btree object for the file and each of those Btrees points
@@ -3269,28 +7580,36 @@
-**
-** 1) The current writer (BtShared.pWriter) concludes its transaction, OR
-** 2) The number of locks held by other connections drops to zero.
--**
++ WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
++ return rc;
++}
++
++/*
++** This routine is called to implement sqlite3_wal_checkpoint() and
++** related interfaces.
+ **
-** while in the 'pending-lock' state, no connection may start a new
-** transaction.
--**
++** Obtain a CHECKPOINT lock and then backfill as much information as
++** we can from WAL into the database.
+ **
-** This feature is included to help prevent writer-starvation.
--*/
++** If parameter xBusy is not NULL, it is a pointer to a busy-handler
++** callback. In this case this function runs a blocking checkpoint.
+ */
-struct BtShared {
- Pager *pPager; /* The page cache */
- sqlite3 *db; /* Database connection currently using this Btree */
- BtCursor *pCursor; /* A list of all open cursors */
- MemPage *pPage1; /* First page of the database */
-- u8 readOnly; /* True if the underlying file is readonly */
-- u8 pageSizeFixed; /* True if the page size can no longer be changed */
-- u8 secureDelete; /* True if secure_delete is enabled */
-- u8 initiallyEmpty; /* Database is empty at start of transaction */
- u8 openFlags; /* Flags to sqlite3BtreeOpen() */
-#ifndef SQLITE_OMIT_AUTOVACUUM
- u8 autoVacuum; /* True if auto-vacuum is enabled */
- u8 incrVacuum; /* True if incr-vacuum is enabled */
-#endif
- u8 inTransaction; /* Transaction state */
-- u8 doNotUseWAL; /* If true, do not open write-ahead-log file */
+- u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
+- u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
- u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
- u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
- u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
@@ -3308,21 +7627,36 @@
- BtShared *pNext; /* Next on a list of sharable BtShared structs */
- BtLock *pLock; /* List of locks held on this shared-btree struct */
- Btree *pWriter; /* Btree with currently open write transaction */
-- u8 isExclusive; /* True if pWriter has an EXCLUSIVE lock on the db */
-- u8 isPending; /* If waiting for read-locks to clear */
-#endif
- u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
-};
-+ if( pWal->readOnly ) return SQLITE_READONLY;
-+ WALTRACE(("WAL%p: checkpoint begins\n", pWal));
-+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
-+ if( rc ){
-+ /* Usually this is SQLITE_BUSY meaning that another thread or process
-+ ** is already running a checkpoint, or maybe a recovery. But it might
-+ ** also be SQLITE_IOERR. */
-+ return rc;
-+ }
-+ pWal->ckptLock = 1;
++SQLITE_PRIVATE int sqlite3WalCheckpoint(
++ Wal *pWal, /* Wal connection */
++ int eMode, /* PASSIVE, FULL or RESTART */
++ int (*xBusy)(void*), /* Function to call when busy */
++ void *pBusyArg, /* Context argument for xBusyHandler */
++ int sync_flags, /* Flags to sync db file with (or 0) */
++ int nBuf, /* Size of temporary buffer */
++ u8 *zBuf, /* Temporary buffer to use */
++ int *pnLog, /* OUT: Number of frames in WAL */
++ int *pnCkpt /* OUT: Number of backfilled frames in WAL */
++){
++ int rc; /* Return code */
++ int isChanged = 0; /* True if a new wal-index header is loaded */
++ int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
+
+-/*
+-** Allowed values for BtShared.btsFlags
+-*/
+-#define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */
+-#define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */
+-#define BTS_SECURE_DELETE 0x0004 /* PRAGMA secure_delete is enabled */
+-#define BTS_INITIALLY_EMPTY 0x0008 /* Database was empty at trans start */
+-#define BTS_NO_WAL 0x0010 /* Do not open write-ahead-log files */
+-#define BTS_EXCLUSIVE 0x0020 /* pWriter has an exclusive lock */
+-#define BTS_PENDING 0x0040 /* Waiting for read-locks to clear */
++ assert( pWal->ckptLock==0 );
++ assert( pWal->writeLock==0 );
-/*
-** An instance of the following structure is used to hold information
@@ -3340,6 +7674,27 @@
- u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
- u16 nSize; /* Size of the cell content on the main b-tree page */
-};
++ if( pWal->readOnly ) return SQLITE_READONLY;
++ WALTRACE(("WAL%p: checkpoint begins\n", pWal));
++ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
++ if( rc ){
++ /* Usually this is SQLITE_BUSY meaning that another thread or process
++ ** is already running a checkpoint, or maybe a recovery. But it might
++ ** also be SQLITE_IOERR. */
++ return rc;
++ }
++ pWal->ckptLock = 1;
+
+-/*
+-** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
+-** this will be declared corrupt. This value is calculated based on a
+-** maximum database size of 2^31 pages a minimum fanout of 2 for a
+-** root-node and 3 for all other internal nodes.
+-**
+-** If a tree that appears to be taller than this is encountered, it is
+-** assumed that the database is corrupt.
+-*/
+-#define BTCURSOR_MAX_DEPTH 20
+ /* If this is a blocking-checkpoint, then obtain the write-lock as well
+ ** to prevent any writers from running while the checkpoint is underway.
+ ** This has to be done before the call to walIndexReadHdr() below.
@@ -3360,28 +7715,13 @@
+ }
-/*
--** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
--** this will be declared corrupt. This value is calculated based on a
--** maximum database size of 2^31 pages a minimum fanout of 2 for a
--** root-node and 3 for all other internal nodes.
--**
--** If a tree that appears to be taller than this is encountered, it is
--** assumed that the database is corrupt.
--*/
--#define BTCURSOR_MAX_DEPTH 20
-+ /* Read the wal-index header. */
-+ if( rc==SQLITE_OK ){
-+ rc = walIndexReadHdr(pWal, &isChanged);
-+ }
-
--/*
-** A cursor is a pointer to a particular entry within a particular
-** b-tree within a database file.
-**
-** The entry is identified by its MemPage and the index in
-** MemPage.aCell[] of the entry.
-**
--** A single database file can shared by two more database connections,
+-** A single database file can be shared by two more database connections,
-** but cursors cannot be shared. Each cursor is associated with a
-** particular database connection identified BtCursor.pBtree.db.
-**
@@ -3393,6 +7733,9 @@
- BtShared *pBt; /* The BtShared this cursor points to */
- BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
- struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
+-#ifndef SQLITE_OMIT_INCRBLOB
+- Pgno *aOverflow; /* Cache of overflow page locations */
+-#endif
- Pgno pgnoRoot; /* The root page of this tree */
- sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */
- CellInfo info; /* A parse of the cell we are pointing at */
@@ -3404,20 +7747,16 @@
- u8 validNKey; /* True if info.nKey is valid */
- u8 eState; /* One of the CURSOR_XXX constants (see below) */
-#ifndef SQLITE_OMIT_INCRBLOB
-- Pgno *aOverflow; /* Cache of overflow page locations */
- u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
-#endif
- i16 iPage; /* Index of current page in apPage */
- u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
- MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
-};
-+ /* Copy data from the log to the database file. */
++ /* Read the wal-index header. */
+ if( rc==SQLITE_OK ){
-+ if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
-+ rc = SQLITE_CORRUPT_BKPT;
-+ }else{
-+ rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
-+ }
++ rc = walIndexReadHdr(pWal, &isChanged);
++ }
-/*
-** Potential values for BtCursor.eState.
@@ -3448,25 +7787,23 @@
-#define CURSOR_VALID 1
-#define CURSOR_REQUIRESEEK 2
-#define CURSOR_FAULT 3
-+ /* If no error occurred, set the output variables. */
-+ if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
-+ if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
-+ if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
++ /* Copy data from the log to the database file. */
++ if( rc==SQLITE_OK ){
++ if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
++ rc = SQLITE_CORRUPT_BKPT;
++ }else{
++ rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
+ }
-+ }
-/*
-** The database page the PENDING_BYTE occupies. This page is never used.
-*/
-# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
-+ if( isChanged ){
-+ /* If a new wal-index header was loaded before the checkpoint was
-+ ** performed, then the pager-cache associated with pWal is now
-+ ** out of date. So zero the cached wal-index header to ensure that
-+ ** next time the pager opens a snapshot on this database it knows that
-+ ** the cache needs to be reset.
-+ */
-+ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
++ /* If no error occurred, set the output variables. */
++ if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
++ if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
++ if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
++ }
+ }
-/*
@@ -3483,6 +7820,16 @@
-** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
-** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
-** this test.
++ if( isChanged ){
++ /* If a new wal-index header was loaded before the checkpoint was
++ ** performed, then the pager-cache associated with pWal is now
++ ** out of date. So zero the cached wal-index header to ensure that
++ ** next time the pager opens a snapshot on this database it knows that
++ ** the cache needs to be reset.
++ */
++ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
++ }
++
+ /* Release the locks. */
+ sqlite3WalEndWriteTransaction(pWal);
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
@@ -3582,7 +7929,7 @@
+ */
+ assert( pWal->readLock>=0 || pWal->lockError );
+ assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
-
++
+ if( op==0 ){
+ if( pWal->exclusiveMode ){
+ pWal->exclusiveMode = 0;
@@ -3606,50 +7953,65 @@
+ return rc;
+}
--/*
++/*
++** Return true if the argument is non-NULL and the WAL module is using
++** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
++** WAL module is using shared-memory, return false.
++*/
++SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
++ return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
++}
+
++#ifdef SQLITE_ENABLE_ZIPVFS
+ /*
-** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
-** if the database supports auto-vacuum or not. Because it is used
-** within an expression that is an argument to another macro
-** (sqliteMallocRaw), it is not possible to use conditional compilation.
-** So, this macro is defined instead.
-+/*
-+** Return true if the argument is non-NULL and the WAL module is using
-+** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
-+** WAL module is using shared-memory, return false.
++** If the argument is not NULL, it points to a Wal object that holds a
++** read-lock. This function returns the database page-size if it is known,
++** or zero if it is not (or if pWal is NULL).
*/
-#ifndef SQLITE_OMIT_AUTOVACUUM
-#define ISAUTOVACUUM (pBt->autoVacuum)
-#else
-#define ISAUTOVACUUM 0
--#endif
--
-+SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
-+ return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
++SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
++ assert( pWal==0 || pWal->readLock>=0 );
++ return (pWal ? pWal->szPage : 0);
+}
+ #endif
--/*
++#endif /* #ifndef SQLITE_OMIT_WAL */
+
++/************** End of wal.c *************************************************/
++/************** Begin file btmutex.c *****************************************/
+ /*
-** This structure is passed around through all the sanity checking routines
-** in order to keep track of some global state information.
++** 2007 August 27
+ **
+-** The aRef[] array is allocated so that there is 1 bit for each page in
+-** the database. As the integrity-check proceeds, for each page used in
+-** the database the corresponding bit is set. This allows integrity-check to
+-** detect pages that are used twice and orphaned pages (both of which
+-** indicate corruption).
-*/
-typedef struct IntegrityCk IntegrityCk;
-struct IntegrityCk {
- BtShared *pBt; /* The tree being checked out */
- Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
+- u8 *aPgRef; /* 1 bit per page in the db (see above) */
- Pgno nPage; /* Number of pages in the database */
-- int *anRef; /* Number of times each page is referenced */
- int mxErr; /* Stop accumulating errors when this reaches zero */
- int nErr; /* Number of messages written to zErrMsg so far */
- int mallocFailed; /* A memory allocation error has occurred */
- StrAccum errMsg; /* Accumulate the error message text here */
-};
-+#endif /* #ifndef SQLITE_OMIT_WAL */
-
-+/************** End of wal.c *************************************************/
-+/************** Begin file btmutex.c *****************************************/
- /*
--** Read or write a two- and four-byte big-endian integer values.
-+** 2007 August 27
-+**
+-
+-/*
+-** Routines to read or write a two- and four-byte big-endian integer values.
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
@@ -3674,7 +8036,7 @@
#ifndef SQLITE_OMIT_SHARED_CACHE
#if SQLITE_THREADSAFE
-@@ -85801,10 +87170,16 @@
+@@ -87992,10 +89440,16 @@
*/
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
int rc = sqlite3_overload_function(db, "MATCH", 2);
@@ -3691,7 +8053,7 @@
}
/*
-@@ -91158,60 +92533,6 @@
+@@ -93389,60 +94843,6 @@
#ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
/*
@@ -3752,11 +8114,15 @@
** PRAGMA table_info(<table>)
**
** Return a single row for each column of the named table. The columns of
-@@ -91849,6 +93170,40 @@
+@@ -94090,6 +95490,44 @@
sqlite3_rekey(db, zKey, i/2);
}
}else
+/** BEGIN CRYPTO **/
++ if( sqlite3StrICmp(zLeft, "cipher_version")==0 && !zRight ){
++ extern void codec_vdbe_return_static_string(Parse *pParse, const char *zLabel, const char *value);
++ codec_vdbe_return_static_string(pParse, "cipher_version", CIPHER_VERSION);
++ }else
+ if( sqlite3StrICmp(zLeft, "cipher")==0 && zRight ){
+ extern int codec_set_cipher_name(sqlite3*, int, const char *, int);
+ codec_set_cipher_name(db, iDb, zRight, 2); // change cipher for both
@@ -3781,13 +8147,13 @@
+ extern int codec_set_page_size(sqlite3*, int, int);
+ codec_set_page_size(db, iDb, atoi(zRight)); // change page size
+ }else
++ if( sqlite3StrICmp(zLeft,"cipher_default_use_hmac")==0 ){
++ extern void codec_set_default_use_hmac(int);
++ codec_set_default_use_hmac(sqlite3GetBoolean(zRight,1));
++ }else
+ if( sqlite3StrICmp(zLeft,"cipher_use_hmac")==0 ){
+ extern int codec_set_use_hmac(sqlite3*, int, int);
-+ if(sqlite3GetBoolean(zRight)) {
-+ codec_set_use_hmac(db, iDb, 1);
-+ } else {
-+ codec_set_use_hmac(db, iDb, 0);
-+ }
++ codec_set_use_hmac(db, iDb, sqlite3GetBoolean(zRight,1));
+ }else
+/** END CRYPTO **/
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]