aboutsummaryrefslogtreecommitdiffstats
path: root/Plugins
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@unit193.net>2025-01-16 01:58:22 -0500
committerLibravatarUnit 193 <unit193@unit193.net>2025-01-16 01:58:22 -0500
commita5ae79be08125b31bb6b8d9703090a98c6fd2e30 (patch)
tree569ee612c9de85b2bb423efa485688ef1d43852e /Plugins
parent21966b4f924b0a1933d9662e75ff253bd154fdb7 (diff)
parent81a21e6ce040e7740de86340c8ea4dba30e69bc3 (diff)
Update upstream source from tag 'upstream/3.4.13+dfsg'
Update to upstream version '3.4.13+dfsg' with Debian dir bf81ee0219cb8e4562a4751df17d75814772d2d6
Diffstat (limited to 'Plugins')
-rw-r--r--Plugins/DbAndroid/dbandroidinstance.cpp11
-rw-r--r--Plugins/DbAndroid/dbandroidinstance.h1
-rw-r--r--Plugins/DbSqliteCipher/DbSqliteCipher.pro2
-rw-r--r--Plugins/DbSqliteCipher/sqlcipher.c41160
-rw-r--r--Plugins/DbSqliteCipher/sqlcipher.h1057
-rw-r--r--Plugins/DbSqliteCipher/update_sqlite_version.tcl2
-rw-r--r--Plugins/DbSqliteWx/DbSqliteWx.pro14
-rw-r--r--Plugins/DbSqliteWx/update_sqlite_version.tcl2
-rw-r--r--Plugins/DbSqliteWx/wxsqlite3.c41021
-rw-r--r--Plugins/DbSqliteWx/wxsqlite3.h959
-rw-r--r--Plugins/ScriptingPython/scriptingpython.cpp18
-rw-r--r--Plugins/ScriptingTcl/ScriptingTcl.pro19
-rw-r--r--Plugins/SqlEnterpriseFormatter/formatcreatetable.cpp20
13 files changed, 60127 insertions, 24159 deletions
diff --git a/Plugins/DbAndroid/dbandroidinstance.cpp b/Plugins/DbAndroid/dbandroidinstance.cpp
index c1b5629..62a42c4 100644
--- a/Plugins/DbAndroid/dbandroidinstance.cpp
+++ b/Plugins/DbAndroid/dbandroidinstance.cpp
@@ -124,6 +124,17 @@ Db* DbAndroidInstance::clone() const
return new DbAndroidInstance(plugin, name, path, connOptions);
}
+bool DbAndroidInstance::isTransactionActive() const
+{
+ // FIXME: Since there is no way to detect active transaction by PRAGMA or SQL function,
+ // this plugin cannot just test this state. It could potentially be implemented by tracking BEGIN/END keywords
+ // as first keywords in executed queries, but it will require more work and testing.
+ //
+ // Current consiequence of negleting this is that if user uses import() function enclosed with BEGIN & END,
+ // the query will fail due to already active transaction. In that case user needs to skip the BEGIN & END.
+ return false;
+}
+
bool DbAndroidInstance::isOpenInternal()
{
return (connection && connection->isConnected());
diff --git a/Plugins/DbAndroid/dbandroidinstance.h b/Plugins/DbAndroid/dbandroidinstance.h
index e81bd40..48877dd 100644
--- a/Plugins/DbAndroid/dbandroidinstance.h
+++ b/Plugins/DbAndroid/dbandroidinstance.h
@@ -30,6 +30,7 @@ class DbAndroidInstance : public AbstractDb
bool loadExtension(const QString& filePath, const QString& initFunc);
bool isComplete(const QString& sql) const;
Db* clone() const;
+ bool isTransactionActive() const;
protected:
bool isOpenInternal();
diff --git a/Plugins/DbSqliteCipher/DbSqliteCipher.pro b/Plugins/DbSqliteCipher/DbSqliteCipher.pro
index 33cd7c6..5ee3af6 100644
--- a/Plugins/DbSqliteCipher/DbSqliteCipher.pro
+++ b/Plugins/DbSqliteCipher/DbSqliteCipher.pro
@@ -25,7 +25,7 @@ HEADERS += dbsqlitecipher.h \
dbsqlitecipherinstance.h
sqlcipher.h
-mac: {
+macx: {
exists( /opt/local/include/openssl-3/openssl/crypto.h ) {
message( "Configuring OpenSSL from MacPorts" )
INCLUDEPATH += /opt/local/include/openssl-3
diff --git a/Plugins/DbSqliteCipher/sqlcipher.c b/Plugins/DbSqliteCipher/sqlcipher.c
index 0a86228..db651c5 100644
--- a/Plugins/DbSqliteCipher/sqlcipher.c
+++ b/Plugins/DbSqliteCipher/sqlcipher.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.39.4. By combining all the individual C code files into this
+** version 3.46.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
@@ -16,6 +16,46 @@
** if you want a wrapper to interface SQLite with your choice of programming
** language. The code for the "sqlcipher_sqlite3" command-line shell is also in a
** separate file. This file contains only code for the core SQLite library.
+**
+** The content in this amalgamation comes from Fossil check-in
+** c9c2ab54ba1f5f46360f1b4f35d849cd3f08 with changes in files:
+**
+** .fossil-settings/empty-dirs
+** .fossil-settings/ignore-glob
+** LICENSE.md
+** Makefile.in
+** Makefile.msc
+** README.md
+** aclocal.m4
+** configure
+** configure.ac
+** ltmain.sh
+** sqlcipher_sqlite3.1
+** sqlcipher_sqlite3.pc.in
+** sqlite_cfg.h.in
+** src/attach.c
+** src/backup.c
+** src/ctime.c
+** src/func.c
+** src/global.c
+** src/main.c
+** src/malloc.c
+** src/pager.c
+** src/pager.h
+** src/pragma.c
+** src/pragma.h
+** src/shell.c.in
+** src/sqlite.h.in
+** src/sqliteInt.h
+** src/tclsqlite.c
+** src/test1.c
+** src/test_config.c
+** src/test_thread.c
+** src/util.c
+** src/vacuum.c
+** src/wal.c
+** tool/mkpragmatab.tcl
+** tool/mksqlcipher_sqlite3c.tcl
*/
#define SQLITE_CORE 1
#define SQLITE_AMALGAMATION 1
@@ -51,11 +91,11 @@
** used on lines of code that actually
** implement parts of coverage testing.
**
-** OPTIMIZATION-IF-TRUE - This branch is allowed to alway be false
+** OPTIMIZATION-IF-TRUE - This branch is allowed to always be false
** and the correct answer is still obtained,
** though perhaps more slowly.
**
-** OPTIMIZATION-IF-FALSE - This branch is allowed to alway be true
+** OPTIMIZATION-IF-FALSE - This branch is allowed to always be true
** and the correct answer is still obtained,
** though perhaps more slowly.
**
@@ -124,6 +164,10 @@
#define SQLITE_4_BYTE_ALIGNED_MALLOC
#endif /* defined(_MSC_VER) && !defined(_WIN64) */
+#if !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800
+#define HAVE_LOG2 0
+#endif /* !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800 */
+
#endif /* SQLITE_MSVC_H */
/************** End of msvc.h ************************************************/
@@ -453,9 +497,9 @@ extern "C" {
** [sqlcipher_sqlite3_libversion_number()], [sqlcipher_sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.39.4"
-#define SQLITE_VERSION_NUMBER 3039004
-#define SQLITE_SOURCE_ID "2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26alt1"
+#define SQLITE_VERSION "3.46.1"
+#define SQLITE_VERSION_NUMBER 3046001
+#define SQLITE_SOURCE_ID "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69aalt1"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -727,6 +771,8 @@ typedef int (*sqlcipher_sqlite3_callback)(void*,int,char**, char**);
** the 1st parameter to sqlcipher_sqlite3_exec() while sqlcipher_sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into
** the 2nd parameter of sqlcipher_sqlite3_exec() while sqlcipher_sqlite3_exec() is running.
+** <li> The application must not dereference the arrays or string pointers
+** passed as the 3rd and 4th callback parameters after it returns.
** </ul>
*/
SQLITE_API int sqlcipher_sqlite3_exec(
@@ -835,6 +881,7 @@ SQLITE_API int sqlcipher_sqlite3_exec(
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
+#define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
@@ -870,6 +917,7 @@ SQLITE_API int sqlcipher_sqlite3_exec(
#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8))
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
+#define SQLITE_NOTICE_RBU (SQLITE_NOTICE | (3<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
@@ -977,13 +1025,17 @@ SQLITE_API int sqlcipher_sqlite3_exec(
**
** SQLite uses one of these integer values as the second
** argument to calls it makes to the xLock() and xUnlock() methods
-** of an [sqlcipher_sqlite3_io_methods] object.
+** of an [sqlcipher_sqlite3_io_methods] object. These values are ordered from
+** lest restrictive to most restrictive.
+**
+** The argument to xLock() is always SHARED or higher. The argument to
+** xUnlock is either SHARED or NONE.
*/
-#define SQLITE_LOCK_NONE 0
-#define SQLITE_LOCK_SHARED 1
-#define SQLITE_LOCK_RESERVED 2
-#define SQLITE_LOCK_PENDING 3
-#define SQLITE_LOCK_EXCLUSIVE 4
+#define SQLITE_LOCK_NONE 0 /* xUnlock() only */
+#define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */
+#define SQLITE_LOCK_RESERVED 2 /* xLock() only */
+#define SQLITE_LOCK_PENDING 3 /* xLock() only */
+#define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */
/*
** CAPI3REF: Synchronization Type Flags
@@ -1061,7 +1113,14 @@ struct sqlcipher_sqlite3_file {
** <li> [SQLITE_LOCK_PENDING], or
** <li> [SQLITE_LOCK_EXCLUSIVE].
** </ul>
-** xLock() increases the lock. xUnlock() decreases the lock.
+** xLock() upgrades the database file lock. In other words, xLock() moves the
+** database file lock in the direction NONE toward EXCLUSIVE. The argument to
+** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
+** SQLITE_LOCK_NONE. If the database file lock is already at or above the
+** requested lock, then the call to xLock() is a no-op.
+** xUnlock() downgrades the database file lock to either SHARED or NONE.
+** If the lock is already at or below the requested lock state, then the call
+** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
** PENDING, or EXCLUSIVE lock on the file. It returns true
@@ -1166,9 +1225,8 @@ struct sqlcipher_sqlite3_io_methods {
** opcode causes the xFileControl method to write the current state of
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
-** into an integer that the pArg argument points to. This capability
-** is used during testing and is only available when the SQLITE_TEST
-** compile-time option is used.
+** into an integer that the pArg argument points to.
+** This capability is only available if SQLite is compiled with [SQLITE_DEBUG].
**
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
@@ -1472,7 +1530,6 @@ struct sqlcipher_sqlite3_io_methods {
** in wal mode after the client has finished copying pages from the wal
** file to the database file, but before the *-shm file is updated to
** record the fact that the pages have been checkpointed.
-** </ul>
**
** <li>[[SQLITE_FCNTL_EXTERNAL_READER]]
** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect
@@ -1485,10 +1542,16 @@ struct sqlcipher_sqlite3_io_methods {
** the database is not a wal-mode db, or if there is no such connection in any
** other process. This opcode cannot be used to detect transactions opened
** by clients within the current process, only within other processes.
-** </ul>
**
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
-** Used by the cksmvfs VFS module only.
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the
+** [checksum VFS shim] only.
+**
+** <li>[[SQLITE_FCNTL_RESET_CACHE]]
+** If there is currently no transaction open on the database, and the
+** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control
+** purges the contents of the in-memory page cache. If there is an open
+** transaction, or if the db is a temp-db, this opcode is a no-op, not an error.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1531,6 +1594,7 @@ struct sqlcipher_sqlite3_io_methods {
#define SQLITE_FCNTL_CKPT_START 39
#define SQLITE_FCNTL_EXTERNAL_READER 40
#define SQLITE_FCNTL_CKSM_FILE 41
+#define SQLITE_FCNTL_RESET_CACHE 42
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1561,6 +1625,26 @@ typedef struct sqlcipher_sqlite3_mutex sqlcipher_sqlite3_mutex;
typedef struct sqlcipher_sqlite3_api_routines sqlcipher_sqlite3_api_routines;
/*
+** CAPI3REF: File Name
+**
+** Type [sqlcipher_sqlite3_filename] is used by SQLite to pass filenames to the
+** xOpen method of a [VFS]. It may be cast to (const char*) and treated
+** as a normal, nul-terminated, UTF-8 buffer containing the filename, but
+** may also be passed to special APIs such as:
+**
+** <ul>
+** <li> sqlcipher_sqlite3_filename_database()
+** <li> sqlcipher_sqlite3_filename_journal()
+** <li> sqlcipher_sqlite3_filename_wal()
+** <li> sqlcipher_sqlite3_uri_parameter()
+** <li> sqlcipher_sqlite3_uri_boolean()
+** <li> sqlcipher_sqlite3_uri_int64()
+** <li> sqlcipher_sqlite3_uri_key()
+** </ul>
+*/
+typedef const char *sqlcipher_sqlite3_filename;
+
+/*
** CAPI3REF: OS Interface Object
**
** An instance of the sqlcipher_sqlite3_vfs object defines the interface between
@@ -1738,7 +1822,7 @@ struct sqlcipher_sqlite3_vfs {
sqlcipher_sqlite3_vfs *pNext; /* Next registered VFS */
const char *zName; /* Name of this virtual file system */
void *pAppData; /* Pointer to application-specific data */
- int (*xOpen)(sqlcipher_sqlite3_vfs*, const char *zName, sqlcipher_sqlite3_file*,
+ int (*xOpen)(sqlcipher_sqlite3_vfs*, sqlcipher_sqlite3_filename zName, sqlcipher_sqlite3_file*,
int flags, int *pOutFlags);
int (*xDelete)(sqlcipher_sqlite3_vfs*, const char *zName, int syncDir);
int (*xAccess)(sqlcipher_sqlite3_vfs*, const char *zName, int flags, int *pResOut);
@@ -1925,20 +2009,23 @@ SQLITE_API int sqlcipher_sqlite3_os_end(void);
** must ensure that no other SQLite interfaces are invoked by other
** threads while sqlcipher_sqlite3_config() is running.</b>
**
-** The sqlcipher_sqlite3_config() interface
-** may only be invoked prior to library initialization using
-** [sqlcipher_sqlite3_initialize()] or after shutdown by [sqlcipher_sqlite3_shutdown()].
-** ^If sqlcipher_sqlite3_config() is called after [sqlcipher_sqlite3_initialize()] and before
-** [sqlcipher_sqlite3_shutdown()] then it will return SQLITE_MISUSE.
-** Note, however, that ^sqlcipher_sqlite3_config() can be called as part of the
-** implementation of an application-defined [sqlcipher_sqlite3_os_init()].
-**
** The first argument to sqlcipher_sqlite3_config() is an integer
** [configuration option] that determines
** what property of SQLite is to be configured. Subsequent arguments
** vary depending on the [configuration option]
** in the first argument.
**
+** For most configuration options, the sqlcipher_sqlite3_config() interface
+** may only be invoked prior to library initialization using
+** [sqlcipher_sqlite3_initialize()] or after shutdown by [sqlcipher_sqlite3_shutdown()].
+** The exceptional configuration options that may be invoked at any time
+** are called "anytime configuration options".
+** ^If sqlcipher_sqlite3_config() is called after [sqlcipher_sqlite3_initialize()] and before
+** [sqlcipher_sqlite3_shutdown()] with a first argument that is not an anytime
+** configuration option, then the sqlcipher_sqlite3_config() call will return SQLITE_MISUSE.
+** Note, however, that ^sqlcipher_sqlite3_config() can be called as part of the
+** implementation of an application-defined [sqlcipher_sqlite3_os_init()].
+**
** ^When a configuration option is set, sqlcipher_sqlite3_config() returns [SQLITE_OK].
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
@@ -2046,6 +2133,23 @@ struct sqlcipher_sqlite3_mem_methods {
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlcipher_sqlite3_config()] interface.
**
+** Most of the configuration options for sqlcipher_sqlite3_config()
+** will only work if invoked prior to [sqlcipher_sqlite3_initialize()] or after
+** [sqlcipher_sqlite3_shutdown()]. The few exceptions to this rule are called
+** "anytime configuration options".
+** ^Calling [sqlcipher_sqlite3_config()] with a first argument that is not an
+** anytime configuration option in between calls to [sqlcipher_sqlite3_initialize()] and
+** [sqlcipher_sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE.
+**
+** The set of anytime configuration options can change (by insertions
+** and/or deletions) from one release of SQLite to the next.
+** As of SQLite version 3.42.0, the complete set of anytime configuration
+** options is:
+** <ul>
+** <li> SQLITE_CONFIG_LOG
+** <li> SQLITE_CONFIG_PCACHE_HDRSZ
+** </ul>
+**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
** should check the return code from [sqlcipher_sqlite3_config()] to make sure that
@@ -2376,7 +2480,7 @@ struct sqlcipher_sqlite3_mem_methods {
** is stored in each sorted record and the required column values loaded
** from the database as records are returned in sorted order. The default
** value for this option is to never use this optimization. Specifying a
-** negative value for this option restores the default behaviour.
+** negative value for this option restores the default behavior.
** This option is only available if SQLite is compiled with the
** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
**
@@ -2390,30 +2494,46 @@ struct sqlcipher_sqlite3_mem_methods {
** configuration setting is never used, then the default maximum is determined
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
** compile-time option is not set, then the default maximum is 1073741824.
+**
+** [[SQLITE_CONFIG_ROWID_IN_VIEW]]
+** <dt>SQLITE_CONFIG_ROWID_IN_VIEW
+** <dd>The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability
+** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is
+** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability
+** defaults to on. This configuration option queries the current setting or
+** changes the setting to off or on. The argument is a pointer to an integer.
+** If that integer initially holds a value of 1, then the ability for VIEWs to
+** have ROWIDs is activated. If the integer initially holds zero, then the
+** ability is deactivated. Any other initial value for the integer leaves the
+** setting unchanged. After changes, if any, the integer is written with
+** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite
+** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and
+** recommended case) then the integer is always filled with zero, regardless
+** if its initial value.
** </dl>
*/
-#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
-#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
-#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* sqlcipher_sqlite3_mem_methods* */
-#define SQLITE_CONFIG_GETMALLOC 5 /* sqlcipher_sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
-#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
-#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
-#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
-#define SQLITE_CONFIG_MUTEX 10 /* sqlcipher_sqlite3_mutex_methods* */
-#define SQLITE_CONFIG_GETMUTEX 11 /* sqlcipher_sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
-#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#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 /* sqlcipher_sqlite3_pcache_methods2* */
-#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlcipher_sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
+#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
+#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
+#define SQLITE_CONFIG_MALLOC 4 /* sqlcipher_sqlite3_mem_methods* */
+#define SQLITE_CONFIG_GETMALLOC 5 /* sqlcipher_sqlite3_mem_methods* */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
+#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
+#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
+#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
+#define SQLITE_CONFIG_MUTEX 10 /* sqlcipher_sqlite3_mutex_methods* */
+#define SQLITE_CONFIG_GETMUTEX 11 /* sqlcipher_sqlite3_mutex_methods* */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
+#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 /* sqlcipher_sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlcipher_sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
-#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
-#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlcipher_sqlite3_int64, sqlcipher_sqlite3_int64 */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlcipher_sqlite3_int64, sqlcipher_sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
@@ -2421,6 +2541,7 @@ struct sqlcipher_sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlcipher_sqlite3_int64 */
+#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2454,7 +2575,7 @@ struct sqlcipher_sqlite3_mem_methods {
** configuration for a database connection can only be changed when that
** connection is not currently using lookaside memory, or in other words
** when the "current value" returned by
-** [sqlcipher_sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
+** [sqlcipher_sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
** Any attempt to change the lookaside memory configuration when lookaside
** memory is in use leaves the configuration unchanged and returns
** [SQLITE_BUSY].)^</dd>
@@ -2551,7 +2672,7 @@ struct sqlcipher_sqlite3_mem_methods {
** database handle, SQLite checks if this will mean that there are now no
** connections at all to the database. If so, it performs a checkpoint
** operation before closing the connection. This option may be used to
-** override this behaviour. The first parameter passed to this operation
+** override this behavior. The first parameter passed to this operation
** is an integer - positive to disable checkpoints-on-close, or zero (the
** default) to enable them, and negative to leave the setting unchanged.
** The second parameter is a pointer to an integer
@@ -2604,8 +2725,12 @@ struct sqlcipher_sqlite3_mem_methods {
** <li> sqlcipher_sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
** </ol>
** Because resetting a database is destructive and irreversible, the
-** process requires the use of this obscure API and multiple steps to help
-** ensure that it does not happen by accident.
+** process requires the use of this obscure API and multiple steps to
+** help ensure that it does not happen by accident. Because this
+** feature must be capable of resetting corrupt databases, and
+** shutting down virtual tables may require access to that corrupt
+** storage, the library must abandon any installed virtual tables
+** without calling their xDestroy() methods.
**
** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the
@@ -2616,6 +2741,7 @@ struct sqlcipher_sqlite3_mem_methods {
** <ul>
** <li> The [PRAGMA writable_schema=ON] statement.
** <li> The [PRAGMA journal_mode=OFF] statement.
+** <li> The [PRAGMA schema_version=N] statement.
** <li> Writes to the [sqlite_dbpage] virtual table.
** <li> Direct writes to [shadow tables].
** </ul>
@@ -2643,7 +2769,7 @@ struct sqlcipher_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
-** <dt>SQLITE_DBCONFIG_DQS_DML</td>
+** <dt>SQLITE_DBCONFIG_DQS_DML</dt>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@@ -2652,7 +2778,7 @@ struct sqlcipher_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
-** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
+** <dt>SQLITE_DBCONFIG_DQS_DDL</dt>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
@@ -2661,7 +2787,7 @@ struct sqlcipher_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
-** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
+** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@@ -2681,7 +2807,7 @@ struct sqlcipher_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
-** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
+** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
@@ -2690,7 +2816,7 @@ struct sqlcipher_sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
-** is now scarcely any need to generated database files that are compatible
+** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version
@@ -2699,8 +2825,40 @@ struct sqlcipher_sqlite3_mem_methods {
** the [VACUUM] command will fail with an obscure error when attempting to
** process a table with generated columns and a descending index. This is
** not considered a bug since SQLite versions 3.3.0 and earlier do not support
-** either generated columns or decending indexes.
+** either generated columns or descending indexes.
** </dd>
+**
+** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
+** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
+** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
+** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
+** a flag that enables collection of the sqlcipher_sqlite3_stmt_scanstatus_v2()
+** statistics. For statistics to be collected, the flag must be set on
+** the database handle both when the SQL statement is prepared and when it
+** is stepped. The flag is set (collection of statistics is enabled)
+** by default. This option takes two arguments: an integer and a pointer to
+** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the statement scanstatus option. If the second argument
+** is not NULL, then the value of the statement scanstatus setting after
+** processing the first argument is written into the integer that the second
+** argument points to.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
+** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
+** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
+** in which tables and indexes are scanned so that the scans start at the end
+** and work toward the beginning rather than starting at the beginning and
+** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
+** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** two arguments which are an integer and a pointer to an integer. The first
+** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
+** reverse scan order flag, respectively. If the second argument is not NULL,
+** then 0 or 1 is written into the integer that the second argument points to
+** depending on if the reverse scan order flag is set after processing the
+** first argument.
+** </dd>
+**
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2721,7 +2879,9 @@ struct sqlcipher_sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
+#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -2943,8 +3103,13 @@ SQLITE_API sqlcipher_sqlite3_int64 sqlcipher_sqlite3_total_changes64(sqlcipher_s
** ^A call to sqlcipher_sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlcipher_sqlite3_interrupt() call returns.
+**
+** ^The [sqlcipher_sqlite3_is_interrupted(D)] interface can be used to determine whether
+** or not an interrupt is currently in effect for [database connection] D.
+** It returns 1 if an interrupt is currently in effect, or 0 otherwise.
*/
SQLITE_API void sqlcipher_sqlite3_interrupt(sqlcipher_sqlite3*);
+SQLITE_API int sqlcipher_sqlite3_is_interrupted(sqlcipher_sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -3491,8 +3656,8 @@ SQLITE_API int sqlcipher_sqlite3_set_authorizer(
#define SQLITE_RECURSIVE 33 /* NULL NULL */
/*
-** CAPI3REF: Tracing And Profiling Functions
-** METHOD: sqlcipher_sqlite3
+** CAPI3REF: Deprecated Tracing And Profiling Functions
+** DEPRECATED
**
** These routines are deprecated. Use the [sqlcipher_sqlite3_trace_v2()] interface
** instead of the routines described here.
@@ -3562,8 +3727,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlcipher_sqlite3_profile(sqlcipher_sqlite3*,
** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
** information as is provided by the [sqlcipher_sqlite3_profile()] callback.
** ^The P argument is a pointer to the [prepared statement] and the
-** X argument points to a 64-bit integer which is the estimated of
-** the number of nanosecond that the prepared statement took to run.
+** X argument points to a 64-bit integer which is approximately
+** the number of nanoseconds that the prepared statement took to run.
** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
**
** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
@@ -3595,8 +3760,10 @@ SQLITE_API SQLITE_DEPRECATED void *sqlcipher_sqlite3_profile(sqlcipher_sqlite3*,
** M argument should be the bitwise OR-ed combination of
** zero or more [SQLITE_TRACE] constants.
**
-** ^Each call to either sqlcipher_sqlite3_trace() or sqlcipher_sqlite3_trace_v2() overrides
-** (cancels) any prior calls to sqlcipher_sqlite3_trace() or sqlcipher_sqlite3_trace_v2().
+** ^Each call to either sqlcipher_sqlite3_trace(D,X,P) or sqlcipher_sqlite3_trace_v2(D,M,X,P)
+** overrides (cancels) all prior calls to sqlcipher_sqlite3_trace(D,X,P) or
+** sqlcipher_sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each
+** database connection may have at most one trace callback.
**
** ^The X callback is invoked whenever any of the events identified by
** mask M occur. ^The integer return value from the callback is currently
@@ -3626,7 +3793,7 @@ SQLITE_API int sqlcipher_sqlite3_trace_v2(
**
** ^The sqlcipher_sqlite3_progress_handler(D,N,X,P) interface causes the callback
** function X to be invoked periodically during long running calls to
-** [sqlcipher_sqlite3_exec()], [sqlcipher_sqlite3_step()] and [sqlcipher_sqlite3_get_table()] for
+** [sqlcipher_sqlite3_step()] and [sqlcipher_sqlite3_prepare()] and similar for
** database connection D. An example use for this
** interface is to keep a GUI updated during a large query.
**
@@ -3651,6 +3818,13 @@ SQLITE_API int sqlcipher_sqlite3_trace_v2(
** Note that [sqlcipher_sqlite3_prepare_v2()] and [sqlcipher_sqlite3_step()] both modify their
** database connections for the meaning of "modify" in this paragraph.
**
+** The progress handler callback would originally only be invoked from the
+** bytecode engine. It still might be invoked during [sqlcipher_sqlite3_prepare()]
+** and similar because those routines might force a reparse of the schema
+** which involves running the bytecode engine. However, beginning with
+** SQLite version 3.41.0, the progress handler callback might also be
+** invoked directly from [sqlcipher_sqlite3_prepare()] while analyzing and generating
+** code for complex queries.
*/
SQLITE_API void sqlcipher_sqlite3_progress_handler(sqlcipher_sqlite3*, int, int(*)(void*), void*);
@@ -3687,13 +3861,18 @@ SQLITE_API void sqlcipher_sqlite3_progress_handler(sqlcipher_sqlite3*, int, int(
**
** <dl>
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
-** <dd>The database is opened in read-only mode. If the database does not
-** already exist, an error is returned.</dd>)^
+** <dd>The database is opened in read-only mode. If the database does
+** not already exist, an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
-** <dd>The database is opened for reading and writing if possible, or reading
-** only if the file is write protected by the operating system. In either
-** case the database must already exist, otherwise an error is returned.</dd>)^
+** <dd>The database is opened for reading and writing if possible, or
+** reading only if the file is write protected by the operating
+** system. In either case the database must already exist, otherwise
+** an error is returned. For historical reasons, if opening in
+** read-write mode fails due to OS-level permissions, an attempt is
+** made to open it in read-only mode. [sqlcipher_sqlite3_db_readonly()] can be
+** used to determine whether the database is actually
+** read-write.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
** <dd>The database is opened for reading and writing, and is created if
@@ -3731,6 +3910,9 @@ SQLITE_API void sqlcipher_sqlite3_progress_handler(sqlcipher_sqlite3*, int, int(
** <dd>The database is opened [shared cache] enabled, overriding
** the default shared cache setting provided by
** [sqlcipher_sqlite3_enable_shared_cache()].)^
+** The [use of shared cache mode is discouraged] and hence shared cache
+** capabilities may be omitted from many builds of SQLite. In such cases,
+** this option is a no-op.
**
** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
** <dd>The database is opened [shared cache] disabled, overriding
@@ -3746,7 +3928,7 @@ SQLITE_API void sqlcipher_sqlite3_progress_handler(sqlcipher_sqlite3*, int, int(
** to return an extended result code.</dd>
**
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
-** <dd>The database filename is not allowed to be a symbolic link</dd>
+** <dd>The database filename is not allowed to contain a symbolic link</dd>
** </dl>)^
**
** If the 3rd parameter to sqlcipher_sqlite3_open_v2() is not one of the
@@ -3950,7 +4132,7 @@ SQLITE_API int sqlcipher_sqlite3_open_v2(
** as F) must be one of:
** <ul>
** <li> A database filename pointer created by the SQLite core and
-** passed into the xOpen() method of a VFS implemention, or
+** passed into the xOpen() method of a VFS implementation, or
** <li> A filename obtained from [sqlcipher_sqlite3_db_filename()], or
** <li> A new filename constructed using [sqlcipher_sqlite3_create_filename()].
** </ul>
@@ -4005,10 +4187,10 @@ SQLITE_API int sqlcipher_sqlite3_open_v2(
**
** See the [URI filename] documentation for additional information.
*/
-SQLITE_API const char *sqlcipher_sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int sqlcipher_sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlcipher_sqlite3_int64 sqlcipher_sqlite3_uri_int64(const char*, const char*, sqlcipher_sqlite3_int64);
-SQLITE_API const char *sqlcipher_sqlite3_uri_key(const char *zFilename, int N);
+SQLITE_API const char *sqlcipher_sqlite3_uri_parameter(sqlcipher_sqlite3_filename z, const char *zParam);
+SQLITE_API int sqlcipher_sqlite3_uri_boolean(sqlcipher_sqlite3_filename z, const char *zParam, int bDefault);
+SQLITE_API sqlcipher_sqlite3_int64 sqlcipher_sqlite3_uri_int64(sqlcipher_sqlite3_filename, const char*, sqlcipher_sqlite3_int64);
+SQLITE_API const char *sqlcipher_sqlite3_uri_key(sqlcipher_sqlite3_filename z, int N);
/*
** CAPI3REF: Translate filenames
@@ -4037,9 +4219,9 @@ SQLITE_API const char *sqlcipher_sqlite3_uri_key(const char *zFilename, int N);
** return value from [sqlcipher_sqlite3_db_filename()], then the result is
** undefined and is likely a memory access violation.
*/
-SQLITE_API const char *sqlcipher_sqlite3_filename_database(const char*);
-SQLITE_API const char *sqlcipher_sqlite3_filename_journal(const char*);
-SQLITE_API const char *sqlcipher_sqlite3_filename_wal(const char*);
+SQLITE_API const char *sqlcipher_sqlite3_filename_database(sqlcipher_sqlite3_filename);
+SQLITE_API const char *sqlcipher_sqlite3_filename_journal(sqlcipher_sqlite3_filename);
+SQLITE_API const char *sqlcipher_sqlite3_filename_wal(sqlcipher_sqlite3_filename);
/*
** CAPI3REF: Database File Corresponding To A Journal
@@ -4063,7 +4245,7 @@ SQLITE_API sqlcipher_sqlite3_file *sqlcipher_sqlite3_database_file_object(const
/*
** CAPI3REF: Create and Destroy VFS Filenames
**
-** These interfces are provided for use by [VFS shim] implementations and
+** These interfaces are provided for use by [VFS shim] implementations and
** are not useful outside of that context.
**
** The sqlcipher_sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
@@ -4105,14 +4287,14 @@ SQLITE_API sqlcipher_sqlite3_file *sqlcipher_sqlite3_database_file_object(const
** then the corresponding [sqlcipher_sqlite3_module.xClose() method should also be
** invoked prior to calling sqlcipher_sqlite3_free_filename(Y).
*/
-SQLITE_API char *sqlcipher_sqlite3_create_filename(
+SQLITE_API sqlcipher_sqlite3_filename sqlcipher_sqlite3_create_filename(
const char *zDatabase,
const char *zJournal,
const char *zWal,
int nParam,
const char **azParam
);
-SQLITE_API void sqlcipher_sqlite3_free_filename(char*);
+SQLITE_API void sqlcipher_sqlite3_free_filename(sqlcipher_sqlite3_filename);
/*
** CAPI3REF: Error Codes And Messages
@@ -4142,14 +4324,17 @@ SQLITE_API void sqlcipher_sqlite3_free_filename(char*);
** </ul>
**
** ^The sqlcipher_sqlite3_errmsg() and sqlcipher_sqlite3_errmsg16() return English-language
-** text that describes the error, as either UTF-8 or UTF-16 respectively.
+** text that describes the error, as either UTF-8 or UTF-16 respectively,
+** or NULL if no error message is available.
+** (See how SQLite handles [invalid UTF] for exceptions to this rule.)
** ^(Memory to hold the error message string is managed internally.
** The application does not need to worry about freeing the result.
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
-** ^The sqlcipher_sqlite3_errstr() interface returns the English-language text
-** that describes the [result code], as UTF-8.
+** ^The sqlcipher_sqlite3_errstr(E) interface returns the English-language text
+** that describes the [result code] E, as UTF-8, or NULL if E is not an
+** result code for which a text error message is available.
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
@@ -4611,6 +4796,41 @@ SQLITE_API int sqlcipher_sqlite3_stmt_readonly(sqlcipher_sqlite3_stmt *pStmt);
SQLITE_API int sqlcipher_sqlite3_stmt_isexplain(sqlcipher_sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement
+** METHOD: sqlcipher_sqlite3_stmt
+**
+** The sqlcipher_sqlite3_stmt_explain(S,E) interface changes the EXPLAIN
+** setting for [prepared statement] S. If E is zero, then S becomes
+** a normal prepared statement. If E is 1, then S behaves as if
+** its SQL text began with "[EXPLAIN]". If E is 2, then S behaves as if
+** its SQL text began with "[EXPLAIN QUERY PLAN]".
+**
+** Calling sqlcipher_sqlite3_stmt_explain(S,E) might cause S to be reprepared.
+** SQLite tries to avoid a reprepare, but a reprepare might be necessary
+** on the first transition into EXPLAIN or EXPLAIN QUERY PLAN mode.
+**
+** Because of the potential need to reprepare, a call to
+** sqlcipher_sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be
+** reprepared because it was created using [sqlcipher_sqlite3_prepare()] instead of
+** the newer [sqlcipher_sqlite3_prepare_v2()] or [sqlcipher_sqlite3_prepare_v3()] interfaces and
+** hence has no saved SQL text with which to reprepare.
+**
+** Changing the explain setting for a prepared statement does not change
+** the original SQL text for the statement. Hence, if the SQL text originally
+** began with EXPLAIN or EXPLAIN QUERY PLAN, but sqlcipher_sqlite3_stmt_explain(S,0)
+** is called to convert the statement into an ordinary statement, the EXPLAIN
+** or EXPLAIN QUERY PLAN keywords will still appear in the sqlcipher_sqlite3_sql(S)
+** output, even though the statement now acts like a normal SQL statement.
+**
+** This routine returns SQLITE_OK if the explain mode is successfully
+** changed, or an error code if the explain mode could not be changed.
+** The explain mode cannot be changed while a statement is active.
+** Hence, it is good practice to call [sqlcipher_sqlite3_reset(S)]
+** immediately prior to calling sqlcipher_sqlite3_stmt_explain(S,E).
+*/
+SQLITE_API int sqlcipher_sqlite3_stmt_explain(sqlcipher_sqlite3_stmt *pStmt, int eMode);
+
+/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: sqlcipher_sqlite3_stmt
**
@@ -4773,7 +4993,7 @@ typedef struct sqlcipher_sqlite3_context sqlcipher_sqlite3_context;
** with it may be passed. ^It is called to dispose of the BLOB or string even
** if the call to the bind API fails, except the destructor is not called if
** the third parameter is a NULL pointer or the fourth parameter is negative.
-** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that
+** ^ (2) The special constant, [SQLITE_STATIC], may be passed to indicate that
** the application remains responsible for disposing of the object. ^In this
** case, the object and the provided pointer to it must remain valid until
** either the prepared statement is finalized or the same SQL parameter is
@@ -5452,20 +5672,33 @@ SQLITE_API int sqlcipher_sqlite3_finalize(sqlcipher_sqlite3_stmt *pStmt);
** ^The [sqlcipher_sqlite3_reset(S)] interface resets the [prepared statement] S
** back to the beginning of its program.
**
-** ^If the most recent call to [sqlcipher_sqlite3_step(S)] for the
-** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
-** or if [sqlcipher_sqlite3_step(S)] has never before been called on S,
-** then [sqlcipher_sqlite3_reset(S)] returns [SQLITE_OK].
+** ^The return code from [sqlcipher_sqlite3_reset(S)] indicates whether or not
+** the previous evaluation of prepared statement S completed successfully.
+** ^If [sqlcipher_sqlite3_step(S)] has never before been called on S or if
+** [sqlcipher_sqlite3_step(S)] has not been called since the previous call
+** to [sqlcipher_sqlite3_reset(S)], then [sqlcipher_sqlite3_reset(S)] will return
+** [SQLITE_OK].
**
** ^If the most recent call to [sqlcipher_sqlite3_step(S)] for the
** [prepared statement] S indicated an error, then
** [sqlcipher_sqlite3_reset(S)] returns an appropriate [error code].
+** ^The [sqlcipher_sqlite3_reset(S)] interface might also return an [error code]
+** if there were no prior errors but the process of resetting
+** the prepared statement caused a new error. ^For example, if an
+** [INSERT] statement with a [RETURNING] clause is only stepped one time,
+** that one call to [sqlcipher_sqlite3_step(S)] might return SQLITE_ROW but
+** the overall statement might still fail and the [sqlcipher_sqlite3_reset(S)] call
+** might return SQLITE_BUSY if locking constraints prevent the
+** database change from committing. Therefore, it is important that
+** applications check the return code from [sqlcipher_sqlite3_reset(S)] even if
+** no prior call to [sqlcipher_sqlite3_step(S)] indicated a problem.
**
** ^The [sqlcipher_sqlite3_reset(S)] interface does not change the values
** of any [sqlcipher_sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int sqlcipher_sqlite3_reset(sqlcipher_sqlite3_stmt *pStmt);
+
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
@@ -5671,10 +5904,21 @@ SQLITE_API int sqlcipher_sqlite3_create_window_function(
** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
** schema structures such as [CHECK constraints], [DEFAULT clauses],
** [expression indexes], [partial indexes], or [generated columns].
-** The SQLITE_DIRECTONLY flags is a security feature which is recommended
-** for all [application-defined SQL functions], and especially for functions
-** that have side-effects or that could potentially leak sensitive
-** information.
+** <p>
+** The SQLITE_DIRECTONLY flag is recommended for any
+** [application-defined SQL function]
+** that has side-effects or that could potentially leak sensitive information.
+** This will prevent attacks in which an application is tricked
+** into using a database file that has had its schema surreptitiously
+** modified to invoke the application-defined function in ways that are
+** harmful.
+** <p>
+** Some people say it is good practice to set SQLITE_DIRECTONLY on all
+** [application-defined SQL functions], regardless of whether or not they
+** are security sensitive, as doing so prevents those functions from being used
+** inside of the database schema, and thus ensures that the database
+** can be inspected and modified using generic tools (such as the [CLI])
+** that do not have access to the application-defined functions.
** </dd>
**
** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd>
@@ -5701,13 +5945,27 @@ SQLITE_API int sqlcipher_sqlite3_create_window_function(
** </dd>
**
** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd>
-** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
+** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
** [sqlcipher_sqlite3_value_subtype()] to inspect the sub-types of its arguments.
-** Specifying this flag makes no difference for scalar or aggregate user
-** functions. However, if it is not specified for a user-defined window
-** function, then any sub-types belonging to arguments passed to the window
-** function may be discarded before the window function is called (i.e.
-** sqlcipher_sqlite3_value_subtype() will always return 0).
+** This flag instructs SQLite to omit some corner-case optimizations that
+** might disrupt the operation of the [sqlcipher_sqlite3_value_subtype()] function,
+** causing it to return zero rather than the correct subtype().
+** SQL functions that invokes [sqlcipher_sqlite3_value_subtype()] should have this
+** property. If the SQLITE_SUBTYPE property is omitted, then the return
+** value from [sqlcipher_sqlite3_value_subtype()] might sometimes be zero even though
+** a non-zero subtype was specified by the function argument expression.
+**
+** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
+** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call
+** [sqlcipher_sqlite3_result_subtype()] to cause a sub-type to be associated with its
+** result.
+** Every function that invokes [sqlcipher_sqlite3_result_subtype()] should have this
+** property. If it does not, then the call to [sqlcipher_sqlite3_result_subtype()]
+** might become a no-op if the function is used as term in an
+** [expression index]. On the other hand, SQL functions that never invoke
+** [sqlcipher_sqlite3_result_subtype()] should avoid setting this property, as the
+** purpose of this property is to disable certain optimizations that are
+** incompatible with subtypes.
** </dd>
** </dl>
*/
@@ -5715,6 +5973,7 @@ SQLITE_API int sqlcipher_sqlite3_create_window_function(
#define SQLITE_DIRECTONLY 0x000080000
#define SQLITE_SUBTYPE 0x000100000
#define SQLITE_INNOCUOUS 0x000200000
+#define SQLITE_RESULT_SUBTYPE 0x001000000
/*
** CAPI3REF: Deprecated Functions
@@ -5881,6 +6140,28 @@ SQLITE_API int sqlcipher_sqlite3_value_nochange(sqlcipher_sqlite3_value*);
SQLITE_API int sqlcipher_sqlite3_value_frombind(sqlcipher_sqlite3_value*);
/*
+** CAPI3REF: Report the internal text encoding state of an sqlcipher_sqlite3_value object
+** METHOD: sqlcipher_sqlite3_value
+**
+** ^(The sqlcipher_sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8],
+** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current text encoding
+** of the value X, assuming that X has type TEXT.)^ If sqlcipher_sqlite3_value_type(X)
+** returns something other than SQLITE_TEXT, then the return value from
+** sqlcipher_sqlite3_value_encoding(X) is meaningless. ^Calls to
+** [sqlcipher_sqlite3_value_text(X)], [sqlcipher_sqlite3_value_text16(X)], [sqlcipher_sqlite3_value_text16be(X)],
+** [sqlcipher_sqlite3_value_text16le(X)], [sqlcipher_sqlite3_value_bytes(X)], or
+** [sqlcipher_sqlite3_value_bytes16(X)] might change the encoding of the value X and
+** thus change the return from subsequent calls to sqlcipher_sqlite3_value_encoding(X).
+**
+** This routine is intended for used by applications that test and validate
+** the SQLite implementation. This routine is inquiring about the opaque
+** internal state of an [sqlcipher_sqlite3_value] object. Ordinary applications should
+** not need to know what the internal state of an sqlcipher_sqlite3_value object is and
+** hence should not need to use this interface.
+*/
+SQLITE_API int sqlcipher_sqlite3_value_encoding(sqlcipher_sqlite3_value*);
+
+/*
** CAPI3REF: Finding The Subtype Of SQL Values
** METHOD: sqlcipher_sqlite3_value
**
@@ -5889,6 +6170,12 @@ SQLITE_API int sqlcipher_sqlite3_value_frombind(sqlcipher_sqlite3_value*);
** information can be used to pass a limited amount of context from
** one SQL function to another. Use the [sqlcipher_sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
+**
+** Every [application-defined SQL function] that invoke this interface
+** should include the [SQLITE_SUBTYPE] property in the text
+** encoding argument when the function is [sqlcipher_sqlite3_create_function|registered].
+** If the [SQLITE_SUBTYPE] property is omitted, then sqlcipher_sqlite3_value_subtype()
+** might return zero instead of the upstream subtype in some corner cases.
*/
SQLITE_API unsigned int sqlcipher_sqlite3_value_subtype(sqlcipher_sqlite3_value*);
@@ -5932,7 +6219,7 @@ SQLITE_API void sqlcipher_sqlite3_value_free(sqlcipher_sqlite3_value*);
**
** ^The sqlcipher_sqlite3_aggregate_context(C,N) routine returns a NULL pointer
** when first called if N is less than or equal to zero or if a memory
-** allocate error occurs.
+** allocation error occurs.
**
** ^(The amount of space allocated by sqlcipher_sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call. Changing the
@@ -5987,48 +6274,56 @@ SQLITE_API sqlcipher_sqlite3 *sqlcipher_sqlite3_context_db_handle(sqlcipher_sqli
** METHOD: sqlcipher_sqlite3_context
**
** These functions may be used by (non-aggregate) SQL functions to
-** associate metadata with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated metadata may be preserved. An example
-** of where this might be useful is in a regular-expression matching
-** function. The compiled version of the regular expression can be stored as
-** metadata associated with the pattern string.
+** associate auxiliary data with argument values. If the same argument
+** value is passed to multiple invocations of the same SQL function during
+** query execution, under some circumstances the associated auxiliary data
+** might be preserved. An example of where this might be useful is in a
+** regular-expression matching function. The compiled version of the regular
+** expression can be stored as auxiliary data associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The sqlcipher_sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** ^The sqlcipher_sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
** associated by the sqlcipher_sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
** value to the application-defined function. ^N is zero for the left-most
-** function argument. ^If there is no metadata
+** function argument. ^If there is no auxiliary data
** associated with the function argument, the sqlcipher_sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
-** ^The sqlcipher_sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
-** argument of the application-defined function. ^Subsequent
+** ^The sqlcipher_sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
+** N-th argument of the application-defined function. ^Subsequent
** calls to sqlcipher_sqlite3_get_auxdata(C,N) return P from the most recent
-** sqlcipher_sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or
-** NULL if the metadata has been discarded.
+** sqlcipher_sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or
+** NULL if the auxiliary data has been discarded.
** ^After each call to sqlcipher_sqlite3_set_auxdata(C,N,P,X) where X is not NULL,
** SQLite will invoke the destructor function X with parameter P exactly
-** once, when the metadata is discarded.
-** SQLite is free to discard the metadata at any time, including: <ul>
+** once, when the auxiliary data is discarded.
+** SQLite is free to discard the auxiliary data at any time, including: <ul>
** <li> ^(when the corresponding function parameter changes)^, or
** <li> ^(when [sqlcipher_sqlite3_reset()] or [sqlcipher_sqlite3_finalize()] is called for the
** SQL statement)^, or
** <li> ^(when sqlcipher_sqlite3_set_auxdata() is invoked again on the same
** parameter)^, or
** <li> ^(during the original sqlcipher_sqlite3_set_auxdata() call when a memory
-** allocation error occurs.)^ </ul>
+** allocation error occurs.)^
+** <li> ^(during the original sqlcipher_sqlite3_set_auxdata() call if the function
+** is evaluated during query planning instead of during query execution,
+** as sometimes happens with [SQLITE_ENABLE_STAT4].)^ </ul>
**
-** Note the last bullet in particular. The destructor X in
+** Note the last two bullets in particular. The destructor X in
** sqlcipher_sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
** sqlcipher_sqlite3_set_auxdata() interface even returns. Hence sqlcipher_sqlite3_set_auxdata()
** should be called near the end of the function implementation and the
** function implementation should not make any use of P after
-** sqlcipher_sqlite3_set_auxdata() has been called.
-**
-** ^(In practice, metadata is preserved between function calls for
+** sqlcipher_sqlite3_set_auxdata() has been called. Furthermore, a call to
+** sqlcipher_sqlite3_get_auxdata() that occurs immediately after a corresponding call
+** to sqlcipher_sqlite3_set_auxdata() might still return NULL if an out-of-memory
+** condition occurred during the sqlcipher_sqlite3_set_auxdata() call or if the
+** function is being evaluated during query planning rather than during
+** query execution.
+**
+** ^(In practice, auxiliary data is preserved between function calls for
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
**
@@ -6038,10 +6333,67 @@ SQLITE_API sqlcipher_sqlite3 *sqlcipher_sqlite3_context_db_handle(sqlcipher_sqli
**
** These routines must be called from the same thread in which
** the SQL function is running.
+**
+** See also: [sqlcipher_sqlite3_get_clientdata()] and [sqlcipher_sqlite3_set_clientdata()].
*/
SQLITE_API void *sqlcipher_sqlite3_get_auxdata(sqlcipher_sqlite3_context*, int N);
SQLITE_API void sqlcipher_sqlite3_set_auxdata(sqlcipher_sqlite3_context*, int N, void*, void (*)(void*));
+/*
+** CAPI3REF: Database Connection Client Data
+** METHOD: sqlcipher_sqlite3
+**
+** These functions are used to associate one or more named pointers
+** with a [database connection].
+** A call to sqlcipher_sqlite3_set_clientdata(D,N,P,X) causes the pointer P
+** to be attached to [database connection] D using name N. Subsequent
+** calls to sqlcipher_sqlite3_get_clientdata(D,N) will return a copy of pointer P
+** or a NULL pointer if there were no prior calls to
+** sqlcipher_sqlite3_set_clientdata() with the same values of D and N.
+** Names are compared using strcmp() and are thus case sensitive.
+**
+** If P and X are both non-NULL, then the destructor X is invoked with
+** argument P on the first of the following occurrences:
+** <ul>
+** <li> An out-of-memory error occurs during the call to
+** sqlcipher_sqlite3_set_clientdata() which attempts to register pointer P.
+** <li> A subsequent call to sqlcipher_sqlite3_set_clientdata(D,N,P,X) is made
+** with the same D and N parameters.
+** <li> The database connection closes. SQLite does not make any guarantees
+** about the order in which destructors are called, only that all
+** destructors will be called exactly once at some point during the
+** database connection closing process.
+** </ul>
+**
+** SQLite does not do anything with client data other than invoke
+** destructors on the client data at the appropriate time. The intended
+** use for client data is to provide a mechanism for wrapper libraries
+** to store additional information about an SQLite database connection.
+**
+** There is no limit (other than available memory) on the number of different
+** client data pointers (with different names) that can be attached to a
+** single database connection. However, the implementation is optimized
+** for the case of having only one or two different client data names.
+** Applications and wrapper libraries are discouraged from using more than
+** one client data name each.
+**
+** There is no way to enumerate the client data pointers
+** associated with a database connection. The N parameter can be thought
+** of as a secret key such that only code that knows the secret key is able
+** to access the associated data.
+**
+** Security Warning: These interfaces should not be exposed in scripting
+** languages or in other circumstances where it might be possible for an
+** an attacker to invoke them. Any agent that can invoke these interfaces
+** can probably also take control of the process.
+**
+** Database connection client data is only available for SQLite
+** version 3.44.0 ([dateof:3.44.0]) and later.
+**
+** See also: [sqlcipher_sqlite3_set_auxdata()] and [sqlcipher_sqlite3_get_auxdata()].
+*/
+SQLITE_API void *sqlcipher_sqlite3_get_clientdata(sqlcipher_sqlite3*,const char*);
+SQLITE_API int sqlcipher_sqlite3_set_clientdata(sqlcipher_sqlite3*, const char*, void*, void(*)(void*));
/*
** CAPI3REF: Constants Defining Special Destructor Behavior
@@ -6137,9 +6489,10 @@ typedef void (*sqlcipher_sqlite3_destructor_type)(void*);
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
** ^SQLite takes the text result from the application from
** the 2nd parameter of the sqlcipher_sqlite3_result_text* interfaces.
-** ^If the 3rd parameter to the sqlcipher_sqlite3_result_text* interfaces
-** is negative, then SQLite takes result text from the 2nd parameter
-** through the first zero character.
+** ^If the 3rd parameter to any of the sqlcipher_sqlite3_result_text* interfaces
+** other than sqlcipher_sqlite3_result_text64() is negative, then SQLite computes
+** the string length itself by searching the 2nd parameter for the first
+** zero character.
** ^If the 3rd parameter to the sqlcipher_sqlite3_result_text* interfaces
** is non-negative, then as many bytes (not characters) of the text
** pointed to by the 2nd parameter are taken as the application-defined
@@ -6242,6 +6595,20 @@ SQLITE_API int sqlcipher_sqlite3_result_zeroblob64(sqlcipher_sqlite3_context*, s
** higher order bits are discarded.
** The number of subtype bytes preserved by SQLite might increase
** in future releases of SQLite.
+**
+** Every [application-defined SQL function] that invokes this interface
+** should include the [SQLITE_RESULT_SUBTYPE] property in its
+** text encoding argument when the SQL function is
+** [sqlcipher_sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE]
+** property is omitted from the function that invokes sqlcipher_sqlite3_result_subtype(),
+** then in some cases the sqlcipher_sqlite3_result_subtype() might fail to set
+** the result subtype.
+**
+** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any
+** SQL function that invokes the sqlcipher_sqlite3_result_subtype() interface
+** and that does not have the SQLITE_RESULT_SUBTYPE property will raise
+** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1
+** by default.
*/
SQLITE_API void sqlcipher_sqlite3_result_subtype(sqlcipher_sqlite3_context*,unsigned int);
@@ -6473,6 +6840,13 @@ SQLITE_API void sqlcipher_sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of sqlcipher_sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
+**
+** If a negative argument is passed to sqlcipher_sqlite3_sleep() the results vary by
+** VFS and operating system. Some system treat a negative argument as an
+** instruction to sleep forever. Others understand it to mean do not sleep
+** at all. ^In SQLite version 3.42.0 and later, a negative
+** argument passed into sqlcipher_sqlite3_sleep() is changed to zero before it is relayed
+** down into the xSleep method of the VFS.
*/
SQLITE_API int sqlcipher_sqlite3_sleep(int);
@@ -6695,7 +7069,7 @@ SQLITE_API const char *sqlcipher_sqlite3_db_name(sqlcipher_sqlite3 *db, int N);
** <li> [sqlcipher_sqlite3_filename_wal()]
** </ul>
*/
-SQLITE_API const char *sqlcipher_sqlite3_db_filename(sqlcipher_sqlite3 *db, const char *zDbName);
+SQLITE_API sqlcipher_sqlite3_filename sqlcipher_sqlite3_db_filename(sqlcipher_sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
@@ -6726,7 +7100,7 @@ SQLITE_API int sqlcipher_sqlite3_db_readonly(sqlcipher_sqlite3 *db, const char *
SQLITE_API int sqlcipher_sqlite3_txn_state(sqlcipher_sqlite3*,const char *zSchema);
/*
-** CAPI3REF: Allowed return values from [sqlcipher_sqlite3_txn_state()]
+** CAPI3REF: Allowed return values from sqlcipher_sqlite3_txn_state()
** KEYWORDS: {transaction state}
**
** These constants define the current transaction state of a database file.
@@ -6832,7 +7206,7 @@ SQLITE_API void *sqlcipher_sqlite3_rollback_hook(sqlcipher_sqlite3*, void(*)(voi
** function C that is invoked prior to each autovacuum of the database
** file. ^The callback is passed a copy of the generic data pointer (P),
** the schema-name of the attached database that is being autovacuumed,
-** the the size of the database file in pages, the number of free pages,
+** the size of the database file in pages, the number of free pages,
** and the number of bytes per page, respectively. The callback should
** return the number of free pages that should be removed by the
** autovacuum. ^If the callback returns zero, then no autovacuum happens.
@@ -6858,7 +7232,7 @@ SQLITE_API void *sqlcipher_sqlite3_rollback_hook(sqlcipher_sqlite3*, void(*)(voi
** ^Each call to the sqlcipher_sqlite3_autovacuum_pages() interface overrides all
** previous invocations for that database connection. ^If the callback
** argument (C) to sqlcipher_sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer,
-** then the autovacuum steps callback is cancelled. The return value
+** then the autovacuum steps callback is canceled. The return value
** from sqlcipher_sqlite3_autovacuum_pages() is normally SQLITE_OK, but might
** be some other error code if something goes wrong. The current
** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other
@@ -6924,6 +7298,12 @@ SQLITE_API int sqlcipher_sqlite3_autovacuum_pages(
** The exceptions defined in this paragraph might change in a future
** release of SQLite.
**
+** Whether the update hook is invoked before or after the
+** corresponding change is currently unspecified and may differ
+** depending on the type of change. Do not rely on the order of the
+** hook call with regards to the final result of the operation which
+** triggers the hook.
+**
** The update hook implementation must not do anything that will modify
** the database connection that invoked the update hook. Any actions
** to modify the database connection must be deferred until after the
@@ -6953,6 +7333,11 @@ SQLITE_API void *sqlcipher_sqlite3_update_hook(
** to the same database. Sharing is enabled if the argument is true
** and disabled if the argument is false.)^
**
+** This interface is omitted if SQLite is compiled with
+** [-DSQLITE_OMIT_SHARED_CACHE]. The [-DSQLITE_OMIT_SHARED_CACHE]
+** compile-time option is recommended because the
+** [use of shared cache mode is discouraged].
+**
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
** In prior versions of SQLite,
@@ -7051,7 +7436,7 @@ SQLITE_API int sqlcipher_sqlite3_db_release_memory(sqlcipher_sqlite3*);
** ^The soft heap limit may not be greater than the hard heap limit.
** ^If the hard heap limit is enabled and if sqlcipher_sqlite3_soft_heap_limit(N)
** is invoked with a value of N that is greater than the hard heap limit,
-** the the soft heap limit is set to the value of the hard heap limit.
+** the soft heap limit is set to the value of the hard heap limit.
** ^The soft heap limit is automatically enabled whenever the hard heap
** limit is enabled. ^When sqlcipher_sqlite3_hard_heap_limit64(N) is invoked and
** the soft heap limit is outside the range of 1..N, then the soft heap
@@ -7313,15 +7698,6 @@ SQLITE_API int sqlcipher_sqlite3_cancel_auto_extension(void(*xEntryPoint)(void))
SQLITE_API void sqlcipher_sqlite3_reset_auto_extension(void);
/*
-** The interface to the virtual-table mechanism is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-*/
-
-/*
** Structures used by the virtual table interface
*/
typedef struct sqlcipher_sqlite3_vtab sqlcipher_sqlite3_vtab;
@@ -7381,6 +7757,10 @@ struct sqlcipher_sqlite3_module {
/* The methods above are in versions 1 and 2 of the sqlite_module object.
** Those below are for version 3 and greater. */
int (*xShadowName)(const char*);
+ /* The methods above are in versions 1 through 3 of the sqlite_module object.
+ ** Those below are for version 4 and greater. */
+ int (*xIntegrity)(sqlcipher_sqlite3_vtab *pVTab, const char *zSchema,
+ const char *zTabName, int mFlags, char **pzErr);
};
/*
@@ -7439,10 +7819,10 @@ struct sqlcipher_sqlite3_module {
** when the omit flag is true there is no guarantee that the constraint will
** not be checked again using byte code.)^
**
-** ^The idxNum and idxPtr values are recorded and passed into the
+** ^The idxNum and idxStr values are recorded and passed into the
** [xFilter] method.
-** ^[sqlcipher_sqlite3_free()] is used to free idxPtr if and only if
-** needToFreeIdxPtr is true.
+** ^[sqlcipher_sqlite3_free()] is used to free idxStr if and only if
+** needToFreeIdxStr is true.
**
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
** the correct order to satisfy the ORDER BY clause so that no separate
@@ -7562,7 +7942,7 @@ struct sqlcipher_sqlite3_index_info {
** the [sqlcipher_sqlite3_vtab_collation()] interface. For most real-world virtual
** tables, the collating sequence of constraints does not matter (for example
** because the constraints are numeric) and so the sqlcipher_sqlite3_vtab_collation()
-** interface is no commonly needed.
+** interface is not commonly needed.
*/
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
@@ -7722,16 +8102,6 @@ SQLITE_API int sqlcipher_sqlite3_declare_vtab(sqlcipher_sqlite3*, const char *zS
SQLITE_API int sqlcipher_sqlite3_overload_function(sqlcipher_sqlite3*, const char *zFuncName, int nArg);
/*
-** The interface to the virtual-table mechanism defined above (back up
-** to a comment remarkably similar to this one) is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-*/
-
-/*
** CAPI3REF: A Handle To An Open BLOB
** KEYWORDS: {BLOB handle} {BLOB handles}
**
@@ -7878,7 +8248,7 @@ SQLITE_API int sqlcipher_sqlite3_blob_reopen(sqlcipher_sqlite3_blob *, sqlcipher
** code is returned and the transaction rolled back.
**
** Calling this function with an argument that is not a NULL pointer or an
-** open blob handle results in undefined behaviour. ^Calling this routine
+** open blob handle results in undefined behavior. ^Calling this routine
** with a null pointer (such as would be returned by a failed call to
** [sqlcipher_sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
** is passed a valid open blob handle, the values returned by the
@@ -8105,18 +8475,20 @@ SQLITE_API int sqlcipher_sqlite3_vfs_unregister(sqlcipher_sqlite3_vfs*);
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by sqlcipher_sqlite3_mutex_try(). On those systems, sqlcipher_sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** sqlcipher_sqlite3_mutex_try() as an optimization so this is acceptable
-** behavior.)^
+** will always return SQLITE_BUSY. In most cases the SQLite core only uses
+** sqlcipher_sqlite3_mutex_try() as an optimization, so this is acceptable
+** behavior. The exceptions are unix builds that set the
+** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working
+** sqlcipher_sqlite3_mutex_try() is required.)^
**
** ^The sqlcipher_sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated.
**
-** ^If the argument to sqlcipher_sqlite3_mutex_enter(), sqlcipher_sqlite3_mutex_try(), or
-** sqlcipher_sqlite3_mutex_leave() is a NULL pointer, then all three routines
-** behave as no-ops.
+** ^If the argument to sqlcipher_sqlite3_mutex_enter(), sqlcipher_sqlite3_mutex_try(),
+** sqlcipher_sqlite3_mutex_leave(), or sqlcipher_sqlite3_mutex_free() is a NULL pointer,
+** then any of the four routines behaves as a no-op.
**
** See also: [sqlcipher_sqlite3_mutex_held()] and [sqlcipher_sqlite3_mutex_notheld()].
*/
@@ -8358,6 +8730,7 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
+#define SQLITE_TESTCTRL_FK_NO_ACTION 7
#define SQLITE_TESTCTRL_BITVEC_TEST 8
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
@@ -8365,6 +8738,7 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ASSERT 12
#define SQLITE_TESTCTRL_ALWAYS 13
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
+#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
@@ -8386,7 +8760,8 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33
-#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34
+#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -8399,7 +8774,7 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...);
** The sqlcipher_sqlite3_keyword_count() interface returns the number of distinct
** keywords understood by SQLite.
**
-** The sqlcipher_sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and
+** The sqlcipher_sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and
** makes *Z point to that keyword expressed as UTF8 and writes the number
** of bytes in the keyword into *L. The string that *Z points to is not
** zero-terminated. The sqlcipher_sqlite3_keyword_name(N,Z,L) routine returns
@@ -9346,7 +9721,7 @@ typedef struct sqlcipher_sqlite3_backup sqlcipher_sqlite3_backup;
** if the application incorrectly accesses the destination [database connection]
** and so no error code is reported, but the operations may malfunction
** nevertheless. Use of the destination database connection while a
-** backup is in progress might also also cause a mutex deadlock.
+** backup is in progress might also cause a mutex deadlock.
**
** If running in [shared cache mode], the application must
** guarantee that the shared cache used by the destination database
@@ -9774,7 +10149,7 @@ SQLITE_API int sqlcipher_sqlite3_wal_checkpoint_v2(
*/
#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
-#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */
#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
/*
@@ -9842,7 +10217,7 @@ SQLITE_API int sqlcipher_sqlite3_vtab_config(sqlcipher_sqlite3*, int op, ...);
** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
** <dd>Calls of the form
** [sqlcipher_sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** prohibits that virtual table from being used from within triggers and
** views.
** </dd>
@@ -9850,18 +10225,28 @@ SQLITE_API int sqlcipher_sqlite3_vtab_config(sqlcipher_sqlite3*, int op, ...);
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [sqlcipher_sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
+**
+** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
+** <dd>Calls of the form
+** [sqlcipher_sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
+** instruct the query planner to begin at least a read transaction on
+** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
+** virtual table is used.
+** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3
+#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -9934,7 +10319,7 @@ SQLITE_API int sqlcipher_sqlite3_vtab_nochange(sqlcipher_sqlite3_context*);
** <li><p> Otherwise, "BINARY" is returned.
** </ol>
*/
-SQLITE_API SQLITE_EXPERIMENTAL const char *sqlcipher_sqlite3_vtab_collation(sqlcipher_sqlite3_index_info*,int);
+SQLITE_API const char *sqlcipher_sqlite3_vtab_collation(sqlcipher_sqlite3_index_info*,int);
/*
** CAPI3REF: Determine if a virtual table query is DISTINCT
@@ -9968,24 +10353,45 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlcipher_sqlite3_vtab_collation(sqlc
** <li value="2"><p>
** ^(If the sqlcipher_sqlite3_vtab_distinct() interface returns 2, that means
** that the query planner does not need the rows returned in any particular
-** order, as long as rows with the same values in all "aOrderBy" columns
-** are adjacent.)^ ^(Furthermore, only a single row for each particular
-** combination of values in the columns identified by the "aOrderBy" field
-** needs to be returned.)^ ^It is always ok for two or more rows with the same
-** values in all "aOrderBy" columns to be returned, as long as all such rows
-** are adjacent. ^The virtual table may, if it chooses, omit extra rows
-** that have the same value for all columns identified by "aOrderBy".
-** ^However omitting the extra rows is optional.
+** order, as long as rows with the same values in all columns identified
+** by "aOrderBy" are adjacent.)^ ^(Furthermore, when two or more rows
+** contain the same values for all columns identified by "colUsed", all but
+** one such row may optionally be omitted from the result.)^
+** The virtual table is not required to omit rows that are duplicates
+** over the "colUsed" columns, but if the virtual table can do that without
+** too much extra effort, it could potentially help the query to run faster.
** This mode is used for a DISTINCT query.
** <li value="3"><p>
-** ^(If the sqlcipher_sqlite3_vtab_distinct() interface returns 3, that means
-** that the query planner needs only distinct rows but it does need the
-** rows to be sorted.)^ ^The virtual table implementation is free to omit
-** rows that are identical in all aOrderBy columns, if it wants to, but
-** it is not required to omit any rows. This mode is used for queries
+** ^(If the sqlcipher_sqlite3_vtab_distinct() interface returns 3, that means the
+** virtual table must return rows in the order defined by "aOrderBy" as
+** if the sqlcipher_sqlite3_vtab_distinct() interface had returned 0. However if
+** two or more rows in the result have the same values for all columns
+** identified by "colUsed", then all but one such row may optionally be
+** omitted.)^ Like when the return value is 2, the virtual table
+** is not required to omit rows that are duplicates over the "colUsed"
+** columns, but if the virtual table can do that without
+** too much extra effort, it could potentially help the query to run faster.
+** This mode is used for queries
** that have both DISTINCT and ORDER BY clauses.
** </ol>
**
+** <p>The following table summarizes the conditions under which the
+** virtual table is allowed to set the "orderByConsumed" flag based on
+** the value returned by sqlcipher_sqlite3_vtab_distinct(). This table is a
+** restatement of the previous four paragraphs:
+**
+** <table border=1 cellspacing=0 cellpadding=10 width="90%">
+** <tr>
+** <td valign="top">sqlcipher_sqlite3_vtab_distinct() return value
+** <td valign="top">Rows are returned in aOrderBy order
+** <td valign="top">Rows with the same value in all aOrderBy columns are adjacent
+** <td valign="top">Duplicates over all colUsed columns may be omitted
+** <tr><td>0<td>yes<td>yes<td>no
+** <tr><td>1<td>no<td>yes<td>no
+** <tr><td>2<td>no<td>yes<td>yes
+** <tr><td>3<td>yes<td>yes<td>yes
+** </table>
+**
** ^For the purposes of comparing virtual table output values to see if the
** values are same value for sorting purposes, two NULL values are considered
** to be the same. In other words, the comparison operator is "IS"
@@ -10022,7 +10428,7 @@ SQLITE_API int sqlcipher_sqlite3_vtab_distinct(sqlcipher_sqlite3_index_info*);
** communicated to the xBestIndex method as a
** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use
** this constraint, it must set the corresponding
-** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under
+** aConstraintUsage[].argvIndex to a positive integer. ^(Then, under
** the usual mode of handling IN operators, SQLite generates [bytecode]
** that invokes the [xFilter|xFilter() method] once for each value
** on the right-hand side of the IN operator.)^ Thus the virtual table
@@ -10091,21 +10497,20 @@ SQLITE_API int sqlcipher_sqlite3_vtab_in(sqlcipher_sqlite3_index_info*, int iCon
** is undefined and probably harmful.
**
** The X parameter in a call to sqlcipher_sqlite3_vtab_in_first(X,P) or
-** sqlcipher_sqlite3_vtab_in_next(X,P) must be one of the parameters to the
+** sqlcipher_sqlite3_vtab_in_next(X,P) should be one of the parameters to the
** xFilter method which invokes these routines, and specifically
** a parameter that was previously selected for all-at-once IN constraint
** processing use the [sqlcipher_sqlite3_vtab_in()] interface in the
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
** an xFilter argument that was selected for all-at-once IN constraint
-** processing, then these routines return [SQLITE_MISUSE])^ or perhaps
-** exhibit some other undefined or harmful behavior.
+** processing, then these routines return [SQLITE_ERROR].)^
**
** ^(Use these routines to access all values on the right-hand side
** of the IN constraint using code like the following:
**
** <blockquote><pre>
** &nbsp; for(rc=sqlcipher_sqlite3_vtab_in_first(pList, &pVal);
-** &nbsp; rc==SQLITE_OK && pVal
+** &nbsp; rc==SQLITE_OK && pVal;
** &nbsp; rc=sqlcipher_sqlite3_vtab_in_next(pList, &pVal)
** &nbsp; ){
** &nbsp; // do something with pVal
@@ -10203,6 +10608,10 @@ SQLITE_API int sqlcipher_sqlite3_vtab_rhs_value(sqlcipher_sqlite3_index_info*, i
** managed by the prepared statement S and will be automatically freed when
** S is finalized.
**
+** Not all values are available for all query elements. When a value is
+** not available, the output variable is set to -1 if the value is numeric,
+** or to NULL if it is a string (SQLITE_SCANSTAT_NAME).
+**
** <dl>
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
** <dd>^The [sqlcipher_sqlite3_int64] variable pointed to by the V parameter will be
@@ -10230,12 +10639,24 @@ SQLITE_API int sqlcipher_sqlite3_vtab_rhs_value(sqlcipher_sqlite3_index_info*, i
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
-** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
+** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECTID</dt>
** <dd>^The "int" variable pointed to by the V parameter will be set to the
-** "select-id" for the X-th loop. The select-id identifies which query or
-** subquery the loop is part of. The main query has a select-id of zero.
-** The select-id is the same value as is output in the first column
-** of an [EXPLAIN QUERY PLAN] query.
+** id for the X-th query plan element. The id value is unique within the
+** statement. The select-id is the same value as is output in the first
+** column of an [EXPLAIN QUERY PLAN] query.
+**
+** [[SQLITE_SCANSTAT_PARENTID]] <dt>SQLITE_SCANSTAT_PARENTID</dt>
+** <dd>The "int" variable pointed to by the V parameter will be set to the
+** the id of the parent of the current query element, if applicable, or
+** to zero if the query element has no parent. This is the same value as
+** returned in the second column of an [EXPLAIN QUERY PLAN] query.
+**
+** [[SQLITE_SCANSTAT_NCYCLE]] <dt>SQLITE_SCANSTAT_NCYCLE</dt>
+** <dd>The sqlcipher_sqlite3_int64 output value is set to the number of cycles,
+** according to the processor time-stamp counter, that elapsed while the
+** query element was being processed. This value is not available for
+** all query elements - if it is unavailable the output variable is
+** set to -1.
** </dl>
*/
#define SQLITE_SCANSTAT_NLOOP 0
@@ -10244,12 +10665,14 @@ SQLITE_API int sqlcipher_sqlite3_vtab_rhs_value(sqlcipher_sqlite3_index_info*, i
#define SQLITE_SCANSTAT_NAME 3
#define SQLITE_SCANSTAT_EXPLAIN 4
#define SQLITE_SCANSTAT_SELECTID 5
+#define SQLITE_SCANSTAT_PARENTID 6
+#define SQLITE_SCANSTAT_NCYCLE 7
/*
** CAPI3REF: Prepared Statement Scan Status
** METHOD: sqlcipher_sqlite3_stmt
**
-** This interface returns information about the predicted and measured
+** These interfaces return information about the predicted and measured
** performance for pStmt. Advanced applications can use this
** interface to compare the predicted and the measured performance and
** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
@@ -10260,19 +10683,25 @@ SQLITE_API int sqlcipher_sqlite3_vtab_rhs_value(sqlcipher_sqlite3_index_info*, i
**
** The "iScanStatusOp" parameter determines which status information to return.
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
-** of this interface is undefined.
-** ^The requested measurement is written into a variable pointed to by
-** the "pOut" parameter.
-** Parameter "idx" identifies the specific loop to retrieve statistics for.
-** Loops are numbered starting from zero. ^If idx is out of range - less than
-** zero or greater than or equal to the total number of loops used to implement
-** the statement - a non-zero value is returned and the variable that pOut
-** points to is unchanged.
-**
-** ^Statistics might not be available for all loops in all statements. ^In cases
-** where there exist loops with no available statistics, this function behaves
-** as if the loop did not exist - it returns non-zero and leave the variable
-** that pOut points to unchanged.
+** of this interface is undefined. ^The requested measurement is written into
+** a variable pointed to by the "pOut" parameter.
+**
+** The "flags" parameter must be passed a mask of flags. At present only
+** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX
+** is specified, then status information is available for all elements
+** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If
+** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements
+** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of
+** the EXPLAIN QUERY PLAN output) are available. Invoking API
+** sqlcipher_sqlite3_stmt_scanstatus() is equivalent to calling
+** sqlcipher_sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter.
+**
+** Parameter "idx" identifies the specific query element to retrieve statistics
+** for. Query elements are numbered starting from zero. A value of -1 may be
+** to query for statistics regarding the entire query. ^If idx is out of range
+** - less than -1 or greater than or equal to the total number of query
+** elements used to implement the statement - a non-zero value is returned and
+** the variable that pOut points to is unchanged.
**
** See also: [sqlcipher_sqlite3_stmt_scanstatus_reset()]
*/
@@ -10282,6 +10711,19 @@ SQLITE_API int sqlcipher_sqlite3_stmt_scanstatus(
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
void *pOut /* Result written here */
);
+SQLITE_API int sqlcipher_sqlite3_stmt_scanstatus_v2(
+ sqlcipher_sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
+ int idx, /* Index of loop to report on */
+ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
+ int flags, /* Mask of flags defined below */
+ void *pOut /* Result written here */
+);
+
+/*
+** CAPI3REF: Prepared Statement Scan Status
+** KEYWORDS: {scan status flags}
+*/
+#define SQLITE_SCANSTAT_COMPLEX 0x0001
/*
** CAPI3REF: Zero Scan-Status Counters
@@ -10372,6 +10814,10 @@ SQLITE_API int sqlcipher_sqlite3_db_cacheflush(sqlcipher_sqlite3*);
** function is not defined for operations on WITHOUT ROWID tables, or for
** DELETE operations on rowid tables.
**
+** ^The sqlcipher_sqlite3_preupdate_hook(D,C,P) function returns the P argument from
+** the previous call on the same [database connection] D, or NULL for
+** the first call on D.
+**
** The [sqlcipher_sqlite3_preupdate_old()], [sqlcipher_sqlite3_preupdate_new()],
** [sqlcipher_sqlite3_preupdate_count()], and [sqlcipher_sqlite3_preupdate_depth()] interfaces
** provide additional information about a preupdate event. These routines
@@ -10411,7 +10857,7 @@ SQLITE_API int sqlcipher_sqlite3_db_cacheflush(sqlcipher_sqlite3*);
** When the [sqlcipher_sqlite3_blob_write()] API is used to update a blob column,
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
** in this case the new values are not available. In this case, when a
-** callback made with op==SQLITE_DELETE is actuall a write using the
+** callback made with op==SQLITE_DELETE is actually a write using the
** sqlcipher_sqlite3_blob_write() API, the [sqlcipher_sqlite3_preupdate_blobwrite()] returns
** the index of the column being written. In other cases, where the
** pre-update hook is being invoked for some other reason, including a
@@ -10672,6 +11118,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlcipher_sqlite3_snapshot_recover(sqlcipher_
** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
** of the database exists.
**
+** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set,
+** the returned buffer content will remain accessible and unchanged
+** until either the next write operation on the connection or when
+** the connection is closed, and applications must not modify the
+** buffer. If the bit had been clear, the returned buffer will not
+** be accessed by SQLite after the call.
+**
** A call to sqlcipher_sqlite3_serialize(D,S,P,F) might return NULL even if the
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
** allocation error occurs.
@@ -10720,6 +11173,9 @@ SQLITE_API unsigned char *sqlcipher_sqlite3_serialize(
** SQLite will try to increase the buffer size using sqlcipher_sqlite3_realloc64()
** if writes on the database cause it to grow larger than M bytes.
**
+** Applications must not modify the buffer P or invalidate it before
+** the database connection D is closed.
+**
** The sqlcipher_sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
** database is currently in a read transaction or is involved in a backup
** operation.
@@ -10728,6 +11184,13 @@ SQLITE_API unsigned char *sqlcipher_sqlite3_serialize(
** S argument to sqlcipher_sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
** function returns SQLITE_ERROR.
**
+** The deserialized database should not be in [WAL mode]. If the database
+** is in WAL mode, then any attempt to use the database file will result
+** in an [SQLITE_CANTOPEN] error. The application can set the
+** [file format version numbers] (bytes 18 and 19) of the input database P
+** to 0x01 prior to invoking sqlcipher_sqlite3_deserialize(D,S,P,N,M,F) to force the
+** database file into rollback mode and work around this limitation.
+**
** If sqlcipher_sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
** [sqlcipher_sqlite3_free()] is invoked on argument P prior to returning.
@@ -10777,6 +11240,19 @@ SQLITE_API int sqlcipher_sqlite3_deserialize(
# undef double
#endif
+#if defined(__wasi__)
+# undef SQLITE_WASI
+# define SQLITE_WASI 1
+# undef SQLITE_OMIT_WAL
+# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
+# ifndef SQLITE_OMIT_LOAD_EXTENSION
+# define SQLITE_OMIT_LOAD_EXTENSION
+# endif
+# ifndef SQLITE_THREADSAFE
+# define SQLITE_THREADSAFE 0
+# endif
+#endif
+
#if 0
} /* End of the 'extern "C"' block */
#endif
@@ -10983,16 +11459,20 @@ SQLITE_API int sqlcipher_sqlite3session_create(
SQLITE_API void sqlcipher_sqlite3session_delete(sqlcipher_sqlite3_session *pSession);
/*
-** CAPIREF: Conigure a Session Object
+** CAPI3REF: Configure a Session Object
** METHOD: sqlcipher_sqlite3_session
**
** This method is used to configure a session object after it has been
-** created. At present the only valid value for the second parameter is
-** [SQLITE_SESSION_OBJCONFIG_SIZE].
+** created. At present the only valid values for the second parameter are
+** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
**
-** Arguments for sqlcipher_sqlite3session_object_config()
+*/
+SQLITE_API int sqlcipher_sqlite3session_object_config(sqlcipher_sqlite3_session*, int op, void *pArg);
+
+/*
+** CAPI3REF: Options for sqlcipher_sqlite3session_object_config
**
-** The following values may passed as the the 4th parameter to
+** The following values may passed as the the 2nd parameter to
** sqlcipher_sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
@@ -11008,12 +11488,21 @@ SQLITE_API void sqlcipher_sqlite3session_delete(sqlcipher_sqlite3_session *pSess
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
+**
+** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd>
+** This option is used to set, clear or query the flag that enables
+** collection of data for tables with no explicit PRIMARY KEY.
+**
+** Normally, tables with no explicit PRIMARY KEY are simply ignored
+** by the sessions module. However, if this flag is set, it behaves
+** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
+** as their leftmost columns.
+**
+** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
+** the first table has been attached to the session object.
*/
-SQLITE_API int sqlcipher_sqlite3session_object_config(sqlcipher_sqlite3_session*, int op, void *pArg);
-
-/*
-*/
-#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/*
** CAPI3REF: Enable Or Disable A Session Object
@@ -11775,6 +12264,18 @@ SQLITE_API int sqlcipher_sqlite3changeset_concat(
/*
+** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
+*/
+SQLITE_API int sqlcipher_sqlite3changeset_upgrade(
+ sqlcipher_sqlite3 *db,
+ const char *zDb,
+ int nIn, const void *pIn, /* Input changeset */
+ int *pnOut, void **ppOut /* OUT: Inverse of input */
+);
+
+
+
+/*
** CAPI3REF: Changegroup Handle
**
** A changegroup is an object used to combine two or more
@@ -11821,6 +12322,38 @@ typedef struct sqlcipher_sqlite3_changegroup sqlcipher_sqlite3_changegroup;
SQLITE_API int sqlcipher_sqlite3changegroup_new(sqlcipher_sqlite3_changegroup **pp);
/*
+** CAPI3REF: Add a Schema to a Changegroup
+** METHOD: sqlcipher_sqlite3_changegroup_schema
+**
+** This method may be used to optionally enforce the rule that the changesets
+** added to the changegroup handle must match the schema of database zDb
+** ("main", "temp", or the name of an attached database). If
+** sqlcipher_sqlite3changegroup_add() is called to add a changeset that is not compatible
+** with the configured schema, SQLITE_SCHEMA is returned and the changegroup
+** object is left in an undefined state.
+**
+** A changeset schema is considered compatible with the database schema in
+** the same way as for sqlcipher_sqlite3changeset_apply(). Specifically, for each
+** table in the changeset, there exists a database table with:
+**
+** <ul>
+** <li> The name identified by the changeset, and
+** <li> at least as many columns as recorded in the changeset, and
+** <li> the primary key columns in the same position as recorded in
+** the changeset.
+** </ul>
+**
+** The output of the changegroup object always has the same schema as the
+** database nominated using this function. In cases where changesets passed
+** to sqlcipher_sqlite3changegroup_add() have fewer columns than the corresponding table
+** in the database schema, these are filled in using the default column
+** values from the database schema. This makes it possible to combined
+** changesets that have different numbers of columns for a single table
+** within a changegroup, provided that they are otherwise compatible.
+*/
+SQLITE_API int sqlcipher_sqlite3changegroup_schema(sqlcipher_sqlite3_changegroup*, sqlcipher_sqlite3*, const char *zDb);
+
+/*
** CAPI3REF: Add A Changeset To A Changegroup
** METHOD: sqlcipher_sqlite3_changegroup
**
@@ -11888,17 +12421,46 @@ SQLITE_API int sqlcipher_sqlite3changegroup_new(sqlcipher_sqlite3_changegroup **
** If the new changeset contains changes to a table that is already present
** in the changegroup, then the number of columns and the position of the
** primary key columns for the table must be consistent. If this is not the
-** case, this function fails with SQLITE_SCHEMA. If the input changeset
-** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
-** returned. Or, if an out-of-memory condition occurs during processing, this
-** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
-** of the final contents of the changegroup is undefined.
+** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup
+** object has been configured with a database schema using the
+** sqlcipher_sqlite3changegroup_schema() API, then it is possible to combine changesets
+** with different numbers of columns for a single table, provided that
+** they are otherwise compatible.
+**
+** If the input changeset appears to be corrupt and the corruption is
+** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition
+** occurs during processing, this function returns SQLITE_NOMEM.
**
-** If no error occurs, SQLITE_OK is returned.
+** In all cases, if an error occurs the state of the final contents of the
+** changegroup is undefined. If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int sqlcipher_sqlite3changegroup_add(sqlcipher_sqlite3_changegroup*, int nData, void *pData);
/*
+** CAPI3REF: Add A Single Change To A Changegroup
+** METHOD: sqlcipher_sqlite3_changegroup
+**
+** This function adds the single change currently indicated by the iterator
+** passed as the second argument to the changegroup object. The rules for
+** adding the change are just as described for [sqlcipher_sqlite3changegroup_add()].
+**
+** If the change is successfully added to the changegroup, SQLITE_OK is
+** returned. Otherwise, an SQLite error code is returned.
+**
+** The iterator must point to a valid entry when this function is called.
+** If it does not, SQLITE_ERROR is returned and no change is added to the
+** changegroup. Additionally, the iterator must not have been opened with
+** the SQLITE_CHANGESETAPPLY_INVERT flag. In this case SQLITE_ERROR is also
+** returned.
+*/
+SQLITE_API int sqlcipher_sqlite3changegroup_add_change(
+ sqlcipher_sqlite3_changegroup*,
+ sqlcipher_sqlite3_changeset_iter*
+);
+
+
+
+/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
** METHOD: sqlcipher_sqlite3_changegroup
**
@@ -12146,9 +12708,30 @@ SQLITE_API int sqlcipher_sqlite3changeset_apply_v2(
** Invert the changeset before applying it. This is equivalent to inverting
** a changeset using sqlcipher_sqlite3changeset_invert() before applying it. It is
** an error to specify this flag with a patchset.
+**
+** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd>
+** Do not invoke the conflict handler callback for any changes that
+** would not actually modify the database even if they were applied.
+** Specifically, this means that the conflict handler is not invoked
+** for:
+** <ul>
+** <li>a delete change if the row being deleted cannot be found,
+** <li>an update change if the modified fields are already set to
+** their new values in the conflicting row, or
+** <li>an insert change if all fields of the conflicting row match
+** the row being inserted.
+** </ul>
+**
+** <dt>SQLITE_CHANGESETAPPLY_FKNOACTION <dd>
+** If this flag it set, then all foreign key constraints in the target
+** database behave as if they were declared with "ON UPDATE NO ACTION ON
+** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL
+** or SET DEFAULT.
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
+#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
+#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008
/*
** CAPI3REF: Constants Passed To The Conflict Handler
@@ -12681,8 +13264,8 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
-** registered with.
+** Return a copy of the pUserData pointer passed to the xCreateFunction()
+** API when the extension function was registered.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
@@ -12714,8 +13297,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the text of column iCol of
+** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -12725,8 +13311,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of phrases in the current query, as returned by xPhraseCount,
+** 0 is returned. Otherwise, this function returns the number of tokens in
+** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -12742,12 +13330,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
+** output by xInstCount(). If iIdx is less than zero or greater than
+** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
+** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. Returns SQLITE_OK if successful, or an error
-** code (i.e. SQLITE_NOMEM) if an error occurs.
+** first token of the phrase. SQLITE_OK is returned if successful, or an
+** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -12773,6 +13362,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
+** If parameter iPhrase is less than zero, or greater than or equal to
+** the number of phrases in the query, as returned by xPhraseCount(),
+** this function returns SQLITE_RANGE.
+**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -12887,6 +13480,39 @@ struct Fts5PhraseIter {
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
+**
+** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase iPhrase of the current
+** query. Before returning, output parameter *ppToken is set to point
+** to a buffer containing the requested token, and *pnToken to the
+** size of this buffer in bytes.
+**
+** If iPhrase or iToken are less than zero, or if iPhrase is greater than
+** or equal to the number of phrases in the query as reported by
+** xPhraseCount(), or if iToken is equal to or greater than the number of
+** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
+ are both zeroed.
+**
+** The output text is not a copy of the query text that specified the
+** token. It is the output of the tokenizer module. For tokendata=1
+** tables, this includes any embedded 0x00 and trailing data.
+**
+** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase hit iIdx within the
+** current row. If iIdx is less than zero or greater than or equal to the
+** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
+** output variable (*ppToken) is set to point to a buffer containing the
+** matching document token, and (*pnToken) to the size of that buffer in
+** bytes. This API is not available if the specified token matches a
+** prefix query term. In that case both output variables are always set
+** to 0.
+**
+** The output text is not a copy of the document text that was tokenized.
+** It is the output of the tokenizer module. For tokendata=1 tables, this
+** includes any embedded 0x00 and trailing data.
+**
+** This API can be quite slow if used with an FTS5 table created with the
+** "detail=none" or "detail=column" option.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 3 */
@@ -12924,6 +13550,13 @@ struct Fts5ExtensionApi {
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
+
+ /* Below this point are iVersion>=3 only */
+ int (*xQueryToken)(Fts5Context*,
+ int iPhrase, int iToken,
+ const char **ppToken, int *pnToken
+ );
+ int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
};
/*
@@ -13118,8 +13751,8 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
@@ -13167,7 +13800,7 @@ struct fts5_api {
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -13176,7 +13809,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -13184,7 +13817,7 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
@@ -13215,7 +13848,7 @@ struct fts5_api {
** autoconf-based build
*/
#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
-#include "config.h"
+#include "sqlite_cfg.h"
#define SQLITECONFIG_H 1
#endif
@@ -13295,7 +13928,7 @@ struct fts5_api {
** level of recursion for each term. A stack overflow can result
** if the number of terms is too large. In practice, most SQL
** never has more than 3 or 4 terms. Use a value of 0 to disable
-** any limit on the number of terms in a compount SELECT.
+** any limit on the number of terms in a compound SELECT.
*/
#ifndef SQLITE_MAX_COMPOUND_SELECT
# define SQLITE_MAX_COMPOUND_SELECT 500
@@ -13410,7 +14043,7 @@ struct fts5_api {
** max_page_count macro.
*/
#ifndef SQLITE_MAX_PAGE_COUNT
-# define SQLITE_MAX_PAGE_COUNT 1073741823
+# define SQLITE_MAX_PAGE_COUNT 0xfffffffe /* 4294967294 */
#endif
/*
@@ -13445,8 +14078,8 @@ struct fts5_api {
#endif
/*
-** WAL mode depends on atomic aligned 32-bit loads and stores in a few
-** places. The following macros try to make this explicit.
+** A few places in the code require atomic load/store of aligned
+** integer values.
*/
#ifndef __has_extension
# define __has_extension(x) 0 /* compatibility with non-clang compilers */
@@ -13502,15 +14135,22 @@ struct fts5_api {
#endif
/*
-** A macro to hint to the compiler that a function should not be
+** Macros to hint to the compiler that a function should or should not be
** inlined.
*/
#if defined(__GNUC__)
# define SQLITE_NOINLINE __attribute__((noinline))
+# define SQLITE_INLINE __attribute__((always_inline)) inline
#elif defined(_MSC_VER) && _MSC_VER>=1310
# define SQLITE_NOINLINE __declspec(noinline)
+# define SQLITE_INLINE __forceinline
#else
# define SQLITE_NOINLINE
+# define SQLITE_INLINE
+#endif
+#if defined(SQLITE_COVERAGE_TEST) || defined(__STRICT_ANSI__)
+# undef SQLITE_INLINE
+# define SQLITE_INLINE
#endif
/*
@@ -13533,6 +14173,29 @@ struct fts5_api {
#endif
/*
+** Enable SQLITE_USE_SEH by default on MSVC builds. Only omit
+** SEH support if the -DSQLITE_OMIT_SEH option is given.
+*/
+#if defined(_MSC_VER) && !defined(SQLITE_OMIT_SEH)
+# define SQLITE_USE_SEH 1
+#else
+# undef SQLITE_USE_SEH
+#endif
+
+/*
+** Enable SQLITE_DIRECT_OVERFLOW_READ, unless the build explicitly
+** disables it using -DSQLITE_DIRECT_OVERFLOW_READ=0
+*/
+#if defined(SQLITE_DIRECT_OVERFLOW_READ) && SQLITE_DIRECT_OVERFLOW_READ+1==1
+ /* Disable if -DSQLITE_DIRECT_OVERFLOW_READ=0 */
+# undef SQLITE_DIRECT_OVERFLOW_READ
+#else
+ /* In all other cases, enable */
+# define SQLITE_DIRECT_OVERFLOW_READ 1
+#endif
+
+
+/*
** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
** 0 means mutexes are permanently disable and the library is never
** threadsafe. 1 means the library is serialized which is the highest
@@ -13800,6 +14463,8 @@ struct fts5_api {
# define SQLITE_OMIT_ALTERTABLE
#endif
+#define SQLITE_DIGIT_SEPARATOR '_'
+
/*
** Return true (non-zero) if the input is an integer that is too large
** to fit in 32-bits. This macro is used inside of various testcase()
@@ -14092,8 +14757,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3HashClear(Hash*);
#define TK_TRUEFALSE 170
#define TK_ISNOT 171
#define TK_FUNCTION 172
-#define TK_UMINUS 173
-#define TK_UPLUS 174
+#define TK_UPLUS 173
+#define TK_UMINUS 174
#define TK_TRUTH 175
#define TK_REGISTER 176
#define TK_VECTOR 177
@@ -14102,8 +14767,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3HashClear(Hash*);
#define TK_ASTERISK 180
#define TK_SPAN 181
#define TK_ERROR 182
-#define TK_SPACE 183
-#define TK_ILLEGAL 184
+#define TK_QNUMBER 183
+#define TK_SPACE 184
+#define TK_ILLEGAL 185
/************** End of parse.h ***********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -14328,15 +14994,9 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
/*
** The datatype used to store estimates of the number of rows in a
-** table or index. This is an unsigned integer type. For 99.9% of
-** the world, a 32-bit integer is sufficient. But a 64-bit integer
-** can be used at compile-time if desired.
+** table or index.
*/
-#ifdef SQLITE_64BIT_STATS
- typedef u64 tRowcnt; /* 64-bit only if requested at compile-time */
-#else
- typedef u32 tRowcnt; /* 32-bit is the default */
-#endif
+typedef u64 tRowcnt;
/*
** Estimated quantities used for query planning are stored as 16-bit
@@ -14371,7 +15031,7 @@ typedef INT16_TYPE LogEst;
# define SQLITE_PTRSIZE __SIZEOF_POINTER__
# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
defined(_M_ARM) || defined(__arm__) || defined(__x86) || \
- (defined(__APPLE__) && defined(__POWERPC__)) || \
+ (defined(__APPLE__) && defined(__ppc__)) || \
(defined(__TOS_AIX__) && !defined(__64BIT__))
# define SQLITE_PTRSIZE 4
# else
@@ -14397,8 +15057,31 @@ typedef INT16_TYPE LogEst;
** the end of buffer S. This macro returns true if P points to something
** contained within the buffer S.
*/
-#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
+#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
+/*
+** P is one byte past the end of a large buffer. Return true if a span of bytes
+** between S..E crosses the end of that buffer. In other words, return true
+** if the sub-buffer S..E-1 overflows the buffer whose last byte is P-1.
+**
+** S is the start of the span. E is one byte past the end of end of span.
+**
+** P
+** |-----------------| FALSE
+** |-------|
+** S E
+**
+** P
+** |-----------------|
+** |-------| TRUE
+** S E
+**
+** P
+** |-----------------|
+** |-------| FALSE
+** S E
+*/
+#define SQLITE_OVERFLOW(P,S,E) (((uptr)(S)<(uptr)(P))&&((uptr)(E)>(uptr)(P)))
/*
** Macros to determine whether the machine is big or little endian,
@@ -14408,16 +15091,33 @@ typedef INT16_TYPE LogEst;
** using C-preprocessor macros. If that is unsuccessful, or if
** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined
** at run-time.
+**
+** If you are building SQLite on some obscure platform for which the
+** following ifdef magic does not work, you can always include either:
+**
+** -DSQLITE_BYTEORDER=1234
+**
+** or
+**
+** -DSQLITE_BYTEORDER=4321
+**
+** to cause the build to work for little-endian or big-endian processors,
+** respectively.
*/
-#ifndef SQLITE_BYTEORDER
-# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+#ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */
+# if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
+# define SQLITE_BYTEORDER 4321
+# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
+# define SQLITE_BYTEORDER 1234
+# elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1
+# define SQLITE_BYTEORDER 4321
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64)
-# define SQLITE_BYTEORDER 1234
-# elif defined(sparc) || defined(__ppc__) || \
- defined(__ARMEB__) || defined(__AARCH64EB__)
-# define SQLITE_BYTEORDER 4321
+# define SQLITE_BYTEORDER 1234
+# elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__)
+# define SQLITE_BYTEORDER 4321
# else
# define SQLITE_BYTEORDER 0
# endif
@@ -14482,9 +15182,9 @@ typedef INT16_TYPE LogEst;
** pointers. In that case, only verify 4-byte alignment.
*/
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
-# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&3)==0)
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0)
#else
-# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0)
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0)
#endif
/*
@@ -14538,15 +15238,39 @@ SQLITE_PRIVATE u32 sqlcipher_sqlite3TreeTrace;
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE) \
|| defined(SQLITE_ENABLE_TREETRACE))
# define TREETRACE_ENABLED 1
-# define SELECTTRACE(K,P,S,X) \
+# define TREETRACE(K,P,S,X) \
if(sqlcipher_sqlite3TreeTrace&(K)) \
sqlcipher_sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
sqlcipher_sqlite3DebugPrintf X
#else
-# define SELECTTRACE(K,P,S,X)
+# define TREETRACE(K,P,S,X)
# define TREETRACE_ENABLED 0
#endif
+/* TREETRACE flag meanings:
+**
+** 0x00000001 Beginning and end of SELECT processing
+** 0x00000002 WHERE clause processing
+** 0x00000004 Query flattener
+** 0x00000008 Result-set wildcard expansion
+** 0x00000010 Query name resolution
+** 0x00000020 Aggregate analysis
+** 0x00000040 Window functions
+** 0x00000080 Generated column names
+** 0x00000100 Move HAVING terms into WHERE
+** 0x00000200 Count-of-view optimization
+** 0x00000400 Compound SELECT processing
+** 0x00000800 Drop superfluous ORDER BY
+** 0x00001000 LEFT JOIN simplifies to JOIN
+** 0x00002000 Constant propagation
+** 0x00004000 Push-down optimization
+** 0x00008000 After all FROM-clause analysis
+** 0x00010000 Beginning of DELETE/INSERT/UPDATE processing
+** 0x00020000 Transform DISTINCT into GROUP BY
+** 0x00040000 SELECT tree dump after all code has been generated
+** 0x00080000 NOT NULL strength reduction
+*/
+
/*
** Macros for "wheretrace"
*/
@@ -14559,6 +15283,36 @@ SQLITE_PRIVATE u32 sqlcipher_sqlite3WhereTrace;
# define WHERETRACE(K,X)
#endif
+/*
+** Bits for the sqlcipher_sqlite3WhereTrace mask:
+**
+** (---any--) Top-level block structure
+** 0x-------F High-level debug messages
+** 0x----FFF- More detail
+** 0xFFFF---- Low-level debug messages
+**
+** 0x00000001 Code generation
+** 0x00000002 Solver
+** 0x00000004 Solver costs
+** 0x00000008 WhereLoop inserts
+**
+** 0x00000010 Display sqlcipher_sqlite3_index_info xBestIndex calls
+** 0x00000020 Range an equality scan metrics
+** 0x00000040 IN operator decisions
+** 0x00000080 WhereLoop cost adjustments
+** 0x00000100
+** 0x00000200 Covering index decisions
+** 0x00000400 OR optimization
+** 0x00000800 Index scanner
+** 0x00001000 More details associated with code generation
+** 0x00002000
+** 0x00004000 Show all WHERE terms at key points
+** 0x00008000 Show the full SELECT statement at key places
+**
+** 0x00010000 Show more detail when printing WHERE terms
+** 0x00020000 Show WHERE terms returned from whereScanNext()
+*/
+
/*
** An instance of the following structure is used to store the busy-handler
@@ -14579,7 +15333,7 @@ struct BusyHandler {
/*
** Name of table that holds the database schema.
**
-** The PREFERRED names are used whereever possible. But LEGACY is also
+** The PREFERRED names are used wherever possible. But LEGACY is also
** used for backwards compatibility.
**
** 1. Queries can use either the PREFERRED or the LEGACY names
@@ -14688,16 +15442,19 @@ typedef struct Column Column;
typedef struct Cte Cte;
typedef struct CteUse CteUse;
typedef struct Db Db;
+typedef struct DbClientData DbClientData;
typedef struct DbFixer DbFixer;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct FKey FKey;
+typedef struct FpDecode FpDecode;
typedef struct FuncDestructor FuncDestructor;
typedef struct FuncDef FuncDef;
typedef struct FuncDefHash FuncDefHash;
typedef struct IdList IdList;
typedef struct Index Index;
+typedef struct IndexedExpr IndexedExpr;
typedef struct IndexSample IndexSample;
typedef struct KeyClass KeyClass;
typedef struct KeyInfo KeyInfo;
@@ -14710,6 +15467,7 @@ typedef struct Parse Parse;
typedef struct ParseCleanup ParseCleanup;
typedef struct PreUpdate PreUpdate;
typedef struct PrintfArguments PrintfArguments;
+typedef struct RCStr RCStr;
typedef struct RenameToken RenameToken;
typedef struct Returning Returning;
typedef struct RowSet RowSet;
@@ -14763,6 +15521,7 @@ typedef struct With With;
#define MASKBIT32(n) (((unsigned int)1)<<(n))
#define SMASKBIT32(n) ((n)<=31?((unsigned int)1)<<(n):0)
#define ALLBITS ((Bitmask)-1)
+#define TOPBIT (((Bitmask)1)<<(BMS-1))
/* A VList object records a mapping between parameters/variables/wildcards
** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
@@ -14777,6 +15536,331 @@ typedef int VList;
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
** pointer types (i.e. FuncDef) defined above.
*/
+/************** Include os.h in the middle of sqliteInt.h ********************/
+/************** Begin file os.h **********************************************/
+/*
+** 2001 September 16
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This header file (together with is companion C source-code file
+** "os.c") attempt to abstract the underlying operating system so that
+** the SQLite library will work on both POSIX and windows systems.
+**
+** This header file is #include-ed by sqliteInt.h and thus ends up
+** being included by every source file.
+*/
+#ifndef _SQLITE_OS_H_
+#define _SQLITE_OS_H_
+
+/*
+** Attempt to automatically detect the operating system and setup the
+** necessary pre-processor macros for it.
+*/
+/************** Include os_setup.h in the middle of os.h *********************/
+/************** Begin file os_setup.h ****************************************/
+/*
+** 2013 November 25
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains pre-processor directives related to operating system
+** detection and/or setup.
+*/
+#ifndef SQLITE_OS_SETUP_H
+#define SQLITE_OS_SETUP_H
+
+/*
+** Figure out if we are dealing with Unix, Windows, or some other operating
+** system.
+**
+** After the following block of preprocess macros, all of
+**
+** SQLITE_OS_KV
+** SQLITE_OS_OTHER
+** SQLITE_OS_UNIX
+** SQLITE_OS_WIN
+**
+** will defined to either 1 or 0. One of them will be 1. The others will be 0.
+** If none of the macros are initially defined, then select either
+** SQLITE_OS_UNIX or SQLITE_OS_WIN depending on the target platform.
+**
+** If SQLITE_OS_OTHER=1 is specified at compile-time, then the application
+** must provide its own VFS implementation together with sqlcipher_sqlite3_os_init()
+** and sqlcipher_sqlite3_os_end() routines.
+*/
+#if !defined(SQLITE_OS_KV) && !defined(SQLITE_OS_OTHER) && \
+ !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_WIN)
+# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
+ defined(__MINGW32__) || defined(__BORLANDC__)
+# define SQLITE_OS_WIN 1
+# define SQLITE_OS_UNIX 0
+# else
+# define SQLITE_OS_WIN 0
+# define SQLITE_OS_UNIX 1
+# endif
+#endif
+#if SQLITE_OS_OTHER+1>1
+# undef SQLITE_OS_KV
+# define SQLITE_OS_KV 0
+# undef SQLITE_OS_UNIX
+# define SQLITE_OS_UNIX 0
+# undef SQLITE_OS_WIN
+# define SQLITE_OS_WIN 0
+#endif
+#if SQLITE_OS_KV+1>1
+# undef SQLITE_OS_OTHER
+# define SQLITE_OS_OTHER 0
+# undef SQLITE_OS_UNIX
+# define SQLITE_OS_UNIX 0
+# undef SQLITE_OS_WIN
+# define SQLITE_OS_WIN 0
+# define SQLITE_OMIT_LOAD_EXTENSION 1
+# define SQLITE_OMIT_WAL 1
+# define SQLITE_OMIT_DEPRECATED 1
+# undef SQLITE_TEMP_STORE
+# define SQLITE_TEMP_STORE 3 /* Always use memory for temporary storage */
+# define SQLITE_DQS 0
+# define SQLITE_OMIT_SHARED_CACHE 1
+# define SQLITE_OMIT_AUTOINIT 1
+#endif
+#if SQLITE_OS_UNIX+1>1
+# undef SQLITE_OS_KV
+# define SQLITE_OS_KV 0
+# undef SQLITE_OS_OTHER
+# define SQLITE_OS_OTHER 0
+# undef SQLITE_OS_WIN
+# define SQLITE_OS_WIN 0
+#endif
+#if SQLITE_OS_WIN+1>1
+# undef SQLITE_OS_KV
+# define SQLITE_OS_KV 0
+# undef SQLITE_OS_OTHER
+# define SQLITE_OS_OTHER 0
+# undef SQLITE_OS_UNIX
+# define SQLITE_OS_UNIX 0
+#endif
+
+
+#endif /* SQLITE_OS_SETUP_H */
+
+/************** End of os_setup.h ********************************************/
+/************** Continuing where we left off in os.h *************************/
+
+/* If the SET_FULLSYNC macro is not defined above, then make it
+** a no-op
+*/
+#ifndef SET_FULLSYNC
+# define SET_FULLSYNC(x,y)
+#endif
+
+/* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h
+*/
+#ifndef SQLITE_MAX_PATHLEN
+# define SQLITE_MAX_PATHLEN FILENAME_MAX
+#endif
+
+/* Maximum number of symlinks that will be resolved while trying to
+** expand a filename in xFullPathname() in the VFS.
+*/
+#ifndef SQLITE_MAX_SYMLINK
+# define SQLITE_MAX_SYMLINK 200
+#endif
+
+/*
+** The default size of a disk sector
+*/
+#ifndef SQLITE_DEFAULT_SECTOR_SIZE
+# define SQLITE_DEFAULT_SECTOR_SIZE 4096
+#endif
+
+/*
+** Temporary files are named starting with this prefix followed by 16 random
+** alphanumeric characters, and no file extension. They are stored in the
+** OS's standard temporary file directory, and are deleted prior to exit.
+** If sqlite is being embedded in another program, you may wish to change the
+** prefix to reflect your program's name, so that if your program exits
+** prematurely, old temporary files can be easily identified. This can be done
+** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
+**
+** 2006-10-31: The default prefix used to be "sqlite_". But then
+** Mcafee started using SQLite in their anti-virus product and it
+** started putting files with the "sqlite" name in the c:/temp folder.
+** This annoyed many windows users. Those users would then do a
+** Google search for "sqlite", find the telephone numbers of the
+** developers and call to wake them up at night and complain.
+** For this reason, the default name prefix is changed to be "sqlite"
+** spelled backwards. So the temp files are still identified, but
+** anybody smart enough to figure out the code is also likely smart
+** enough to know that calling the developer will not help get rid
+** of the file.
+*/
+#ifndef SQLITE_TEMP_FILE_PREFIX
+# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
+#endif
+
+/*
+** The following values may be passed as the second argument to
+** sqlcipher_sqlite3OsLock(). The various locks exhibit the following semantics:
+**
+** SHARED: Any number of processes may hold a SHARED lock simultaneously.
+** RESERVED: A single process may hold a RESERVED lock on a file at
+** any time. Other processes may hold and obtain new SHARED locks.
+** PENDING: A single process may hold a PENDING lock on a file at
+** any one time. Existing SHARED locks may persist, but no new
+** SHARED locks may be obtained by other processes.
+** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
+**
+** PENDING_LOCK may not be passed directly to sqlcipher_sqlite3OsLock(). Instead, a
+** process that requests an EXCLUSIVE lock may actually obtain a PENDING
+** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
+** sqlcipher_sqlite3OsLock().
+*/
+#define NO_LOCK 0
+#define SHARED_LOCK 1
+#define RESERVED_LOCK 2
+#define PENDING_LOCK 3
+#define EXCLUSIVE_LOCK 4
+
+/*
+** File Locking Notes: (Mostly about windows but also some info for Unix)
+**
+** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
+** those functions are not available. So we use only LockFile() and
+** UnlockFile().
+**
+** LockFile() prevents not just writing but also reading by other processes.
+** A SHARED_LOCK is obtained by locking a single randomly-chosen
+** byte out of a specific range of bytes. The lock byte is obtained at
+** random so two separate readers can probably access the file at the
+** same time, unless they are unlucky and choose the same lock byte.
+** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
+** There can only be one writer. A RESERVED_LOCK is obtained by locking
+** a single byte of the file that is designated as the reserved lock byte.
+** A PENDING_LOCK is obtained by locking a designated byte different from
+** the RESERVED_LOCK byte.
+**
+** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
+** which means we can use reader/writer locks. When reader/writer locks
+** are used, the lock is placed on the same range of bytes that is used
+** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
+** will support two or more Win95 readers or two or more WinNT readers.
+** But a single Win95 reader will lock out all WinNT readers and a single
+** WinNT reader will lock out all other Win95 readers.
+**
+** The following #defines specify the range of bytes used for locking.
+** SHARED_SIZE is the number of bytes available in the pool from which
+** a random byte is selected for a shared lock. The pool of bytes for
+** shared locks begins at SHARED_FIRST.
+**
+** The same locking strategy and
+** byte ranges are used for Unix. This leaves open the possibility of having
+** clients on win95, winNT, and unix all talking to the same shared file
+** and all locking correctly. To do so would require that samba (or whatever
+** tool is being used for file sharing) implements locks correctly between
+** windows and unix. I'm guessing that isn't likely to happen, but by
+** using the same locking range we are at least open to the possibility.
+**
+** Locking in windows is manditory. For this reason, we cannot store
+** actual data in the bytes used for locking. The pager never allocates
+** the pages involved in locking therefore. SHARED_SIZE is selected so
+** that all locks will fit on a single page even at the minimum page size.
+** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
+** is set high so that we don't have to allocate an unused page except
+** for very large databases. But one should test the page skipping logic
+** by setting PENDING_BYTE low and running the entire regression suite.
+**
+** Changing the value of PENDING_BYTE results in a subtly incompatible
+** file format. Depending on how it is changed, you might not notice
+** the incompatibility right away, even running a full regression test.
+** The default location of PENDING_BYTE is the first byte past the
+** 1GB boundary.
+**
+*/
+#ifdef SQLITE_OMIT_WSD
+# define PENDING_BYTE (0x40000000)
+#else
+# define PENDING_BYTE sqlcipher_sqlite3PendingByte
+#endif
+#define RESERVED_BYTE (PENDING_BYTE+1)
+#define SHARED_FIRST (PENDING_BYTE+2)
+#define SHARED_SIZE 510
+
+/*
+** Wrapper around OS specific sqlcipher_sqlite3_os_init() function.
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3OsInit(void);
+
+/*
+** Functions for accessing sqlcipher_sqlite3_file methods
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3OsClose(sqlcipher_sqlite3_file*);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsRead(sqlcipher_sqlite3_file*, void*, int amt, i64 offset);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsWrite(sqlcipher_sqlite3_file*, const void*, int amt, i64 offset);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsTruncate(sqlcipher_sqlite3_file*, i64 size);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsSync(sqlcipher_sqlite3_file*, int);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsFileSize(sqlcipher_sqlite3_file*, i64 *pSize);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsLock(sqlcipher_sqlite3_file*, int);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsUnlock(sqlcipher_sqlite3_file*, int);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsCheckReservedLock(sqlcipher_sqlite3_file *id, int *pResOut);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsFileControl(sqlcipher_sqlite3_file*,int,void*);
+SQLITE_PRIVATE void sqlcipher_sqlite3OsFileControlHint(sqlcipher_sqlite3_file*,int,void*);
+#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
+SQLITE_PRIVATE int sqlcipher_sqlite3OsSectorSize(sqlcipher_sqlite3_file *id);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsDeviceCharacteristics(sqlcipher_sqlite3_file *id);
+#ifndef SQLITE_OMIT_WAL
+SQLITE_PRIVATE int sqlcipher_sqlite3OsShmMap(sqlcipher_sqlite3_file *,int,int,int,void volatile **);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsShmLock(sqlcipher_sqlite3_file *id, int, int, int);
+SQLITE_PRIVATE void sqlcipher_sqlite3OsShmBarrier(sqlcipher_sqlite3_file *id);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsShmUnmap(sqlcipher_sqlite3_file *id, int);
+#endif /* SQLITE_OMIT_WAL */
+SQLITE_PRIVATE int sqlcipher_sqlite3OsFetch(sqlcipher_sqlite3_file *id, i64, int, void **);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsUnfetch(sqlcipher_sqlite3_file *, i64, void *);
+
+
+/*
+** Functions for accessing sqlcipher_sqlite3_vfs methods
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3OsOpen(sqlcipher_sqlite3_vfs *, const char *, sqlcipher_sqlite3_file*, int, int *);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsDelete(sqlcipher_sqlite3_vfs *, const char *, int);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsAccess(sqlcipher_sqlite3_vfs *, const char *, int, int *pResOut);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsFullPathname(sqlcipher_sqlite3_vfs *, const char *, int, char *);
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+SQLITE_PRIVATE void *sqlcipher_sqlite3OsDlOpen(sqlcipher_sqlite3_vfs *, const char *);
+SQLITE_PRIVATE void sqlcipher_sqlite3OsDlError(sqlcipher_sqlite3_vfs *, int, char *);
+SQLITE_PRIVATE void (*sqlcipher_sqlite3OsDlSym(sqlcipher_sqlite3_vfs *, void *, const char *))(void);
+SQLITE_PRIVATE void sqlcipher_sqlite3OsDlClose(sqlcipher_sqlite3_vfs *, void *);
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
+SQLITE_PRIVATE int sqlcipher_sqlite3OsRandomness(sqlcipher_sqlite3_vfs *, int, char *);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsSleep(sqlcipher_sqlite3_vfs *, int);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsGetLastError(sqlcipher_sqlite3_vfs*);
+SQLITE_PRIVATE int sqlcipher_sqlite3OsCurrentTimeInt64(sqlcipher_sqlite3_vfs *, sqlcipher_sqlite3_int64*);
+
+/*
+** Convenience functions for opening and closing files using
+** sqlcipher_sqlite3_malloc() to obtain space for the file-handle structure.
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3OsOpenMalloc(sqlcipher_sqlite3_vfs *, const char *, sqlcipher_sqlite3_file **, int,int*);
+SQLITE_PRIVATE void sqlcipher_sqlite3OsCloseFree(sqlcipher_sqlite3_file *);
+
+#endif /* _SQLITE_OS_H_ */
+
+/************** End of os.h **************************************************/
+/************** Continuing where we left off in sqliteInt.h ******************/
/************** Include pager.h in the middle of sqliteInt.h *****************/
/************** Begin file pager.h *******************************************/
/*
@@ -15002,7 +16086,7 @@ SQLITE_PRIVATE sqlcipher_sqlite3_file *sqlcipher_sqlite3PagerJrnlFile(Pager*);
SQLITE_PRIVATE const char *sqlcipher_sqlite3PagerJournalname(Pager*);
SQLITE_PRIVATE void *sqlcipher_sqlite3PagerTempSpace(Pager*);
SQLITE_PRIVATE int sqlcipher_sqlite3PagerIsMemdb(Pager*);
-SQLITE_PRIVATE void sqlcipher_sqlite3PagerCacheStat(Pager *, int, int, int *);
+SQLITE_PRIVATE void sqlcipher_sqlite3PagerCacheStat(Pager *, int, int, u64*);
SQLITE_PRIVATE void sqlcipher_sqlite3PagerClearCache(Pager*);
SQLITE_PRIVATE int sqlcipher_sqlite3SectorSize(sqlcipher_sqlite3_file *);
@@ -15032,6 +16116,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3PagerRefdump(Pager*);
# define enable_simulated_io_errors()
#endif
+#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
+SQLITE_PRIVATE int sqlcipher_sqlite3PagerWalSystemErrno(Pager*);
+#endif
+
#endif /* SQLITE_PAGER_H */
/************** End of pager.h ***********************************************/
@@ -15223,7 +16311,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeNewDb(Btree *p);
** reduce network bandwidth.
**
** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by
-** standard SQLite. The other hints are provided for extentions that use
+** standard SQLite. The other hints are provided for extensions that use
** the SQLite parser and code generator but substitute their own storage
** engine.
*/
@@ -15361,15 +16449,22 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreePrevious(BtCursor*, int flags);
SQLITE_PRIVATE i64 sqlcipher_sqlite3BtreeIntegerKey(BtCursor*);
SQLITE_PRIVATE void sqlcipher_sqlite3BtreeCursorPin(BtCursor*);
SQLITE_PRIVATE void sqlcipher_sqlite3BtreeCursorUnpin(BtCursor*);
-#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
SQLITE_PRIVATE i64 sqlcipher_sqlite3BtreeOffset(BtCursor*);
-#endif
SQLITE_PRIVATE int sqlcipher_sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE const void *sqlcipher_sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
SQLITE_PRIVATE u32 sqlcipher_sqlite3BtreePayloadSize(BtCursor*);
SQLITE_PRIVATE sqlcipher_sqlite3_int64 sqlcipher_sqlite3BtreeMaxRecordSize(BtCursor*);
-SQLITE_PRIVATE char *sqlcipher_sqlite3BtreeIntegrityCheck(sqlcipher_sqlite3*,Btree*,Pgno*aRoot,int nRoot,int,int*);
+SQLITE_PRIVATE int sqlcipher_sqlite3BtreeIntegrityCheck(
+ sqlcipher_sqlite3 *db, /* Database connection that is running the check */
+ Btree *p, /* The btree to be checked */
+ Pgno *aRoot, /* An array of root pages numbers for individual trees */
+ sqlcipher_sqlite3_value *aCnt, /* OUT: entry counts for each btree in aRoot[] */
+ int nRoot, /* Number of entries in aRoot[] */
+ int mxErr, /* Stop reporting errors after this many */
+ int *pnErr, /* OUT: Write number of errors seen to this variable */
+ char **pzOut /* OUT: Write the error message string here */
+);
SQLITE_PRIVATE struct Pager *sqlcipher_sqlite3BtreePager(Btree*);
SQLITE_PRIVATE i64 sqlcipher_sqlite3BtreeRowCountEst(BtCursor*);
@@ -15408,6 +16503,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeCheckpoint(Btree*, int, int *, int *)
SQLITE_PRIVATE int sqlcipher_sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64);
+SQLITE_PRIVATE void sqlcipher_sqlite3BtreeClearCache(Btree*);
+
/*
** If we are not using shared cache, then there is no need to
** use mutexes to access the BtShared structures. So make the
@@ -15524,14 +16621,14 @@ struct VdbeOp {
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
char *zComment; /* Comment to improve readability */
#endif
-#ifdef VDBE_PROFILE
- u32 cnt; /* Number of times this instruction was executed */
- u64 cycles; /* Total time spent executing this instruction */
-#endif
#ifdef SQLITE_VDBE_COVERAGE
u32 iSrcLine; /* Source-code line that generated this opcode
** with flags in the upper 8 bits */
#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+ u64 nExec;
+ u64 nCycle;
+#endif
};
typedef struct VdbeOp VdbeOp;
@@ -15583,6 +16680,7 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */
#define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlcipher_sqlite3_context object */
+#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */
/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
@@ -15632,48 +16730,48 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Vacuum 5
#define OP_VFilter 6 /* jump, synopsis: iplan=r[P3] zplan='P4' */
#define OP_VUpdate 7 /* synopsis: data=r[P3@P2] */
-#define OP_Goto 8 /* jump */
-#define OP_Gosub 9 /* jump */
-#define OP_InitCoroutine 10 /* jump */
-#define OP_Yield 11 /* jump */
-#define OP_MustBeInt 12 /* jump */
-#define OP_Jump 13 /* jump */
-#define OP_Once 14 /* jump */
-#define OP_If 15 /* jump */
-#define OP_IfNot 16 /* jump */
-#define OP_IsNullOrType 17 /* jump, synopsis: if typeof(r[P1]) IN (P3,5) goto P2 */
-#define OP_IfNullRow 18 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_Init 8 /* jump0, synopsis: Start at P2 */
+#define OP_Goto 9 /* jump */
+#define OP_Gosub 10 /* jump */
+#define OP_InitCoroutine 11 /* jump0 */
+#define OP_Yield 12 /* jump0 */
+#define OP_MustBeInt 13 /* jump0 */
+#define OP_Jump 14 /* jump */
+#define OP_Once 15 /* jump */
+#define OP_If 16 /* jump */
+#define OP_IfNot 17 /* jump */
+#define OP_IsType 18 /* jump, synopsis: if typeof(P1.P3) in P5 goto P2 */
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
-#define OP_SeekLT 20 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekLE 21 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekGE 22 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekGT 23 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IfNotOpen 24 /* jump, synopsis: if( !csr[P1] ) goto P2 */
-#define OP_IfNoHope 25 /* jump, synopsis: key=r[P3@P4] */
-#define OP_NoConflict 26 /* jump, synopsis: key=r[P3@P4] */
-#define OP_NotFound 27 /* jump, synopsis: key=r[P3@P4] */
-#define OP_Found 28 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekRowid 29 /* jump, synopsis: intkey=r[P3] */
-#define OP_NotExists 30 /* jump, synopsis: intkey=r[P3] */
-#define OP_Last 31 /* jump */
-#define OP_IfSmaller 32 /* jump */
-#define OP_SorterSort 33 /* jump */
-#define OP_Sort 34 /* jump */
-#define OP_Rewind 35 /* jump */
-#define OP_SorterNext 36 /* jump */
-#define OP_Prev 37 /* jump */
-#define OP_Next 38 /* jump */
-#define OP_IdxLE 39 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IdxGT 40 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IdxLT 41 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IdxGE 42 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IfNullRow 20 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_SeekLT 21 /* jump0, synopsis: key=r[P3@P4] */
+#define OP_SeekLE 22 /* jump0, synopsis: key=r[P3@P4] */
+#define OP_SeekGE 23 /* jump0, synopsis: key=r[P3@P4] */
+#define OP_SeekGT 24 /* jump0, synopsis: key=r[P3@P4] */
+#define OP_IfNotOpen 25 /* jump, synopsis: if( !csr[P1] ) goto P2 */
+#define OP_IfNoHope 26 /* jump, synopsis: key=r[P3@P4] */
+#define OP_NoConflict 27 /* jump, synopsis: key=r[P3@P4] */
+#define OP_NotFound 28 /* jump, synopsis: key=r[P3@P4] */
+#define OP_Found 29 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekRowid 30 /* jump0, synopsis: intkey=r[P3] */
+#define OP_NotExists 31 /* jump, synopsis: intkey=r[P3] */
+#define OP_Last 32 /* jump0 */
+#define OP_IfSizeBetween 33 /* jump */
+#define OP_SorterSort 34 /* jump */
+#define OP_Sort 35 /* jump */
+#define OP_Rewind 36 /* jump0 */
+#define OP_SorterNext 37 /* jump */
+#define OP_Prev 38 /* jump */
+#define OP_Next 39 /* jump */
+#define OP_IdxLE 40 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IdxGT 41 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IdxLT 42 /* jump, synopsis: key=r[P3@P4] */
#define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
#define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_RowSetRead 45 /* jump, synopsis: r[P3]=rowset(P1) */
-#define OP_RowSetTest 46 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program 47 /* jump */
-#define OP_FkIfZero 48 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
-#define OP_IfPos 49 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IdxGE 45 /* jump, synopsis: key=r[P3@P4] */
+#define OP_RowSetRead 46 /* jump, synopsis: r[P3]=rowset(P1) */
+#define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
+#define OP_Program 48 /* jump0 */
+#define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
#define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
#define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
#define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
@@ -15683,12 +16781,12 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
#define OP_Ge 57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
#define OP_ElseEq 58 /* jump, same as TK_ESCAPE */
-#define OP_IfNotZero 59 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
-#define OP_DecrJumpZero 60 /* jump, synopsis: if (--r[P1])==0 goto P2 */
-#define OP_IncrVacuum 61 /* jump */
-#define OP_VNext 62 /* jump */
-#define OP_Filter 63 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */
-#define OP_Init 64 /* jump, synopsis: Start at P2 */
+#define OP_IfPos 59 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IfNotZero 60 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
+#define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */
+#define OP_IncrVacuum 62 /* jump */
+#define OP_VNext 63 /* jump */
+#define OP_Filter 64 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */
#define OP_PureFunc 65 /* synopsis: r[P3]=func(r[P2@NP]) */
#define OP_Function 66 /* synopsis: r[P3]=func(r[P2@NP]) */
#define OP_Return 67
@@ -15702,7 +16800,7 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Null 75 /* synopsis: r[P2..P3]=NULL */
#define OP_SoftNull 76 /* synopsis: r[P1]=NULL */
#define OP_Blob 77 /* synopsis: r[P2]=P4 (len=P1) */
-#define OP_Variable 78 /* synopsis: r[P2]=parameter(P1,P4) */
+#define OP_Variable 78 /* synopsis: r[P2]=parameter(P1) */
#define OP_Move 79 /* synopsis: r[P2@P3]=r[P1@P3] */
#define OP_Copy 80 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
#define OP_SCopy 81 /* synopsis: r[P2]=r[P1] */
@@ -15798,19 +16896,22 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_VCreate 171
#define OP_VDestroy 172
#define OP_VOpen 173
-#define OP_VInitIn 174 /* synopsis: r[P2]=ValueList(P1,P3) */
-#define OP_VColumn 175 /* synopsis: r[P3]=vcolumn(P2) */
-#define OP_VRename 176
-#define OP_Pagecount 177
-#define OP_MaxPgcnt 178
-#define OP_ClrSubtype 179 /* synopsis: r[P1].subtype = 0 */
-#define OP_FilterAdd 180 /* synopsis: filter(P1) += key(P3@P4) */
-#define OP_Trace 181
-#define OP_CursorHint 182
-#define OP_ReleaseReg 183 /* synopsis: release r[P1@P2] mask P3 */
-#define OP_Noop 184
-#define OP_Explain 185
-#define OP_Abortable 186
+#define OP_VCheck 174
+#define OP_VInitIn 175 /* synopsis: r[P2]=ValueList(P1,P3) */
+#define OP_VColumn 176 /* synopsis: r[P3]=vcolumn(P2) */
+#define OP_VRename 177
+#define OP_Pagecount 178
+#define OP_MaxPgcnt 179
+#define OP_ClrSubtype 180 /* synopsis: r[P1].subtype = 0 */
+#define OP_GetSubtype 181 /* synopsis: r[P2] = r[P1].subtype */
+#define OP_SetSubtype 182 /* synopsis: r[P2].subtype = r[P1] */
+#define OP_FilterAdd 183 /* synopsis: filter(P1) += key(P3@P4) */
+#define OP_Trace 184
+#define OP_CursorHint 185
+#define OP_ReleaseReg 186 /* synopsis: release r[P1@P2] mask P3 */
+#define OP_Noop 187
+#define OP_Explain 188
+#define OP_Abortable 189
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
@@ -15822,31 +16923,33 @@ typedef struct VdbeOpList VdbeOpList;
#define OPFLG_IN3 0x08 /* in3: P3 is an input */
#define OPFLG_OUT2 0x10 /* out2: P2 is an output */
#define OPFLG_OUT3 0x20 /* out3: P3 is an output */
+#define OPFLG_NCYCLE 0x40 /* ncycle:Cycles count against P1 */
+#define OPFLG_JUMP0 0x80 /* jump0: P2 might be zero */
#define OPFLG_INITIALIZER {\
-/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,\
-/* 8 */ 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03,\
-/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x09, 0x09, 0x09, 0x09,\
-/* 24 */ 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x01,\
-/* 32 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
-/* 40 */ 0x01, 0x01, 0x01, 0x26, 0x26, 0x23, 0x0b, 0x01,\
-/* 48 */ 0x01, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
-/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x01, 0x01, 0x01,\
+/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x41, 0x00,\
+/* 8 */ 0x81, 0x01, 0x01, 0x81, 0x83, 0x83, 0x01, 0x01,\
+/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0xc9, 0xc9, 0xc9,\
+/* 24 */ 0xc9, 0x01, 0x49, 0x49, 0x49, 0x49, 0xc9, 0x49,\
+/* 32 */ 0xc1, 0x01, 0x41, 0x41, 0xc1, 0x01, 0x41, 0x41,\
+/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x23, 0x0b,\
+/* 48 */ 0x81, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
+/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01, 0x41,\
/* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\
/* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\
/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\
-/* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x00, 0x00,\
-/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x26, 0x26,\
+/* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40, 0x00,\
+/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x26, 0x26,\
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
-/* 112 */ 0x00, 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00,\
-/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\
-/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
-/* 136 */ 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10, 0x00,\
+/* 112 */ 0x40, 0x00, 0x12, 0x40, 0x40, 0x10, 0x40, 0x00,\
+/* 120 */ 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10, 0x10,\
+/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50,\
+/* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\
/* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\
/* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\
/* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\
-/* 176 */ 0x00, 0x10, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,\
-/* 184 */ 0x00, 0x00, 0x00,}
+/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x50,\
+/* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12, 0x00,\
+/* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}
/* The resolve3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode. The smaller the maximum
@@ -15899,14 +17002,20 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeNoJumpsOutsideSubrtn(Vdbe*,int,int,in
#endif
SQLITE_PRIVATE VdbeOp *sqlcipher_sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
#ifndef SQLITE_OMIT_EXPLAIN
-SQLITE_PRIVATE void sqlcipher_sqlite3VdbeExplain(Parse*,u8,const char*,...);
+SQLITE_PRIVATE int sqlcipher_sqlite3VdbeExplain(Parse*,u8,const char*,...);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeExplainPop(Parse*);
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeExplainParent(Parse*);
# define ExplainQueryPlan(P) sqlcipher_sqlite3VdbeExplain P
+# ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+# define ExplainQueryPlan2(V,P) (V = sqlcipher_sqlite3VdbeExplain P)
+# else
+# define ExplainQueryPlan2(V,P) ExplainQueryPlan(P)
+# endif
# define ExplainQueryPlanPop(P) sqlcipher_sqlite3VdbeExplainPop(P)
# define ExplainQueryPlanParent(P) sqlcipher_sqlite3VdbeExplainParent(P)
#else
# define ExplainQueryPlan(P)
+# define ExplainQueryPlan2(V,P)
# define ExplainQueryPlanPop(P)
# define ExplainQueryPlanParent(P) 0
# define sqlcipher_sqlite3ExplainBreakpoint(A,B) /*no-op*/
@@ -15922,6 +17031,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeChangeP5(Vdbe*, u16 P5);
+SQLITE_PRIVATE void sqlcipher_sqlite3VdbeTypeofColumn(Vdbe*, int);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeJumpHere(Vdbe*, int addr);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr);
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeChangeToNoop(Vdbe*, int addr);
@@ -15936,6 +17046,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeUsesBtree(Vdbe*, int);
SQLITE_PRIVATE VdbeOp *sqlcipher_sqlite3VdbeGetOp(Vdbe*, int);
+SQLITE_PRIVATE VdbeOp *sqlcipher_sqlite3VdbeGetLastOp(Vdbe*);
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMakeLabel(Parse*);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeRunOnlyOnce(Vdbe*);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeReusable(Vdbe*);
@@ -15981,6 +17092,8 @@ SQLITE_PRIVATE RecordCompare sqlcipher_sqlite3VdbeFindCompare(UnpackedRecord*);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeHasSubProgram(Vdbe*);
+SQLITE_PRIVATE void sqlcipher_sqlite3MemSetArrayInt64(sqlcipher_sqlite3_value *aMem, int iIdx, i64 val);
+
SQLITE_PRIVATE int sqlcipher_sqlite3NotPureFunc(sqlcipher_sqlite3_context*);
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeBytecodeVtabInit(sqlcipher_sqlite3*);
@@ -16013,7 +17126,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** The VdbeCoverage macros are used to set a coverage testing point
** for VDBE branch instructions. The coverage testing points are line
** numbers in the sqlcipher_sqlite3.c source file. VDBE branch coverage testing
-** only works with an amalagmation build. That's ok since a VDBE branch
+** only works with an amalgamation build. That's ok since a VDBE branch
** coverage build designed for testing the test suite only. No application
** should ever ship with VDBE branch coverage measuring turned on.
**
@@ -16031,7 +17144,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** // NULL option is not possible
**
** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested
-** // in distingishing equal and not-equal.
+** // in distinguishing equal and not-equal.
**
** Every VDBE branch operation must be tagged with one of the macros above.
** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and
@@ -16041,7 +17154,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** During testing, the test application will invoke
** sqlcipher_sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback
** routine that is invoked as each bytecode branch is taken. The callback
-** contains the sqlcipher_sqlite3.c source line number ov the VdbeCoverage macro and
+** contains the sqlcipher_sqlite3.c source line number of the VdbeCoverage macro and
** flags to indicate whether or not the branch was taken. The test application
** is responsible for keeping track of this and reporting byte-code branches
** that are never taken.
@@ -16077,14 +17190,22 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeSetLineNumber(Vdbe*,int);
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*);
+SQLITE_PRIVATE void sqlcipher_sqlite3VdbeScanStatusRange(Vdbe*, int, int, int);
+SQLITE_PRIVATE void sqlcipher_sqlite3VdbeScanStatusCounters(Vdbe*, int, int, int);
#else
-# define sqlcipher_sqlite3VdbeScanStatus(a,b,c,d,e)
+# define sqlcipher_sqlite3VdbeScanStatus(a,b,c,d,e,f)
+# define sqlcipher_sqlite3VdbeScanStatusRange(a,b,c,d)
+# define sqlcipher_sqlite3VdbeScanStatusCounters(a,b,c,d)
#endif
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
SQLITE_PRIVATE void sqlcipher_sqlite3VdbePrintOp(FILE*, int, VdbeOp*);
#endif
+#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlcipher_sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr);
+#endif
+
#endif /* SQLITE_VDBE_H */
/************** End of vdbe.h ************************************************/
@@ -16133,7 +17254,7 @@ struct PgHdr {
** private to pcache.c and should not be accessed by other modules.
** pCache is grouped with the public elements for efficiency.
*/
- i16 nRef; /* Number of users of this page */
+ i64 nRef; /* Number of users of this page */
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
/* NB: pDirtyNext and pDirtyPrev are undefined if the
@@ -16214,12 +17335,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3PcacheClearSyncFlags(PCache *);
SQLITE_PRIVATE void sqlcipher_sqlite3PcacheClear(PCache*);
/* Return the total number of outstanding page references */
-SQLITE_PRIVATE int sqlcipher_sqlite3PcacheRefCount(PCache*);
+SQLITE_PRIVATE i64 sqlcipher_sqlite3PcacheRefCount(PCache*);
/* Increment the reference count of an existing page */
SQLITE_PRIVATE void sqlcipher_sqlite3PcacheRef(PgHdr*);
-SQLITE_PRIVATE int sqlcipher_sqlite3PcachePageRefcount(PgHdr*);
+SQLITE_PRIVATE i64 sqlcipher_sqlite3PcachePageRefcount(PgHdr*);
/* Return the total number of pages stored in the cache */
SQLITE_PRIVATE int sqlcipher_sqlite3PcachePagecount(PCache*);
@@ -16284,297 +17405,6 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PCacheIsDirty(PCache *pCache);
/************** End of pcache.h **********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
-/************** Include os.h in the middle of sqliteInt.h ********************/
-/************** Begin file os.h **********************************************/
-/*
-** 2001 September 16
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This header file (together with is companion C source-code file
-** "os.c") attempt to abstract the underlying operating system so that
-** the SQLite library will work on both POSIX and windows systems.
-**
-** This header file is #include-ed by sqliteInt.h and thus ends up
-** being included by every source file.
-*/
-#ifndef _SQLITE_OS_H_
-#define _SQLITE_OS_H_
-
-/*
-** Attempt to automatically detect the operating system and setup the
-** necessary pre-processor macros for it.
-*/
-/************** Include os_setup.h in the middle of os.h *********************/
-/************** Begin file os_setup.h ****************************************/
-/*
-** 2013 November 25
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This file contains pre-processor directives related to operating system
-** detection and/or setup.
-*/
-#ifndef SQLITE_OS_SETUP_H
-#define SQLITE_OS_SETUP_H
-
-/*
-** Figure out if we are dealing with Unix, Windows, or some other operating
-** system.
-**
-** After the following block of preprocess macros, all of SQLITE_OS_UNIX,
-** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of
-** the three will be 1. The other two will be 0.
-*/
-#if defined(SQLITE_OS_OTHER)
-# if SQLITE_OS_OTHER==1
-# undef SQLITE_OS_UNIX
-# define SQLITE_OS_UNIX 0
-# undef SQLITE_OS_WIN
-# define SQLITE_OS_WIN 0
-# else
-# undef SQLITE_OS_OTHER
-# endif
-#endif
-#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
-# define SQLITE_OS_OTHER 0
-# ifndef SQLITE_OS_WIN
-# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
- defined(__MINGW32__) || defined(__BORLANDC__)
-# define SQLITE_OS_WIN 1
-# define SQLITE_OS_UNIX 0
-# else
-# define SQLITE_OS_WIN 0
-# define SQLITE_OS_UNIX 1
-# endif
-# else
-# define SQLITE_OS_UNIX 0
-# endif
-#else
-# ifndef SQLITE_OS_WIN
-# define SQLITE_OS_WIN 0
-# endif
-#endif
-
-#endif /* SQLITE_OS_SETUP_H */
-
-/************** End of os_setup.h ********************************************/
-/************** Continuing where we left off in os.h *************************/
-
-/* If the SET_FULLSYNC macro is not defined above, then make it
-** a no-op
-*/
-#ifndef SET_FULLSYNC
-# define SET_FULLSYNC(x,y)
-#endif
-
-/* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h
-*/
-#ifndef SQLITE_MAX_PATHLEN
-# define SQLITE_MAX_PATHLEN FILENAME_MAX
-#endif
-
-/* Maximum number of symlinks that will be resolved while trying to
-** expand a filename in xFullPathname() in the VFS.
-*/
-#ifndef SQLITE_MAX_SYMLINK
-# define SQLITE_MAX_SYMLINK 200
-#endif
-
-/*
-** The default size of a disk sector
-*/
-#ifndef SQLITE_DEFAULT_SECTOR_SIZE
-# define SQLITE_DEFAULT_SECTOR_SIZE 4096
-#endif
-
-/*
-** Temporary files are named starting with this prefix followed by 16 random
-** alphanumeric characters, and no file extension. They are stored in the
-** OS's standard temporary file directory, and are deleted prior to exit.
-** If sqlite is being embedded in another program, you may wish to change the
-** prefix to reflect your program's name, so that if your program exits
-** prematurely, old temporary files can be easily identified. This can be done
-** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
-**
-** 2006-10-31: The default prefix used to be "sqlite_". But then
-** Mcafee started using SQLite in their anti-virus product and it
-** started putting files with the "sqlite" name in the c:/temp folder.
-** This annoyed many windows users. Those users would then do a
-** Google search for "sqlite", find the telephone numbers of the
-** developers and call to wake them up at night and complain.
-** For this reason, the default name prefix is changed to be "sqlite"
-** spelled backwards. So the temp files are still identified, but
-** anybody smart enough to figure out the code is also likely smart
-** enough to know that calling the developer will not help get rid
-** of the file.
-*/
-#ifndef SQLITE_TEMP_FILE_PREFIX
-# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
-#endif
-
-/*
-** The following values may be passed as the second argument to
-** sqlcipher_sqlite3OsLock(). The various locks exhibit the following semantics:
-**
-** SHARED: Any number of processes may hold a SHARED lock simultaneously.
-** RESERVED: A single process may hold a RESERVED lock on a file at
-** any time. Other processes may hold and obtain new SHARED locks.
-** PENDING: A single process may hold a PENDING lock on a file at
-** any one time. Existing SHARED locks may persist, but no new
-** SHARED locks may be obtained by other processes.
-** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
-**
-** PENDING_LOCK may not be passed directly to sqlcipher_sqlite3OsLock(). Instead, a
-** process that requests an EXCLUSIVE lock may actually obtain a PENDING
-** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
-** sqlcipher_sqlite3OsLock().
-*/
-#define NO_LOCK 0
-#define SHARED_LOCK 1
-#define RESERVED_LOCK 2
-#define PENDING_LOCK 3
-#define EXCLUSIVE_LOCK 4
-
-/*
-** File Locking Notes: (Mostly about windows but also some info for Unix)
-**
-** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
-** those functions are not available. So we use only LockFile() and
-** UnlockFile().
-**
-** LockFile() prevents not just writing but also reading by other processes.
-** A SHARED_LOCK is obtained by locking a single randomly-chosen
-** byte out of a specific range of bytes. The lock byte is obtained at
-** random so two separate readers can probably access the file at the
-** same time, unless they are unlucky and choose the same lock byte.
-** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
-** There can only be one writer. A RESERVED_LOCK is obtained by locking
-** a single byte of the file that is designated as the reserved lock byte.
-** A PENDING_LOCK is obtained by locking a designated byte different from
-** the RESERVED_LOCK byte.
-**
-** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
-** which means we can use reader/writer locks. When reader/writer locks
-** are used, the lock is placed on the same range of bytes that is used
-** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
-** will support two or more Win95 readers or two or more WinNT readers.
-** But a single Win95 reader will lock out all WinNT readers and a single
-** WinNT reader will lock out all other Win95 readers.
-**
-** The following #defines specify the range of bytes used for locking.
-** SHARED_SIZE is the number of bytes available in the pool from which
-** a random byte is selected for a shared lock. The pool of bytes for
-** shared locks begins at SHARED_FIRST.
-**
-** The same locking strategy and
-** byte ranges are used for Unix. This leaves open the possibility of having
-** clients on win95, winNT, and unix all talking to the same shared file
-** and all locking correctly. To do so would require that samba (or whatever
-** tool is being used for file sharing) implements locks correctly between
-** windows and unix. I'm guessing that isn't likely to happen, but by
-** using the same locking range we are at least open to the possibility.
-**
-** Locking in windows is manditory. For this reason, we cannot store
-** actual data in the bytes used for locking. The pager never allocates
-** the pages involved in locking therefore. SHARED_SIZE is selected so
-** that all locks will fit on a single page even at the minimum page size.
-** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
-** is set high so that we don't have to allocate an unused page except
-** for very large databases. But one should test the page skipping logic
-** by setting PENDING_BYTE low and running the entire regression suite.
-**
-** Changing the value of PENDING_BYTE results in a subtly incompatible
-** file format. Depending on how it is changed, you might not notice
-** the incompatibility right away, even running a full regression test.
-** The default location of PENDING_BYTE is the first byte past the
-** 1GB boundary.
-**
-*/
-#ifdef SQLITE_OMIT_WSD
-# define PENDING_BYTE (0x40000000)
-#else
-# define PENDING_BYTE sqlcipher_sqlite3PendingByte
-#endif
-#define RESERVED_BYTE (PENDING_BYTE+1)
-#define SHARED_FIRST (PENDING_BYTE+2)
-#define SHARED_SIZE 510
-
-/*
-** Wrapper around OS specific sqlcipher_sqlite3_os_init() function.
-*/
-SQLITE_PRIVATE int sqlcipher_sqlite3OsInit(void);
-
-/*
-** Functions for accessing sqlcipher_sqlite3_file methods
-*/
-SQLITE_PRIVATE void sqlcipher_sqlite3OsClose(sqlcipher_sqlite3_file*);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsRead(sqlcipher_sqlite3_file*, void*, int amt, i64 offset);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsWrite(sqlcipher_sqlite3_file*, const void*, int amt, i64 offset);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsTruncate(sqlcipher_sqlite3_file*, i64 size);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsSync(sqlcipher_sqlite3_file*, int);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsFileSize(sqlcipher_sqlite3_file*, i64 *pSize);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsLock(sqlcipher_sqlite3_file*, int);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsUnlock(sqlcipher_sqlite3_file*, int);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsCheckReservedLock(sqlcipher_sqlite3_file *id, int *pResOut);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsFileControl(sqlcipher_sqlite3_file*,int,void*);
-SQLITE_PRIVATE void sqlcipher_sqlite3OsFileControlHint(sqlcipher_sqlite3_file*,int,void*);
-#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
-SQLITE_PRIVATE int sqlcipher_sqlite3OsSectorSize(sqlcipher_sqlite3_file *id);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsDeviceCharacteristics(sqlcipher_sqlite3_file *id);
-#ifndef SQLITE_OMIT_WAL
-SQLITE_PRIVATE int sqlcipher_sqlite3OsShmMap(sqlcipher_sqlite3_file *,int,int,int,void volatile **);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsShmLock(sqlcipher_sqlite3_file *id, int, int, int);
-SQLITE_PRIVATE void sqlcipher_sqlite3OsShmBarrier(sqlcipher_sqlite3_file *id);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsShmUnmap(sqlcipher_sqlite3_file *id, int);
-#endif /* SQLITE_OMIT_WAL */
-SQLITE_PRIVATE int sqlcipher_sqlite3OsFetch(sqlcipher_sqlite3_file *id, i64, int, void **);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsUnfetch(sqlcipher_sqlite3_file *, i64, void *);
-
-
-/*
-** Functions for accessing sqlcipher_sqlite3_vfs methods
-*/
-SQLITE_PRIVATE int sqlcipher_sqlite3OsOpen(sqlcipher_sqlite3_vfs *, const char *, sqlcipher_sqlite3_file*, int, int *);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsDelete(sqlcipher_sqlite3_vfs *, const char *, int);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsAccess(sqlcipher_sqlite3_vfs *, const char *, int, int *pResOut);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsFullPathname(sqlcipher_sqlite3_vfs *, const char *, int, char *);
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
-SQLITE_PRIVATE void *sqlcipher_sqlite3OsDlOpen(sqlcipher_sqlite3_vfs *, const char *);
-SQLITE_PRIVATE void sqlcipher_sqlite3OsDlError(sqlcipher_sqlite3_vfs *, int, char *);
-SQLITE_PRIVATE void (*sqlcipher_sqlite3OsDlSym(sqlcipher_sqlite3_vfs *, void *, const char *))(void);
-SQLITE_PRIVATE void sqlcipher_sqlite3OsDlClose(sqlcipher_sqlite3_vfs *, void *);
-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
-SQLITE_PRIVATE int sqlcipher_sqlite3OsRandomness(sqlcipher_sqlite3_vfs *, int, char *);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsSleep(sqlcipher_sqlite3_vfs *, int);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsGetLastError(sqlcipher_sqlite3_vfs*);
-SQLITE_PRIVATE int sqlcipher_sqlite3OsCurrentTimeInt64(sqlcipher_sqlite3_vfs *, sqlcipher_sqlite3_int64*);
-
-/*
-** Convenience functions for opening and closing files using
-** sqlcipher_sqlite3_malloc() to obtain space for the file-handle structure.
-*/
-SQLITE_PRIVATE int sqlcipher_sqlite3OsOpenMalloc(sqlcipher_sqlite3_vfs *, const char *, sqlcipher_sqlite3_file **, int,int*);
-SQLITE_PRIVATE void sqlcipher_sqlite3OsCloseFree(sqlcipher_sqlite3_file *);
-
-#endif /* _SQLITE_OS_H_ */
-
-/************** End of os.h **************************************************/
-/************** Continuing where we left off in sqliteInt.h ******************/
/************** Include mutex.h in the middle of sqliteInt.h *****************/
/************** Begin file mutex.h *******************************************/
/*
@@ -16663,7 +17493,7 @@ SQLITE_API int sqlcipher_sqlite3_mutex_held(sqlcipher_sqlite3_mutex*);
/*
** Default synchronous levels.
**
-** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ
+** Note that (for historical reasons) the PAGER_SYNCHRONOUS_* macros differ
** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1.
**
** PAGER_SYNCHRONOUS DEFAULT_SYNCHRONOUS
@@ -16702,7 +17532,7 @@ struct Db {
** An instance of the following structure stores a database schema.
**
** Most Schema objects are associated with a Btree. The exception is
-** the Schema for the TEMP databaes (sqlcipher_sqlite3.aDb[1]) which is free-standing.
+** the Schema for the TEMP database (sqlcipher_sqlite3.aDb[1]) which is free-standing.
** In shared cache mode, a single Schema object can be shared by multiple
** Btrees that refer to the same underlying BtShared object.
**
@@ -16813,13 +17643,14 @@ struct Lookaside {
LookasideSlot *pInit; /* List of buffers not previously used */
LookasideSlot *pFree; /* List of available buffers */
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
- LookasideSlot *pSmallInit; /* List of small buffers not prediously used */
+ LookasideSlot *pSmallInit; /* List of small buffers not previously used */
LookasideSlot *pSmallFree; /* List of available small buffers */
void *pMiddle; /* First byte past end of full-size buffers and
** the first byte of LOOKASIDE_SMALL buffers */
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
void *pStart; /* First byte of available memory space */
void *pEnd; /* First byte past end of available space */
+ void *pTrueEnd; /* True value of pEnd, when db->pnBytesFreed!=0 */
};
struct LookasideSlot {
LookasideSlot *pNext; /* Next buffer in the list of free buffers */
@@ -16829,7 +17660,7 @@ struct LookasideSlot {
#define EnableLookaside db->lookaside.bDisable--;\
db->lookaside.sz=db->lookaside.bDisable?0:db->lookaside.szTrue
-/* Size of the smaller allocations in two-size lookside */
+/* Size of the smaller allocations in two-size lookaside */
#ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE
# define LOOKASIDE_SMALL 0
#else
@@ -16850,6 +17681,10 @@ struct FuncDefHash {
};
#define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ)
+#if defined(SQLITE_USER_AUTHENTICATION)
+# warning "The SQLITE_USER_AUTHENTICATION extension is deprecated. \
+ See ext/userauth/user-auth.txt for details."
+#endif
#ifdef SQLITE_USER_AUTHENTICATION
/*
** Information held in the "sqlcipher_sqlite3" database connection object and used
@@ -17029,6 +17864,7 @@ struct sqlcipher_sqlite3 {
i64 nDeferredCons; /* Net deferred constraints this transaction. */
i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
+ DbClientData *pDbData; /* sqlcipher_sqlite3_set_clientdata() content */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/* The following variables are all protected by the STATIC_MAIN
** mutex, not by sqlcipher_sqlite3.mutex. They are used by code in notify.c.
@@ -17084,7 +17920,7 @@ struct sqlcipher_sqlite3 {
#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
/* result set is empty */
#define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */
-#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */
+#define SQLITE_StmtScanStatus 0x00000400 /* Enable stmt_scanstats() counters */
#define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */
#define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */
#define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */
@@ -17110,6 +17946,8 @@ struct sqlcipher_sqlite3 {
/* DELETE, or UPDATE and return */
/* the count using a callback. */
#define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */
+#define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */
+#define SQLITE_FkNoAction HI(0x00008) /* Treat all FK as NO ACTION */
/* Flags used only if debugging */
#ifdef SQLITE_DEBUG
@@ -17150,7 +17988,7 @@ struct sqlcipher_sqlite3 {
#define SQLITE_CursorHints 0x00000400 /* Add OP_CursorHint opcodes */
#define SQLITE_Stat4 0x00000800 /* Use STAT4 data */
/* TH3 expects this value ^^^^^^^^^^ to be 0x0000800. Don't change it */
-#define SQLITE_PushDown 0x00001000 /* The push-down optimization */
+#define SQLITE_PushDown 0x00001000 /* WHERE-clause push-down opt */
#define SQLITE_SimplifyJoin 0x00002000 /* Convert LEFT JOIN to JOIN */
#define SQLITE_SkipScan 0x00004000 /* Skip-scans */
#define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */
@@ -17164,6 +18002,10 @@ struct sqlcipher_sqlite3 {
#define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */
#define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */
/* TH3 expects this value ^^^^^^^^^^ See flatten04.test */
+#define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */
+#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */
+#define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */
+#define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -17246,10 +18088,17 @@ struct FuncDestructor {
** SQLITE_FUNC_ANYORDER == NC_OrderAgg == SF_OrderByReqd
** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
+** SQLITE_FUNC_BYTELEN == OPFLAG_BYTELENARG
** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
-** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS
+** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS -- opposite meanings!!!
** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API
+**
+** Note that even though SQLITE_FUNC_UNSAFE and SQLITE_INNOCUOUS have the
+** same bit value, their meanings are inverted. SQLITE_FUNC_UNSAFE is
+** used internally and if set means that the function has side effects.
+** SQLITE_INNOCUOUS is used by application code and means "not unsafe".
+** See multiple instances of tag-20230109-1.
*/
#define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
#define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */
@@ -17258,6 +18107,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlcipher_sqlite3GetFuncCollSeq() might be called*/
#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
+#define SQLITE_FUNC_BYTELEN 0x00c0 /* Built-in octet_length() function */
#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
/* 0x0200 -- available for reuse */
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
@@ -17266,14 +18116,15 @@ struct FuncDestructor {
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
** single query - might change over time */
#define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */
-/* 0x8000 -- available for reuse */
+#define SQLITE_FUNC_RUNONLY 0x8000 /* Cannot be used by valueFromFunction */
#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */
-#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */
+/* SQLITE_SUBTYPE 0x00100000 // Consumer of subtypes */
#define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */
#define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */
#define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */
+/* SQLITE_RESULT_SUBTYPE 0x01000000 // Generator of subtypes */
#define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */
/* Identifier numbers for each in-line function */
@@ -17365,10 +18216,11 @@ struct FuncDestructor {
#define MFUNCTION(zName, nArg, xPtr, xFunc) \
{nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
-#define JFUNCTION(zName, nArg, iArg, xFunc) \
- {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|\
- SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
+#define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, bJsonB, iArg, xFunc) \
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\
+ SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|\
+ ((bRS)*SQLITE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \
+ SQLITE_INT_TO_PTR(iArg|((bJsonB)*JSON_BLOB)),0,xFunc,0, 0, 0, #zName, {0} }
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
{nArg, SQLITE_FUNC_BUILTIN|\
SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
@@ -17558,6 +18410,7 @@ struct CollSeq {
#define SQLITE_AFF_NUMERIC 0x43 /* 'C' */
#define SQLITE_AFF_INTEGER 0x44 /* 'D' */
#define SQLITE_AFF_REAL 0x45 /* 'E' */
+#define SQLITE_AFF_FLEXNUM 0x46 /* 'F' */
#define sqlcipher_sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
@@ -17628,6 +18481,7 @@ struct VTable {
sqlcipher_sqlite3_vtab *pVtab; /* Pointer to vtab instance */
int nRef; /* Number of pointers to this structure */
u8 bConstraint; /* True if constraints are supported */
+ u8 bAllSchemas; /* True if might use any attached schema */
u8 eVtabRisk; /* Riskiness of allowing hacker access */
int iSavepoint; /* Depth of the SAVEPOINT stack */
VTable *pNext; /* Next in linked list (see above) */
@@ -17707,8 +18561,7 @@ struct Table {
#define TF_HasStored 0x00000040 /* Has one or more STORED columns */
#define TF_HasGenerated 0x00000060 /* Combo: HasVirtual + HasStored */
#define TF_WithoutRowid 0x00000080 /* No rowid. PRIMARY KEY is the key */
-#define TF_StatsUsed 0x00000100 /* Query planner decisions affected by
- ** Index.aiRowLogEst[] values */
+#define TF_MaybeReanalyze 0x00000100 /* Maybe run ANALYZE on this table */
#define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */
#define TF_OOOHidden 0x00000400 /* Out-of-Order hidden columns */
#define TF_HasNotNull 0x00000800 /* Contains NOT NULL constraints */
@@ -17736,7 +18589,7 @@ struct Table {
#ifndef SQLITE_OMIT_VIRTUALTABLE
# define IsVirtual(X) ((X)->eTabType==TABTYP_VTAB)
# define ExprIsVtab(X) \
- ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->eTabType==TABTYP_VTAB)
+ ((X)->op==TK_COLUMN && (X)->y.pTab->eTabType==TABTYP_VTAB)
#else
# define IsVirtual(X) 0
# define ExprIsVtab(X) 0
@@ -17764,6 +18617,15 @@ struct Table {
#define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0)
#define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0)
+/* Macro is true if the SQLITE_ALLOW_ROWID_IN_VIEW (mis-)feature is
+** available. By default, this macro is false
+*/
+#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
+# define ViewCanHaveRowid 0
+#else
+# define ViewCanHaveRowid (sqlcipher_sqlite3Config.mNoVisibleRowid==0)
+#endif
+
/*
** Each foreign key constraint is an instance of the following structure.
**
@@ -17835,7 +18697,7 @@ struct FKey {
** foreign key.
**
** The OE_Default value is a place holder that means to use whatever
-** conflict resolution algorthm is required from context.
+** conflict resolution algorithm is required from context.
**
** The following symbolic values are used to record which type
** of conflict resolution action to take.
@@ -17953,10 +18815,22 @@ struct UnpackedRecord {
** The Index.onError field determines whether or not the indexed columns
** must be unique and what to do if they are not. When Index.onError=OE_None,
** it means this is not a unique index. Otherwise it is a unique index
-** and the value of Index.onError indicate the which conflict resolution
-** algorithm to employ whenever an attempt is made to insert a non-unique
+** and the value of Index.onError indicates which conflict resolution
+** algorithm to employ when an attempt is made to insert a non-unique
** element.
**
+** The colNotIdxed bitmask is used in combination with SrcItem.colUsed
+** for a fast test to see if an index can serve as a covering index.
+** colNotIdxed has a 1 bit for every column of the original table that
+** is *not* available in the index. Thus the expression
+** "colUsed & colNotIdxed" will be non-zero if the index is not a
+** covering index. The most significant bit of of colNotIdxed will always
+** be true (note-20221022-a). If a column beyond the 63rd column of the
+** table is used, the "colUsed & colNotIdxed" test will always be non-zero
+** and we have to assume either that the index is not covering, or use
+** an alternative (slower) algorithm to determine whether or not
+** the index is covering.
+**
** While parsing a CREATE TABLE or CREATE INDEX statement in order to
** generate VDBE code (as opposed to parsing one read from an sqlite_schema
** table as part of parsing an existing database schema), transient instances
@@ -17989,18 +18863,22 @@ struct Index {
unsigned isCovering:1; /* True if this is a covering index */
unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
+ unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
+ unsigned bHasExpr:1; /* Index contains an expression, either a literal
+ ** expression, or a reference to a VIRTUAL column */
#ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */
+ int mxSample; /* Number of slots allocated to aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */
tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */
#endif
- Bitmask colNotIdxed; /* 0 for unindexed columns in pTab */
+ Bitmask colNotIdxed; /* Unindexed columns in pTab */
};
/*
@@ -18075,16 +18953,15 @@ struct AggInfo {
** from source tables rather than from accumulators */
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
** than the source table */
+ u16 nSortingColumn; /* Number of columns in the sorting index */
int sortingIdx; /* Cursor number of the sorting index */
int sortingIdxPTab; /* Cursor number of pseudo-table */
- int nSortingColumn; /* Number of columns in the sorting index */
- int mnReg, mxReg; /* Range of registers allocated for aCol and aFunc */
+ int iFirstReg; /* First register in range for aCol[] and aFunc[] */
ExprList *pGroupBy; /* The group by clause */
struct AggInfo_col { /* For each column used in source tables */
Table *pTab; /* Source table */
Expr *pCExpr; /* The original expression */
int iTable; /* Cursor number of the source table */
- int iMem; /* Memory location that acts as accumulator */
i16 iColumn; /* Column number within the source table */
i16 iSorterColumn; /* Column number in the sorting index */
} *aCol;
@@ -18095,15 +18972,32 @@ struct AggInfo {
struct AggInfo_func { /* For each aggregate function */
Expr *pFExpr; /* Expression encoding the function */
FuncDef *pFunc; /* The aggregate function implementation */
- int iMem; /* Memory location that acts as accumulator */
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
int iDistAddr; /* Address of OP_OpenEphemeral */
+ int iOBTab; /* Ephemeral table to implement ORDER BY */
+ u8 bOBPayload; /* iOBTab has payload columns separate from key */
+ u8 bOBUnique; /* Enforce uniqueness on iOBTab keys */
+ u8 bUseSubtype; /* Transfer subtype info through sorter */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
u32 selId; /* Select to which this AggInfo belongs */
+#ifdef SQLITE_DEBUG
+ Select *pSelect; /* SELECT statement that this AggInfo supports */
+#endif
};
/*
+** Macros to compute aCol[] and aFunc[] register numbers.
+**
+** These macros should not be used prior to the call to
+** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg.
+** The assert()s that are part of this macro verify that constraint.
+*/
+#define AggInfoColumnReg(A,I) (assert((A)->iFirstReg),(A)->iFirstReg+(I))
+#define AggInfoFuncReg(A,I) \
+ (assert((A)->iFirstReg),(A)->iFirstReg+(A)->nColumn+(I))
+
+/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
** than 32767 we have to make it 32-bit. 16-bit is preferred because
@@ -18222,7 +19116,7 @@ struct Expr {
** TK_REGISTER: register number
** TK_TRIGGER: 1 -> new, 0 -> old
** EP_Unlikely: 134217728 times likelihood
- ** TK_IN: ephemerial table holding RHS
+ ** TK_IN: ephemeral table holding RHS
** TK_SELECT_COLUMN: Number of columns on the LHS
** TK_SELECT: 1st register of result vector */
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
@@ -18268,7 +19162,7 @@ struct Expr {
#define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
#define EP_Win 0x008000 /* Contains window functions */
#define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
-#define EP_MemToken 0x020000 /* Need to sqlcipher_sqlite3DbFree() Expr.zToken */
+#define EP_FullSize 0x020000 /* Expr structure must remain full sized */
#define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */
#define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */
#define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
@@ -18298,12 +19192,15 @@ struct Expr {
#define ExprClearProperty(E,P) (E)->flags&=~(P)
#define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue)
#define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse)
+#define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0)
/* Macros used to ensure that the correct members of unions are accessed
** in Expr.
*/
#define ExprUseUToken(E) (((E)->flags&EP_IntValue)==0)
#define ExprUseUValue(E) (((E)->flags&EP_IntValue)!=0)
+#define ExprUseWOfst(E) (((E)->flags&(EP_InnerON|EP_OuterON))==0)
+#define ExprUseWJoin(E) (((E)->flags&(EP_InnerON|EP_OuterON))!=0)
#define ExprUseXList(E) (((E)->flags&EP_xIsSelect)==0)
#define ExprUseXSelect(E) (((E)->flags&EP_xIsSelect)!=0)
#define ExprUseYTab(E) (((E)->flags&(EP_WinFunc|EP_Subrtn))==0)
@@ -18413,6 +19310,7 @@ struct ExprList {
#define ENAME_NAME 0 /* The AS clause of a result set */
#define ENAME_SPAN 1 /* Complete text of the result set expression */
#define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */
+#define ENAME_ROWID 3 /* "DB.TABLE._rowid_" for * expansion of rowid */
/*
** An instance of this structure can hold a simple list of identifiers,
@@ -18453,12 +19351,22 @@ struct IdList {
** The SrcItem object represents a single term in the FROM clause of a query.
** The SrcList object is mostly an array of SrcItems.
**
+** The jointype starts out showing the join type between the current table
+** and the next table on the list. The parser builds the list this way.
+** But sqlcipher_sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
+** jointype expresses the join between the table and the previous table.
+**
+** In the colUsed field, the high-order bit (bit 63) is set if the table
+** contains more than 63 columns and the 64-th or later column is used.
+**
** Union member validity:
**
-** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
-** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy
-** u2.pIBIndex fg.isIndexedBy && !fg.isCte
-** u2.pCteUse fg.isCte && !fg.isIndexedBy
+** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
+** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy
+** u1.nRow !fg.isTabFunc && !fg.isIndexedBy
+**
+** u2.pIBIndex fg.isIndexedBy && !fg.isCte
+** u2.pCteUse fg.isCte && !fg.isIndexedBy
*/
struct SrcItem {
Schema *pSchema; /* Schema to which this item is fixed */
@@ -18484,22 +19392,24 @@ struct SrcItem {
unsigned notCte :1; /* This item may not match a CTE */
unsigned isUsing :1; /* u3.pUsing is valid */
unsigned isOn :1; /* u3.pOn was once valid and non-NULL */
- unsigned isSynthUsing :1; /* u3.pUsing is synthensized from NATURAL */
+ unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
+ unsigned rowidUsed :1; /* The ROWID of this table is referenced */
} fg;
int iCursor; /* The VDBE cursor number used to access this table */
union {
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
} u3;
- Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
+ Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
union {
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
ExprList *pFuncArg; /* Arguments to table-valued-function */
+ u32 nRow; /* Number of rows in a VALUES clause */
} u1;
union {
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
- CteUse *pCteUse; /* CTE Usage info info fg.isCte is true */
+ CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
} u2;
};
@@ -18513,23 +19423,11 @@ struct OnOrUsing {
};
/*
-** The following structure describes the FROM clause of a SELECT statement.
-** Each table or subquery in the FROM clause is a separate element of
-** the SrcList.a[] array.
-**
-** With the addition of multiple database support, the following structure
-** can also be used to describe a particular table such as the table that
-** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL,
-** such a table must be a simple name: ID. But in SQLite, the table can
-** now be identified by a database name, a dot, then the table name: ID.ID.
-**
-** The jointype starts out showing the join type between the current table
-** and the next table on the list. The parser builds the list this way.
-** But sqlcipher_sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
-** jointype expresses the join between the table and the previous table.
+** This object represents one or more tables that are the source of
+** content for an SQL statement. For example, a single SrcList object
+** is used to hold the FROM clause of a SELECT statement. SrcList also
+** represents the target tables for DELETE, INSERT, and UPDATE statements.
**
-** In the colUsed field, the high-order bit (bit 63) is set if the table
-** contains more than 63 columns and the 64-th or later column is used.
*/
struct SrcList {
int nSrc; /* Number of tables or subqueries in the FROM clause */
@@ -18572,7 +19470,7 @@ struct SrcList {
#define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */
#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */
#define WHERE_RIGHT_JOIN 0x1000 /* Processing a RIGHT JOIN */
- /* 0x2000 not currently used */
+#define WHERE_KEEP_ALL_JOINS 0x2000 /* Do not do the omit-noop-join opt */
#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */
/* 0x8000 not currently used */
@@ -18617,6 +19515,7 @@ struct NameContext {
int nRef; /* Number of names resolved by this context */
int nNcErr; /* Number of errors encountered while resolving names */
int ncFlags; /* Zero or more NC_* flags defined below */
+ u32 nNestedSelect; /* Number of nested selects using this NC */
Select *pWinSelect; /* SELECT statement for any window functions */
};
@@ -18637,7 +19536,7 @@ struct NameContext {
#define NC_HasAgg 0x000010 /* One or more aggregate functions seen */
#define NC_IdxExpr 0x000020 /* True if resolving columns of CREATE INDEX */
#define NC_SelfRef 0x00002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */
-#define NC_VarSelect 0x000040 /* A correlated subquery has been seen */
+#define NC_Subquery 0x000040 /* A subquery has been seen */
#define NC_UEList 0x000080 /* True if uNC.pEList is used */
#define NC_UAggInfo 0x000100 /* True if uNC.pAggInfo is used */
#define NC_UUpsert 0x000200 /* True if uNC.pUpsert is used */
@@ -18650,6 +19549,7 @@ struct NameContext {
#define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */
#define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */
#define NC_NoSelect 0x080000 /* Do not descend into sub-selects */
+#define NC_Where 0x100000 /* Processing WHERE clause of a SELECT */
#define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */
/*
@@ -18673,6 +19573,7 @@ struct Upsert {
Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */
u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */
+ u8 isDup; /* True if 2nd or later with same pUpsertIdx */
/* Above this point is the parse tree for the ON CONFLICT clauses.
** The next group of fields stores intermediate data. */
void *pToFree; /* Free memory when deleting the Upsert object */
@@ -18762,10 +19663,12 @@ struct Select {
#define SF_View 0x0200000 /* SELECT statement is a view */
#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
#define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */
-#define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */
+#define SF_PushDown 0x1000000 /* Modified by WHERE-clause push-down opt */
#define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */
#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
+#define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
+#define SF_Correlated 0x20000000 /* True if references the outer context */
/* True if S exists and has SF_NestedFrom */
#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
@@ -18874,7 +19777,7 @@ struct SelectDest {
int iSDParm2; /* A second parameter for the eDest disposal method */
int iSdst; /* Base register where results are written */
int nSdst; /* Number of registers allocated */
- char *zAffSdst; /* Affinity used when eDest==SRT_Set */
+ char *zAffSdst; /* Affinity used for SRT_Set */
ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */
};
@@ -18933,11 +19836,34 @@ struct TriggerPrg {
#else
typedef unsigned int yDbMask;
# define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0)
-# define DbMaskZero(M) (M)=0
-# define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I))
-# define DbMaskAllZero(M) (M)==0
-# define DbMaskNonZero(M) (M)!=0
+# define DbMaskZero(M) ((M)=0)
+# define DbMaskSet(M,I) ((M)|=(((yDbMask)1)<<(I)))
+# define DbMaskAllZero(M) ((M)==0)
+# define DbMaskNonZero(M) ((M)!=0)
+#endif
+
+/*
+** For each index X that has as one of its arguments either an expression
+** or the name of a virtual generated column, and if X is in scope such that
+** the value of the expression can simply be read from the index, then
+** there is an instance of this object on the Parse.pIdxExpr list.
+**
+** During code generation, while generating code to evaluate expressions,
+** this list is consulted and if a matching expression is found, the value
+** is read from the index rather than being recomputed.
+*/
+struct IndexedExpr {
+ Expr *pExpr; /* The expression contained in the index */
+ int iDataCur; /* The data cursor associated with the index */
+ int iIdxCur; /* The index cursor */
+ int iIdxCol; /* The index column that contains value of pExpr */
+ u8 bMaybeNullRow; /* True if we need an OP_IfNullRow check */
+ u8 aff; /* Affinity of the pExpr expression */
+ IndexedExpr *pIENext; /* Next in a list of all indexed expressions */
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ const char *zIdxName; /* Name of index, used only for bytecode comments */
#endif
+};
/*
** An instance of the ParseCleanup object specifies an operation that
@@ -18980,11 +19906,15 @@ struct Parse {
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
u8 okConstFactor; /* OK to factor out constants */
u8 disableLookaside; /* Number of times lookaside has been disabled */
- u8 disableVtab; /* Disable all virtual tables for this parse */
+ u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
+ u8 bHasWith; /* True if statement contains WITH */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlcipher_sqlite3ParserAddCleanup() */
#endif
+#ifdef SQLITE_DEBUG
+ u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */
+#endif
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
int nErr; /* Number of errors seen */
@@ -18997,6 +19927,8 @@ struct Parse {
int nLabelAlloc; /* Number of slots in aLabel */
int *aLabel; /* Space to hold the labels */
ExprList *pConstExpr;/* Constant expressions */
+ IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */
+ IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */
Token constraintName;/* Name of the constraint currently being parsed */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
@@ -19004,6 +19936,9 @@ struct Parse {
int regRoot; /* Register holding root page number for new objects */
int nMaxArg; /* Max args passed to user function by sub-program */
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ u32 nProgressSteps; /* xProgress steps taken during sqlcipher_sqlite3_prepare() */
+#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
int nTableLock; /* Number of locks in aTableLock */
TableLock *aTableLock; /* Required table locks for shared-cache mode */
@@ -19017,9 +19952,9 @@ struct Parse {
int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
Returning *pReturning; /* The RETURNING clause */
} u1;
- u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u32 oldmask; /* Mask of old.* columns referenced */
u32 newmask; /* Mask of new.* columns referenced */
+ LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
u8 bReturning; /* Coding a RETURNING trigger */
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
@@ -19143,6 +20078,7 @@ struct AuthContext {
#define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
+#define OPFLAG_BYTELENARG 0xc0 /* OP_Column only for octet_length() */
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
#define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */
#define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */
@@ -19264,6 +20200,7 @@ struct Returning {
int iRetCur; /* Transient table holding RETURNING results */
int nRetCol; /* Number of in pReturnEL after expansion */
int iRetReg; /* Register array for holding a row of RETURNING */
+ char zName[40]; /* Name of trigger: "sqlite_returning_%p" */
};
/*
@@ -19285,6 +20222,28 @@ struct sqlcipher_sqlite3_str {
#define isMalloced(X) (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0)
+/*
+** The following object is the header for an "RCStr" or "reference-counted
+** string". An RCStr is passed around and used like any other char*
+** that has been dynamically allocated. The important interface
+** differences:
+**
+** 1. RCStr strings are reference counted. They are deallocated
+** when the reference count reaches zero.
+**
+** 2. Use sqlcipher_sqlite3RCStrUnref() to free an RCStr string rather than
+** sqlcipher_sqlite3_free()
+**
+** 3. Make a (read-only) copy of a read-only RCStr string using
+** sqlcipher_sqlite3RCStrRef().
+**
+** "String" is in the name, but an RCStr object can also be used to hold
+** binary data.
+*/
+struct RCStr {
+ u64 nRCRef; /* Number of references */
+ /* Total structure size should be a multiple of 8 bytes for alignment */
+};
/*
** A pointer to this structure is used to communicate information
@@ -19311,7 +20270,7 @@ typedef struct {
/* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled
** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning
** parameters are for temporary use during development, to help find
-** optimial values for parameters in the query planner. The should not
+** optimal values for parameters in the query planner. The should not
** be used on trunk check-ins. They are a temporary mechanism available
** for transient development builds only.
**
@@ -19337,6 +20296,10 @@ struct Sqlite3Config {
u8 bUseCis; /* Use covering indices for full-scans */
u8 bSmallMalloc; /* Avoid large memory allocations if true */
u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */
+ u8 bUseLongDouble; /* Make use of long double */
+#ifdef SQLITE_DEBUG
+ u8 bJsonSelfcheck; /* Double-check JSON parsing */
+#endif
int mxStrlen; /* Maximum string length */
int neverCorrupt; /* Database is always well-formed */
int szLookaside; /* Default lookaside buffer size */
@@ -19384,6 +20347,11 @@ struct Sqlite3Config {
#ifndef SQLITE_UNTESTABLE
int (*xTestCallback)(int); /* Invoked by sqlcipher_sqlite3FaultSim() */
#endif
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ u32 mNoVisibleRowid; /* TF_NoVisibleRowid if the ROWID_IN_VIEW
+ ** feature is disabled. 0 if rowids can
+ ** occur in views. */
+#endif
int bLocaltimeFault; /* True to fail localtime() calls */
int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */
int iOnceResetThreshold; /* When to reset OP_Once counters */
@@ -19423,6 +20391,7 @@ struct Walker {
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
int walkerDepth; /* Number of subqueries */
u16 eCode; /* A small processing code */
+ u16 mWFlags; /* Use-dependent flags */
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
int n; /* A counter */
@@ -19432,15 +20401,16 @@ struct Walker {
struct RefSrcList *pRefSrcList; /* sqlcipher_sqlite3ReferencesSrcList() */
int *aiCol; /* array of column indexes */
struct IdxCover *pIdxCover; /* Check for index coverage */
- struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */
ExprList *pGroupBy; /* GROUP BY clause */
Select *pSelect; /* HAVING to WHERE clause ctx */
struct WindowRewrite *pRewrite; /* Window rewrite context */
struct WhereConst *pConst; /* WHERE clause constants */
struct RenameCtx *pRename; /* RENAME COLUMN context */
struct Table *pTab; /* Table of generated column */
+ struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */
SrcItem *pSrcItem; /* A single FROM clause item */
- DbFixer *pFix;
+ DbFixer *pFix; /* See sqlcipher_sqlite3FixSelect() */
+ Mem *aMem; /* See sqlcipher_sqlite3BtreeCursorHint() */
} u;
};
@@ -19461,6 +20431,7 @@ struct DbFixer {
/* Forward declarations */
SQLITE_PRIVATE int sqlcipher_sqlite3WalkExpr(Walker*, Expr*);
+SQLITE_PRIVATE int sqlcipher_sqlite3WalkExprNN(Walker*, Expr*);
SQLITE_PRIVATE int sqlcipher_sqlite3WalkExprList(Walker*, ExprList*);
SQLITE_PRIVATE int sqlcipher_sqlite3WalkSelect(Walker*, Select*);
SQLITE_PRIVATE int sqlcipher_sqlite3WalkSelectExpr(Walker*, Select*);
@@ -19541,6 +20512,16 @@ struct CteUse {
};
+/* Client data associated with sqlcipher_sqlite3_set_clientdata() and
+** sqlcipher_sqlite3_get_clientdata().
+*/
+struct DbClientData {
+ DbClientData *pNext; /* Next in a linked list */
+ void *pData; /* The data */
+ void (*xDestructor)(void*); /* Destructor. Might be NULL */
+ char zName[1]; /* Name of this client data. MUST BE LAST */
+};
+
#ifdef SQLITE_DEBUG
/*
** An instance of the TreeView object is used for printing the content of
@@ -19607,6 +20588,9 @@ struct Window {
** due to the SQLITE_SUBTYPE flag */
};
+SQLITE_PRIVATE Select *sqlcipher_sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow);
+SQLITE_PRIVATE void sqlcipher_sqlite3MultiValuesEnd(Parse *pParse, Select *pVal);
+
#ifndef SQLITE_OMIT_WINDOWFUNC
SQLITE_PRIVATE void sqlcipher_sqlite3WindowDelete(sqlcipher_sqlite3*, Window*);
SQLITE_PRIVATE void sqlcipher_sqlite3WindowUnlinkFromSelect(Window*);
@@ -19710,6 +20694,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3CorruptPgnoError(int,Pgno);
# define sqlcipher_sqlite3Isxdigit(x) (sqlcipher_sqlite3CtypeMap[(unsigned char)(x)]&0x08)
# define sqlcipher_sqlite3Tolower(x) (sqlcipher_sqlite3UpperToLower[(unsigned char)(x)])
# define sqlcipher_sqlite3Isquote(x) (sqlcipher_sqlite3CtypeMap[(unsigned char)(x)]&0x80)
+# define sqlcipher_sqlite3JsonId1(x) (sqlcipher_sqlite3CtypeMap[(unsigned char)(x)]&0x42)
+# define sqlcipher_sqlite3JsonId2(x) (sqlcipher_sqlite3CtypeMap[(unsigned char)(x)]&0x46)
#else
# define sqlcipher_sqlite3Toupper(x) toupper((unsigned char)(x))
# define sqlcipher_sqlite3Isspace(x) isspace((unsigned char)(x))
@@ -19719,6 +20705,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3CorruptPgnoError(int,Pgno);
# define sqlcipher_sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
# define sqlcipher_sqlite3Tolower(x) tolower((unsigned char)(x))
# define sqlcipher_sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
+# define sqlcipher_sqlite3JsonId1(x) (sqlcipher_sqlite3IsIdChar(x)&&(x)<'0')
+# define sqlcipher_sqlite3JsonId2(x) sqlcipher_sqlite3IsIdChar(x)
#endif
SQLITE_PRIVATE int sqlcipher_sqlite3IsIdChar(u8);
@@ -19746,6 +20734,7 @@ SQLITE_PRIVATE void *sqlcipher_sqlite3DbReallocOrFree(sqlcipher_sqlite3 *, void
SQLITE_PRIVATE void *sqlcipher_sqlite3DbRealloc(sqlcipher_sqlite3 *, void *, u64);
SQLITE_PRIVATE void sqlcipher_sqlite3DbFree(sqlcipher_sqlite3*, void*);
SQLITE_PRIVATE void sqlcipher_sqlite3DbFreeNN(sqlcipher_sqlite3*, void*);
+SQLITE_PRIVATE void sqlcipher_sqlite3DbNNFreeNN(sqlcipher_sqlite3*, void*);
SQLITE_PRIVATE int sqlcipher_sqlite3MallocSize(const void*);
SQLITE_PRIVATE int sqlcipher_sqlite3DbMallocSize(sqlcipher_sqlite3*, const void*);
SQLITE_PRIVATE void *sqlcipher_sqlite3PageMalloc(int);
@@ -19766,12 +20755,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3HeapNearlyFull(void);
*/
#ifdef SQLITE_USE_ALLOCA
# define sqlcipher_sqlite3StackAllocRaw(D,N) alloca(N)
-# define sqlcipher_sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N)
+# define sqlcipher_sqlite3StackAllocRawNN(D,N) alloca(N)
# define sqlcipher_sqlite3StackFree(D,P)
+# define sqlcipher_sqlite3StackFreeNN(D,P)
#else
# define sqlcipher_sqlite3StackAllocRaw(D,N) sqlcipher_sqlite3DbMallocRaw(D,N)
-# define sqlcipher_sqlite3StackAllocZero(D,N) sqlcipher_sqlite3DbMallocZero(D,N)
+# define sqlcipher_sqlite3StackAllocRawNN(D,N) sqlcipher_sqlite3DbMallocRawNN(D,N)
# define sqlcipher_sqlite3StackFree(D,P) sqlcipher_sqlite3DbFree(D,P)
+# define sqlcipher_sqlite3StackFreeNN(D,P) sqlcipher_sqlite3DbFreeNN(D,P)
#endif
/* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they
@@ -19819,10 +20810,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3MutexWarnOnContention(sqlcipher_sqlite3_mut
# define EXP754 (((u64)0x7ff)<<52)
# define MAN754 ((((u64)1)<<52)-1)
# define IsNaN(X) (((X)&EXP754)==EXP754 && ((X)&MAN754)!=0)
+# define IsOvfl(X) (((X)&EXP754)==EXP754)
SQLITE_PRIVATE int sqlcipher_sqlite3IsNaN(double);
+SQLITE_PRIVATE int sqlcipher_sqlite3IsOverflow(double);
#else
-# define IsNaN(X) 0
-# define sqlcipher_sqlite3IsNaN(X) 0
+# define IsNaN(X) 0
+# define sqlcipher_sqlite3IsNaN(X) 0
+# define sqlcipher_sqlite3IsOVerflow(X) 0
#endif
/*
@@ -19835,6 +20829,20 @@ struct PrintfArguments {
sqlcipher_sqlite3_value **apArg; /* The argument values */
};
+/*
+** An instance of this object receives the decoding of a floating point
+** value into an approximate decimal representation.
+*/
+struct FpDecode {
+ char sign; /* '+' or '-' */
+ char isSpecial; /* 1: Infinity 2: NaN */
+ int n; /* Significant digits in the decode */
+ int iDP; /* Location of the decimal point */
+ char *z; /* Start of significant digits */
+ char zBuf[24]; /* Storage for significant digits */
+};
+
+SQLITE_PRIVATE void sqlcipher_sqlite3FpDecode(FpDecode*,double,int,int);
SQLITE_PRIVATE char *sqlcipher_sqlite3MPrintf(sqlcipher_sqlite3*,const char*, ...);
SQLITE_PRIVATE char *sqlcipher_sqlite3VMPrintf(sqlcipher_sqlite3*,const char*, va_list);
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
@@ -19894,11 +20902,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ShowWinFunc(const Window*);
#endif
SQLITE_PRIVATE void sqlcipher_sqlite3SetString(char **, sqlcipher_sqlite3*, const char*);
+SQLITE_PRIVATE void sqlcipher_sqlite3ProgressCheck(Parse*);
SQLITE_PRIVATE void sqlcipher_sqlite3ErrorMsg(Parse*, const char*, ...);
SQLITE_PRIVATE int sqlcipher_sqlite3ErrorToParser(sqlcipher_sqlite3*,int);
SQLITE_PRIVATE void sqlcipher_sqlite3Dequote(char*);
SQLITE_PRIVATE void sqlcipher_sqlite3DequoteExpr(Expr*);
SQLITE_PRIVATE void sqlcipher_sqlite3DequoteToken(Token*);
+SQLITE_PRIVATE void sqlcipher_sqlite3DequoteNumber(Parse*, Expr*);
SQLITE_PRIVATE void sqlcipher_sqlite3TokenInit(Token*,char*);
SQLITE_PRIVATE int sqlcipher_sqlite3KeywordCode(const unsigned char*, int);
SQLITE_PRIVATE int sqlcipher_sqlite3RunParser(Parse*, const char*);
@@ -19908,6 +20918,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ReleaseTempReg(Parse*,int);
SQLITE_PRIVATE int sqlcipher_sqlite3GetTempRange(Parse*,int);
SQLITE_PRIVATE void sqlcipher_sqlite3ReleaseTempRange(Parse*,int,int);
SQLITE_PRIVATE void sqlcipher_sqlite3ClearTempRegCache(Parse*);
+SQLITE_PRIVATE void sqlcipher_sqlite3TouchRegister(Parse*,int);
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlcipher_sqlite3FirstAvailableRegister(Parse*,int);
+#endif
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlcipher_sqlite3NoTempsInRange(Parse*,int,int);
#endif
@@ -19919,10 +20933,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3PExprAddSelect(Parse*, Expr*, Select*);
SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprAnd(Parse*,Expr*, Expr*);
SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprSimplifiedAndOr(Expr*);
SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprFunction(Parse*,ExprList*, const Token*, int);
+SQLITE_PRIVATE void sqlcipher_sqlite3ExprAddFunctionOrderBy(Parse*,Expr*,ExprList*);
+SQLITE_PRIVATE void sqlcipher_sqlite3ExprOrderByAggregateError(Parse*,Expr*);
SQLITE_PRIVATE void sqlcipher_sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*);
SQLITE_PRIVATE void sqlcipher_sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
SQLITE_PRIVATE void sqlcipher_sqlite3ExprDelete(sqlcipher_sqlite3*, Expr*);
-SQLITE_PRIVATE void sqlcipher_sqlite3ExprDeferredDelete(Parse*, Expr*);
+SQLITE_PRIVATE void sqlcipher_sqlite3ExprDeleteGeneric(sqlcipher_sqlite3*,void*);
+SQLITE_PRIVATE int sqlcipher_sqlite3ExprDeferredDelete(Parse*, Expr*);
SQLITE_PRIVATE void sqlcipher_sqlite3ExprUnmapAndDelete(Parse*, Expr*);
SQLITE_PRIVATE ExprList *sqlcipher_sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
SQLITE_PRIVATE ExprList *sqlcipher_sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
@@ -19931,6 +20948,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprListSetSortOrder(ExprList*,int,int);
SQLITE_PRIVATE void sqlcipher_sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int);
SQLITE_PRIVATE void sqlcipher_sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
SQLITE_PRIVATE void sqlcipher_sqlite3ExprListDelete(sqlcipher_sqlite3*, ExprList*);
+SQLITE_PRIVATE void sqlcipher_sqlite3ExprListDeleteGeneric(sqlcipher_sqlite3*,void*);
SQLITE_PRIVATE u32 sqlcipher_sqlite3ExprListFlags(const ExprList*);
SQLITE_PRIVATE int sqlcipher_sqlite3IndexHasDuplicateRootPage(Index*);
SQLITE_PRIVATE int sqlcipher_sqlite3Init(sqlcipher_sqlite3*, char**);
@@ -19951,7 +20969,7 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3ColumnColl(Column*);
SQLITE_PRIVATE void sqlcipher_sqlite3DeleteColumnNames(sqlcipher_sqlite3*,Table*);
SQLITE_PRIVATE void sqlcipher_sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect);
SQLITE_PRIVATE int sqlcipher_sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
-SQLITE_PRIVATE void sqlcipher_sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char);
+SQLITE_PRIVATE void sqlcipher_sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char);
SQLITE_PRIVATE Table *sqlcipher_sqlite3ResultSetOfSelect(Parse*,Select*,char);
SQLITE_PRIVATE void sqlcipher_sqlite3OpenSchemaTable(Parse *, int);
SQLITE_PRIVATE Index *sqlcipher_sqlite3PrimaryKeyIndex(Table*);
@@ -20027,6 +21045,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3DbMaskAllZero(yDbMask);
SQLITE_PRIVATE void sqlcipher_sqlite3DropTable(Parse*, SrcList*, int, int);
SQLITE_PRIVATE void sqlcipher_sqlite3CodeDropTable(Parse*, Table*, int, int);
SQLITE_PRIVATE void sqlcipher_sqlite3DeleteTable(sqlcipher_sqlite3*, Table*);
+SQLITE_PRIVATE void sqlcipher_sqlite3DeleteTableGeneric(sqlcipher_sqlite3*, void*);
SQLITE_PRIVATE void sqlcipher_sqlite3FreeIndex(sqlcipher_sqlite3*, Index*);
#ifndef SQLITE_OMIT_AUTOINCREMENT
SQLITE_PRIVATE void sqlcipher_sqlite3AutoincrementBegin(Parse *pParse);
@@ -20063,8 +21082,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(Parse*, Select*, SelectDest*);
SQLITE_PRIVATE Select *sqlcipher_sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
Expr*,ExprList*,u32,Expr*);
SQLITE_PRIVATE void sqlcipher_sqlite3SelectDelete(sqlcipher_sqlite3*, Select*);
+SQLITE_PRIVATE void sqlcipher_sqlite3SelectDeleteGeneric(sqlcipher_sqlite3*,void*);
SQLITE_PRIVATE Table *sqlcipher_sqlite3SrcListLookup(Parse*, SrcList*);
-SQLITE_PRIVATE int sqlcipher_sqlite3IsReadOnly(Parse*, Table*, int);
+SQLITE_PRIVATE int sqlcipher_sqlite3IsReadOnly(Parse*, Table*, Trigger*);
SQLITE_PRIVATE void sqlcipher_sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE Expr *sqlcipher_sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
@@ -20126,7 +21146,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprCompare(const Parse*,const Expr*,const E
SQLITE_PRIVATE int sqlcipher_sqlite3ExprCompareSkip(Expr*,Expr*,int);
SQLITE_PRIVATE int sqlcipher_sqlite3ExprListCompare(const ExprList*,const ExprList*, int);
SQLITE_PRIVATE int sqlcipher_sqlite3ExprImpliesExpr(const Parse*,const Expr*,const Expr*, int);
-SQLITE_PRIVATE int sqlcipher_sqlite3ExprImpliesNonNullRow(Expr*,int);
+SQLITE_PRIVATE int sqlcipher_sqlite3ExprImpliesNonNullRow(Expr*,int,int);
SQLITE_PRIVATE void sqlcipher_sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
SQLITE_PRIVATE void sqlcipher_sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void sqlcipher_sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
@@ -20148,12 +21168,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3LeaveMutexAndCloseZombie(sqlcipher_sqlite3*
SQLITE_PRIVATE u32 sqlcipher_sqlite3IsTrueOrFalse(const char*);
SQLITE_PRIVATE int sqlcipher_sqlite3ExprIdToTrueFalse(Expr*);
SQLITE_PRIVATE int sqlcipher_sqlite3ExprTruthValue(const Expr*);
-SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstant(Expr*);
-SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstantNotJoin(Expr*);
+SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstant(Parse*,Expr*);
SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstantOrFunction(Expr*, u8);
SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
-SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsTableConstant(Expr*,int);
-SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsTableConstraint(Expr*,const SrcItem*);
+SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int,int);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
SQLITE_PRIVATE int sqlcipher_sqlite3ExprContainsSubquery(Expr*);
#endif
@@ -20161,6 +21179,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsInteger(const Expr*, int*);
SQLITE_PRIVATE int sqlcipher_sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int sqlcipher_sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
SQLITE_PRIVATE int sqlcipher_sqlite3IsRowid(const char*);
+SQLITE_PRIVATE const char *sqlcipher_sqlite3RowidAlias(Table *pTab);
SQLITE_PRIVATE void sqlcipher_sqlite3GenerateRowDelete(
Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
SQLITE_PRIVATE void sqlcipher_sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
@@ -20275,8 +21294,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3FixSrcList(DbFixer*, SrcList*);
SQLITE_PRIVATE int sqlcipher_sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int sqlcipher_sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int sqlcipher_sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
+
SQLITE_PRIVATE int sqlcipher_sqlite3RealSameAsInt(double,sqlcipher_sqlite3_int64);
-SQLITE_PRIVATE void sqlcipher_sqlite3Int64ToText(i64,char*);
+SQLITE_PRIVATE i64 sqlcipher_sqlite3RealToI64(double);
+SQLITE_PRIVATE int sqlcipher_sqlite3Int64ToText(i64,char*);
SQLITE_PRIVATE int sqlcipher_sqlite3AtoF(const char *z, double*, int, u8);
SQLITE_PRIVATE int sqlcipher_sqlite3GetInt32(const char *, int*);
SQLITE_PRIVATE int sqlcipher_sqlite3GetUInt32(const char*, u32*);
@@ -20286,6 +21307,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Utf16ByteLen(const void *pData, int nChar);
#endif
SQLITE_PRIVATE int sqlcipher_sqlite3Utf8CharLen(const char *pData, int nByte);
SQLITE_PRIVATE u32 sqlcipher_sqlite3Utf8Read(const u8**);
+SQLITE_PRIVATE int sqlcipher_sqlite3Utf8ReadLimited(const u8*, int, u32*);
SQLITE_PRIVATE LogEst sqlcipher_sqlite3LogEst(u64);
SQLITE_PRIVATE LogEst sqlcipher_sqlite3LogEstAdd(LogEst,LogEst);
SQLITE_PRIVATE LogEst sqlcipher_sqlite3LogEstFromDouble(double);
@@ -20321,18 +21343,22 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VarintLen(u64 v);
SQLITE_PRIVATE const char *sqlcipher_sqlite3IndexAffinityStr(sqlcipher_sqlite3*, Index*);
+SQLITE_PRIVATE char *sqlcipher_sqlite3TableAffinityStr(sqlcipher_sqlite3*,const Table*);
SQLITE_PRIVATE void sqlcipher_sqlite3TableAffinity(Vdbe*, Table*, int);
SQLITE_PRIVATE char sqlcipher_sqlite3CompareAffinity(const Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlcipher_sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlcipher_sqlite3TableColumnAffinity(const Table*,int);
SQLITE_PRIVATE char sqlcipher_sqlite3ExprAffinity(const Expr *pExpr);
+SQLITE_PRIVATE int sqlcipher_sqlite3ExprDataType(const Expr *pExpr);
SQLITE_PRIVATE int sqlcipher_sqlite3Atoi64(const char*, i64*, int, u8);
SQLITE_PRIVATE int sqlcipher_sqlite3DecOrHexToI64(const char*, i64*);
SQLITE_PRIVATE void sqlcipher_sqlite3ErrorWithMsg(sqlcipher_sqlite3*, int, const char*,...);
SQLITE_PRIVATE void sqlcipher_sqlite3Error(sqlcipher_sqlite3*,int);
SQLITE_PRIVATE void sqlcipher_sqlite3ErrorClear(sqlcipher_sqlite3*);
SQLITE_PRIVATE void sqlcipher_sqlite3SystemError(sqlcipher_sqlite3*,int);
+#if !defined(SQLITE_OMIT_BLOB_LITERAL)
SQLITE_PRIVATE void *sqlcipher_sqlite3HexToBlob(sqlcipher_sqlite3*, const char *z, int n);
+#endif
SQLITE_PRIVATE u8 sqlcipher_sqlite3HexToInt(int h);
SQLITE_PRIVATE int sqlcipher_sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
@@ -20342,6 +21368,9 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3ErrName(int);
#ifndef SQLITE_OMIT_DESERIALIZE
SQLITE_PRIVATE int sqlcipher_sqlite3MemdbInit(void);
+SQLITE_PRIVATE int sqlcipher_sqlite3IsMemdb(const sqlcipher_sqlite3_vfs*);
+#else
+# define sqlcipher_sqlite3IsMemdb(X) 0
#endif
SQLITE_PRIVATE const char *sqlcipher_sqlite3ErrStr(int);
@@ -20373,6 +21402,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3FileSuffix3(const char*, char*);
SQLITE_PRIVATE u8 sqlcipher_sqlite3GetBoolean(const char *z,u8);
SQLITE_PRIVATE const void *sqlcipher_sqlite3ValueText(sqlcipher_sqlite3_value*, u8);
+SQLITE_PRIVATE int sqlcipher_sqlite3ValueIsOfClass(const sqlcipher_sqlite3_value*, void(*)(void*));
SQLITE_PRIVATE int sqlcipher_sqlite3ValueBytes(sqlcipher_sqlite3_value*, u8);
SQLITE_PRIVATE void sqlcipher_sqlite3ValueSetStr(sqlcipher_sqlite3_value*, int, const void *,u8,
void(*)(void*));
@@ -20392,7 +21422,6 @@ SQLITE_PRIVATE const unsigned char sqlcipher_sqlite3OpcodeProperty[];
SQLITE_PRIVATE const char sqlcipher_sqlite3StrBINARY[];
SQLITE_PRIVATE const unsigned char sqlcipher_sqlite3StdTypeLen[];
SQLITE_PRIVATE const char sqlcipher_sqlite3StdTypeAffinity[];
-SQLITE_PRIVATE const char sqlcipher_sqlite3StdTypeMap[];
SQLITE_PRIVATE const char *sqlcipher_sqlite3StdType[];
SQLITE_PRIVATE const unsigned char sqlcipher_sqlite3UpperToLower[];
SQLITE_PRIVATE const unsigned char *sqlcipher_sqlite3aLTb;
@@ -20425,7 +21454,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3MatchEName(
const struct ExprList_item*,
const char*,
const char*,
- const char*
+ const char*,
+ int*
);
SQLITE_PRIVATE Bitmask sqlcipher_sqlite3ExprColUsed(Expr*);
SQLITE_PRIVATE u8 sqlcipher_sqlite3StrIHash(const char*);
@@ -20481,8 +21511,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3OomClear(sqlcipher_sqlite3*);
SQLITE_PRIVATE int sqlcipher_sqlite3ApiExit(sqlcipher_sqlite3 *db, int);
SQLITE_PRIVATE int sqlcipher_sqlite3OpenTempDatabase(Parse *);
+SQLITE_PRIVATE char *sqlcipher_sqlite3RCStrRef(char*);
+SQLITE_PRIVATE void sqlcipher_sqlite3RCStrUnref(void*);
+SQLITE_PRIVATE char *sqlcipher_sqlite3RCStrNew(u64);
+SQLITE_PRIVATE char *sqlcipher_sqlite3RCStrResize(char*,u64);
+
SQLITE_PRIVATE void sqlcipher_sqlite3StrAccumInit(StrAccum*, sqlcipher_sqlite3*, char*, int, int);
-SQLITE_PRIVATE int sqlcipher_sqlite3StrAccumEnlarge(StrAccum*, int);
+SQLITE_PRIVATE int sqlcipher_sqlite3StrAccumEnlarge(StrAccum*, i64);
SQLITE_PRIVATE char *sqlcipher_sqlite3StrAccumFinish(StrAccum*);
SQLITE_PRIVATE void sqlcipher_sqlite3StrAccumSetError(StrAccum*, u8);
SQLITE_PRIVATE void sqlcipher_sqlite3ResultStrAccum(sqlcipher_sqlite3_context*,StrAccum*);
@@ -20596,10 +21631,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VtabCallDestroy(sqlcipher_sqlite3*, int, con
SQLITE_PRIVATE int sqlcipher_sqlite3VtabBegin(sqlcipher_sqlite3 *, VTable *);
SQLITE_PRIVATE FuncDef *sqlcipher_sqlite3VtabOverloadFunction(sqlcipher_sqlite3 *,FuncDef*, int nArg, Expr*);
-#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
- && !defined(SQLITE_OMIT_VIRTUALTABLE)
-SQLITE_PRIVATE void sqlcipher_sqlite3VtabUsesAllSchemas(sqlcipher_sqlite3_index_info*);
-#endif
+SQLITE_PRIVATE void sqlcipher_sqlite3VtabUsesAllSchemas(Parse*);
SQLITE_PRIVATE sqlcipher_sqlite3_int64 sqlcipher_sqlite3StmtCurrentTime(sqlcipher_sqlite3_context*);
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
SQLITE_PRIVATE int sqlcipher_sqlite3TransferBindings(sqlcipher_sqlite3_stmt *, sqlcipher_sqlite3_stmt *);
@@ -20624,6 +21656,7 @@ SQLITE_PRIVATE Cte *sqlcipher_sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8
SQLITE_PRIVATE void sqlcipher_sqlite3CteDelete(sqlcipher_sqlite3*,Cte*);
SQLITE_PRIVATE With *sqlcipher_sqlite3WithAdd(Parse*,With*,Cte*);
SQLITE_PRIVATE void sqlcipher_sqlite3WithDelete(sqlcipher_sqlite3*,With*);
+SQLITE_PRIVATE void sqlcipher_sqlite3WithDeleteGeneric(sqlcipher_sqlite3*,void*);
SQLITE_PRIVATE With *sqlcipher_sqlite3WithPush(Parse*, With*, u8);
#else
# define sqlcipher_sqlite3CteNew(P,T,E,S) ((void*)0)
@@ -20636,7 +21669,7 @@ SQLITE_PRIVATE With *sqlcipher_sqlite3WithPush(Parse*, With*, u8);
SQLITE_PRIVATE Upsert *sqlcipher_sqlite3UpsertNew(sqlcipher_sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
SQLITE_PRIVATE void sqlcipher_sqlite3UpsertDelete(sqlcipher_sqlite3*,Upsert*);
SQLITE_PRIVATE Upsert *sqlcipher_sqlite3UpsertDup(sqlcipher_sqlite3*,Upsert*);
-SQLITE_PRIVATE int sqlcipher_sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*);
+SQLITE_PRIVATE int sqlcipher_sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*,Upsert*);
SQLITE_PRIVATE void sqlcipher_sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int);
SQLITE_PRIVATE Upsert *sqlcipher_sqlite3UpsertOfIndex(Upsert*,Index*);
SQLITE_PRIVATE int sqlcipher_sqlite3UpsertNextIsIPK(Upsert*);
@@ -20735,6 +21768,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprCheckHeight(Parse*, int);
#define sqlcipher_sqlite3SelectExprHeight(x) 0
#define sqlcipher_sqlite3ExprCheckHeight(x,y)
#endif
+SQLITE_PRIVATE void sqlcipher_sqlite3ExprSetErrorOffset(Expr*,int);
SQLITE_PRIVATE u32 sqlcipher_sqlite3Get4byte(const u8*);
SQLITE_PRIVATE void sqlcipher_sqlite3Put4byte(u8*, u32);
@@ -20836,6 +21870,22 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VectorErrorMsg(Parse*, Expr*);
SQLITE_PRIVATE const char **sqlcipher_sqlite3CompileOptions(int *pnOpt);
#endif
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
+SQLITE_PRIVATE int sqlcipher_sqlite3KvvfsInit(void);
+#endif
+
+#if defined(VDBE_PROFILE) \
+ || defined(SQLITE_PERFORMANCE_TRACE) \
+ || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+SQLITE_PRIVATE sqlcipher_sqlite3_uint64 sqlcipher_sqlite3Hwtime(void);
+#endif
+
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+# define IS_STMT_SCANSTATUS(db) (db->flags & SQLITE_StmtScanStatus)
+#else
+# define IS_STMT_SCANSTATUS(db) 0
+#endif
+
#endif /* SQLITEINT_H */
/************** End of sqliteInt.h *******************************************/
@@ -20877,101 +21927,6 @@ SQLITE_PRIVATE const char **sqlcipher_sqlite3CompileOptions(int *pnOpt);
*/
#ifdef SQLITE_PERFORMANCE_TRACE
-/*
-** hwtime.h contains inline assembler code for implementing
-** high-performance timing routines.
-*/
-/************** Include hwtime.h in the middle of os_common.h ****************/
-/************** Begin file hwtime.h ******************************************/
-/*
-** 2008 May 27
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This file contains inline asm code for retrieving "high-performance"
-** counters for x86 and x86_64 class CPUs.
-*/
-#ifndef SQLITE_HWTIME_H
-#define SQLITE_HWTIME_H
-
-/*
-** The following routine only works on pentium-class (or newer) processors.
-** It uses the RDTSC opcode to read the cycle count value out of the
-** processor and returns that value. This can be used for high-res
-** profiling.
-*/
-#if !defined(__STRICT_ANSI__) && \
- (defined(__GNUC__) || defined(_MSC_VER)) && \
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
-
- #if defined(__GNUC__)
-
- __inline__ sqlite_uint64 sqlcipher_sqlite3Hwtime(void){
- unsigned int lo, hi;
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
- return (sqlite_uint64)hi << 32 | lo;
- }
-
- #elif defined(_MSC_VER)
-
- __declspec(naked) __inline sqlite_uint64 __cdecl sqlcipher_sqlite3Hwtime(void){
- __asm {
- rdtsc
- ret ; return value at EDX:EAX
- }
- }
-
- #endif
-
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
-
- __inline__ sqlite_uint64 sqlcipher_sqlite3Hwtime(void){
- unsigned long val;
- __asm__ __volatile__ ("rdtsc" : "=A" (val));
- return val;
- }
-
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
-
- __inline__ sqlite_uint64 sqlcipher_sqlite3Hwtime(void){
- unsigned long long retval;
- unsigned long junk;
- __asm__ __volatile__ ("\n\
- 1: mftbu %1\n\
- mftb %L0\n\
- mftbu %0\n\
- cmpw %0,%1\n\
- bne 1b"
- : "=r" (retval), "=r" (junk));
- return retval;
- }
-
-#else
-
- /*
- ** asm() is needed for hardware timing support. Without asm(),
- ** disable the sqlcipher_sqlite3Hwtime() routine.
- **
- ** sqlcipher_sqlite3Hwtime() is only used for some obscure debugging
- ** and analysis configurations, not in any deliverable, so this
- ** should not be a great loss.
- */
-SQLITE_PRIVATE sqlite_uint64 sqlcipher_sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
-
-#endif
-
-#endif /* !defined(SQLITE_HWTIME_H) */
-
-/************** End of hwtime.h **********************************************/
-/************** Continuing where we left off in os_common.h ******************/
-
static sqlite_uint64 g_start;
static sqlite_uint64 g_elapsed;
#define TIMER_START g_start=sqlcipher_sqlite3Hwtime()
@@ -21067,7 +22022,7 @@ SQLITE_API extern int sqlcipher_sqlite3_open_file_count;
** autoconf-based build
*/
#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
-/* #include "config.h" */
+/* #include "sqlite_cfg.h" */
#define SQLITECONFIG_H 1
#endif
@@ -21099,14 +22054,14 @@ static const char * const sqlcipher_sqlite3azCompileOpt[] = {
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
"4_BYTE_ALIGNED_MALLOC",
#endif
-#ifdef SQLITE_64BIT_STATS
- "64BIT_STATS",
-#endif
#ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN
# if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1
"ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN),
# endif
#endif
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ "ALLOW_ROWID_IN_VIEW",
+#endif
#ifdef SQLITE_ALLOW_URI_AUTHORITY
"ALLOW_URI_AUTHORITY",
#endif
@@ -21232,6 +22187,9 @@ static const char * const sqlcipher_sqlite3azCompileOpt[] = {
#ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
"DISABLE_SKIPAHEAD_DISTINCT",
#endif
+#ifdef SQLITE_DQS
+ "DQS=" CTIMEOPT_VAL(SQLITE_DQS),
+#endif
#ifdef SQLITE_ENABLE_8_3_NAMES
"ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
#endif
@@ -21394,6 +22352,9 @@ static const char * const sqlcipher_sqlite3azCompileOpt[] = {
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
"EXPLAIN_ESTIMATED_ROWS",
#endif
+#ifdef SQLITE_EXTRA_AUTOEXT
+ "EXTRA_AUTOEXT=" CTIMEOPT_VAL(SQLITE_EXTRA_AUTOEXT),
+#endif
#ifdef SQLITE_EXTRA_IFNULLROW
"EXTRA_IFNULLROW",
#endif
@@ -21440,6 +22401,9 @@ static const char * const sqlcipher_sqlite3azCompileOpt[] = {
#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
"INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
#endif
+#ifdef SQLITE_LEGACY_JSON_VALID
+ "LEGACY_JSON_VALID",
+#endif
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
"LIKE_DOESNT_MATCH_BLOBS",
#endif
@@ -21677,6 +22641,9 @@ static const char * const sqlcipher_sqlite3azCompileOpt[] = {
#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
"OMIT_SCHEMA_VERSION_PRAGMAS",
#endif
+#ifdef SQLITE_OMIT_SEH
+ "OMIT_SEH",
+#endif
#ifdef SQLITE_OMIT_SHARED_CACHE
"OMIT_SHARED_CACHE",
#endif
@@ -21727,9 +22694,6 @@ static const char * const sqlcipher_sqlite3azCompileOpt[] = {
#ifdef SQLITE_OMIT_XFER_OPT
"OMIT_XFER_OPT",
#endif
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- "PCACHE_SEPARATE_HEADER",
-#endif
#ifdef SQLITE_PERFORMANCE_TRACE
"PERFORMANCE_TRACE",
#endif
@@ -21931,7 +22895,7 @@ SQLITE_PRIVATE const unsigned char *sqlcipher_sqlite3aGTb = &sqlcipher_sqlite3Up
** isalnum() 0x06
** isxdigit() 0x08
** toupper() 0x20
-** SQLite identifier character 0x40
+** SQLite identifier character 0x40 $, _, or non-ascii
** Quote character 0x80
**
** Bit 0x20 is set if the mapped character requires translation to upper
@@ -22086,6 +23050,10 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlcipher_sqlite3Config = {
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
0, /* bSmallMalloc */
1, /* bExtraSchemaChecks */
+ sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */
+#ifdef SQLITE_DEBUG
+ 0, /* bJsonSelfcheck */
+#endif
0x7ffffffe, /* mxStrlen */
0, /* neverCorrupt */
SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
@@ -22128,13 +23096,16 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlcipher_sqlite3Config = {
#ifndef SQLITE_UNTESTABLE
0, /* xTestCallback */
#endif
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ 0, /* mNoVisibleRowid. 0 == allow rowid-in-view */
+#endif
0, /* bLocaltimeFault */
0, /* xAltLocaltime */
0x7ffffffe, /* iOnceResetThreshold */
SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */
0, /* iPrngSeed */
#ifdef SQLITE_DEBUG
- {0,0,0,0,0,0} /* aTune */
+ {0,0,0,0,0,0}, /* aTune */
#endif
};
@@ -22218,10 +23189,6 @@ SQLITE_PRIVATE const char sqlcipher_sqlite3StrBINARY[] = "BINARY";
**
** sqlcipher_sqlite3StdTypeAffinity[] The affinity associated with each entry
** in sqlcipher_sqlite3StdType[].
-**
-** sqlcipher_sqlite3StdTypeMap[] The type value (as returned from
-** sqlcipher_sqlite3_column_type() or sqlcipher_sqlite3_value_type())
-** for each entry in sqlcipher_sqlite3StdType[].
*/
SQLITE_PRIVATE const unsigned char sqlcipher_sqlite3StdTypeLen[] = { 3, 4, 3, 7, 4, 4 };
SQLITE_PRIVATE const char sqlcipher_sqlite3StdTypeAffinity[] = {
@@ -22232,14 +23199,6 @@ SQLITE_PRIVATE const char sqlcipher_sqlite3StdTypeAffinity[] = {
SQLITE_AFF_REAL,
SQLITE_AFF_TEXT
};
-SQLITE_PRIVATE const char sqlcipher_sqlite3StdTypeMap[] = {
- 0,
- SQLITE_BLOB,
- SQLITE_INTEGER,
- SQLITE_INTEGER,
- SQLITE_FLOAT,
- SQLITE_TEXT
-};
SQLITE_PRIVATE const char *sqlcipher_sqlite3StdType[] = {
"ANY",
"BLOB",
@@ -22327,6 +23286,9 @@ typedef struct VdbeSorter VdbeSorter;
/* Elements of the linked list at Vdbe.pAuxData */
typedef struct AuxData AuxData;
+/* A cache of large TEXT or BLOB values in a VdbeCursor */
+typedef struct VdbeTxtBlbCache VdbeTxtBlbCache;
+
/* Types of VDBE cursors */
#define CURTYPE_BTREE 0
#define CURTYPE_SORTER 1
@@ -22358,6 +23320,7 @@ struct VdbeCursor {
Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
Bool noReuse:1; /* OpenEphemeral may not reuse this cursor */
+ Bool colCache:1; /* pCache pointer is initialized and non-NULL */
u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */
union { /* pBtx for isEphermeral. pAltMap otherwise */
Btree *pBtx; /* Separate file holding temporary table */
@@ -22398,6 +23361,7 @@ struct VdbeCursor {
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
u64 maskUsed; /* Mask of columns used by this cursor */
#endif
+ VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */
/* 2*nField extra array elements allocated for aType[], beyond the one
** static element declared in the structure. nField total array slots for
@@ -22410,13 +23374,26 @@ struct VdbeCursor {
#define IsNullCursor(P) \
((P)->eCurType==CURTYPE_PSEUDO && (P)->nullRow && (P)->seekResult==0)
-
/*
** A value for VdbeCursor.cacheStatus that means the cache is always invalid.
*/
#define CACHE_STALE 0
/*
+** Large TEXT or BLOB values can be slow to load, so we want to avoid
+** loading them more than once. For that reason, large TEXT and BLOB values
+** can be stored in a cache defined by this object, and attached to the
+** VdbeCursor using the pCache field.
+*/
+struct VdbeTxtBlbCache {
+ char *pCValue; /* A RCStr buffer to hold the value */
+ i64 iOffset; /* File offset of the row being cached */
+ int iCol; /* Column for which the cache is valid */
+ u32 cacheStatus; /* Vdbe.cacheCtr value */
+ u32 colCacheCtr; /* Column cache counter */
+};
+
+/*
** When a sub-program is executed (OP_Program), a structure of this type
** is allocated to store the current value of the program counter, as
** well as the current memory cell array and various other frame specific
@@ -22442,7 +23419,6 @@ struct VdbeFrame {
Vdbe *v; /* VM this frame belongs to */
VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
Op *aOp; /* Program instructions for parent frame */
- i64 *anExec; /* Event counters from parent frame */
Mem *aMem; /* Array of memory cells for parent frame */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
u8 *aOnce; /* Bitmask used by OP_Once */
@@ -22658,10 +23634,19 @@ typedef unsigned bft; /* Bit Field Type */
/* The ScanStatus object holds a single value for the
** sqlcipher_sqlite3_stmt_scanstatus() interface.
+**
+** aAddrRange[]:
+** This array is used by ScanStatus elements associated with EQP
+** notes that make an SQLITE_SCANSTAT_NCYCLE value available. It is
+** an array of up to 3 ranges of VM addresses for which the Vdbe.anCycle[]
+** values should be summed to calculate the NCYCLE value. Each pair of
+** integer addresses is a start and end address (both inclusive) for a range
+** instructions. A start value of 0 indicates an empty range.
*/
typedef struct ScanStatus ScanStatus;
struct ScanStatus {
int addrExplain; /* OP_Explain for loop */
+ int aAddrRange[6];
int addrLoop; /* Address of "loops" counter */
int addrVisit; /* Address of "rows visited" counter */
int iSelectID; /* The "Select-ID" for this loop */
@@ -22691,7 +23676,7 @@ struct DblquoteStr {
*/
struct Vdbe {
sqlcipher_sqlite3 *db; /* The database connection that owns this statement */
- Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
+ Vdbe **ppVPrev,*pVNext; /* Linked list of VDBEs with the same Vdbe.db */
Parse *pParse; /* Parsing context used to create this Vdbe */
ynVar nVar; /* Number of entries in aVar[] */
int nMem; /* Number of memory locations currently allocated */
@@ -22717,7 +23702,7 @@ struct Vdbe {
int nOp; /* Number of instructions in the program */
int nOpAlloc; /* Slots allocated for aOp[] */
Mem *aColName; /* Column names to return */
- Mem *pResultSet; /* Pointer to an array of results */
+ Mem *pResultRow; /* Current output row */
char *zErrMsg; /* Error message written here */
VList *pVList; /* Name of variables */
#ifndef SQLITE_OMIT_TRACE
@@ -22728,16 +23713,18 @@ struct Vdbe {
u32 nWrite; /* Number of write operations that have occurred */
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
+ u16 nResAlloc; /* Column slots allocated to aColName[] */
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 eVdbeState; /* On of the VDBE_*_STATE values */
bft expired:2; /* 1: recompile VM immediately 2: when convenient */
- bft explain:2; /* True if EXPLAIN present on SQL command */
+ bft explain:2; /* 0: normal, 1: EXPLAIN, 2: EXPLAIN QUERY PLAN */
bft changeCntOn:1; /* True to update the change-counter */
bft usesStmtJournal:1; /* True if uses a statement journal */
bft readOnly:1; /* True for statements that do not write */
bft bIsReader:1; /* True for statements that read */
+ bft haveEqpOps:1; /* Bytecode supports EXPLAIN QUERY PLAN */
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
u32 aCounter[9]; /* Counters used by sqlcipher_sqlite3_stmt_status() */
@@ -22754,7 +23741,6 @@ struct Vdbe {
SubProgram *pProgram; /* Linked list of all sub-programs used by VM */
AuxData *pAuxData; /* Linked list of auxdata allocations */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- i64 *anExec; /* Number of times each op has been executed */
int nScan; /* Entries in aScan[] */
ScanStatus *aScan; /* Scan definitions for sqlcipher_sqlite3_stmt_scanstatus() */
#endif
@@ -22785,7 +23771,7 @@ struct PreUpdate {
i64 iKey1; /* First key value passed to hook */
i64 iKey2; /* Second key value passed to hook */
Mem *aNew; /* Array of new.* values */
- Table *pTab; /* Schema object being upated */
+ Table *pTab; /* Schema object being updated */
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
};
@@ -22875,6 +23861,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMemSetZeroBlob(Mem*,int);
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMemIsRowSet(const Mem*);
#endif
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMemSetRowSet(Mem*);
+SQLITE_PRIVATE void sqlcipher_sqlite3VdbeMemZeroTerminateIfAble(Mem*);
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMemMakeWriteable(Mem*);
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMemStringify(Mem*, u8, u8);
SQLITE_PRIVATE int sqlcipher_sqlite3IntFloatCompare(i64,double);
@@ -22921,6 +23908,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
+SQLITE_PRIVATE void sqlcipher_sqlite3VdbeValueListFree(void*);
+
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*);
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeAssertAbortable(Vdbe*);
@@ -23249,6 +24238,8 @@ SQLITE_API int sqlcipher_sqlite3_db_status(
sqlcipher_sqlite3BtreeEnterAll(db);
db->pnBytesFreed = &nByte;
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
+ db->lookaside.pEnd = db->lookaside.pStart;
for(i=0; i<db->nDb; i++){
Schema *pSchema = db->aDb[i].pSchema;
if( ALWAYS(pSchema!=0) ){
@@ -23274,6 +24265,7 @@ SQLITE_API int sqlcipher_sqlite3_db_status(
}
}
db->pnBytesFreed = 0;
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
sqlcipher_sqlite3BtreeLeaveAll(db);
*pHighwater = 0;
@@ -23291,9 +24283,12 @@ SQLITE_API int sqlcipher_sqlite3_db_status(
int nByte = 0; /* Used to accumulate return value */
db->pnBytesFreed = &nByte;
- for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
+ db->lookaside.pEnd = db->lookaside.pStart;
+ for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pVNext){
sqlcipher_sqlite3VdbeDelete(pVdbe);
}
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
db->pnBytesFreed = 0;
*pHighwater = 0; /* IMP: R-64479-57858 */
@@ -23314,7 +24309,7 @@ SQLITE_API int sqlcipher_sqlite3_db_status(
case SQLITE_DBSTATUS_CACHE_MISS:
case SQLITE_DBSTATUS_CACHE_WRITE:{
int i;
- int nRet = 0;
+ u64 nRet = 0;
assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 );
assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 );
@@ -23327,7 +24322,7 @@ SQLITE_API int sqlcipher_sqlite3_db_status(
*pHighwater = 0; /* IMP: R-42420-56072 */
/* IMP: R-54100-20147 */
/* IMP: R-29431-39229 */
- *pCurrent = nRet;
+ *pCurrent = (int)nRet & 0x7fffffff;
break;
}
@@ -23424,12 +24419,14 @@ struct DateTime {
int tz; /* Timezone offset in minutes */
double s; /* Seconds */
char validJD; /* True (1) if iJD is valid */
- char rawS; /* Raw numeric value stored in s */
char validYMD; /* True (1) if Y,M,D are valid */
char validHMS; /* True (1) if h,m,s are valid */
- char validTZ; /* True (1) if tz is valid */
- char tzSet; /* Timezone was set explicitly */
- char isError; /* An overflow has occurred */
+ char nFloor; /* Days to implement "floor" */
+ unsigned rawS : 1; /* Raw numeric value stored in s */
+ unsigned isError : 1; /* An overflow has occurred */
+ unsigned useSubsec : 1; /* Display subsecond precision */
+ unsigned isUtc : 1; /* Time is known to be UTC */
+ unsigned isLocal : 1; /* Time is known to be localtime */
};
@@ -23462,8 +24459,8 @@ struct DateTime {
*/
static int getDigits(const char *zDate, const char *zFormat, ...){
/* The aMx[] array translates the 3rd character of each format
- ** spec into a max size: a b c d e f */
- static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 };
+ ** spec into a max size: a b c d e f */
+ static const u16 aMx[] = { 12, 14, 24, 31, 59, 14712 };
va_list ap;
int cnt = 0;
char nextC;
@@ -23527,6 +24524,8 @@ static int parseTimezone(const char *zDate, DateTime *p){
sgn = +1;
}else if( c=='Z' || c=='z' ){
zDate++;
+ p->isLocal = 0;
+ p->isUtc = 1;
goto zulu_time;
}else{
return c!=0;
@@ -23539,7 +24538,6 @@ static int parseTimezone(const char *zDate, DateTime *p){
p->tz = sgn*(nMn + nHr*60);
zulu_time:
while( sqlcipher_sqlite3Isspace(*zDate) ){ zDate++; }
- p->tzSet = 1;
return *zDate!=0;
}
@@ -23583,7 +24581,6 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
p->m = m;
p->s = s + ms;
if( parseTimezone(zDate, p) ) return 1;
- p->validTZ = (p->tz!=0)?1:0;
return 0;
}
@@ -23629,17 +24626,42 @@ static void computeJD(DateTime *p){
p->iJD = (sqlcipher_sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
p->validJD = 1;
if( p->validHMS ){
- p->iJD += p->h*3600000 + p->m*60000 + (sqlcipher_sqlite3_int64)(p->s*1000);
- if( p->validTZ ){
+ p->iJD += p->h*3600000 + p->m*60000 + (sqlcipher_sqlite3_int64)(p->s*1000 + 0.5);
+ if( p->tz ){
p->iJD -= p->tz*60000;
p->validYMD = 0;
p->validHMS = 0;
- p->validTZ = 0;
+ p->tz = 0;
+ p->isUtc = 1;
+ p->isLocal = 0;
}
}
}
/*
+** Given the YYYY-MM-DD information current in p, determine if there
+** is day-of-month overflow and set nFloor to the number of days that
+** would need to be subtracted from the date in order to bring the
+** date back to the end of the month.
+*/
+static void computeFloor(DateTime *p){
+ assert( p->validYMD || p->isError );
+ assert( p->D>=0 && p->D<=31 );
+ assert( p->M>=0 && p->M<=12 );
+ if( p->D<=28 ){
+ p->nFloor = 0;
+ }else if( (1<<p->M) & 0x15aa ){
+ p->nFloor = 0;
+ }else if( p->M!=2 ){
+ p->nFloor = (p->D==31);
+ }else if( p->Y%4!=0 || (p->Y%100==0 && p->Y%400!=0) ){
+ p->nFloor = p->D - 28;
+ }else{
+ p->nFloor = p->D - 29;
+ }
+}
+
+/*
** Parse dates of the form
**
** YYYY-MM-DD HH:MM:SS.FFF
@@ -23677,12 +24699,16 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
p->Y = neg ? -Y : Y;
p->M = M;
p->D = D;
- if( p->validTZ ){
+ computeFloor(p);
+ if( p->tz ){
computeJD(p);
}
return 0;
}
+
+static void clearYMD_HMS_TZ(DateTime *p); /* Forward declaration */
+
/*
** Set the time to the current time reported by the VFS.
**
@@ -23692,6 +24718,9 @@ static int setDateTimeToCurrent(sqlcipher_sqlite3_context *context, DateTime *p)
p->iJD = sqlcipher_sqlite3StmtCurrentTime(context);
if( p->iJD>0 ){
p->validJD = 1;
+ p->isUtc = 1;
+ p->isLocal = 0;
+ clearYMD_HMS_TZ(p);
return 0;
}else{
return 1;
@@ -23744,6 +24773,11 @@ static int parseDateOrTime(
}else if( sqlcipher_sqlite3AtoF(zDate, &r, sqlcipher_sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){
setRawDateNumber(p, r);
return 0;
+ }else if( (sqlcipher_sqlite3StrICmp(zDate,"subsec")==0
+ || sqlcipher_sqlite3StrICmp(zDate,"subsecond")==0)
+ && sqlcipher_sqlite3NotPureFunc(context) ){
+ p->useSubsec = 1;
+ return setDateTimeToCurrent(context, p);
}
return 1;
}
@@ -23799,17 +24833,14 @@ static void computeYMD(DateTime *p){
** Compute the Hour, Minute, and Seconds from the julian day number.
*/
static void computeHMS(DateTime *p){
- int s;
+ int day_ms, day_min; /* milliseconds, minutes into the day */
if( p->validHMS ) return;
computeJD(p);
- s = (int)((p->iJD + 43200000) % 86400000);
- p->s = s/1000.0;
- s = (int)p->s;
- p->s -= s;
- p->h = s/3600;
- s -= p->h*3600;
- p->m = s/60;
- p->s += s - p->m*60;
+ day_ms = (int)((p->iJD + 43200000) % 86400000);
+ p->s = (day_ms % 60000)/1000.0;
+ day_min = day_ms/60000;
+ p->m = day_min % 60;
+ p->h = day_min / 60;
p->rawS = 0;
p->validHMS = 1;
}
@@ -23828,7 +24859,7 @@ static void computeYMD_HMS(DateTime *p){
static void clearYMD_HMS_TZ(DateTime *p){
p->validYMD = 0;
p->validHMS = 0;
- p->validTZ = 0;
+ p->tz = 0;
}
#ifndef SQLITE_OMIT_LOCALTIME
@@ -23960,7 +24991,7 @@ static int toLocaltime(
p->validHMS = 1;
p->validJD = 0;
p->rawS = 0;
- p->validTZ = 0;
+ p->tz = 0;
p->isError = 0;
return SQLITE_OK;
}
@@ -23980,15 +25011,34 @@ static const struct {
float rLimit; /* Maximum NNN value for this transform */
float rXform; /* Constant used for this transform */
} aXformType[] = {
- { 6, "second", 4.6427e+14, 1.0 },
- { 6, "minute", 7.7379e+12, 60.0 },
- { 4, "hour", 1.2897e+11, 3600.0 },
- { 3, "day", 5373485.0, 86400.0 },
- { 5, "month", 176546.0, 2592000.0 },
- { 4, "year", 14713.0, 31536000.0 },
+ /* 0 */ { 6, "second", 4.6427e+14, 1.0 },
+ /* 1 */ { 6, "minute", 7.7379e+12, 60.0 },
+ /* 2 */ { 4, "hour", 1.2897e+11, 3600.0 },
+ /* 3 */ { 3, "day", 5373485.0, 86400.0 },
+ /* 4 */ { 5, "month", 176546.0, 30.0*86400.0 },
+ /* 5 */ { 4, "year", 14713.0, 365.0*86400.0 },
};
/*
+** If the DateTime p is raw number, try to figure out if it is
+** a julian day number of a unix timestamp. Set the p value
+** appropriately.
+*/
+static void autoAdjustDate(DateTime *p){
+ if( !p->rawS || p->validJD ){
+ p->rawS = 0;
+ }else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */
+ && p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */
+ ){
+ double r = p->s*1000.0 + 210866760000000.0;
+ clearYMD_HMS_TZ(p);
+ p->iJD = (sqlcipher_sqlite3_int64)(r + 0.5);
+ p->validJD = 1;
+ p->rawS = 0;
+ }
+}
+
+/*
** Process a modifier to a date-time stamp. The modifiers are
** as follows:
**
@@ -23998,14 +25048,20 @@ static const struct {
** NNN.NNNN seconds
** NNN months
** NNN years
+** +/-YYYY-MM-DD HH:MM:SS.SSS
+** ceiling
+** floor
** start of month
** start of year
** start of week
** start of day
** weekday N
** unixepoch
+** auto
** localtime
** utc
+** subsec
+** subsecond
**
** Return 0 on success and 1 if there is any kind of error. If the error
** is in a system call (i.e. localtime()), then an error message is written
@@ -24031,19 +25087,39 @@ static int parseModifier(
*/
if( sqlcipher_sqlite3_stricmp(z, "auto")==0 ){
if( idx>1 ) return 1; /* IMP: R-33611-57934 */
- if( !p->rawS || p->validJD ){
- rc = 0;
- p->rawS = 0;
- }else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */
- && p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */
- ){
- r = p->s*1000.0 + 210866760000000.0;
- clearYMD_HMS_TZ(p);
- p->iJD = (sqlcipher_sqlite3_int64)(r + 0.5);
- p->validJD = 1;
- p->rawS = 0;
- rc = 0;
- }
+ autoAdjustDate(p);
+ rc = 0;
+ }
+ break;
+ }
+ case 'c': {
+ /*
+ ** ceiling
+ **
+ ** Resolve day-of-month overflow by rolling forward into the next
+ ** month. As this is the default action, this modifier is really
+ ** a no-op that is only included for symmetry. See "floor".
+ */
+ if( sqlcipher_sqlite3_stricmp(z, "ceiling")==0 ){
+ computeJD(p);
+ clearYMD_HMS_TZ(p);
+ rc = 0;
+ p->nFloor = 0;
+ }
+ break;
+ }
+ case 'f': {
+ /*
+ ** floor
+ **
+ ** Resolve day-of-month overflow by rolling back to the end of the
+ ** previous month.
+ */
+ if( sqlcipher_sqlite3_stricmp(z, "floor")==0 ){
+ computeJD(p);
+ p->iJD -= p->nFloor*86400000;
+ clearYMD_HMS_TZ(p);
+ rc = 0;
}
break;
}
@@ -24073,7 +25149,9 @@ static int parseModifier(
** show local time.
*/
if( sqlcipher_sqlite3_stricmp(z, "localtime")==0 && sqlcipher_sqlite3NotPureFunc(pCtx) ){
- rc = toLocaltime(p, pCtx);
+ rc = p->isLocal ? SQLITE_OK : toLocaltime(p, pCtx);
+ p->isUtc = 0;
+ p->isLocal = 1;
}
break;
}
@@ -24098,11 +25176,11 @@ static int parseModifier(
}
#ifndef SQLITE_OMIT_LOCALTIME
else if( sqlcipher_sqlite3_stricmp(z, "utc")==0 && sqlcipher_sqlite3NotPureFunc(pCtx) ){
- if( p->tzSet==0 ){
+ if( p->isUtc==0 ){
i64 iOrigJD; /* Original localtime */
i64 iGuess; /* Guess at the corresponding utc time */
int cnt = 0; /* Safety to prevent infinite loop */
- int iErr; /* Guess is off by this much */
+ i64 iErr; /* Guess is off by this much */
computeJD(p);
iGuess = iOrigJD = p->iJD;
@@ -24121,7 +25199,8 @@ static int parseModifier(
memset(p, 0, sizeof(*p));
p->iJD = iGuess;
p->validJD = 1;
- p->tzSet = 1;
+ p->isUtc = 1;
+ p->isLocal = 0;
}
rc = SQLITE_OK;
}
@@ -24138,10 +25217,10 @@ static int parseModifier(
*/
if( sqlcipher_sqlite3_strnicmp(z, "weekday ", 8)==0
&& sqlcipher_sqlite3AtoF(&z[8], &r, sqlcipher_sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0
- && (n=(int)r)==r && n>=0 && r<7 ){
+ && r>=0.0 && r<7.0 && (n=(int)r)==r ){
sqlcipher_sqlite3_int64 Z;
computeYMD_HMS(p);
- p->validTZ = 0;
+ p->tz = 0;
p->validJD = 0;
computeJD(p);
Z = ((p->iJD + 129600000)/86400000) % 7;
@@ -24158,8 +25237,22 @@ static int parseModifier(
**
** Move the date backwards to the beginning of the current day,
** or month or year.
+ **
+ ** subsecond
+ ** subsec
+ **
+ ** Show subsecond precision in the output of datetime() and
+ ** unixepoch() and strftime('%s').
*/
- if( sqlcipher_sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
+ if( sqlcipher_sqlite3_strnicmp(z, "start of ", 9)!=0 ){
+ if( sqlcipher_sqlite3_stricmp(z, "subsec")==0
+ || sqlcipher_sqlite3_stricmp(z, "subsecond")==0
+ ){
+ p->useSubsec = 1;
+ rc = 0;
+ }
+ break;
+ }
if( !p->validJD && !p->validYMD && !p->validHMS ) break;
z += 9;
computeYMD(p);
@@ -24167,7 +25260,7 @@ static int parseModifier(
p->h = p->m = 0;
p->s = 0.0;
p->rawS = 0;
- p->validTZ = 0;
+ p->tz = 0;
p->validJD = 0;
if( sqlcipher_sqlite3_stricmp(z,"month")==0 ){
p->D = 1;
@@ -24195,18 +25288,74 @@ static int parseModifier(
case '9': {
double rRounder;
int i;
- for(n=1; z[n] && z[n]!=':' && !sqlcipher_sqlite3Isspace(z[n]); n++){}
+ int Y,M,D,h,m,x;
+ const char *z2 = z;
+ char z0 = z[0];
+ for(n=1; z[n]; n++){
+ if( z[n]==':' ) break;
+ if( sqlcipher_sqlite3Isspace(z[n]) ) break;
+ if( z[n]=='-' ){
+ if( n==5 && getDigits(&z[1], "40f", &Y)==1 ) break;
+ if( n==6 && getDigits(&z[1], "50f", &Y)==1 ) break;
+ }
+ }
if( sqlcipher_sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){
- rc = 1;
+ assert( rc==1 );
break;
}
- if( z[n]==':' ){
+ if( z[n]=='-' ){
+ /* A modifier of the form (+|-)YYYY-MM-DD adds or subtracts the
+ ** specified number of years, months, and days. MM is limited to
+ ** the range 0-11 and DD is limited to 0-30.
+ */
+ if( z0!='+' && z0!='-' ) break; /* Must start with +/- */
+ if( n==5 ){
+ if( getDigits(&z[1], "40f-20a-20d", &Y, &M, &D)!=3 ) break;
+ }else{
+ assert( n==6 );
+ if( getDigits(&z[1], "50f-20a-20d", &Y, &M, &D)!=3 ) break;
+ z++;
+ }
+ if( M>=12 ) break; /* M range 0..11 */
+ if( D>=31 ) break; /* D range 0..30 */
+ computeYMD_HMS(p);
+ p->validJD = 0;
+ if( z0=='-' ){
+ p->Y -= Y;
+ p->M -= M;
+ D = -D;
+ }else{
+ p->Y += Y;
+ p->M += M;
+ }
+ x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
+ p->Y += x;
+ p->M -= x*12;
+ computeFloor(p);
+ computeJD(p);
+ p->validHMS = 0;
+ p->validYMD = 0;
+ p->iJD += (i64)D*86400000;
+ if( z[11]==0 ){
+ rc = 0;
+ break;
+ }
+ if( sqlcipher_sqlite3Isspace(z[11])
+ && getDigits(&z[12], "20c:20e", &h, &m)==2
+ ){
+ z2 = &z[12];
+ n = 2;
+ }else{
+ break;
+ }
+ }
+ if( z2[n]==':' ){
/* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
** specified number of hours, minutes, seconds, and fractional seconds
** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
** omitted.
*/
- const char *z2 = z;
+
DateTime tx;
sqlcipher_sqlite3_int64 day;
if( !sqlcipher_sqlite3Isdigit(*z2) ) z2++;
@@ -24216,7 +25365,7 @@ static int parseModifier(
tx.iJD -= 43200000;
day = tx.iJD/86400000;
tx.iJD -= day*86400000;
- if( z[0]=='-' ) tx.iJD = -tx.iJD;
+ if( z0=='-' ) tx.iJD = -tx.iJD;
computeJD(p);
clearYMD_HMS_TZ(p);
p->iJD += tx.iJD;
@@ -24229,11 +25378,12 @@ static int parseModifier(
z += n;
while( sqlcipher_sqlite3Isspace(*z) ) z++;
n = sqlcipher_sqlite3Strlen30(z);
- if( n>10 || n<3 ) break;
+ if( n<3 || n>10 ) break;
if( sqlcipher_sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
computeJD(p);
- rc = 1;
+ assert( rc==1 );
rRounder = r<0 ? -0.5 : +0.5;
+ p->nFloor = 0;
for(i=0; i<ArraySize(aXformType); i++){
if( aXformType[i].nName==n
&& sqlcipher_sqlite3_strnicmp(aXformType[i].zName, z, n)==0
@@ -24241,22 +25391,24 @@ static int parseModifier(
){
switch( i ){
case 4: { /* Special processing to add months */
- int x;
- assert( strcmp(aXformType[i].zName,"month")==0 );
+ assert( strcmp(aXformType[4].zName,"month")==0 );
computeYMD_HMS(p);
p->M += (int)r;
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
p->Y += x;
p->M -= x*12;
+ computeFloor(p);
p->validJD = 0;
r -= (int)r;
break;
}
case 5: { /* Special processing to add years */
int y = (int)r;
- assert( strcmp(aXformType[i].zName,"year")==0 );
+ assert( strcmp(aXformType[5].zName,"year")==0 );
computeYMD_HMS(p);
+ assert( p->M>=0 && p->M<=12 );
p->Y += y;
+ computeFloor(p);
p->validJD = 0;
r -= (int)r;
break;
@@ -24317,6 +25469,12 @@ static int isDate(
}
computeJD(p);
if( p->isError || !validJulianDay(p->iJD) ) return 1;
+ if( argc==1 && p->validYMD && p->D>28 ){
+ /* Make sure a YYYY-MM-DD is normalized.
+ ** Example: 2023-02-31 -> 2023-03-03 */
+ assert( p->validJD );
+ p->validYMD = 0;
+ }
return 0;
}
@@ -24357,7 +25515,11 @@ static void unixepochFunc(
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
computeJD(&x);
- sqlcipher_sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
+ if( x.useSubsec ){
+ sqlcipher_sqlite3_result_double(context, (x.iJD - 21086676*(i64)10000000)/1000.0);
+ }else{
+ sqlcipher_sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
+ }
}
}
@@ -24373,8 +25535,8 @@ static void datetimeFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
- int Y, s;
- char zBuf[24];
+ int Y, s, n;
+ char zBuf[32];
computeYMD_HMS(&x);
Y = x.Y;
if( Y<0 ) Y = -Y;
@@ -24395,15 +25557,28 @@ static void datetimeFunc(
zBuf[15] = '0' + (x.m/10)%10;
zBuf[16] = '0' + (x.m)%10;
zBuf[17] = ':';
- s = (int)x.s;
- zBuf[18] = '0' + (s/10)%10;
- zBuf[19] = '0' + (s)%10;
- zBuf[20] = 0;
+ if( x.useSubsec ){
+ s = (int)(1000.0*x.s + 0.5);
+ zBuf[18] = '0' + (s/10000)%10;
+ zBuf[19] = '0' + (s/1000)%10;
+ zBuf[20] = '.';
+ zBuf[21] = '0' + (s/100)%10;
+ zBuf[22] = '0' + (s/10)%10;
+ zBuf[23] = '0' + (s)%10;
+ zBuf[24] = 0;
+ n = 24;
+ }else{
+ s = (int)x.s;
+ zBuf[18] = '0' + (s/10)%10;
+ zBuf[19] = '0' + (s)%10;
+ zBuf[20] = 0;
+ n = 20;
+ }
if( x.Y<0 ){
zBuf[0] = '-';
- sqlcipher_sqlite3_result_text(context, zBuf, 20, SQLITE_TRANSIENT);
+ sqlcipher_sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
}else{
- sqlcipher_sqlite3_result_text(context, &zBuf[1], 19, SQLITE_TRANSIENT);
+ sqlcipher_sqlite3_result_text(context, &zBuf[1], n-1, SQLITE_TRANSIENT);
}
}
}
@@ -24420,7 +25595,7 @@ static void timeFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
- int s;
+ int s, n;
char zBuf[16];
computeHMS(&x);
zBuf[0] = '0' + (x.h/10)%10;
@@ -24429,11 +25604,24 @@ static void timeFunc(
zBuf[3] = '0' + (x.m/10)%10;
zBuf[4] = '0' + (x.m)%10;
zBuf[5] = ':';
- s = (int)x.s;
- zBuf[6] = '0' + (s/10)%10;
- zBuf[7] = '0' + (s)%10;
- zBuf[8] = 0;
- sqlcipher_sqlite3_result_text(context, zBuf, 8, SQLITE_TRANSIENT);
+ if( x.useSubsec ){
+ s = (int)(1000.0*x.s + 0.5);
+ zBuf[6] = '0' + (s/10000)%10;
+ zBuf[7] = '0' + (s/1000)%10;
+ zBuf[8] = '.';
+ zBuf[9] = '0' + (s/100)%10;
+ zBuf[10] = '0' + (s/10)%10;
+ zBuf[11] = '0' + (s)%10;
+ zBuf[12] = 0;
+ n = 12;
+ }else{
+ s = (int)x.s;
+ zBuf[6] = '0' + (s/10)%10;
+ zBuf[7] = '0' + (s)%10;
+ zBuf[8] = 0;
+ n = 8;
+ }
+ sqlcipher_sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
}
}
@@ -24475,21 +25663,82 @@ static void dateFunc(
}
/*
+** Compute the number of days after the most recent January 1.
+**
+** In other words, compute the zero-based day number for the
+** current year:
+**
+** Jan01 = 0, Jan02 = 1, ..., Jan31 = 30, Feb01 = 31, ...
+** Dec31 = 364 or 365.
+*/
+static int daysAfterJan01(DateTime *pDate){
+ DateTime jan01 = *pDate;
+ assert( jan01.validYMD );
+ assert( jan01.validHMS );
+ assert( pDate->validJD );
+ jan01.validJD = 0;
+ jan01.M = 1;
+ jan01.D = 1;
+ computeJD(&jan01);
+ return (int)((pDate->iJD-jan01.iJD+43200000)/86400000);
+}
+
+/*
+** Return the number of days after the most recent Monday.
+**
+** In other words, return the day of the week according
+** to this code:
+**
+** 0=Monday, 1=Tuesday, 2=Wednesday, ..., 6=Sunday.
+*/
+static int daysAfterMonday(DateTime *pDate){
+ assert( pDate->validJD );
+ return (int)((pDate->iJD+43200000)/86400000) % 7;
+}
+
+/*
+** Return the number of days after the most recent Sunday.
+**
+** In other words, return the day of the week according
+** to this code:
+**
+** 0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday
+*/
+static int daysAfterSunday(DateTime *pDate){
+ assert( pDate->validJD );
+ return (int)((pDate->iJD+129600000)/86400000) % 7;
+}
+
+/*
** strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
**
** Return a string described by FORMAT. Conversions as follows:
**
-** %d day of month
+** %d day of month 01-31
+** %e day of month 1-31
** %f ** fractional seconds SS.SSS
+** %F ISO date. YYYY-MM-DD
+** %G ISO year corresponding to %V 0000-9999.
+** %g 2-digit ISO year corresponding to %V 00-99
** %H hour 00-24
-** %j day of year 000-366
+** %k hour 0-24 (leading zero converted to space)
+** %I hour 01-12
+** %j day of year 001-366
** %J ** julian day number
+** %l hour 1-12 (leading zero converted to space)
** %m month 01-12
** %M minute 00-59
+** %p "am" or "pm"
+** %P "AM" or "PM"
+** %R time as HH:MM
** %s seconds since 1970-01-01
** %S seconds 00-59
-** %w day of week 0-6 sunday==0
-** %W week of year 00-53
+** %T time as HH:MM:SS
+** %u day of week 1-7 Monday==1, Sunday==7
+** %w day of week 0-6 Sunday==0, Monday==1
+** %U week of year 00-53 (First Sunday is start of week 01)
+** %V week of year 01-53 (First week containing Thursday is week 01)
+** %W week of year 00-53 (First Monday is start of week 01)
** %Y year 0000-9999
** %% %
*/
@@ -24514,44 +25763,61 @@ static void strftimeFunc(
computeJD(&x);
computeYMD_HMS(&x);
for(i=j=0; zFmt[i]; i++){
+ char cf;
if( zFmt[i]!='%' ) continue;
if( j<i ) sqlcipher_sqlite3_str_append(&sRes, zFmt+j, (int)(i-j));
i++;
j = i + 1;
- switch( zFmt[i] ){
- case 'd': {
- sqlcipher_sqlite3_str_appendf(&sRes, "%02d", x.D);
+ cf = zFmt[i];
+ switch( cf ){
+ case 'd': /* Fall thru */
+ case 'e': {
+ sqlcipher_sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D);
break;
}
- case 'f': {
+ case 'f': { /* Fractional seconds. (Non-standard) */
double s = x.s;
if( s>59.999 ) s = 59.999;
sqlcipher_sqlite3_str_appendf(&sRes, "%06.3f", s);
break;
}
- case 'H': {
- sqlcipher_sqlite3_str_appendf(&sRes, "%02d", x.h);
+ case 'F': {
+ sqlcipher_sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D);
break;
}
- case 'W': /* Fall thru */
- case 'j': {
- int nDay; /* Number of days since 1st day of year */
+ case 'G': /* Fall thru */
+ case 'g': {
DateTime y = x;
- y.validJD = 0;
- y.M = 1;
- y.D = 1;
- computeJD(&y);
- nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
- if( zFmt[i]=='W' ){
- int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
- wd = (int)(((x.iJD+43200000)/86400000)%7);
- sqlcipher_sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7);
+ assert( y.validJD );
+ /* Move y so that it is the Thursday in the same week as x */
+ y.iJD += (3 - daysAfterMonday(&x))*86400000;
+ y.validYMD = 0;
+ computeYMD(&y);
+ if( cf=='g' ){
+ sqlcipher_sqlite3_str_appendf(&sRes, "%02d", y.Y%100);
}else{
- sqlcipher_sqlite3_str_appendf(&sRes,"%03d",nDay+1);
+ sqlcipher_sqlite3_str_appendf(&sRes, "%04d", y.Y);
}
break;
}
- case 'J': {
+ case 'H':
+ case 'k': {
+ sqlcipher_sqlite3_str_appendf(&sRes, cf=='H' ? "%02d" : "%2d", x.h);
+ break;
+ }
+ case 'I': /* Fall thru */
+ case 'l': {
+ int h = x.h;
+ if( h>12 ) h -= 12;
+ if( h==0 ) h = 12;
+ sqlcipher_sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h);
+ break;
+ }
+ case 'j': { /* Day of year. Jan01==1, Jan02==2, and so forth */
+ sqlcipher_sqlite3_str_appendf(&sRes,"%03d",daysAfterJan01(&x)+1);
+ break;
+ }
+ case 'J': { /* Julian day number. (Non-standard) */
sqlcipher_sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0);
break;
}
@@ -24563,18 +25829,62 @@ static void strftimeFunc(
sqlcipher_sqlite3_str_appendf(&sRes,"%02d",x.m);
break;
}
+ case 'p': /* Fall thru */
+ case 'P': {
+ if( x.h>=12 ){
+ sqlcipher_sqlite3_str_append(&sRes, cf=='p' ? "PM" : "pm", 2);
+ }else{
+ sqlcipher_sqlite3_str_append(&sRes, cf=='p' ? "AM" : "am", 2);
+ }
+ break;
+ }
+ case 'R': {
+ sqlcipher_sqlite3_str_appendf(&sRes, "%02d:%02d", x.h, x.m);
+ break;
+ }
case 's': {
- i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
- sqlcipher_sqlite3_str_appendf(&sRes,"%lld",iS);
+ if( x.useSubsec ){
+ sqlcipher_sqlite3_str_appendf(&sRes,"%.3f",
+ (x.iJD - 21086676*(i64)10000000)/1000.0);
+ }else{
+ i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
+ sqlcipher_sqlite3_str_appendf(&sRes,"%lld",iS);
+ }
break;
}
case 'S': {
sqlcipher_sqlite3_str_appendf(&sRes,"%02d",(int)x.s);
break;
}
- case 'w': {
- sqlcipher_sqlite3_str_appendchar(&sRes, 1,
- (char)(((x.iJD+129600000)/86400000) % 7) + '0');
+ case 'T': {
+ sqlcipher_sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s);
+ break;
+ }
+ case 'u': /* Day of week. 1 to 7. Monday==1, Sunday==7 */
+ case 'w': { /* Day of week. 0 to 6. Sunday==0, Monday==1 */
+ char c = (char)daysAfterSunday(&x) + '0';
+ if( c=='0' && cf=='u' ) c = '7';
+ sqlcipher_sqlite3_str_appendchar(&sRes, 1, c);
+ break;
+ }
+ case 'U': { /* Week num. 00-53. First Sun of the year is week 01 */
+ sqlcipher_sqlite3_str_appendf(&sRes,"%02d",
+ (daysAfterJan01(&x)-daysAfterSunday(&x)+7)/7);
+ break;
+ }
+ case 'V': { /* Week num. 01-53. First week with a Thur is week 01 */
+ DateTime y = x;
+ /* Adjust y so that is the Thursday in the same week as x */
+ assert( y.validJD );
+ y.iJD += (3 - daysAfterMonday(&x))*86400000;
+ y.validYMD = 0;
+ computeYMD(&y);
+ sqlcipher_sqlite3_str_appendf(&sRes,"%02d", daysAfterJan01(&y)/7+1);
+ break;
+ }
+ case 'W': { /* Week num. 00-53. First Mon of the year is week 01 */
+ sqlcipher_sqlite3_str_appendf(&sRes,"%02d",
+ (daysAfterJan01(&x)-daysAfterMonday(&x)+7)/7);
break;
}
case 'Y': {
@@ -24624,6 +25934,115 @@ static void cdateFunc(
}
/*
+** timediff(DATE1, DATE2)
+**
+** Return the amount of time that must be added to DATE2 in order to
+** convert it into DATE2. The time difference format is:
+**
+** +YYYY-MM-DD HH:MM:SS.SSS
+**
+** The initial "+" becomes "-" if DATE1 occurs before DATE2. For
+** date/time values A and B, the following invariant should hold:
+**
+** datetime(A) == (datetime(B, timediff(A,B))
+**
+** Both DATE arguments must be either a julian day number, or an
+** ISO-8601 string. The unix timestamps are not supported by this
+** routine.
+*/
+static void timediffFunc(
+ sqlcipher_sqlite3_context *context,
+ int NotUsed1,
+ sqlcipher_sqlite3_value **argv
+){
+ char sign;
+ int Y, M;
+ DateTime d1, d2;
+ sqlcipher_sqlite3_str sRes;
+ UNUSED_PARAMETER(NotUsed1);
+ if( isDate(context, 1, &argv[0], &d1) ) return;
+ if( isDate(context, 1, &argv[1], &d2) ) return;
+ computeYMD_HMS(&d1);
+ computeYMD_HMS(&d2);
+ if( d1.iJD>=d2.iJD ){
+ sign = '+';
+ Y = d1.Y - d2.Y;
+ if( Y ){
+ d2.Y = d1.Y;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ M = d1.M - d2.M;
+ if( M<0 ){
+ Y--;
+ M += 12;
+ }
+ if( M!=0 ){
+ d2.M = d1.M;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ while( d1.iJD<d2.iJD ){
+ M--;
+ if( M<0 ){
+ M = 11;
+ Y--;
+ }
+ d2.M--;
+ if( d2.M<1 ){
+ d2.M = 12;
+ d2.Y--;
+ }
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ d1.iJD -= d2.iJD;
+ d1.iJD += (u64)1486995408 * (u64)100000;
+ }else /* d1<d2 */{
+ sign = '-';
+ Y = d2.Y - d1.Y;
+ if( Y ){
+ d2.Y = d1.Y;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ M = d2.M - d1.M;
+ if( M<0 ){
+ Y--;
+ M += 12;
+ }
+ if( M!=0 ){
+ d2.M = d1.M;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ while( d1.iJD>d2.iJD ){
+ M--;
+ if( M<0 ){
+ M = 11;
+ Y--;
+ }
+ d2.M++;
+ if( d2.M>12 ){
+ d2.M = 1;
+ d2.Y++;
+ }
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ d1.iJD = d2.iJD - d1.iJD;
+ d1.iJD += (u64)1486995408 * (u64)100000;
+ }
+ clearYMD_HMS_TZ(&d1);
+ computeYMD_HMS(&d1);
+ sqlcipher_sqlite3StrAccumInit(&sRes, 0, 0, 0, 100);
+ sqlcipher_sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f",
+ sign, Y, M, d1.D-1, d1.h, d1.m, d1.s);
+ sqlcipher_sqlite3ResultStrAccum(context, &sRes);
+}
+
+
+/*
** current_timestamp()
**
** This function returns the same value as datetime('now').
@@ -24683,6 +26102,36 @@ static void currentTimeFunc(
}
#endif
+#if !defined(SQLITE_OMIT_DATETIME_FUNCS) && defined(SQLITE_DEBUG)
+/*
+** datedebug(...)
+**
+** This routine returns JSON that describes the internal DateTime object.
+** Used for debugging and testing only. Subject to change.
+*/
+static void datedebugFunc(
+ sqlcipher_sqlite3_context *context,
+ int argc,
+ sqlcipher_sqlite3_value **argv
+){
+ DateTime x;
+ if( isDate(context, argc, argv, &x)==0 ){
+ char *zJson;
+ zJson = sqlcipher_sqlite3_mprintf(
+ "{iJD:%lld,Y:%d,M:%d,D:%d,h:%d,m:%d,tz:%d,"
+ "s:%.3f,validJD:%d,validYMS:%d,validHMS:%d,"
+ "nFloor:%d,rawS:%d,isError:%d,useSubsec:%d,"
+ "isUtc:%d,isLocal:%d}",
+ x.iJD, x.Y, x.M, x.D, x.h, x.m, x.tz,
+ x.s, x.validJD, x.validYMD, x.validHMS,
+ x.nFloor, x.rawS, x.isError, x.useSubsec,
+ x.isUtc, x.isLocal);
+ sqlcipher_sqlite3_result_text(context, zJson, -1, sqlcipher_sqlite3_free);
+ }
+}
+#endif /* !SQLITE_OMIT_DATETIME_FUNCS && SQLITE_DEBUG */
+
+
/*
** This function registered all of the above C functions as SQL
** functions. This should be the only routine in this file with
@@ -24697,6 +26146,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3RegisterDateTimeFunctions(void){
PURE_DATE(time, -1, 0, 0, timeFunc ),
PURE_DATE(datetime, -1, 0, 0, datetimeFunc ),
PURE_DATE(strftime, -1, 0, 0, strftimeFunc ),
+ PURE_DATE(timediff, 2, 0, 0, timediffFunc ),
+#ifdef SQLITE_DEBUG
+ PURE_DATE(datedebug, -1, 0, 0, datedebugFunc ),
+#endif
DFUNCTION(current_time, 0, 0, 0, ctimeFunc ),
DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
DFUNCTION(current_date, 0, 0, 0, cdateFunc ),
@@ -24819,9 +26272,11 @@ SQLITE_PRIVATE int sqlcipher_sqlite3OsFileSize(sqlcipher_sqlite3_file *id, i64 *
}
SQLITE_PRIVATE int sqlcipher_sqlite3OsLock(sqlcipher_sqlite3_file *id, int lockType){
DO_OS_MALLOC_TEST(id);
+ assert( lockType>=SQLITE_LOCK_SHARED && lockType<=SQLITE_LOCK_EXCLUSIVE );
return id->pMethods->xLock(id, lockType);
}
SQLITE_PRIVATE int sqlcipher_sqlite3OsUnlock(sqlcipher_sqlite3_file *id, int lockType){
+ assert( lockType==SQLITE_LOCK_NONE || lockType==SQLITE_LOCK_SHARED );
return id->pMethods->xUnlock(id, lockType);
}
SQLITE_PRIVATE int sqlcipher_sqlite3OsCheckReservedLock(sqlcipher_sqlite3_file *id, int *pResOut){
@@ -24848,7 +26303,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3OsFileControl(sqlcipher_sqlite3_file *id, in
/* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
** is using a regular VFS, it is called after the corresponding
** transaction has been committed. Injecting a fault at this point
- ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
+ ** confuses the test scripts - the COMMIT command returns SQLITE_NOMEM
** but the transaction is committed anyway.
**
** The core must call OsFileControl() though, not OsFileControlHint(),
@@ -24936,6 +26391,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3OsOpen(
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */
+ assert( zPath || (flags & SQLITE_OPEN_EXCLUSIVE) );
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
@@ -25468,7 +26924,7 @@ static void *sqlcipher_sqlite3MemMalloc(int nByte){
** or sqlcipher_sqlite3MemRealloc().
**
** For this low-level routine, we already know that pPrior!=0 since
-** cases where pPrior==0 will have been intecepted and dealt with
+** cases where pPrior==0 will have been intercepted and dealt with
** by higher-level routines.
*/
static void sqlcipher_sqlite3MemFree(void *pPrior){
@@ -25556,7 +27012,7 @@ static int sqlcipher_sqlite3MemInit(void *NotUsed){
return SQLITE_OK;
}
len = sizeof(cpuCount);
- /* One usually wants to use hw.acctivecpu for MT decisions, but not here */
+ /* One usually wants to use hw.activecpu for MT decisions, but not here */
sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0);
if( cpuCount>1 ){
/* defer MT decisions to system malloc */
@@ -27251,9 +28707,13 @@ static int memsys5Roundup(int n){
if( n<=mem5.szAtom ) return mem5.szAtom;
return mem5.szAtom*2;
}
- if( n>0x40000000 ) return 0;
+ if( n>0x10000000 ){
+ if( n>0x40000000 ) return 0;
+ if( n>0x20000000 ) return 0x40000000;
+ return 0x20000000;
+ }
for(iFullSz=mem5.szAtom*8; iFullSz<n; iFullSz *= 4);
- if( (iFullSz/2)>=n ) return iFullSz/2;
+ if( (iFullSz/2)>=(i64)n ) return iFullSz/2;
return iFullSz;
}
@@ -27544,7 +29004,7 @@ static void checkMutexFree(sqlcipher_sqlite3_mutex *p){
assert( SQLITE_MUTEX_FAST<2 );
assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( ((CheckMutex*)p)->iType<2 )
#endif
{
@@ -28019,7 +29479,7 @@ SQLITE_PRIVATE sqlcipher_sqlite3_mutex_methods const *sqlcipher_sqlite3DefaultMu
/*
** The sqlcipher_sqlite3_mutex.id, sqlcipher_sqlite3_mutex.nRef, and sqlcipher_sqlite3_mutex.owner fields
-** are necessary under two condidtions: (1) Debug builds and (2) using
+** are necessary under two conditions: (1) Debug builds and (2) using
** home-grown mutexes. Encapsulate these conditions into a single #define.
*/
#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX)
@@ -28216,7 +29676,7 @@ static sqlcipher_sqlite3_mutex *pthreadMutexAlloc(int iType){
*/
static void pthreadMutexFree(sqlcipher_sqlite3_mutex *p){
assert( p->nRef==0 );
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE )
#endif
{
@@ -28520,7 +29980,7 @@ struct sqlcipher_sqlite3_mutex {
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
#ifdef SQLITE_DEBUG
- volatile int nRef; /* Number of enterances */
+ volatile int nRef; /* Number of entrances */
volatile DWORD owner; /* Thread holding this mutex */
volatile LONG trace; /* True to trace changes */
#endif
@@ -28569,7 +30029,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3MemoryBarrier(void){
SQLITE_MEMORY_BARRIER;
#elif defined(__GNUC__)
__sync_synchronize();
-#elif MSVC_VERSION>=1300
+#elif MSVC_VERSION>=1400
_ReadWriteBarrier();
#elif defined(MemoryBarrier)
MemoryBarrier();
@@ -29116,6 +30576,24 @@ static void sqlcipher_sqlite3MallocAlarm(int nByte){
sqlcipher_sqlite3_mutex_enter(mem0.mutex);
}
+#ifdef SQLITE_DEBUG
+/*
+** This routine is called whenever an out-of-memory condition is seen,
+** It's only purpose to to serve as a breakpoint for gdb or similar
+** code debuggers when working on out-of-memory conditions, for example
+** caused by PRAGMA hard_heap_limit=N.
+*/
+static SQLITE_NOINLINE void test_oom_breakpoint(u64 n){
+ static u64 nOomFault = 0;
+ nOomFault += n;
+ /* The assert() is never reached in a human lifetime. It is here mostly
+ ** to prevent code optimizers from optimizing out this function. */
+ assert( (nOomFault>>32) < 0xffffffff );
+}
+#else
+# define test_oom_breakpoint(X) /* No-op for production builds */
+#endif
+
/*
** Do a memory allocation with statistics and alarms. Assume the
** lock is already held.
@@ -29142,6 +30620,7 @@ static void mallocWithAlarm(int n, void **pp){
if( mem0.hardLimit ){
nUsed = sqlcipher_sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.hardLimit - nFull ){
+ test_oom_breakpoint(1);
*pp = 0;
return;
}
@@ -29166,17 +30645,33 @@ static void mallocWithAlarm(int n, void **pp){
}
/*
+** Maximum size of any single memory allocation.
+**
+** This is not a limit on the total amount of memory used. This is
+** a limit on the size parameter to sqlcipher_sqlite3_malloc() and sqlcipher_sqlite3_realloc().
+**
+** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391
+** This provides a 256-byte safety margin for defense against 32-bit
+** signed integer overflow bugs when computing memory allocation sizes.
+** Paranoid applications might want to reduce the maximum allocation size
+** further for an even larger safety margin. 0x3fffffff or 0x0fffffff
+** or even smaller would be reasonable upper bounds on the size of a memory
+** allocations for most applications.
+*/
+#ifndef SQLITE_MAX_ALLOCATION_SIZE
+# define SQLITE_MAX_ALLOCATION_SIZE 2147483391
+#endif
+#if SQLITE_MAX_ALLOCATION_SIZE>2147483391
+# error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391
+#endif
+
+/*
** Allocate memory. This routine is like sqlcipher_sqlite3_malloc() except that it
** assumes the memory subsystem has already been initialized.
*/
SQLITE_PRIVATE void *sqlcipher_sqlite3Malloc(u64 n){
void *p;
- if( n==0 || n>=0x7fffff00 ){
- /* A memory allocation of a number of bytes which is near the maximum
- ** signed integer value might cause an integer overflow inside of the
- ** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving
- ** 255 bytes of overhead. SQLite itself will never use anything near
- ** this amount. The only way to reach the limit is with sqlcipher_sqlite3_malloc() */
+ if( n==0 || n>SQLITE_MAX_ALLOCATION_SIZE ){
p = 0;
}else if( sqlcipher_sqlite3GlobalConfig.bMemstat ){
sqlcipher_sqlite3_mutex_enter(mem0.mutex);
@@ -29212,7 +30707,7 @@ SQLITE_API void *sqlcipher_sqlite3_malloc64(sqlcipher_sqlite3_uint64 n){
*/
#ifndef SQLITE_OMIT_LOOKASIDE
static int isLookaside(sqlcipher_sqlite3 *db, const void *p){
- return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd);
+ return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pTrueEnd);
}
#else
#define isLookaside(A,B) 0
@@ -29236,18 +30731,16 @@ static int lookasideMallocSize(sqlcipher_sqlite3 *db, const void *p){
SQLITE_PRIVATE int sqlcipher_sqlite3DbMallocSize(sqlcipher_sqlite3 *db, const void *p){
assert( p!=0 );
#ifdef SQLITE_DEBUG
- if( db==0 || !isLookaside(db,p) ){
- if( db==0 ){
- assert( sqlcipher_sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
- assert( sqlcipher_sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
- }else{
- assert( sqlcipher_sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- assert( sqlcipher_sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- }
+ if( db==0 ){
+ assert( sqlcipher_sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
+ assert( sqlcipher_sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
+ }else if( !isLookaside(db,p) ){
+ assert( sqlcipher_sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlcipher_sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
}
#endif
if( db ){
- if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
+ if( ((uptr)p)<(uptr)(db->lookaside.pTrueEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
assert( sqlcipher_sqlite3_mutex_held(db->mutex) );
@@ -29303,14 +30796,11 @@ SQLITE_PRIVATE void sqlcipher_sqlite3DbFreeNN(sqlcipher_sqlite3 *db, void *p){
assert( db==0 || sqlcipher_sqlite3_mutex_held(db->mutex) );
assert( p!=0 );
if( db ){
- if( db->pnBytesFreed ){
- measureAllocationSize(db, p);
- return;
- }
if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
#endif
@@ -29321,6 +30811,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3DbFreeNN(sqlcipher_sqlite3 *db, void *p){
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
#endif
@@ -29329,6 +30820,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3DbFreeNN(sqlcipher_sqlite3 *db, void *p){
return;
}
}
+ if( db->pnBytesFreed ){
+ measureAllocationSize(db, p);
+ return;
+ }
}
assert( sqlcipher_sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlcipher_sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
@@ -29336,6 +30831,43 @@ SQLITE_PRIVATE void sqlcipher_sqlite3DbFreeNN(sqlcipher_sqlite3 *db, void *p){
sqlcipher_sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlcipher_sqlite3_free(p);
}
+SQLITE_PRIVATE void sqlcipher_sqlite3DbNNFreeNN(sqlcipher_sqlite3 *db, void *p){
+ assert( db!=0 );
+ assert( sqlcipher_sqlite3_mutex_held(db->mutex) );
+ assert( p!=0 );
+ if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
+ LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
+#ifdef SQLITE_DEBUG
+ memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
+#endif
+ pBuf->pNext = db->lookaside.pSmallFree;
+ db->lookaside.pSmallFree = pBuf;
+ return;
+ }
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
+ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
+ LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
+#ifdef SQLITE_DEBUG
+ memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
+#endif
+ pBuf->pNext = db->lookaside.pFree;
+ db->lookaside.pFree = pBuf;
+ return;
+ }
+ }
+ if( db->pnBytesFreed ){
+ measureAllocationSize(db, p);
+ return;
+ }
+ assert( sqlcipher_sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlcipher_sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ sqlcipher_sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
+ sqlcipher_sqlite3_free(p);
+}
SQLITE_PRIVATE void sqlcipher_sqlite3DbFree(sqlcipher_sqlite3 *db, void *p){
assert( db==0 || sqlcipher_sqlite3_mutex_held(db->mutex) );
if( p ) sqlcipher_sqlite3DbFreeNN(db, p);
@@ -29377,6 +30909,7 @@ SQLITE_PRIVATE void *sqlcipher_sqlite3Realloc(void *pOld, u64 nBytes){
sqlcipher_sqlite3MallocAlarm(nDiff);
if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){
sqlcipher_sqlite3_mutex_leave(mem0.mutex);
+ test_oom_breakpoint(1);
return 0;
}
}
@@ -29635,9 +31168,14 @@ SQLITE_PRIVATE char *sqlcipher_sqlite3DbStrNDup(sqlcipher_sqlite3 *db, const cha
*/
SQLITE_PRIVATE char *sqlcipher_sqlite3DbSpanDup(sqlcipher_sqlite3 *db, const char *zStart, const char *zEnd){
int n;
+#ifdef SQLITE_DEBUG
+ /* Because of the way the parser works, the span is guaranteed to contain
+ ** at least one non-space character */
+ for(n=0; sqlcipher_sqlite3Isspace(zStart[n]); n++){ assert( &zStart[n]<zEnd ); }
+#endif
while( sqlcipher_sqlite3Isspace(zStart[0]) ) zStart++;
n = (int)(zEnd - zStart);
- while( ALWAYS(n>0) && sqlcipher_sqlite3Isspace(zStart[n-1]) ) n--;
+ while( sqlcipher_sqlite3Isspace(zStart[n-1]) ) n--;
return sqlcipher_sqlite3DbStrNDup(db, zStart, n);
}
@@ -29733,7 +31271,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ApiExit(sqlcipher_sqlite3* db, int rc){
if( db->mallocFailed || rc ){
return apiHandleError(db, rc);
}
- return rc & db->errMask;
+ return 0;
}
/************** End of malloc.c **********************************************/
@@ -29845,43 +31383,6 @@ static const et_info fmtinfo[] = {
** %!S Like %S but prefer the zName over the zAlias
*/
-/* Floating point constants used for rounding */
-static const double arRound[] = {
- 5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05,
- 5.0e-06, 5.0e-07, 5.0e-08, 5.0e-09, 5.0e-10,
-};
-
-/*
-** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
-** conversions will work.
-*/
-#ifndef SQLITE_OMIT_FLOATING_POINT
-/*
-** "*val" is a double such that 0.1 <= *val < 10.0
-** Return the ascii code for the leading digit of *val, then
-** multiply "*val" by 10.0 to renormalize.
-**
-** Example:
-** input: *val = 3.14159
-** output: *val = 1.4159 function return = '3'
-**
-** The counter *cnt is incremented each time. After counter exceeds
-** 16 (the number of significant digits in a 64-bit float) '0' is
-** always returned.
-*/
-static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
- int digit;
- LONGDOUBLE_TYPE d;
- if( (*cnt)<=0 ) return '0';
- (*cnt)--;
- digit = (int)*val;
- d = digit;
- digit += '0';
- *val = (*val - d)*10.0;
- return (char)digit;
-}
-#endif /* SQLITE_OMIT_FLOATING_POINT */
-
/*
** Set the StrAccum object to an error mode.
*/
@@ -29973,18 +31474,15 @@ SQLITE_API void sqlcipher_sqlite3_str_vappendf(
u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
sqlite_uint64 longvalue; /* Value for integer types */
- LONGDOUBLE_TYPE realvalue; /* Value for real types */
+ double realvalue; /* Value for real types */
const et_info *infop; /* Pointer to the appropriate info structure */
char *zOut; /* Rendering buffer */
int nOut; /* Size of the rendering buffer */
char *zExtra = 0; /* Malloced memory used by some conversion */
-#ifndef SQLITE_OMIT_FLOATING_POINT
- int exp, e2; /* exponent of real numbers */
- int nsd; /* Number of significant digits returned */
- double rounder; /* Used for rounding floating point values */
+ int exp, e2; /* exponent of real numbers */
etByte flag_dp; /* True if decimal point should be shown */
etByte flag_rtz; /* True if trailing zeros should be removed */
-#endif
+
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
char buf[etBUFSIZE]; /* Conversion buffer */
@@ -30259,74 +31757,69 @@ SQLITE_API void sqlcipher_sqlite3_str_vappendf(
break;
case etFLOAT:
case etEXP:
- case etGENERIC:
+ case etGENERIC: {
+ FpDecode s;
+ int iRound;
+ int j;
+
if( bArgList ){
realvalue = getDoubleArg(pArgList);
}else{
realvalue = va_arg(ap,double);
}
-#ifdef SQLITE_OMIT_FLOATING_POINT
- length = 0;
-#else
if( precision<0 ) precision = 6; /* Set default precision */
#ifdef SQLITE_FP_PRECISION_LIMIT
if( precision>SQLITE_FP_PRECISION_LIMIT ){
precision = SQLITE_FP_PRECISION_LIMIT;
}
#endif
- if( realvalue<0.0 ){
- realvalue = -realvalue;
- prefix = '-';
- }else{
- prefix = flag_prefix;
- }
- if( xtype==etGENERIC && precision>0 ) precision--;
- testcase( precision>0xfff );
- idx = precision & 0xfff;
- rounder = arRound[idx%10];
- while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; }
if( xtype==etFLOAT ){
- double rx = (double)realvalue;
- sqlcipher_sqlite3_uint64 u;
- int ex;
- memcpy(&u, &rx, sizeof(u));
- ex = -1023 + (int)((u>>52)&0x7ff);
- if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16;
- realvalue += rounder;
- }
- /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
- exp = 0;
- if( sqlcipher_sqlite3IsNaN((double)realvalue) ){
- bufpt = "NaN";
- length = 3;
- break;
+ iRound = -precision;
+ }else if( xtype==etGENERIC ){
+ if( precision==0 ) precision = 1;
+ iRound = precision;
+ }else{
+ iRound = precision+1;
}
- if( realvalue>0.0 ){
- LONGDOUBLE_TYPE scale = 1.0;
- while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;}
- while( realvalue>=1e10*scale && exp<=350 ){ scale *= 1e10; exp+=10; }
- while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
- realvalue /= scale;
- while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
- while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
- if( exp>350 ){
+ sqlcipher_sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16);
+ if( s.isSpecial ){
+ if( s.isSpecial==2 ){
+ bufpt = flag_zeropad ? "null" : "NaN";
+ length = sqlcipher_sqlite3Strlen30(bufpt);
+ break;
+ }else if( flag_zeropad ){
+ s.z[0] = '9';
+ s.iDP = 1000;
+ s.n = 1;
+ }else{
+ memcpy(buf, "-Inf", 5);
bufpt = buf;
- buf[0] = prefix;
- memcpy(buf+(prefix!=0),"Inf",4);
- length = 3+(prefix!=0);
+ if( s.sign=='-' ){
+ /* no-op */
+ }else if( flag_prefix ){
+ buf[0] = flag_prefix;
+ }else{
+ bufpt++;
+ }
+ length = sqlcipher_sqlite3Strlen30(bufpt);
break;
}
}
- bufpt = buf;
+ if( s.sign=='-' ){
+ prefix = '-';
+ }else{
+ prefix = flag_prefix;
+ }
+
+ exp = s.iDP-1;
+
/*
** If the field type is etGENERIC, then convert to either etEXP
** or etFLOAT, as appropriate.
*/
- if( xtype!=etFLOAT ){
- realvalue += rounder;
- if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
- }
if( xtype==etGENERIC ){
+ assert( precision>0 );
+ precision--;
flag_rtz = !flag_alternateform;
if( exp<-4 || exp>precision ){
xtype = etEXP;
@@ -30340,29 +31833,32 @@ SQLITE_API void sqlcipher_sqlite3_str_vappendf(
if( xtype==etEXP ){
e2 = 0;
}else{
- e2 = exp;
+ e2 = s.iDP - 1;
}
+ bufpt = buf;
{
i64 szBufNeeded; /* Size of a temporary buffer needed */
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15;
+ if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
if( szBufNeeded > etBUFSIZE ){
bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded);
if( bufpt==0 ) return;
}
}
zOut = bufpt;
- nsd = 16 + flag_altform2*10;
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
/* The sign in front of the number */
if( prefix ){
*(bufpt++) = prefix;
}
/* Digits prior to the decimal point */
+ j = 0;
if( e2<0 ){
*(bufpt++) = '0';
}else{
for(; e2>=0; e2--){
- *(bufpt++) = et_getdigit(&realvalue,&nsd);
+ *(bufpt++) = j<s.n ? s.z[j++] : '0';
+ if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
}
}
/* The decimal point */
@@ -30371,13 +31867,12 @@ SQLITE_API void sqlcipher_sqlite3_str_vappendf(
}
/* "0" digits after the decimal point but before the first
** significant digit of the number */
- for(e2++; e2<0; precision--, e2++){
- assert( precision>0 );
+ for(e2++; e2<0 && precision>0; precision--, e2++){
*(bufpt++) = '0';
}
/* Significant digits after the decimal point */
while( (precision--)>0 ){
- *(bufpt++) = et_getdigit(&realvalue,&nsd);
+ *(bufpt++) = j<s.n ? s.z[j++] : '0';
}
/* Remove trailing zeros and the "." if no digits follow the "." */
if( flag_rtz && flag_dp ){
@@ -30393,6 +31888,7 @@ SQLITE_API void sqlcipher_sqlite3_str_vappendf(
}
/* Add the "eNNN" suffix */
if( xtype==etEXP ){
+ exp = s.iDP - 1;
*(bufpt++) = aDigits[infop->charset];
if( exp<0 ){
*(bufpt++) = '-'; exp = -exp;
@@ -30426,8 +31922,8 @@ SQLITE_API void sqlcipher_sqlite3_str_vappendf(
while( nPad-- ) bufpt[i++] = '0';
length = width;
}
-#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */
break;
+ }
case etSIZE:
if( !bArgList ){
*(va_arg(ap,int*)) = pAccum->nChar;
@@ -30476,13 +31972,26 @@ SQLITE_API void sqlcipher_sqlite3_str_vappendf(
}
}
if( precision>1 ){
+ i64 nPrior = 1;
width -= precision-1;
if( width>1 && !flag_leftjustify ){
sqlcipher_sqlite3_str_appendchar(pAccum, width-1, ' ');
width = 0;
}
- while( precision-- > 1 ){
- sqlcipher_sqlite3_str_append(pAccum, buf, length);
+ sqlcipher_sqlite3_str_append(pAccum, buf, length);
+ precision--;
+ while( precision > 1 ){
+ i64 nCopyBytes;
+ if( nPrior > precision-1 ) nPrior = precision - 1;
+ nCopyBytes = length*nPrior;
+ if( nCopyBytes + pAccum->nChar >= pAccum->nAlloc ){
+ sqlcipher_sqlite3StrAccumEnlarge(pAccum, nCopyBytes);
+ }
+ if( pAccum->accError ) break;
+ sqlcipher_sqlite3_str_append(pAccum,
+ &pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes);
+ precision -= nPrior;
+ nPrior *= 2;
}
}
bufpt = buf;
@@ -30626,9 +32135,13 @@ SQLITE_API void sqlcipher_sqlite3_str_vappendf(
sqlcipher_sqlite3_str_appendall(pAccum, pItem->zAlias);
}else{
Select *pSel = pItem->pSelect;
- assert( pSel!=0 );
+ assert( pSel!=0 ); /* Because of tag-20240424-1 */
if( pSel->selFlags & SF_NestedFrom ){
sqlcipher_sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
+ }else if( pSel->selFlags & SF_MultiValue ){
+ assert( !pItem->fg.isTabFunc && !pItem->fg.isIndexedBy );
+ sqlcipher_sqlite3_str_appendf(pAccum, "%u-ROW VALUES CLAUSE",
+ pItem->u1.nRow);
}else{
sqlcipher_sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId);
}
@@ -30710,9 +32223,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3RecordErrorOffsetOfExpr(sqlcipher_sqlite3 *
** Return the number of bytes of text that StrAccum is able to accept
** after the attempted enlargement. The value returned might be zero.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3StrAccumEnlarge(StrAccum *p, int N){
+SQLITE_PRIVATE int sqlcipher_sqlite3StrAccumEnlarge(StrAccum *p, i64 N){
char *zNew;
- assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
+ assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){
testcase(p->accError==SQLITE_TOOBIG);
testcase(p->accError==SQLITE_NOMEM);
@@ -30723,8 +32236,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3StrAccumEnlarge(StrAccum *p, int N){
return p->nAlloc - p->nChar - 1;
}else{
char *zOld = isMalloced(p) ? p->zText : 0;
- i64 szNew = p->nChar;
- szNew += (sqlcipher_sqlite3_int64)N + 1;
+ i64 szNew = p->nChar + N + 1;
if( szNew+p->nChar<=p->mxAlloc ){
/* Force exponential buffer size growth as long as it does not overflow,
** to avoid having to call this routine too often */
@@ -30754,7 +32266,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3StrAccumEnlarge(StrAccum *p, int N){
return 0;
}
}
- return N;
+ assert( N>=0 && N<=0x7fffffff );
+ return (int)N;
}
/*
@@ -31045,12 +32558,22 @@ SQLITE_API char *sqlcipher_sqlite3_vsnprintf(int n, char *zBuf, const char *zFor
return zBuf;
}
SQLITE_API char *sqlcipher_sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
- char *z;
+ StrAccum acc;
va_list ap;
+ if( n<=0 ) return zBuf;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zBuf==0 || zFormat==0 ) {
+ (void)SQLITE_MISUSE_BKPT;
+ if( zBuf ) zBuf[0] = 0;
+ return zBuf;
+ }
+#endif
+ sqlcipher_sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
va_start(ap,zFormat);
- z = sqlcipher_sqlite3_vsnprintf(n, zBuf, zFormat, ap);
+ sqlcipher_sqlite3_str_vappendf(&acc, zFormat, ap);
va_end(ap);
- return z;
+ zBuf[acc.nChar] = 0;
+ return zBuf;
}
/*
@@ -31128,6 +32651,75 @@ SQLITE_API void sqlcipher_sqlite3_str_appendf(StrAccum *p, const char *zFormat,
va_end(ap);
}
+
+/*****************************************************************************
+** Reference counted string/blob storage
+*****************************************************************************/
+
+/*
+** Increase the reference count of the string by one.
+**
+** The input parameter is returned.
+*/
+SQLITE_PRIVATE char *sqlcipher_sqlite3RCStrRef(char *z){
+ RCStr *p = (RCStr*)z;
+ assert( p!=0 );
+ p--;
+ p->nRCRef++;
+ return z;
+}
+
+/*
+** Decrease the reference count by one. Free the string when the
+** reference count reaches zero.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3RCStrUnref(void *z){
+ RCStr *p = (RCStr*)z;
+ assert( p!=0 );
+ p--;
+ assert( p->nRCRef>0 );
+ if( p->nRCRef>=2 ){
+ p->nRCRef--;
+ }else{
+ sqlcipher_sqlite3_free(p);
+ }
+}
+
+/*
+** Create a new string that is capable of holding N bytes of text, not counting
+** the zero byte at the end. The string is uninitialized.
+**
+** The reference count is initially 1. Call sqlcipher_sqlite3RCStrUnref() to free the
+** newly allocated string.
+**
+** This routine returns 0 on an OOM.
+*/
+SQLITE_PRIVATE char *sqlcipher_sqlite3RCStrNew(u64 N){
+ RCStr *p = sqlcipher_sqlite3_malloc64( N + sizeof(*p) + 1 );
+ if( p==0 ) return 0;
+ p->nRCRef = 1;
+ return (char*)&p[1];
+}
+
+/*
+** Change the size of the string so that it is able to hold N bytes.
+** The string might be reallocated, so return the new allocation.
+*/
+SQLITE_PRIVATE char *sqlcipher_sqlite3RCStrResize(char *z, u64 N){
+ RCStr *p = (RCStr*)z;
+ RCStr *pNew;
+ assert( p!=0 );
+ p--;
+ assert( p->nRCRef==1 );
+ pNew = sqlcipher_sqlite3_realloc64(p, N+sizeof(RCStr)+1);
+ if( pNew==0 ){
+ sqlcipher_sqlite3_free(p);
+ return 0;
+ }else{
+ return (char*)&pNew[1];
+ }
+}
+
/************** End of printf.c **********************************************/
/************** Begin file treeview.c ****************************************/
/*
@@ -31326,8 +32918,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewSrcList(TreeView *pView, const SrcL
x.printfFlags |= SQLITE_PRINTF_INTERNAL;
sqlcipher_sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem);
if( pItem->pTab ){
- sqlcipher_sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx",
- pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed);
+ sqlcipher_sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s",
+ pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab,
+ pItem->colUsed,
+ pItem->fg.rowidUsed ? "+rowid" : "");
}
if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){
sqlcipher_sqlite3_str_appendf(&x, " FULL-OUTER-JOIN");
@@ -31350,6 +32944,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewSrcList(TreeView *pView, const SrcL
if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){
sqlcipher_sqlite3_str_appendf(&x, " ON");
}
+ if( pItem->fg.isTabFunc ) sqlcipher_sqlite3_str_appendf(&x, " isTabFunc");
+ if( pItem->fg.isCorrelated ) sqlcipher_sqlite3_str_appendf(&x, " isCorrelated");
+ if( pItem->fg.isMaterialized ) sqlcipher_sqlite3_str_appendf(&x, " isMaterialized");
+ if( pItem->fg.viaCoroutine ) sqlcipher_sqlite3_str_appendf(&x, " viaCoroutine");
+ if( pItem->fg.notCte ) sqlcipher_sqlite3_str_appendf(&x, " notCte");
+ if( pItem->fg.isNestedFrom ) sqlcipher_sqlite3_str_appendf(&x, " isNestedFrom");
+
sqlcipher_sqlite3StrAccumFinish(&x);
sqlcipher_sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
n = 0;
@@ -31360,12 +32961,14 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewSrcList(TreeView *pView, const SrcL
sqlcipher_sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING");
}
if( pItem->pSelect ){
+ sqlcipher_sqlite3TreeViewPush(&pView, i+1<pSrc->nSrc);
if( pItem->pTab ){
Table *pTab = pItem->pTab;
sqlcipher_sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
}
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
sqlcipher_sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0);
+ sqlcipher_sqlite3TreeViewPop(&pView);
}
if( pItem->fg.isTabFunc ){
sqlcipher_sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
@@ -31469,7 +33072,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewSelect(TreeView *pView, const Selec
sqlcipher_sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
sqlcipher_sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0);
if( p->pLimit->pRight ){
- sqlcipher_sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
+ sqlcipher_sqlite3TreeViewItem(pView, "OFFSET", 0);
sqlcipher_sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0);
sqlcipher_sqlite3TreeViewPop(&pView);
}
@@ -31537,6 +33140,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewWindow(TreeView *pView, const Windo
sqlcipher_sqlite3TreeViewItem(pView, "FILTER", 1);
sqlcipher_sqlite3TreeViewExpr(pView, pWin->pFilter, 0);
sqlcipher_sqlite3TreeViewPop(&pView);
+ if( pWin->eFrmType==TK_FILTER ) return;
}
sqlcipher_sqlite3TreeViewPush(&pView, more);
if( pWin->zName ){
@@ -31546,7 +33150,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewWindow(TreeView *pView, const Windo
}
if( pWin->zBase ) nElement++;
if( pWin->pOrderBy ) nElement++;
- if( pWin->eFrmType ) nElement++;
+ if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ) nElement++;
if( pWin->eExclude ) nElement++;
if( pWin->zBase ){
sqlcipher_sqlite3TreeViewPush(&pView, (--nElement)>0);
@@ -31559,7 +33163,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewWindow(TreeView *pView, const Windo
if( pWin->pOrderBy ){
sqlcipher_sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY");
}
- if( pWin->eFrmType ){
+ if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ){
char zBuf[30];
const char *zFrmType = "ROWS";
if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE";
@@ -31619,7 +33223,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewExpr(TreeView *pView, const Expr *p
sqlcipher_sqlite3TreeViewPop(&pView);
return;
}
- if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){
+ if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags || pExpr->pAggInfo ){
StrAccum x;
sqlcipher_sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0);
sqlcipher_sqlite3_str_appendf(&x, " fg.af=%x.%c",
@@ -31636,6 +33240,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewExpr(TreeView *pView, const Expr *p
if( ExprHasVVAProperty(pExpr, EP_Immutable) ){
sqlcipher_sqlite3_str_appendf(&x, " IMMUTABLE");
}
+ if( pExpr->pAggInfo!=0 ){
+ sqlcipher_sqlite3_str_appendf(&x, " agg-column[%d]", pExpr->iAgg);
+ }
sqlcipher_sqlite3StrAccumFinish(&x);
}else{
zFlgs[0] = 0;
@@ -31765,7 +33372,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewExpr(TreeView *pView, const Expr *p
};
assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT );
assert( pExpr->pRight );
- assert( sqlcipher_sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE );
+ assert( sqlcipher_sqlite3ExprSkipCollateAndLikely(pExpr->pRight)->op
+ == TK_TRUEFALSE );
x = (pExpr->op2==TK_ISNOT)*2 + sqlcipher_sqlite3ExprTruthValue(pExpr->pRight);
zUniOp = azOp[x];
break;
@@ -31803,7 +33411,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewExpr(TreeView *pView, const Expr *p
assert( ExprUseXList(pExpr) );
pFarg = pExpr->x.pList;
#ifndef SQLITE_OMIT_WINDOWFUNC
- pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0;
+ pWin = IsWindowFunc(pExpr) ? pExpr->y.pWin : 0;
#else
pWin = 0;
#endif
@@ -31829,7 +33437,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewExpr(TreeView *pView, const Expr *p
sqlcipher_sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs);
}
if( pFarg ){
- sqlcipher_sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);
+ sqlcipher_sqlite3TreeViewExprList(pView, pFarg, pWin!=0 || pExpr->pLeft, 0);
+ if( pExpr->pLeft ){
+ Expr *pOB = pExpr->pLeft;
+ assert( pOB->op==TK_ORDER );
+ assert( ExprUseXList(pOB) );
+ sqlcipher_sqlite3TreeViewExprList(pView, pOB->x.pList, pWin!=0, "ORDERBY");
+ }
}
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pWin ){
@@ -31838,6 +33452,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewExpr(TreeView *pView, const Expr *p
#endif
break;
}
+ case TK_ORDER: {
+ sqlcipher_sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, "ORDERBY");
+ break;
+ }
#ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS: {
assert( ExprUseXSelect(pExpr) );
@@ -31891,7 +33509,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TreeViewExpr(TreeView *pView, const Expr *p
assert( pExpr->x.pList->nExpr==2 );
pY = pExpr->x.pList->a[0].pExpr;
pZ = pExpr->x.pList->a[1].pExpr;
- sqlcipher_sqlite3TreeViewLine(pView, "BETWEEN");
+ sqlcipher_sqlite3TreeViewLine(pView, "BETWEEN%s", zFlgs);
sqlcipher_sqlite3TreeViewExpr(pView, pX, 1);
sqlcipher_sqlite3TreeViewExpr(pView, pY, 1);
sqlcipher_sqlite3TreeViewExpr(pView, pZ, 0);
@@ -32447,16 +34065,41 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ShowWinFunc(const Window *p){ sqlcipher_sql
** This structure is the current state of the generator.
*/
static SQLITE_WSD struct sqlcipher_sqlite3PrngType {
- unsigned char isInit; /* True if initialized */
- unsigned char i, j; /* State variables */
- unsigned char s[256]; /* State variables */
+ u32 s[16]; /* 64 bytes of chacha20 state */
+ u8 out[64]; /* Output bytes */
+ u8 n; /* Output bytes remaining */
} sqlcipher_sqlite3Prng;
+
+/* The RFC-7539 ChaCha20 block function
+*/
+#define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
+#define QR(a, b, c, d) ( \
+ a += b, d ^= a, d = ROTL(d,16), \
+ c += d, b ^= c, b = ROTL(b,12), \
+ a += b, d ^= a, d = ROTL(d, 8), \
+ c += d, b ^= c, b = ROTL(b, 7))
+static void chacha_block(u32 *out, const u32 *in){
+ int i;
+ u32 x[16];
+ memcpy(x, in, 64);
+ for(i=0; i<10; i++){
+ QR(x[0], x[4], x[ 8], x[12]);
+ QR(x[1], x[5], x[ 9], x[13]);
+ QR(x[2], x[6], x[10], x[14]);
+ QR(x[3], x[7], x[11], x[15]);
+ QR(x[0], x[5], x[10], x[15]);
+ QR(x[1], x[6], x[11], x[12]);
+ QR(x[2], x[7], x[ 8], x[13]);
+ QR(x[3], x[4], x[ 9], x[14]);
+ }
+ for(i=0; i<16; i++) out[i] = x[i]+in[i];
+}
+
/*
** Return N random bytes.
*/
SQLITE_API void sqlcipher_sqlite3_randomness(int N, void *pBuf){
- unsigned char t;
unsigned char *zBuf = pBuf;
/* The "wsdPrng" macro will resolve to the pseudo-random number generator
@@ -32486,53 +34129,46 @@ SQLITE_API void sqlcipher_sqlite3_randomness(int N, void *pBuf){
sqlcipher_sqlite3_mutex_enter(mutex);
if( N<=0 || pBuf==0 ){
- wsdPrng.isInit = 0;
+ wsdPrng.s[0] = 0;
sqlcipher_sqlite3_mutex_leave(mutex);
return;
}
/* Initialize the state of the random number generator once,
- ** the first time this routine is called. The seed value does
- ** not need to contain a lot of randomness since we are not
- ** trying to do secure encryption or anything like that...
- **
- ** Nothing in this file or anywhere else in SQLite does any kind of
- ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
- ** number generator) not as an encryption device.
+ ** the first time this routine is called.
*/
- if( !wsdPrng.isInit ){
+ if( wsdPrng.s[0]==0 ){
sqlcipher_sqlite3_vfs *pVfs = sqlcipher_sqlite3_vfs_find(0);
- int i;
- char k[256];
- wsdPrng.j = 0;
- wsdPrng.i = 0;
+ static const u32 chacha20_init[] = {
+ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
+ };
+ memcpy(&wsdPrng.s[0], chacha20_init, 16);
if( NEVER(pVfs==0) ){
- memset(k, 0, sizeof(k));
+ memset(&wsdPrng.s[4], 0, 44);
}else{
- sqlcipher_sqlite3OsRandomness(pVfs, 256, k);
- }
- for(i=0; i<256; i++){
- wsdPrng.s[i] = (u8)i;
- }
- for(i=0; i<256; i++){
- wsdPrng.j += wsdPrng.s[i] + k[i];
- t = wsdPrng.s[wsdPrng.j];
- wsdPrng.s[wsdPrng.j] = wsdPrng.s[i];
- wsdPrng.s[i] = t;
+ sqlcipher_sqlite3OsRandomness(pVfs, 44, (char*)&wsdPrng.s[4]);
}
- wsdPrng.isInit = 1;
+ wsdPrng.s[15] = wsdPrng.s[12];
+ wsdPrng.s[12] = 0;
+ wsdPrng.n = 0;
}
assert( N>0 );
- do{
- wsdPrng.i++;
- t = wsdPrng.s[wsdPrng.i];
- wsdPrng.j += t;
- wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j];
- wsdPrng.s[wsdPrng.j] = t;
- t += wsdPrng.s[wsdPrng.i];
- *(zBuf++) = wsdPrng.s[t];
- }while( --N );
+ while( 1 /* exit by break */ ){
+ if( N<=wsdPrng.n ){
+ memcpy(zBuf, &wsdPrng.out[wsdPrng.n-N], N);
+ wsdPrng.n -= N;
+ break;
+ }
+ if( wsdPrng.n>0 ){
+ memcpy(zBuf, wsdPrng.out, wsdPrng.n);
+ N -= wsdPrng.n;
+ zBuf += wsdPrng.n;
+ }
+ wsdPrng.s[12]++;
+ chacha_block((u32*)wsdPrng.out, wsdPrng.s);
+ wsdPrng.n = 64;
+ }
sqlcipher_sqlite3_mutex_leave(mutex);
}
@@ -33008,7 +34644,38 @@ SQLITE_PRIVATE u32 sqlcipher_sqlite3Utf8Read(
return c;
}
-
+/*
+** Read a single UTF8 character out of buffer z[], but reading no
+** more than n characters from the buffer. z[] is not zero-terminated.
+**
+** Return the number of bytes used to construct the character.
+**
+** Invalid UTF8 might generate a strange result. No effort is made
+** to detect invalid UTF8.
+**
+** At most 4 bytes will be read out of z[]. The return value will always
+** be between 1 and 4.
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3Utf8ReadLimited(
+ const u8 *z,
+ int n,
+ u32 *piOut
+){
+ u32 c;
+ int i = 1;
+ assert( n>0 );
+ c = z[0];
+ if( c>=0xc0 ){
+ c = sqlcipher_sqlite3Utf8Trans1[c-0xc0];
+ if( n>4 ) n = 4;
+ while( i<n && (z[i] & 0xc0)==0x80 ){
+ c = (c<<6) + (0x3f & z[i]);
+ i++;
+ }
+ }
+ *piOut = c;
+ return i;
+}
/*
@@ -33406,7 +35073,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3UtfSelfTest(void){
/*
** Calls to sqlcipher_sqlite3FaultSim() are used to simulate a failure during testing,
** or to bypass normal error detection during testing in order to let
-** execute proceed futher downstream.
+** execute proceed further downstream.
**
** In deployment, sqlcipher_sqlite3FaultSim() *always* return SQLITE_OK (0). The
** sqlcipher_sqlite3FaultSim() function only returns non-zero during testing.
@@ -33450,6 +35117,19 @@ SQLITE_PRIVATE int sqlcipher_sqlite3IsNaN(double x){
}
#endif /* SQLITE_OMIT_FLOATING_POINT */
+#ifndef SQLITE_OMIT_FLOATING_POINT
+/*
+** Return true if the floating point value is NaN or +Inf or -Inf.
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3IsOverflow(double x){
+ int rc; /* The value return */
+ u64 y;
+ memcpy(&y,&x,sizeof(y));
+ rc = IsOvfl(y);
+ return rc;
+}
+#endif /* SQLITE_OMIT_FLOATING_POINT */
+
/*
** Compute a string length that is limited to what can be stored in
** lower 30 bits of a 32-bit signed integer.
@@ -33523,6 +35203,23 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ErrorClear(sqlcipher_sqlite3 *db){
*/
SQLITE_PRIVATE void sqlcipher_sqlite3SystemError(sqlcipher_sqlite3 *db, int rc){
if( rc==SQLITE_IOERR_NOMEM ) return;
+#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
+ if( rc==SQLITE_IOERR_IN_PAGE ){
+ int ii;
+ int iErr;
+ sqlcipher_sqlite3BtreeEnterAll(db);
+ for(ii=0; ii<db->nDb; ii++){
+ if( db->aDb[ii].pBt ){
+ iErr = sqlcipher_sqlite3PagerWalSystemErrno(sqlcipher_sqlite3BtreePager(db->aDb[ii].pBt));
+ if( iErr ){
+ db->iSysErrno = iErr;
+ }
+ }
+ }
+ sqlcipher_sqlite3BtreeLeaveAll(db);
+ return;
+ }
+#endif
rc &= 0xff;
if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){
db->iSysErrno = sqlcipher_sqlite3OsGetLastError(db->pVfs);
@@ -33558,6 +35255,30 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ErrorWithMsg(sqlcipher_sqlite3 *db, int err
}
/*
+** Check for interrupts and invoke progress callback.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3ProgressCheck(Parse *p){
+ sqlcipher_sqlite3 *db = p->db;
+ if( AtomicLoad(&db->u1.isInterrupted) ){
+ p->nErr++;
+ p->rc = SQLITE_INTERRUPT;
+ }
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ if( db->xProgress ){
+ if( p->rc==SQLITE_INTERRUPT ){
+ p->nProgressSteps = 0;
+ }else if( (++p->nProgressSteps)>=db->nProgressOps ){
+ if( db->xProgress(db->pProgressArg) ){
+ p->nErr++;
+ p->rc = SQLITE_INTERRUPT;
+ }
+ p->nProgressSteps = 0;
+ }
+ }
+#endif
+}
+
+/*
** Add an error message to pParse->zErrMsg and increment pParse->nErr.
**
** This function should be used to report any error that occurs while
@@ -33653,6 +35374,44 @@ SQLITE_PRIVATE void sqlcipher_sqlite3DequoteExpr(Expr *p){
}
/*
+** Expression p is a QNUMBER (quoted number). Dequote the value in p->u.zToken
+** and set the type to INTEGER or FLOAT. "Quoted" integers or floats are those
+** that contain '_' characters that must be removed before further processing.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3DequoteNumber(Parse *pParse, Expr *p){
+ assert( p!=0 || pParse->db->mallocFailed );
+ if( p ){
+ const char *pIn = p->u.zToken;
+ char *pOut = p->u.zToken;
+ int bHex = (pIn[0]=='0' && (pIn[1]=='x' || pIn[1]=='X'));
+ int iValue;
+ assert( p->op==TK_QNUMBER );
+ p->op = TK_INTEGER;
+ do {
+ if( *pIn!=SQLITE_DIGIT_SEPARATOR ){
+ *pOut++ = *pIn;
+ if( *pIn=='e' || *pIn=='E' || *pIn=='.' ) p->op = TK_FLOAT;
+ }else{
+ if( (bHex==0 && (!sqlcipher_sqlite3Isdigit(pIn[-1]) || !sqlcipher_sqlite3Isdigit(pIn[1])))
+ || (bHex==1 && (!sqlcipher_sqlite3Isxdigit(pIn[-1]) || !sqlcipher_sqlite3Isxdigit(pIn[1])))
+ ){
+ sqlcipher_sqlite3ErrorMsg(pParse, "unrecognized token: \"%s\"", p->u.zToken);
+ }
+ }
+ }while( *pIn++ );
+ if( bHex ) p->op = TK_INTEGER;
+
+ /* tag-20240227-a: If after dequoting, the number is an integer that
+ ** fits in 32 bits, then it must be converted into EP_IntValue. Other
+ ** parts of the code expect this. See also tag-20240227-b. */
+ if( p->op==TK_INTEGER && sqlcipher_sqlite3GetInt32(p->u.zToken, &iValue) ){
+ p->u.iValue = iValue;
+ p->flags |= EP_IntValue;
+ }
+ }
+}
+
+/*
** If the input token p is quoted, try to adjust the token to remove
** the quotes. This is not always possible:
**
@@ -33748,43 +35507,40 @@ SQLITE_PRIVATE u8 sqlcipher_sqlite3StrIHash(const char *z){
return h;
}
-/*
-** Compute 10 to the E-th power. Examples: E==1 results in 10.
-** E==2 results in 100. E==50 results in 1.0e50.
+/* Double-Double multiplication. (x[0],x[1]) *= (y,yy)
**
-** This routine only works for values of E between 1 and 341.
+** Reference:
+** T. J. Dekker, "A Floating-Point Technique for Extending the
+** Available Precision". 1971-07-26.
*/
-static LONGDOUBLE_TYPE sqlcipher_sqlite3Pow10(int E){
-#if defined(_MSC_VER)
- static const LONGDOUBLE_TYPE x[] = {
- 1.0e+001L,
- 1.0e+002L,
- 1.0e+004L,
- 1.0e+008L,
- 1.0e+016L,
- 1.0e+032L,
- 1.0e+064L,
- 1.0e+128L,
- 1.0e+256L
- };
- LONGDOUBLE_TYPE r = 1.0;
- int i;
- assert( E>=0 && E<=307 );
- for(i=0; E!=0; i++, E >>=1){
- if( E & 1 ) r *= x[i];
- }
- return r;
-#else
- LONGDOUBLE_TYPE x = 10.0;
- LONGDOUBLE_TYPE r = 1.0;
- while(1){
- if( E & 1 ) r *= x;
- E >>= 1;
- if( E==0 ) break;
- x *= x;
- }
- return r;
-#endif
+static void dekkerMul2(volatile double *x, double y, double yy){
+ /*
+ ** The "volatile" keywords on parameter x[] and on local variables
+ ** below are needed force intermediate results to be truncated to
+ ** binary64 rather than be carried around in an extended-precision
+ ** format. The truncation is necessary for the Dekker algorithm to
+ ** work. Intel x86 floating point might omit the truncation without
+ ** the use of volatile.
+ */
+ volatile double tx, ty, p, q, c, cc;
+ double hx, hy;
+ u64 m;
+ memcpy(&m, (void*)&x[0], 8);
+ m &= 0xfffffffffc000000LL;
+ memcpy(&hx, &m, 8);
+ tx = x[0] - hx;
+ memcpy(&m, &y, 8);
+ m &= 0xfffffffffc000000LL;
+ memcpy(&hy, &m, 8);
+ ty = y - hy;
+ p = hx*hy;
+ q = hx*ty + tx*hy;
+ c = p+q;
+ cc = p - c + q + tx*ty;
+ cc = x[0]*yy + x[1]*y + cc;
+ x[0] = c + cc;
+ x[1] = c - x[0];
+ x[1] += cc;
}
/*
@@ -33825,12 +35581,11 @@ SQLITE_PRIVATE int sqlcipher_sqlite3AtoF(const char *z, double *pResult, int len
const char *zEnd;
/* sign * significand * (10 ^ (esign * exponent)) */
int sign = 1; /* sign of significand */
- i64 s = 0; /* significand */
+ u64 s = 0; /* significand */
int d = 0; /* adjust exponent for shifting decimal point */
int esign = 1; /* sign of exponent */
int e = 0; /* exponent */
int eValid = 1; /* True exponent is either not used or is well-formed */
- double result;
int nDigit = 0; /* Number of digits processed */
int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */
@@ -33870,7 +35625,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3AtoF(const char *z, double *pResult, int len
while( z<zEnd && sqlcipher_sqlite3Isdigit(*z) ){
s = s*10 + (*z - '0');
z+=incr; nDigit++;
- if( s>=((LARGEST_INT64-9)/10) ){
+ if( s>=((LARGEST_UINT64-9)/10) ){
/* skip non-significant significand digits
** (increase exponent by d to shift decimal left) */
while( z<zEnd && sqlcipher_sqlite3Isdigit(*z) ){ z+=incr; d++; }
@@ -33885,7 +35640,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3AtoF(const char *z, double *pResult, int len
/* copy digits from after decimal to significand
** (decrease exponent by d to shift decimal right) */
while( z<zEnd && sqlcipher_sqlite3Isdigit(*z) ){
- if( s<((LARGEST_INT64-9)/10) ){
+ if( s<((LARGEST_UINT64-9)/10) ){
s = s*10 + (*z - '0');
d--;
nDigit++;
@@ -33925,79 +35680,92 @@ SQLITE_PRIVATE int sqlcipher_sqlite3AtoF(const char *z, double *pResult, int len
while( z<zEnd && sqlcipher_sqlite3Isspace(*z) ) z+=incr;
do_atof_calc:
- /* adjust exponent by d, and update sign */
- e = (e*esign) + d;
- if( e<0 ) {
- esign = -1;
- e *= -1;
- } else {
- esign = 1;
+ /* Zero is a special case */
+ if( s==0 ){
+ *pResult = sign<0 ? -0.0 : +0.0;
+ goto atof_return;
}
- if( s==0 ) {
- /* In the IEEE 754 standard, zero is signed. */
- result = sign<0 ? -(double)0 : (double)0;
- } else {
- /* Attempt to reduce exponent.
- **
- ** Branches that are not required for the correct answer but which only
- ** help to obtain the correct answer faster are marked with special
- ** comments, as a hint to the mutation tester.
- */
- while( e>0 ){ /*OPTIMIZATION-IF-TRUE*/
- if( esign>0 ){
- if( s>=(LARGEST_INT64/10) ) break; /*OPTIMIZATION-IF-FALSE*/
- s *= 10;
- }else{
- if( s%10!=0 ) break; /*OPTIMIZATION-IF-FALSE*/
- s /= 10;
- }
- e--;
- }
+ /* adjust exponent by d, and update sign */
+ e = (e*esign) + d;
- /* adjust the sign of significand */
- s = sign<0 ? -s : s;
+ /* Try to adjust the exponent to make it smaller */
+ while( e>0 && s<(LARGEST_UINT64/10) ){
+ s *= 10;
+ e--;
+ }
+ while( e<0 && (s%10)==0 ){
+ s /= 10;
+ e++;
+ }
- if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/
- result = (double)s;
+ if( e==0 ){
+ *pResult = s;
+ }else if( sqlcipher_sqlite3Config.bUseLongDouble ){
+ LONGDOUBLE_TYPE r = (LONGDOUBLE_TYPE)s;
+ if( e>0 ){
+ while( e>=100 ){ e-=100; r *= 1.0e+100L; }
+ while( e>=10 ){ e-=10; r *= 1.0e+10L; }
+ while( e>=1 ){ e-=1; r *= 1.0e+01L; }
}else{
- /* attempt to handle extremely small/large numbers better */
- if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/
- if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/
- LONGDOUBLE_TYPE scale = sqlcipher_sqlite3Pow10(e-308);
- if( esign<0 ){
- result = s / scale;
- result /= 1.0e+308;
- }else{
- result = s * scale;
- result *= 1.0e+308;
- }
- }else{ assert( e>=342 );
- if( esign<0 ){
- result = 0.0*s;
- }else{
+ while( e<=-100 ){ e+=100; r *= 1.0e-100L; }
+ while( e<=-10 ){ e+=10; r *= 1.0e-10L; }
+ while( e<=-1 ){ e+=1; r *= 1.0e-01L; }
+ }
+ assert( r>=0.0 );
+ if( r>+1.7976931348623157081452742373e+308L ){
#ifdef INFINITY
- result = INFINITY*s;
+ *pResult = +INFINITY;
#else
- result = 1e308*1e308*s; /* Infinity */
+ *pResult = 1.0e308*10.0;
#endif
- }
- }
- }else{
- LONGDOUBLE_TYPE scale = sqlcipher_sqlite3Pow10(e);
- if( esign<0 ){
- result = s / scale;
- }else{
- result = s * scale;
- }
+ }else{
+ *pResult = (double)r;
+ }
+ }else{
+ double rr[2];
+ u64 s2;
+ rr[0] = (double)s;
+ s2 = (u64)rr[0];
+#if defined(_MSC_VER) && _MSC_VER<1700
+ if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); }
+#endif
+ rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
+ if( e>0 ){
+ while( e>=100 ){
+ e -= 100;
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
+ }
+ while( e>=10 ){
+ e -= 10;
+ dekkerMul2(rr, 1.0e+10, 0.0);
+ }
+ while( e>=1 ){
+ e -= 1;
+ dekkerMul2(rr, 1.0e+01, 0.0);
+ }
+ }else{
+ while( e<=-100 ){
+ e += 100;
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
+ }
+ while( e<=-10 ){
+ e += 10;
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
+ }
+ while( e<=-1 ){
+ e += 1;
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
}
}
+ *pResult = rr[0]+rr[1];
+ if( sqlcipher_sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300;
}
+ if( sign<0 ) *pResult = -*pResult;
+ assert( !sqlcipher_sqlite3IsNaN(*pResult) );
- /* store the result */
- *pResult = result;
-
- /* return true if number and no extra non-whitespace chracters after */
+atof_return:
+ /* return true if number and no extra non-whitespace characters after */
if( z==zEnd && nDigit>0 && eValid && eType>0 ){
return eType;
}else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){
@@ -34014,11 +35782,14 @@ do_atof_calc:
#endif
/*
-** Render an signed 64-bit integer as text. Store the result in zOut[].
+** Render an signed 64-bit integer as text. Store the result in zOut[] and
+** return the length of the string that was stored, in bytes. The value
+** returned does not include the zero terminator at the end of the output
+** string.
**
** The caller must ensure that zOut[] is at least 21 bytes in size.
*/
-SQLITE_PRIVATE void sqlcipher_sqlite3Int64ToText(i64 v, char *zOut){
+SQLITE_PRIVATE int sqlcipher_sqlite3Int64ToText(i64 v, char *zOut){
int i;
u64 x;
char zTemp[22];
@@ -34029,12 +35800,15 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Int64ToText(i64 v, char *zOut){
}
i = sizeof(zTemp)-2;
zTemp[sizeof(zTemp)-1] = 0;
- do{
- zTemp[i--] = (x%10) + '0';
+ while( 1 /*exit-by-break*/ ){
+ zTemp[i] = (x%10) + '0';
x = x/10;
- }while( x );
- if( v<0 ) zTemp[i--] = '-';
- memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
+ if( x==0 ) break;
+ i--;
+ };
+ if( v<0 ) zTemp[--i] = '-';
+ memcpy(zOut, &zTemp[i], sizeof(zTemp)-i);
+ return sizeof(zTemp)-1-i;
}
/*
@@ -34127,7 +35901,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Atoi64(const char *zNum, i64 *pNum, int leng
/* This test and assignment is needed only to suppress UB warnings
** from clang and -fsanitize=undefined. This test and assignment make
** the code a little larger and slower, and no harm comes from omitting
- ** them, but we must appaise the undefined-behavior pharisees. */
+ ** them, but we must appease the undefined-behavior pharisees. */
*pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
}else if( neg ){
*pNum = -(i64)u;
@@ -34199,11 +35973,15 @@ SQLITE_PRIVATE int sqlcipher_sqlite3DecOrHexToI64(const char *z, i64 *pOut){
u = u*16 + sqlcipher_sqlite3HexToInt(z[k]);
}
memcpy(pOut, &u, 8);
- return (z[k]==0 && k-i<=16) ? 0 : 2;
+ if( k-i>16 ) return 2;
+ if( z[k]!=0 ) return 1;
+ return 0;
}else
#endif /* SQLITE_OMIT_HEX_INTEGER */
{
- return sqlcipher_sqlite3Atoi64(z, pOut, sqlcipher_sqlite3Strlen30(z), SQLITE_UTF8);
+ int n = (int)(0x3fffffff&strspn(z,"+- \n\t0123456789"));
+ if( z[n] ) n++;
+ return sqlcipher_sqlite3Atoi64(z, pOut, n, SQLITE_UTF8);
}
}
@@ -34235,7 +36013,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3GetInt32(const char *zNum, int *pValue){
u32 u = 0;
zNum += 2;
while( zNum[0]=='0' ) zNum++;
- for(i=0; sqlcipher_sqlite3Isxdigit(zNum[i]) && i<8; i++){
+ for(i=0; i<8 && sqlcipher_sqlite3Isxdigit(zNum[i]); i++){
u = u*16 + sqlcipher_sqlite3HexToInt(zNum[i]);
}
if( (u&0x80000000)==0 && sqlcipher_sqlite3Isxdigit(zNum[i])==0 ){
@@ -34283,6 +36061,153 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Atoi(const char *z){
}
/*
+** Decode a floating-point value into an approximate decimal
+** representation.
+**
+** Round the decimal representation to n significant digits if
+** n is positive. Or round to -n signficant digits after the
+** decimal point if n is negative. No rounding is performed if
+** n is zero.
+**
+** The significant digits of the decimal representation are
+** stored in p->z[] which is a often (but not always) a pointer
+** into the middle of p->zBuf[]. There are p->n significant digits.
+** The p->z[] array is *not* zero-terminated.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
+ int i;
+ u64 v;
+ int e, exp = 0;
+ p->isSpecial = 0;
+ p->z = p->zBuf;
+
+ /* Convert negative numbers to positive. Deal with Infinity, 0.0, and
+ ** NaN. */
+ if( r<0.0 ){
+ p->sign = '-';
+ r = -r;
+ }else if( r==0.0 ){
+ p->sign = '+';
+ p->n = 1;
+ p->iDP = 1;
+ p->z = "0";
+ return;
+ }else{
+ p->sign = '+';
+ }
+ memcpy(&v,&r,8);
+ e = v>>52;
+ if( (e&0x7ff)==0x7ff ){
+ p->isSpecial = 1 + (v!=0x7ff0000000000000LL);
+ p->n = 0;
+ p->iDP = 0;
+ return;
+ }
+
+ /* Multiply r by powers of ten until it lands somewhere in between
+ ** 1.0e+19 and 1.0e+17.
+ */
+ if( sqlcipher_sqlite3Config.bUseLongDouble ){
+ LONGDOUBLE_TYPE rr = r;
+ if( rr>=1.0e+19 ){
+ while( rr>=1.0e+119L ){ exp+=100; rr *= 1.0e-100L; }
+ while( rr>=1.0e+29L ){ exp+=10; rr *= 1.0e-10L; }
+ while( rr>=1.0e+19L ){ exp++; rr *= 1.0e-1L; }
+ }else{
+ while( rr<1.0e-97L ){ exp-=100; rr *= 1.0e+100L; }
+ while( rr<1.0e+07L ){ exp-=10; rr *= 1.0e+10L; }
+ while( rr<1.0e+17L ){ exp--; rr *= 1.0e+1L; }
+ }
+ v = (u64)rr;
+ }else{
+ /* If high-precision floating point is not available using "long double",
+ ** then use Dekker-style double-double computation to increase the
+ ** precision.
+ **
+ ** The error terms on constants like 1.0e+100 computed using the
+ ** decimal extension, for example as follows:
+ **
+ ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100)));
+ */
+ double rr[2];
+ rr[0] = r;
+ rr[1] = 0.0;
+ if( rr[0]>9.223372036854774784e+18 ){
+ while( rr[0]>9.223372036854774784e+118 ){
+ exp += 100;
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
+ }
+ while( rr[0]>9.223372036854774784e+28 ){
+ exp += 10;
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
+ }
+ while( rr[0]>9.223372036854774784e+18 ){
+ exp += 1;
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
+ }
+ }else{
+ while( rr[0]<9.223372036854774784e-83 ){
+ exp -= 100;
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
+ }
+ while( rr[0]<9.223372036854774784e+07 ){
+ exp -= 10;
+ dekkerMul2(rr, 1.0e+10, 0.0);
+ }
+ while( rr[0]<9.22337203685477478e+17 ){
+ exp -= 1;
+ dekkerMul2(rr, 1.0e+01, 0.0);
+ }
+ }
+ v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1];
+ }
+
+
+ /* Extract significant digits. */
+ i = sizeof(p->zBuf)-1;
+ assert( v>0 );
+ while( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; }
+ assert( i>=0 && i<sizeof(p->zBuf)-1 );
+ p->n = sizeof(p->zBuf) - 1 - i;
+ assert( p->n>0 );
+ assert( p->n<sizeof(p->zBuf) );
+ p->iDP = p->n + exp;
+ if( iRound<=0 ){
+ iRound = p->iDP - iRound;
+ if( iRound==0 && p->zBuf[i+1]>='5' ){
+ iRound = 1;
+ p->zBuf[i--] = '0';
+ p->n++;
+ p->iDP++;
+ }
+ }
+ if( iRound>0 && (iRound<p->n || p->n>mxRound) ){
+ char *z = &p->zBuf[i+1];
+ if( iRound>mxRound ) iRound = mxRound;
+ p->n = iRound;
+ if( z[iRound]>='5' ){
+ int j = iRound-1;
+ while( 1 /*exit-by-break*/ ){
+ z[j]++;
+ if( z[j]<='9' ) break;
+ z[j] = '0';
+ if( j==0 ){
+ p->z[i--] = '1';
+ p->n++;
+ p->iDP++;
+ break;
+ }else{
+ j--;
+ }
+ }
+ }
+ }
+ p->z = &p->zBuf[i+1];
+ assert( i+p->n < sizeof(p->zBuf) );
+ while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; }
+}
+
+/*
** Try to convert z into an unsigned 32-bit integer. Return true on
** success and false if there is an error.
**
@@ -34545,121 +36470,32 @@ SQLITE_PRIVATE u8 sqlcipher_sqlite3GetVarint(const unsigned char *p, u64 *v){
** this function assumes the single-byte case has already been handled.
*/
SQLITE_PRIVATE u8 sqlcipher_sqlite3GetVarint32(const unsigned char *p, u32 *v){
- u32 a,b;
+ u64 v64;
+ u8 n;
- /* The 1-byte case. Overwhelmingly the most common. Handled inline
- ** by the getVarin32() macro */
- a = *p;
- /* a: p0 (unmasked) */
-#ifndef getVarint32
- if (!(a&0x80))
- {
- /* Values between 0 and 127 */
- *v = a;
- return 1;
- }
-#endif
+ /* Assume that the single-byte case has already been handled by
+ ** the getVarint32() macro */
+ assert( (p[0] & 0x80)!=0 );
- /* The 2-byte case */
- p++;
- b = *p;
- /* b: p1 (unmasked) */
- if (!(b&0x80))
- {
- /* Values between 128 and 16383 */
- a &= 0x7f;
- a = a<<7;
- *v = a | b;
+ if( (p[1] & 0x80)==0 ){
+ /* This is the two-byte case */
+ *v = ((p[0]&0x7f)<<7) | p[1];
return 2;
}
-
- /* The 3-byte case */
- p++;
- a = a<<14;
- a |= *p;
- /* a: p0<<14 | p2 (unmasked) */
- if (!(a&0x80))
- {
- /* Values between 16384 and 2097151 */
- a &= (0x7f<<14)|(0x7f);
- b &= 0x7f;
- b = b<<7;
- *v = a | b;
+ if( (p[2] & 0x80)==0 ){
+ /* This is the three-byte case */
+ *v = ((p[0]&0x7f)<<14) | ((p[1]&0x7f)<<7) | p[2];
return 3;
}
-
- /* A 32-bit varint is used to store size information in btrees.
- ** Objects are rarely larger than 2MiB limit of a 3-byte varint.
- ** A 3-byte varint is sufficient, for example, to record the size
- ** of a 1048569-byte BLOB or string.
- **
- ** We only unroll the first 1-, 2-, and 3- byte cases. The very
- ** rare larger cases can be handled by the slower 64-bit varint
- ** routine.
- */
-#if 1
- {
- u64 v64;
- u8 n;
-
- n = sqlcipher_sqlite3GetVarint(p-2, &v64);
- assert( n>3 && n<=9 );
- if( (v64 & SQLITE_MAX_U32)!=v64 ){
- *v = 0xffffffff;
- }else{
- *v = (u32)v64;
- }
- return n;
- }
-
-#else
- /* For following code (kept for historical record only) shows an
- ** unrolling for the 3- and 4-byte varint cases. This code is
- ** slightly faster, but it is also larger and much harder to test.
- */
- p++;
- b = b<<14;
- b |= *p;
- /* b: p1<<14 | p3 (unmasked) */
- if (!(b&0x80))
- {
- /* Values between 2097152 and 268435455 */
- b &= (0x7f<<14)|(0x7f);
- a &= (0x7f<<14)|(0x7f);
- a = a<<7;
- *v = a | b;
- return 4;
- }
-
- p++;
- a = a<<14;
- a |= *p;
- /* a: p0<<28 | p2<<14 | p4 (unmasked) */
- if (!(a&0x80))
- {
- /* Values between 268435456 and 34359738367 */
- a &= SLOT_4_2_0;
- b &= SLOT_4_2_0;
- b = b<<7;
- *v = a | b;
- return 5;
- }
-
- /* We can only reach this point when reading a corrupt database
- ** file. In that case we are not in any hurry. Use the (relatively
- ** slow) general-purpose sqlcipher_sqlite3GetVarint() routine to extract the
- ** value. */
- {
- u64 v64;
- u8 n;
-
- p -= 4;
- n = sqlcipher_sqlite3GetVarint(p, &v64);
- assert( n>5 && n<=9 );
+ /* four or more bytes */
+ n = sqlcipher_sqlite3GetVarint(p, &v64);
+ assert( n>3 && n<=9 );
+ if( (v64 & SQLITE_MAX_U32)!=v64 ){
+ *v = 0xffffffff;
+ }else{
*v = (u32)v64;
- return n;
}
-#endif
+ return n;
}
/*
@@ -34812,7 +36648,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3SafetyCheckSickOrOk(sqlcipher_sqlite3 *db){
}
/*
-** Attempt to add, substract, or multiply the 64-bit signed value iB against
+** Attempt to add, subtract, or multiply the 64-bit signed value iB against
** the other 64-bit signed integer at *pA and store the result in *pA.
** Return 0 on success. Or if the operation would have resulted in an
** overflow, leave *pA unchanged and return 1.
@@ -35098,6 +36934,104 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VListNameToNum(VList *pIn, const char *zName
return 0;
}
+/*
+** High-resolution hardware timer used for debugging and testing only.
+*/
+#if defined(VDBE_PROFILE) \
+ || defined(SQLITE_PERFORMANCE_TRACE) \
+ || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+/************** Include hwtime.h in the middle of util.c *********************/
+/************** Begin file hwtime.h ******************************************/
+/*
+** 2008 May 27
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains inline asm code for retrieving "high-performance"
+** counters for x86 and x86_64 class CPUs.
+*/
+#ifndef SQLITE_HWTIME_H
+#define SQLITE_HWTIME_H
+
+/*
+** The following routine only works on Pentium-class (or newer) processors.
+** It uses the RDTSC opcode to read the cycle count value out of the
+** processor and returns that value. This can be used for high-res
+** profiling.
+*/
+#if !defined(__STRICT_ANSI__) && \
+ (defined(__GNUC__) || defined(_MSC_VER)) && \
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
+
+ #if defined(__GNUC__)
+
+ __inline__ sqlite_uint64 sqlcipher_sqlite3Hwtime(void){
+ unsigned int lo, hi;
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
+ return (sqlite_uint64)hi << 32 | lo;
+ }
+
+ #elif defined(_MSC_VER)
+
+ __declspec(naked) __inline sqlite_uint64 __cdecl sqlcipher_sqlite3Hwtime(void){
+ __asm {
+ rdtsc
+ ret ; return value at EDX:EAX
+ }
+ }
+
+ #endif
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
+
+ __inline__ sqlite_uint64 sqlcipher_sqlite3Hwtime(void){
+ unsigned int lo, hi;
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
+ return (sqlite_uint64)hi << 32 | lo;
+ }
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
+
+ __inline__ sqlite_uint64 sqlcipher_sqlite3Hwtime(void){
+ unsigned long long retval;
+ unsigned long junk;
+ __asm__ __volatile__ ("\n\
+ 1: mftbu %1\n\
+ mftb %L0\n\
+ mftbu %0\n\
+ cmpw %0,%1\n\
+ bne 1b"
+ : "=r" (retval), "=r" (junk));
+ return retval;
+ }
+
+#else
+
+ /*
+ ** asm() is needed for hardware timing support. Without asm(),
+ ** disable the sqlcipher_sqlite3Hwtime() routine.
+ **
+ ** sqlcipher_sqlite3Hwtime() is only used for some obscure debugging
+ ** and analysis configurations, not in any deliverable, so this
+ ** should not be a great loss.
+ */
+SQLITE_PRIVATE sqlite_uint64 sqlcipher_sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
+
+#endif
+
+#endif /* !defined(SQLITE_HWTIME_H) */
+
+/************** End of hwtime.h **********************************************/
+/************** Continuing where we left off in util.c ***********************/
+#endif
+
/************** End of util.c ************************************************/
/************** Begin file hash.c ********************************************/
/*
@@ -35199,7 +37133,7 @@ static void insertElement(
}
-/* Resize the hash table so that it cantains "new_size" buckets.
+/* Resize the hash table so that it contains "new_size" buckets.
**
** The hash table might fail to resize if sqlcipher_sqlite3_malloc() fails or
** if the new size is the same as the prior size.
@@ -35268,12 +37202,13 @@ static HashElem *findElementWithHash(
count = pH->count;
}
if( pHash ) *pHash = h;
- while( count-- ){
+ while( count ){
assert( elem!=0 );
if( sqlcipher_sqlite3StrICmp(elem->pKey,pKey)==0 ){
return elem;
}
elem = elem->next;
+ count--;
}
return &nullElement;
}
@@ -35392,48 +37327,48 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3OpcodeName(int i){
/* 5 */ "Vacuum" OpHelp(""),
/* 6 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
/* 7 */ "VUpdate" OpHelp("data=r[P3@P2]"),
- /* 8 */ "Goto" OpHelp(""),
- /* 9 */ "Gosub" OpHelp(""),
- /* 10 */ "InitCoroutine" OpHelp(""),
- /* 11 */ "Yield" OpHelp(""),
- /* 12 */ "MustBeInt" OpHelp(""),
- /* 13 */ "Jump" OpHelp(""),
- /* 14 */ "Once" OpHelp(""),
- /* 15 */ "If" OpHelp(""),
- /* 16 */ "IfNot" OpHelp(""),
- /* 17 */ "IsNullOrType" OpHelp("if typeof(r[P1]) IN (P3,5) goto P2"),
- /* 18 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
+ /* 8 */ "Init" OpHelp("Start at P2"),
+ /* 9 */ "Goto" OpHelp(""),
+ /* 10 */ "Gosub" OpHelp(""),
+ /* 11 */ "InitCoroutine" OpHelp(""),
+ /* 12 */ "Yield" OpHelp(""),
+ /* 13 */ "MustBeInt" OpHelp(""),
+ /* 14 */ "Jump" OpHelp(""),
+ /* 15 */ "Once" OpHelp(""),
+ /* 16 */ "If" OpHelp(""),
+ /* 17 */ "IfNot" OpHelp(""),
+ /* 18 */ "IsType" OpHelp("if typeof(P1.P3) in P5 goto P2"),
/* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
- /* 20 */ "SeekLT" OpHelp("key=r[P3@P4]"),
- /* 21 */ "SeekLE" OpHelp("key=r[P3@P4]"),
- /* 22 */ "SeekGE" OpHelp("key=r[P3@P4]"),
- /* 23 */ "SeekGT" OpHelp("key=r[P3@P4]"),
- /* 24 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"),
- /* 25 */ "IfNoHope" OpHelp("key=r[P3@P4]"),
- /* 26 */ "NoConflict" OpHelp("key=r[P3@P4]"),
- /* 27 */ "NotFound" OpHelp("key=r[P3@P4]"),
- /* 28 */ "Found" OpHelp("key=r[P3@P4]"),
- /* 29 */ "SeekRowid" OpHelp("intkey=r[P3]"),
- /* 30 */ "NotExists" OpHelp("intkey=r[P3]"),
- /* 31 */ "Last" OpHelp(""),
- /* 32 */ "IfSmaller" OpHelp(""),
- /* 33 */ "SorterSort" OpHelp(""),
- /* 34 */ "Sort" OpHelp(""),
- /* 35 */ "Rewind" OpHelp(""),
- /* 36 */ "SorterNext" OpHelp(""),
- /* 37 */ "Prev" OpHelp(""),
- /* 38 */ "Next" OpHelp(""),
- /* 39 */ "IdxLE" OpHelp("key=r[P3@P4]"),
- /* 40 */ "IdxGT" OpHelp("key=r[P3@P4]"),
- /* 41 */ "IdxLT" OpHelp("key=r[P3@P4]"),
- /* 42 */ "IdxGE" OpHelp("key=r[P3@P4]"),
+ /* 20 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
+ /* 21 */ "SeekLT" OpHelp("key=r[P3@P4]"),
+ /* 22 */ "SeekLE" OpHelp("key=r[P3@P4]"),
+ /* 23 */ "SeekGE" OpHelp("key=r[P3@P4]"),
+ /* 24 */ "SeekGT" OpHelp("key=r[P3@P4]"),
+ /* 25 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"),
+ /* 26 */ "IfNoHope" OpHelp("key=r[P3@P4]"),
+ /* 27 */ "NoConflict" OpHelp("key=r[P3@P4]"),
+ /* 28 */ "NotFound" OpHelp("key=r[P3@P4]"),
+ /* 29 */ "Found" OpHelp("key=r[P3@P4]"),
+ /* 30 */ "SeekRowid" OpHelp("intkey=r[P3]"),
+ /* 31 */ "NotExists" OpHelp("intkey=r[P3]"),
+ /* 32 */ "Last" OpHelp(""),
+ /* 33 */ "IfSizeBetween" OpHelp(""),
+ /* 34 */ "SorterSort" OpHelp(""),
+ /* 35 */ "Sort" OpHelp(""),
+ /* 36 */ "Rewind" OpHelp(""),
+ /* 37 */ "SorterNext" OpHelp(""),
+ /* 38 */ "Prev" OpHelp(""),
+ /* 39 */ "Next" OpHelp(""),
+ /* 40 */ "IdxLE" OpHelp("key=r[P3@P4]"),
+ /* 41 */ "IdxGT" OpHelp("key=r[P3@P4]"),
+ /* 42 */ "IdxLT" OpHelp("key=r[P3@P4]"),
/* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
/* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
- /* 45 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
- /* 46 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
- /* 47 */ "Program" OpHelp(""),
- /* 48 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
- /* 49 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 45 */ "IdxGE" OpHelp("key=r[P3@P4]"),
+ /* 46 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
+ /* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
+ /* 48 */ "Program" OpHelp(""),
+ /* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
/* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
/* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
/* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
@@ -35443,12 +37378,12 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3OpcodeName(int i){
/* 56 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
/* 57 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
/* 58 */ "ElseEq" OpHelp(""),
- /* 59 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
- /* 60 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
- /* 61 */ "IncrVacuum" OpHelp(""),
- /* 62 */ "VNext" OpHelp(""),
- /* 63 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"),
- /* 64 */ "Init" OpHelp("Start at P2"),
+ /* 59 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 60 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
+ /* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
+ /* 62 */ "IncrVacuum" OpHelp(""),
+ /* 63 */ "VNext" OpHelp(""),
+ /* 64 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"),
/* 65 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"),
/* 66 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"),
/* 67 */ "Return" OpHelp(""),
@@ -35462,7 +37397,7 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3OpcodeName(int i){
/* 75 */ "Null" OpHelp("r[P2..P3]=NULL"),
/* 76 */ "SoftNull" OpHelp("r[P1]=NULL"),
/* 77 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
- /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
+ /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1)"),
/* 79 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
/* 80 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
/* 81 */ "SCopy" OpHelp("r[P2]=r[P1]"),
@@ -35558,25 +37493,1010 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3OpcodeName(int i){
/* 171 */ "VCreate" OpHelp(""),
/* 172 */ "VDestroy" OpHelp(""),
/* 173 */ "VOpen" OpHelp(""),
- /* 174 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"),
- /* 175 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
- /* 176 */ "VRename" OpHelp(""),
- /* 177 */ "Pagecount" OpHelp(""),
- /* 178 */ "MaxPgcnt" OpHelp(""),
- /* 179 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"),
- /* 180 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"),
- /* 181 */ "Trace" OpHelp(""),
- /* 182 */ "CursorHint" OpHelp(""),
- /* 183 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
- /* 184 */ "Noop" OpHelp(""),
- /* 185 */ "Explain" OpHelp(""),
- /* 186 */ "Abortable" OpHelp(""),
+ /* 174 */ "VCheck" OpHelp(""),
+ /* 175 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"),
+ /* 176 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
+ /* 177 */ "VRename" OpHelp(""),
+ /* 178 */ "Pagecount" OpHelp(""),
+ /* 179 */ "MaxPgcnt" OpHelp(""),
+ /* 180 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"),
+ /* 181 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"),
+ /* 182 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"),
+ /* 183 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"),
+ /* 184 */ "Trace" OpHelp(""),
+ /* 185 */ "CursorHint" OpHelp(""),
+ /* 186 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
+ /* 187 */ "Noop" OpHelp(""),
+ /* 188 */ "Explain" OpHelp(""),
+ /* 189 */ "Abortable" OpHelp(""),
};
return azName[i];
}
#endif
/************** End of opcodes.c *********************************************/
+/************** Begin file os_kv.c *******************************************/
+/*
+** 2022-09-06
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains an experimental VFS layer that operates on a
+** Key/Value storage engine where both keys and values must be pure
+** text.
+*/
+/* #include <sqliteInt.h> */
+#if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL))
+
+/*****************************************************************************
+** Debugging logic
+*/
+
+/* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */
+#if 0
+#define SQLITE_KV_TRACE(X) printf X
+#else
+#define SQLITE_KV_TRACE(X)
+#endif
+
+/* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */
+#if 0
+#define SQLITE_KV_LOG(X) printf X
+#else
+#define SQLITE_KV_LOG(X)
+#endif
+
+
+/*
+** Forward declaration of objects used by this VFS implementation
+*/
+typedef struct KVVfsFile KVVfsFile;
+
+/* A single open file. There are only two files represented by this
+** VFS - the database and the rollback journal.
+*/
+struct KVVfsFile {
+ sqlcipher_sqlite3_file base; /* IO methods */
+ const char *zClass; /* Storage class */
+ int isJournal; /* True if this is a journal file */
+ unsigned int nJrnl; /* Space allocated for aJrnl[] */
+ char *aJrnl; /* Journal content */
+ int szPage; /* Last known page size */
+ sqlcipher_sqlite3_int64 szDb; /* Database file size. -1 means unknown */
+ char *aData; /* Buffer to hold page data */
+};
+#define SQLITE_KVOS_SZ 133073
+
+/*
+** Methods for KVVfsFile
+*/
+static int kvvfsClose(sqlcipher_sqlite3_file*);
+static int kvvfsReadDb(sqlcipher_sqlite3_file*, void*, int iAmt, sqlcipher_sqlite3_int64 iOfst);
+static int kvvfsReadJrnl(sqlcipher_sqlite3_file*, void*, int iAmt, sqlcipher_sqlite3_int64 iOfst);
+static int kvvfsWriteDb(sqlcipher_sqlite3_file*,const void*,int iAmt, sqlcipher_sqlite3_int64);
+static int kvvfsWriteJrnl(sqlcipher_sqlite3_file*,const void*,int iAmt, sqlcipher_sqlite3_int64);
+static int kvvfsTruncateDb(sqlcipher_sqlite3_file*, sqlcipher_sqlite3_int64 size);
+static int kvvfsTruncateJrnl(sqlcipher_sqlite3_file*, sqlcipher_sqlite3_int64 size);
+static int kvvfsSyncDb(sqlcipher_sqlite3_file*, int flags);
+static int kvvfsSyncJrnl(sqlcipher_sqlite3_file*, int flags);
+static int kvvfsFileSizeDb(sqlcipher_sqlite3_file*, sqlcipher_sqlite3_int64 *pSize);
+static int kvvfsFileSizeJrnl(sqlcipher_sqlite3_file*, sqlcipher_sqlite3_int64 *pSize);
+static int kvvfsLock(sqlcipher_sqlite3_file*, int);
+static int kvvfsUnlock(sqlcipher_sqlite3_file*, int);
+static int kvvfsCheckReservedLock(sqlcipher_sqlite3_file*, int *pResOut);
+static int kvvfsFileControlDb(sqlcipher_sqlite3_file*, int op, void *pArg);
+static int kvvfsFileControlJrnl(sqlcipher_sqlite3_file*, int op, void *pArg);
+static int kvvfsSectorSize(sqlcipher_sqlite3_file*);
+static int kvvfsDeviceCharacteristics(sqlcipher_sqlite3_file*);
+
+/*
+** Methods for sqlcipher_sqlite3_vfs
+*/
+static int kvvfsOpen(sqlcipher_sqlite3_vfs*, const char *, sqlcipher_sqlite3_file*, int , int *);
+static int kvvfsDelete(sqlcipher_sqlite3_vfs*, const char *zName, int syncDir);
+static int kvvfsAccess(sqlcipher_sqlite3_vfs*, const char *zName, int flags, int *);
+static int kvvfsFullPathname(sqlcipher_sqlite3_vfs*, const char *zName, int, char *zOut);
+static void *kvvfsDlOpen(sqlcipher_sqlite3_vfs*, const char *zFilename);
+static int kvvfsRandomness(sqlcipher_sqlite3_vfs*, int nByte, char *zOut);
+static int kvvfsSleep(sqlcipher_sqlite3_vfs*, int microseconds);
+static int kvvfsCurrentTime(sqlcipher_sqlite3_vfs*, double*);
+static int kvvfsCurrentTimeInt64(sqlcipher_sqlite3_vfs*, sqlcipher_sqlite3_int64*);
+
+static sqlcipher_sqlite3_vfs sqlcipher_sqlite3OsKvvfsObject = {
+ 1, /* iVersion */
+ sizeof(KVVfsFile), /* szOsFile */
+ 1024, /* mxPathname */
+ 0, /* pNext */
+ "kvvfs", /* zName */
+ 0, /* pAppData */
+ kvvfsOpen, /* xOpen */
+ kvvfsDelete, /* xDelete */
+ kvvfsAccess, /* xAccess */
+ kvvfsFullPathname, /* xFullPathname */
+ kvvfsDlOpen, /* xDlOpen */
+ 0, /* xDlError */
+ 0, /* xDlSym */
+ 0, /* xDlClose */
+ kvvfsRandomness, /* xRandomness */
+ kvvfsSleep, /* xSleep */
+ kvvfsCurrentTime, /* xCurrentTime */
+ 0, /* xGetLastError */
+ kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */
+};
+
+/* Methods for sqlcipher_sqlite3_file objects referencing a database file
+*/
+static sqlcipher_sqlite3_io_methods kvvfs_db_io_methods = {
+ 1, /* iVersion */
+ kvvfsClose, /* xClose */
+ kvvfsReadDb, /* xRead */
+ kvvfsWriteDb, /* xWrite */
+ kvvfsTruncateDb, /* xTruncate */
+ kvvfsSyncDb, /* xSync */
+ kvvfsFileSizeDb, /* xFileSize */
+ kvvfsLock, /* xLock */
+ kvvfsUnlock, /* xUnlock */
+ kvvfsCheckReservedLock, /* xCheckReservedLock */
+ kvvfsFileControlDb, /* xFileControl */
+ kvvfsSectorSize, /* xSectorSize */
+ kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, /* xShmMap */
+ 0, /* xShmLock */
+ 0, /* xShmBarrier */
+ 0, /* xShmUnmap */
+ 0, /* xFetch */
+ 0 /* xUnfetch */
+};
+
+/* Methods for sqlcipher_sqlite3_file objects referencing a rollback journal
+*/
+static sqlcipher_sqlite3_io_methods kvvfs_jrnl_io_methods = {
+ 1, /* iVersion */
+ kvvfsClose, /* xClose */
+ kvvfsReadJrnl, /* xRead */
+ kvvfsWriteJrnl, /* xWrite */
+ kvvfsTruncateJrnl, /* xTruncate */
+ kvvfsSyncJrnl, /* xSync */
+ kvvfsFileSizeJrnl, /* xFileSize */
+ kvvfsLock, /* xLock */
+ kvvfsUnlock, /* xUnlock */
+ kvvfsCheckReservedLock, /* xCheckReservedLock */
+ kvvfsFileControlJrnl, /* xFileControl */
+ kvvfsSectorSize, /* xSectorSize */
+ kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, /* xShmMap */
+ 0, /* xShmLock */
+ 0, /* xShmBarrier */
+ 0, /* xShmUnmap */
+ 0, /* xFetch */
+ 0 /* xUnfetch */
+};
+
+/****** Storage subsystem **************************************************/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* Forward declarations for the low-level storage engine
+*/
+static int kvstorageWrite(const char*, const char *zKey, const char *zData);
+static int kvstorageDelete(const char*, const char *zKey);
+static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf);
+#define KVSTORAGE_KEY_SZ 32
+
+/* Expand the key name with an appropriate prefix and put the result
+** zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least
+** KVSTORAGE_KEY_SZ bytes.
+*/
+static void kvstorageMakeKey(
+ const char *zClass,
+ const char *zKeyIn,
+ char *zKeyOut
+){
+ sqlcipher_sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn);
+}
+
+/* Write content into a key. zClass is the particular namespace of the
+** underlying key/value store to use - either "local" or "session".
+**
+** Both zKey and zData are zero-terminated pure text strings.
+**
+** Return the number of errors.
+*/
+static int kvstorageWrite(
+ const char *zClass,
+ const char *zKey,
+ const char *zData
+){
+ FILE *fd;
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ fd = fopen(zXKey, "wb");
+ if( fd ){
+ SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey,
+ (int)strlen(zData), zData,
+ strlen(zData)>50 ? "..." : ""));
+ fputs(zData, fd);
+ fclose(fd);
+ return 0;
+ }else{
+ return 1;
+ }
+}
+
+/* Delete a key (with its corresponding data) from the key/value
+** namespace given by zClass. If the key does not previously exist,
+** this routine is a no-op.
+*/
+static int kvstorageDelete(const char *zClass, const char *zKey){
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ unlink(zXKey);
+ SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey));
+ return 0;
+}
+
+/* Read the value associated with a zKey from the key/value namespace given
+** by zClass and put the text data associated with that key in the first
+** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large
+** enough to hold it all. The value put into zBuf must always be zero
+** terminated, even if it gets truncated because nBuf is not large enough.
+**
+** Return the total number of bytes in the data, without truncation, and
+** not counting the final zero terminator. Return -1 if the key does
+** not exist.
+**
+** If nBuf<=0 then this routine simply returns the size of the data without
+** actually reading it.
+*/
+static int kvstorageRead(
+ const char *zClass,
+ const char *zKey,
+ char *zBuf,
+ int nBuf
+){
+ FILE *fd;
+ struct stat buf;
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ if( access(zXKey, R_OK)!=0
+ || stat(zXKey, &buf)!=0
+ || !S_ISREG(buf.st_mode)
+ ){
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
+ return -1;
+ }
+ if( nBuf<=0 ){
+ return (int)buf.st_size;
+ }else if( nBuf==1 ){
+ zBuf[0] = 0;
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey,
+ (int)buf.st_size));
+ return (int)buf.st_size;
+ }
+ if( nBuf > buf.st_size + 1 ){
+ nBuf = buf.st_size + 1;
+ }
+ fd = fopen(zXKey, "rb");
+ if( fd==0 ){
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
+ return -1;
+ }else{
+ sqlcipher_sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd);
+ fclose(fd);
+ zBuf[n] = 0;
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey,
+ n, zBuf, n>50 ? "..." : ""));
+ return (int)n;
+ }
+}
+
+/*
+** An internal level of indirection which enables us to replace the
+** kvvfs i/o methods with JavaScript implementations in WASM builds.
+** Maintenance reminder: if this struct changes in any way, the JSON
+** rendering of its structure must be updated in
+** sqlcipher_sqlite3_wasm_enum_json(). There are no binary compatibility
+** concerns, so it does not need an iVersion member. This file is
+** necessarily always compiled together with sqlcipher_sqlite3_wasm_enum_json(),
+** and JS code dynamically creates the mapping of members based on
+** that JSON description.
+*/
+typedef struct sqlcipher_sqlite3_kvvfs_methods sqlcipher_sqlite3_kvvfs_methods;
+struct sqlcipher_sqlite3_kvvfs_methods {
+ int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf);
+ int (*xWrite)(const char *zClass, const char *zKey, const char *zData);
+ int (*xDelete)(const char *zClass, const char *zKey);
+ const int nKeySize;
+};
+
+/*
+** This object holds the kvvfs I/O methods which may be swapped out
+** for JavaScript-side implementations in WASM builds. In such builds
+** it cannot be const, but in native builds it should be so that
+** the compiler can hopefully optimize this level of indirection out.
+** That said, kvvfs is intended primarily for use in WASM builds.
+**
+** Note that this is not explicitly flagged as static because the
+** amalgamation build will tag it with SQLITE_PRIVATE.
+*/
+#ifndef SQLITE_WASM
+const
+#endif
+SQLITE_PRIVATE sqlcipher_sqlite3_kvvfs_methods sqlcipher_sqlite3KvvfsMethods = {
+kvstorageRead,
+kvstorageWrite,
+kvstorageDelete,
+KVSTORAGE_KEY_SZ
+};
+
+/****** Utility subroutines ************************************************/
+
+/*
+** Encode binary into the text encoded used to persist on disk.
+** The output text is stored in aOut[], which must be at least
+** nData+1 bytes in length.
+**
+** Return the actual length of the encoded text, not counting the
+** zero terminator at the end.
+**
+** Encoding format
+** ---------------
+**
+** * Non-zero bytes are encoded as upper-case hexadecimal
+**
+** * A sequence of one or more zero-bytes that are not at the
+** beginning of the buffer are encoded as a little-endian
+** base-26 number using a..z. "a" means 0. "b" means 1,
+** "z" means 25. "ab" means 26. "ac" means 52. And so forth.
+**
+** * Because there is no overlap between the encoding characters
+** of hexadecimal and base-26 numbers, it is always clear where
+** one stops and the next begins.
+*/
+static int kvvfsEncode(const char *aData, int nData, char *aOut){
+ int i, j;
+ const unsigned char *a = (const unsigned char*)aData;
+ for(i=j=0; i<nData; i++){
+ unsigned char c = a[i];
+ if( c!=0 ){
+ aOut[j++] = "0123456789ABCDEF"[c>>4];
+ aOut[j++] = "0123456789ABCDEF"[c&0xf];
+ }else{
+ /* A sequence of 1 or more zeros is stored as a little-endian
+ ** base-26 number using a..z as the digits. So one zero is "b".
+ ** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb",
+ ** and so forth.
+ */
+ int k;
+ for(k=1; i+k<nData && a[i+k]==0; k++){}
+ i += k-1;
+ while( k>0 ){
+ aOut[j++] = 'a'+(k%26);
+ k /= 26;
+ }
+ }
+ }
+ aOut[j] = 0;
+ return j;
+}
+
+static const signed char kvvfsHexValue[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+/*
+** Decode the text encoding back to binary. The binary content is
+** written into pOut, which must be at least nOut bytes in length.
+**
+** The return value is the number of bytes actually written into aOut[].
+*/
+static int kvvfsDecode(const char *a, char *aOut, int nOut){
+ int i, j;
+ int c;
+ const unsigned char *aIn = (const unsigned char*)a;
+ i = 0;
+ j = 0;
+ while( 1 ){
+ c = kvvfsHexValue[aIn[i]];
+ if( c<0 ){
+ int n = 0;
+ int mult = 1;
+ c = aIn[i];
+ if( c==0 ) break;
+ while( c>='a' && c<='z' ){
+ n += (c - 'a')*mult;
+ mult *= 26;
+ c = aIn[++i];
+ }
+ if( j+n>nOut ) return -1;
+ memset(&aOut[j], 0, n);
+ j += n;
+ if( c==0 || mult==1 ) break; /* progress stalled if mult==1 */
+ }else{
+ aOut[j] = c<<4;
+ c = kvvfsHexValue[aIn[++i]];
+ if( c<0 ) break;
+ aOut[j++] += c;
+ i++;
+ }
+ }
+ return j;
+}
+
+/*
+** Decode a complete journal file. Allocate space in pFile->aJrnl
+** and store the decoding there. Or leave pFile->aJrnl set to NULL
+** if an error is encountered.
+**
+** The first few characters of the text encoding will be a little-endian
+** base-26 number (digits a..z) that is the total number of bytes
+** in the decoded journal file image. This base-26 number is followed
+** by a single space, then the encoding of the journal. The space
+** separator is required to act as a terminator for the base-26 number.
+*/
+static void kvvfsDecodeJournal(
+ KVVfsFile *pFile, /* Store decoding in pFile->aJrnl */
+ const char *zTxt, /* Text encoding. Zero-terminated */
+ int nTxt /* Bytes in zTxt, excluding zero terminator */
+){
+ unsigned int n = 0;
+ int c, i, mult;
+ i = 0;
+ mult = 1;
+ while( (c = zTxt[i++])>='a' && c<='z' ){
+ n += (zTxt[i] - 'a')*mult;
+ mult *= 26;
+ }
+ sqlcipher_sqlite3_free(pFile->aJrnl);
+ pFile->aJrnl = sqlcipher_sqlite3_malloc64( n );
+ if( pFile->aJrnl==0 ){
+ pFile->nJrnl = 0;
+ return;
+ }
+ pFile->nJrnl = n;
+ n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl);
+ if( n<pFile->nJrnl ){
+ sqlcipher_sqlite3_free(pFile->aJrnl);
+ pFile->aJrnl = 0;
+ pFile->nJrnl = 0;
+ }
+}
+
+/*
+** Read or write the "sz" element, containing the database file size.
+*/
+static sqlcipher_sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){
+ char zData[50];
+ zData[0] = 0;
+ sqlcipher_sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1);
+ return strtoll(zData, 0, 0);
+}
+static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlcipher_sqlite3_int64 sz){
+ char zData[50];
+ sqlcipher_sqlite3_snprintf(sizeof(zData), zData, "%lld", sz);
+ return sqlcipher_sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData);
+}
+
+/****** sqlcipher_sqlite3_io_methods methods ******************************************/
+
+/*
+** Close an kvvfs-file.
+*/
+static int kvvfsClose(sqlcipher_sqlite3_file *pProtoFile){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+
+ SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass,
+ pFile->isJournal ? "journal" : "db"));
+ sqlcipher_sqlite3_free(pFile->aJrnl);
+ sqlcipher_sqlite3_free(pFile->aData);
+ return SQLITE_OK;
+}
+
+/*
+** Read from the -journal file.
+*/
+static int kvvfsReadJrnl(
+ sqlcipher_sqlite3_file *pProtoFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ assert( pFile->isJournal );
+ SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ if( pFile->aJrnl==0 ){
+ int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0);
+ char *aTxt;
+ if( szTxt<=4 ){
+ return SQLITE_IOERR;
+ }
+ aTxt = sqlcipher_sqlite3_malloc64( szTxt+1 );
+ if( aTxt==0 ) return SQLITE_NOMEM;
+ kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1);
+ kvvfsDecodeJournal(pFile, aTxt, szTxt);
+ sqlcipher_sqlite3_free(aTxt);
+ if( pFile->aJrnl==0 ) return SQLITE_IOERR;
+ }
+ if( iOfst+iAmt>pFile->nJrnl ){
+ return SQLITE_IOERR_SHORT_READ;
+ }
+ memcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
+ return SQLITE_OK;
+}
+
+/*
+** Read from the database file.
+*/
+static int kvvfsReadDb(
+ sqlcipher_sqlite3_file *pProtoFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ unsigned int pgno;
+ int got, n;
+ char zKey[30];
+ char *aData = pFile->aData;
+ assert( iOfst>=0 );
+ assert( iAmt>=0 );
+ SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ if( iOfst+iAmt>=512 ){
+ if( (iOfst % iAmt)!=0 ){
+ return SQLITE_IOERR_READ;
+ }
+ if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){
+ return SQLITE_IOERR_READ;
+ }
+ pFile->szPage = iAmt;
+ pgno = 1 + iOfst/iAmt;
+ }else{
+ pgno = 1;
+ }
+ sqlcipher_sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
+ got = sqlcipher_sqlite3KvvfsMethods.xRead(pFile->zClass, zKey,
+ aData, SQLITE_KVOS_SZ-1);
+ if( got<0 ){
+ n = 0;
+ }else{
+ aData[got] = 0;
+ if( iOfst+iAmt<512 ){
+ int k = iOfst+iAmt;
+ aData[k*2] = 0;
+ n = kvvfsDecode(aData, &aData[2000], SQLITE_KVOS_SZ-2000);
+ if( n>=iOfst+iAmt ){
+ memcpy(zBuf, &aData[2000+iOfst], iAmt);
+ n = iAmt;
+ }else{
+ n = 0;
+ }
+ }else{
+ n = kvvfsDecode(aData, zBuf, iAmt);
+ }
+ }
+ if( n<iAmt ){
+ memset(zBuf+n, 0, iAmt-n);
+ return SQLITE_IOERR_SHORT_READ;
+ }
+ return SQLITE_OK;
+}
+
+
+/*
+** Write into the -journal file.
+*/
+static int kvvfsWriteJrnl(
+ sqlcipher_sqlite3_file *pProtoFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ sqlcipher_sqlite3_int64 iEnd = iOfst+iAmt;
+ SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ if( iEnd>=0x10000000 ) return SQLITE_FULL;
+ if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){
+ char *aNew = sqlcipher_sqlite3_realloc(pFile->aJrnl, iEnd);
+ if( aNew==0 ){
+ return SQLITE_IOERR_NOMEM;
+ }
+ pFile->aJrnl = aNew;
+ if( pFile->nJrnl<iOfst ){
+ memset(pFile->aJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl);
+ }
+ pFile->nJrnl = iEnd;
+ }
+ memcpy(pFile->aJrnl+iOfst, zBuf, iAmt);
+ return SQLITE_OK;
+}
+
+/*
+** Write into the database file.
+*/
+static int kvvfsWriteDb(
+ sqlcipher_sqlite3_file *pProtoFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ unsigned int pgno;
+ char zKey[30];
+ char *aData = pFile->aData;
+ SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ assert( iAmt>=512 && iAmt<=65536 );
+ assert( (iAmt & (iAmt-1))==0 );
+ assert( pFile->szPage<0 || pFile->szPage==iAmt );
+ pFile->szPage = iAmt;
+ pgno = 1 + iOfst/iAmt;
+ sqlcipher_sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
+ kvvfsEncode(zBuf, iAmt, aData);
+ if( sqlcipher_sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){
+ return SQLITE_IOERR;
+ }
+ if( iOfst+iAmt > pFile->szDb ){
+ pFile->szDb = iOfst + iAmt;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Truncate an kvvfs-file.
+*/
+static int kvvfsTruncateJrnl(sqlcipher_sqlite3_file *pProtoFile, sqlite_int64 size){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size));
+ assert( size==0 );
+ sqlcipher_sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl");
+ sqlcipher_sqlite3_free(pFile->aJrnl);
+ pFile->aJrnl = 0;
+ pFile->nJrnl = 0;
+ return SQLITE_OK;
+}
+static int kvvfsTruncateDb(sqlcipher_sqlite3_file *pProtoFile, sqlite_int64 size){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ if( pFile->szDb>size
+ && pFile->szPage>0
+ && (size % pFile->szPage)==0
+ ){
+ char zKey[50];
+ unsigned int pgno, pgnoMax;
+ SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size));
+ pgno = 1 + size/pFile->szPage;
+ pgnoMax = 2 + pFile->szDb/pFile->szPage;
+ while( pgno<=pgnoMax ){
+ sqlcipher_sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
+ sqlcipher_sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey);
+ pgno++;
+ }
+ pFile->szDb = size;
+ return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK;
+ }
+ return SQLITE_IOERR;
+}
+
+/*
+** Sync an kvvfs-file.
+*/
+static int kvvfsSyncJrnl(sqlcipher_sqlite3_file *pProtoFile, int flags){
+ int i, n;
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ char *zOut;
+ SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass));
+ if( pFile->nJrnl<=0 ){
+ return kvvfsTruncateJrnl(pProtoFile, 0);
+ }
+ zOut = sqlcipher_sqlite3_malloc64( pFile->nJrnl*2 + 50 );
+ if( zOut==0 ){
+ return SQLITE_IOERR_NOMEM;
+ }
+ n = pFile->nJrnl;
+ i = 0;
+ do{
+ zOut[i++] = 'a' + (n%26);
+ n /= 26;
+ }while( n>0 );
+ zOut[i++] = ' ';
+ kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
+ i = sqlcipher_sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut);
+ sqlcipher_sqlite3_free(zOut);
+ return i ? SQLITE_IOERR : SQLITE_OK;
+}
+static int kvvfsSyncDb(sqlcipher_sqlite3_file *pProtoFile, int flags){
+ return SQLITE_OK;
+}
+
+/*
+** Return the current file-size of an kvvfs-file.
+*/
+static int kvvfsFileSizeJrnl(sqlcipher_sqlite3_file *pProtoFile, sqlite_int64 *pSize){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass));
+ *pSize = pFile->nJrnl;
+ return SQLITE_OK;
+}
+static int kvvfsFileSizeDb(sqlcipher_sqlite3_file *pProtoFile, sqlite_int64 *pSize){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass));
+ if( pFile->szDb>=0 ){
+ *pSize = pFile->szDb;
+ }else{
+ *pSize = kvvfsReadFileSize(pFile);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Lock an kvvfs-file.
+*/
+static int kvvfsLock(sqlcipher_sqlite3_file *pProtoFile, int eLock){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ assert( !pFile->isJournal );
+ SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock));
+
+ if( eLock!=SQLITE_LOCK_NONE ){
+ pFile->szDb = kvvfsReadFileSize(pFile);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Unlock an kvvfs-file.
+*/
+static int kvvfsUnlock(sqlcipher_sqlite3_file *pProtoFile, int eLock){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ assert( !pFile->isJournal );
+ SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock));
+ if( eLock==SQLITE_LOCK_NONE ){
+ pFile->szDb = -1;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on an kvvfs-file.
+*/
+static int kvvfsCheckReservedLock(sqlcipher_sqlite3_file *pProtoFile, int *pResOut){
+ SQLITE_KV_LOG(("xCheckReservedLock\n"));
+ *pResOut = 0;
+ return SQLITE_OK;
+}
+
+/*
+** File control method. For custom operations on an kvvfs-file.
+*/
+static int kvvfsFileControlJrnl(sqlcipher_sqlite3_file *pProtoFile, int op, void *pArg){
+ SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op));
+ return SQLITE_NOTFOUND;
+}
+static int kvvfsFileControlDb(sqlcipher_sqlite3_file *pProtoFile, int op, void *pArg){
+ SQLITE_KV_LOG(("xFileControl(%d) on database\n", op));
+ if( op==SQLITE_FCNTL_SYNC ){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ int rc = SQLITE_OK;
+ SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass));
+ if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){
+ rc = SQLITE_IOERR;
+ }
+ return rc;
+ }
+ return SQLITE_NOTFOUND;
+}
+
+/*
+** Return the sector-size in bytes for an kvvfs-file.
+*/
+static int kvvfsSectorSize(sqlcipher_sqlite3_file *pFile){
+ return 512;
+}
+
+/*
+** Return the device characteristic flags supported by an kvvfs-file.
+*/
+static int kvvfsDeviceCharacteristics(sqlcipher_sqlite3_file *pProtoFile){
+ return 0;
+}
+
+/****** sqlcipher_sqlite3_vfs methods *************************************************/
+
+/*
+** Open an kvvfs file handle.
+*/
+static int kvvfsOpen(
+ sqlcipher_sqlite3_vfs *pProtoVfs,
+ const char *zName,
+ sqlcipher_sqlite3_file *pProtoFile,
+ int flags,
+ int *pOutFlags
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ if( zName==0 ) zName = "";
+ SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName));
+ if( strcmp(zName, "local")==0
+ || strcmp(zName, "session")==0
+ ){
+ pFile->isJournal = 0;
+ pFile->base.pMethods = &kvvfs_db_io_methods;
+ }else
+ if( strcmp(zName, "local-journal")==0
+ || strcmp(zName, "session-journal")==0
+ ){
+ pFile->isJournal = 1;
+ pFile->base.pMethods = &kvvfs_jrnl_io_methods;
+ }else{
+ return SQLITE_CANTOPEN;
+ }
+ if( zName[0]=='s' ){
+ pFile->zClass = "session";
+ }else{
+ pFile->zClass = "local";
+ }
+ pFile->aData = sqlcipher_sqlite3_malloc64(SQLITE_KVOS_SZ);
+ if( pFile->aData==0 ){
+ return SQLITE_NOMEM;
+ }
+ pFile->aJrnl = 0;
+ pFile->nJrnl = 0;
+ pFile->szPage = -1;
+ pFile->szDb = -1;
+ return SQLITE_OK;
+}
+
+/*
+** Delete the file located at zPath. If the dirSync argument is true,
+** ensure the file-system modifications are synced to disk before
+** returning.
+*/
+static int kvvfsDelete(sqlcipher_sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ if( strcmp(zPath, "local-journal")==0 ){
+ sqlcipher_sqlite3KvvfsMethods.xDelete("local", "jrnl");
+ }else
+ if( strcmp(zPath, "session-journal")==0 ){
+ sqlcipher_sqlite3KvvfsMethods.xDelete("session", "jrnl");
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Test for access permissions. Return true if the requested permission
+** is available, or false otherwise.
+*/
+static int kvvfsAccess(
+ sqlcipher_sqlite3_vfs *pProtoVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath));
+ if( strcmp(zPath, "local-journal")==0 ){
+ *pResOut = sqlcipher_sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0;
+ }else
+ if( strcmp(zPath, "session-journal")==0 ){
+ *pResOut = sqlcipher_sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0;
+ }else
+ if( strcmp(zPath, "local")==0 ){
+ *pResOut = sqlcipher_sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0;
+ }else
+ if( strcmp(zPath, "session")==0 ){
+ *pResOut = sqlcipher_sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0;
+ }else
+ {
+ *pResOut = 0;
+ }
+ SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut));
+ return SQLITE_OK;
+}
+
+/*
+** Populate buffer zOut with the full canonical pathname corresponding
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
+** of at least (INST_MAX_PATHNAME+1) bytes.
+*/
+static int kvvfsFullPathname(
+ sqlcipher_sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ size_t nPath;
+#ifdef SQLITE_OS_KV_ALWAYS_LOCAL
+ zPath = "local";
+#endif
+ nPath = strlen(zPath);
+ SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath));
+ if( nOut<nPath+1 ) nPath = nOut - 1;
+ memcpy(zOut, zPath, nPath);
+ zOut[nPath] = 0;
+ return SQLITE_OK;
+}
+
+/*
+** Open the dynamic library located at zPath and return a handle.
+*/
+static void *kvvfsDlOpen(sqlcipher_sqlite3_vfs *pVfs, const char *zPath){
+ return 0;
+}
+
+/*
+** Populate the buffer pointed to by zBufOut with nByte bytes of
+** random data.
+*/
+static int kvvfsRandomness(sqlcipher_sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ memset(zBufOut, 0, nByte);
+ return nByte;
+}
+
+/*
+** Sleep for nMicro microseconds. Return the number of microseconds
+** actually slept.
+*/
+static int kvvfsSleep(sqlcipher_sqlite3_vfs *pVfs, int nMicro){
+ return SQLITE_OK;
+}
+
+/*
+** Return the current time as a Julian Day number in *pTimeOut.
+*/
+static int kvvfsCurrentTime(sqlcipher_sqlite3_vfs *pVfs, double *pTimeOut){
+ sqlcipher_sqlite3_int64 i = 0;
+ int rc;
+ rc = kvvfsCurrentTimeInt64(0, &i);
+ *pTimeOut = i/86400000.0;
+ return rc;
+}
+#include <sys/time.h>
+static int kvvfsCurrentTimeInt64(sqlcipher_sqlite3_vfs *pVfs, sqlcipher_sqlite3_int64 *pTimeOut){
+ static const sqlcipher_sqlite3_int64 unixEpoch = 24405875*(sqlcipher_sqlite3_int64)8640000;
+ struct timeval sNow;
+ (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
+ *pTimeOut = unixEpoch + 1000*(sqlcipher_sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
+ return SQLITE_OK;
+}
+#endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */
+
+#if SQLITE_OS_KV
+/*
+** This routine is called initialize the KV-vfs as the default VFS.
+*/
+SQLITE_API int sqlcipher_sqlite3_os_init(void){
+ return sqlcipher_sqlite3_vfs_register(&sqlcipher_sqlite3OsKvvfsObject, 1);
+}
+SQLITE_API int sqlcipher_sqlite3_os_end(void){
+ return SQLITE_OK;
+}
+#endif /* SQLITE_OS_KV */
+
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
+SQLITE_PRIVATE int sqlcipher_sqlite3KvvfsInit(void){
+ return sqlcipher_sqlite3_vfs_register(&sqlcipher_sqlite3OsKvvfsObject, 0);
+}
+#endif
+
+/************** End of os_kv.c ***********************************************/
/************** Begin file os_unix.c *****************************************/
/*
** 2004 May 22
@@ -35602,7 +38522,7 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3OpcodeName(int i){
** This source file is organized into divisions where the logic for various
** subfunctions is contained within the appropriate division. PLEASE
** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed
-** in the correct division and should be clearly labeled.
+** in the correct division and should be clearly labelled.
**
** The layout of divisions is as follows:
**
@@ -35652,7 +38572,7 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3OpcodeName(int i){
#endif
/* Use pread() and pwrite() if they are available */
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__linux__)
# define HAVE_PREAD 1
# define HAVE_PWRITE 1
#endif
@@ -35667,15 +38587,16 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3OpcodeName(int i){
/*
** standard include files.
*/
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <sys/types.h> /* amalgamator: keep */
+#include <sys/stat.h> /* amalgamator: keep */
#include <fcntl.h>
#include <sys/ioctl.h>
-#include <unistd.h>
+#include <unistd.h> /* amalgamator: keep */
/* #include <time.h> */
-#include <sys/time.h>
+#include <sys/time.h> /* amalgamator: keep */
#include <errno.h>
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
+ && !defined(SQLITE_WASI)
# include <sys/mman.h>
#endif
@@ -35763,9 +38684,46 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3OpcodeName(int i){
*/
#define SQLITE_MAX_SYMLINKS 100
+/*
+** Remove and stub certain info for WASI (WebAssembly System
+** Interface) builds.
+*/
+#ifdef SQLITE_WASI
+# undef HAVE_FCHMOD
+# undef HAVE_FCHOWN
+# undef HAVE_MREMAP
+# define HAVE_MREMAP 0
+# ifndef SQLITE_DEFAULT_UNIX_VFS
+# define SQLITE_DEFAULT_UNIX_VFS "unix-dotfile"
+ /* ^^^ should SQLITE_DEFAULT_UNIX_VFS be "unix-none"? */
+# endif
+# ifndef F_RDLCK
+# define F_RDLCK 0
+# define F_WRLCK 1
+# define F_UNLCK 2
+# if __LONG_MAX == 0x7fffffffL
+# define F_GETLK 12
+# define F_SETLK 13
+# define F_SETLKW 14
+# else
+# define F_GETLK 5
+# define F_SETLK 6
+# define F_SETLKW 7
+# endif
+# endif
+#else /* !SQLITE_WASI */
+# ifndef HAVE_FCHMOD
+# define HAVE_FCHMOD
+# endif
+#endif /* SQLITE_WASI */
+
+#ifdef SQLITE_WASI
+# define osGetpid(X) (pid_t)1
+#else
/* Always cast the getpid() return type for compatibility with
** kernel modules in VxWorks. */
-#define osGetpid(X) (pid_t)getpid()
+# define osGetpid(X) (pid_t)getpid()
+#endif
/*
** Only set the lastErrno if the error code is a real error and not
@@ -36037,7 +38995,11 @@ static struct unix_syscall {
#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\
aSyscall[13].pCurrent)
+#if defined(HAVE_FCHMOD)
{ "fchmod", (sqlcipher_sqlite3_syscall_ptr)fchmod, 0 },
+#else
+ { "fchmod", (sqlcipher_sqlite3_syscall_ptr)0, 0 },
+#endif
#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
@@ -36073,14 +39035,16 @@ static struct unix_syscall {
#endif
#define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent)
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
+ && !defined(SQLITE_WASI)
{ "mmap", (sqlcipher_sqlite3_syscall_ptr)mmap, 0 },
#else
{ "mmap", (sqlcipher_sqlite3_syscall_ptr)0, 0 },
#endif
#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
+ && !defined(SQLITE_WASI)
{ "munmap", (sqlcipher_sqlite3_syscall_ptr)munmap, 0 },
#else
{ "munmap", (sqlcipher_sqlite3_syscall_ptr)0, 0 },
@@ -36145,7 +39109,7 @@ static int robustFchown(int fd, uid_t uid, gid_t gid){
/*
** This is the xSetSystemCall() method of sqlcipher_sqlite3_vfs for all of the
-** "unix" VFSes. Return SQLITE_OK opon successfully updating the
+** "unix" VFSes. Return SQLITE_OK upon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
*/
@@ -36266,6 +39230,9 @@ static int robust_open(const char *z, int f, mode_t m){
break;
}
if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break;
+ if( (f & (O_EXCL|O_CREAT))==(O_EXCL|O_CREAT) ){
+ (void)osUnlink(z);
+ }
osClose(fd);
sqlcipher_sqlite3_log(SQLITE_WARNING,
"attempt to open \"%s\" as file descriptor %d", z, fd);
@@ -36664,7 +39631,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
** If you close a file descriptor that points to a file that has locks,
** all locks on that file that are owned by the current process are
** released. To work around this problem, each unixInodeInfo object
-** maintains a count of the number of pending locks on tha inode.
+** maintains a count of the number of pending locks on the inode.
** When an attempt is made to close an unixFile, if there are
** other unixFile open on the same inode that are holding locks, the call
** to close() the file descriptor is deferred until all of the locks clear.
@@ -36678,7 +39645,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
** not posix compliant. Under LinuxThreads, a lock created by thread
** A cannot be modified or overridden by a different thread B.
** Only thread A can modify the lock. Locking behavior is correct
-** if the appliation uses the newer Native Posix Thread Library (NPTL)
+** if the application uses the newer Native Posix Thread Library (NPTL)
** on linux - with NPTL a lock created by thread A can override locks
** in thread B. But there is no way to know at compile-time which
** threading library is being used. So there is no way to know at
@@ -36828,8 +39795,12 @@ static int unixLogErrorAtLine(
** available, the error message will often be an empty string. Not a
** huge problem. Incorrectly concluding that the GNU version is available
** could lead to a segfault though.
+ **
+ ** Forum post 3f13857fa4062301 reports that the Android SDK may use
+ ** int-type return, depending on its version.
*/
-#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
+#if (defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)) \
+ && !defined(ANDROID) && !defined(__ANDROID__)
zErr =
# endif
strerror_r(iErrno, aErr, sizeof(aErr)-1);
@@ -36880,7 +39851,7 @@ static void storeLastErrno(unixFile *pFile, int error){
}
/*
-** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
+** Close all file descriptors accumulated in the unixInodeInfo->pUnused list.
*/
static void closePendingFds(unixFile *pFile){
unixInodeInfo *pInode = pFile->pInode;
@@ -37228,7 +40199,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
**
** UNLOCKED -> SHARED
** SHARED -> RESERVED
-** SHARED -> (PENDING) -> EXCLUSIVE
+** SHARED -> EXCLUSIVE
** RESERVED -> (PENDING) -> EXCLUSIVE
** PENDING -> EXCLUSIVE
**
@@ -37243,7 +40214,7 @@ static int unixLock(sqlcipher_sqlite3_file *id, int eFileLock){
** slightly in order to be compatible with Windows95 systems simultaneously
** accessing the same database file, in case that is ever required.
**
- ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
+ ** Symbols defined in os.h identify the 'pending byte' and the 'reserved
** byte', each single bytes at well known offsets, and the 'shared byte
** range', a range of 510 bytes at a well known offset.
**
@@ -37251,7 +40222,7 @@ static int unixLock(sqlcipher_sqlite3_file *id, int eFileLock){
** byte'. If this is successful, 'shared byte range' is read-locked
** and the lock on the 'pending byte' released. (Legacy note: When
** SQLite was first developed, Windows95 systems were still very common,
- ** and Widnows95 lacks a shared-lock capability. So on Windows95, a
+ ** and Windows95 lacks a shared-lock capability. So on Windows95, a
** single randomly selected by from the 'shared byte range' is locked.
** Windows95 is now pretty much extinct, but this work-around for the
** lack of shared-locks on Windows95 lives on, for backwards
@@ -37261,19 +40232,20 @@ static int unixLock(sqlcipher_sqlite3_file *id, int eFileLock){
** A RESERVED lock is implemented by grabbing a write-lock on the
** 'reserved byte'.
**
- ** A process may only obtain a PENDING lock after it has obtained a
- ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock
- ** on the 'pending byte'. This ensures that no new SHARED locks can be
- ** obtained, but existing SHARED locks are allowed to persist. A process
- ** does not have to obtain a RESERVED lock on the way to a PENDING lock.
- ** This property is used by the algorithm for rolling back a journal file
- ** after a crash.
+ ** An EXCLUSIVE lock may only be requested after either a SHARED or
+ ** RESERVED lock is held. An EXCLUSIVE lock is implemented by obtaining
+ ** a write-lock on the entire 'shared byte range'. Since all other locks
+ ** require a read-lock on one of the bytes within this range, this ensures
+ ** that no other locks are held on the database.
**
- ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is
- ** implemented by obtaining a write-lock on the entire 'shared byte
- ** range'. Since all other locks require a read-lock on one of the bytes
- ** within this range, this ensures that no other locks are held on the
- ** database.
+ ** If a process that holds a RESERVED lock requests an EXCLUSIVE, then
+ ** a PENDING lock is obtained first. A PENDING lock is implemented by
+ ** obtaining a write-lock on the 'pending byte'. This ensures that no new
+ ** SHARED locks can be obtained, but existing SHARED locks are allowed to
+ ** persist. If the call to this function fails to obtain the EXCLUSIVE
+ ** lock in this case, it holds the PENDING lock instead. The client may
+ ** then re-attempt the EXCLUSIVE lock later on, after existing SHARED
+ ** locks have cleared.
*/
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
@@ -37299,7 +40271,7 @@ static int unixLock(sqlcipher_sqlite3_file *id, int eFileLock){
/* Make sure the locking sequence is correct.
** (1) We never move from unlocked to anything higher than shared lock.
- ** (2) SQLite never explicitly requests a pendig lock.
+ ** (2) SQLite never explicitly requests a pending lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
@@ -37344,7 +40316,7 @@ static int unixLock(sqlcipher_sqlite3_file *id, int eFileLock){
lock.l_len = 1L;
lock.l_whence = SEEK_SET;
if( eFileLock==SHARED_LOCK
- || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
+ || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock==RESERVED_LOCK)
){
lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
lock.l_start = PENDING_BYTE;
@@ -37355,6 +40327,9 @@ static int unixLock(sqlcipher_sqlite3_file *id, int eFileLock){
storeLastErrno(pFile, tErrno);
}
goto end_lock;
+ }else if( eFileLock==EXCLUSIVE_LOCK ){
+ pFile->eFileLock = PENDING_LOCK;
+ pInode->eFileLock = PENDING_LOCK;
}
}
@@ -37442,13 +40417,9 @@ static int unixLock(sqlcipher_sqlite3_file *id, int eFileLock){
}
#endif
-
if( rc==SQLITE_OK ){
pFile->eFileLock = eFileLock;
pInode->eFileLock = eFileLock;
- }else if( eFileLock==EXCLUSIVE_LOCK ){
- pFile->eFileLock = PENDING_LOCK;
- pInode->eFileLock = PENDING_LOCK;
}
end_lock:
@@ -38518,7 +41489,7 @@ static int afpLock(sqlcipher_sqlite3_file *id, int eFileLock){
/* Make sure the locking sequence is correct
** (1) We never move from unlocked to anything higher than shared lock.
- ** (2) SQLite never explicitly requests a pendig lock.
+ ** (2) SQLite never explicitly requests a pending lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
@@ -38634,7 +41605,7 @@ static int afpLock(sqlcipher_sqlite3_file *id, int eFileLock){
if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST +
pInode->sharedByte, 1, 0)) ){
int failed2 = SQLITE_OK;
- /* now attemmpt to get the exclusive lock range */
+ /* now attempt to get the exclusive lock range */
failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
SHARED_SIZE, 1);
if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
@@ -38683,9 +41654,6 @@ static int afpUnlock(sqlcipher_sqlite3_file *id, int eFileLock) {
unixInodeInfo *pInode;
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
int skipShared = 0;
-#ifdef SQLITE_TEST
- int h = pFile->h;
-#endif
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock,
@@ -38701,9 +41669,6 @@ static int afpUnlock(sqlcipher_sqlite3_file *id, int eFileLock) {
assert( pInode->nShared!=0 );
if( pFile->eFileLock>SHARED_LOCK ){
assert( pInode->eFileLock==pFile->eFileLock );
- SimulateIOErrorBenign(1);
- SimulateIOError( h=(-1) )
- SimulateIOErrorBenign(0);
#ifdef SQLITE_DEBUG
/* When reducing a lock such that other processes can start
@@ -38752,9 +41717,6 @@ static int afpUnlock(sqlcipher_sqlite3_file *id, int eFileLock) {
unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte;
pInode->nShared--;
if( pInode->nShared==0 ){
- SimulateIOErrorBenign(1);
- SimulateIOError( h=(-1) )
- SimulateIOErrorBenign(0);
if( !skipShared ){
rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0);
}
@@ -38855,12 +41817,6 @@ static int nfsUnlock(sqlcipher_sqlite3_file *id, int eFileLock){
** Seek to the offset passed as the second argument, then read cnt
** bytes into pBuf. Return the number of bytes actually read.
**
-** NB: If you define USE_PREAD or USE_PREAD64, then it might also
-** be necessary to define _XOPEN_SOURCE to be 500. This varies from
-** one system to another. Since SQLite does not define USE_PREAD
-** in any form by default, we will not attempt to define _XOPEN_SOURCE.
-** See tickets #2741 and #2681.
-**
** To avoid stomping the errno value on a failed read the lastErrno value
** is set before returning.
*/
@@ -38935,7 +41891,7 @@ static int unixRead(
#endif
#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
+ /* Deal with as much of this read request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -39087,7 +42043,7 @@ static int unixWrite(
#endif
#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
+ /* Deal with as much of this write request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -39209,7 +42165,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
/* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
** no-op. But go ahead and call fstat() to validate the file
** descriptor as we need a method to provoke a failure during
- ** coverate testing.
+ ** coverage testing.
*/
#ifdef SQLITE_NO_SYNC
{
@@ -39602,7 +42558,13 @@ static int unixFileControl(sqlcipher_sqlite3_file *id, int op, void *pArg){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
case SQLITE_FCNTL_LOCK_TIMEOUT: {
int iOld = pFile->iBusyTimeout;
+#if SQLITE_ENABLE_SETLK_TIMEOUT==1
pFile->iBusyTimeout = *(int*)pArg;
+#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
+ pFile->iBusyTimeout = !!(*(int*)pArg);
+#else
+# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
+#endif
*(int*)pArg = iOld;
return SQLITE_OK;
}
@@ -39855,6 +42817,25 @@ static int unixGetpagesize(void){
** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and
** unixMutexHeld() is true when reading or writing any other field
** in this structure.
+**
+** aLock[SQLITE_SHM_NLOCK]:
+** This array records the various locks held by clients on each of the
+** SQLITE_SHM_NLOCK slots. If the aLock[] entry is set to 0, then no
+** locks are held by the process on this slot. If it is set to -1, then
+** some client holds an EXCLUSIVE lock on the locking slot. If the aLock[]
+** value is set to a positive value, then it is the number of shared
+** locks currently held on the slot.
+**
+** aMutex[SQLITE_SHM_NLOCK]:
+** Normally, when SQLITE_ENABLE_SETLK_TIMEOUT is not defined, mutex
+** pShmMutex is used to protect the aLock[] array and the right to
+** call fcntl() on unixShmNode.hShm to obtain or release locks.
+**
+** If SQLITE_ENABLE_SETLK_TIMEOUT is defined though, we use an array
+** of mutexes - one for each locking slot. To read or write locking
+** slot aLock[iSlot], the caller must hold the corresponding mutex
+** aMutex[iSlot]. Similarly, to call fcntl() to obtain or release a
+** lock corresponding to slot iSlot, mutex aMutex[iSlot] must be held.
*/
struct unixShmNode {
unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
@@ -39868,10 +42849,11 @@ struct unixShmNode {
char **apRegion; /* Array of mapped shared-memory regions */
int nRef; /* Number of unixShm objects pointing to this */
unixShm *pFirst; /* All unixShm objects pointing to this */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ sqlcipher_sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK];
+#endif
int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */
#ifdef SQLITE_DEBUG
- u8 exclMask; /* Mask of exclusive locks held */
- u8 sharedMask; /* Mask of shared locks held */
u8 nextShmId; /* Next available unixShm.id value */
#endif
};
@@ -39954,16 +42936,35 @@ static int unixShmSystemLock(
struct flock f; /* The posix advisory locking structure */
int rc = SQLITE_OK; /* Result code form fcntl() */
- /* Access to the unixShmNode object is serialized by the caller */
pShmNode = pFile->pInode->pShmNode;
- assert( pShmNode->nRef==0 || sqlcipher_sqlite3_mutex_held(pShmNode->pShmMutex) );
- assert( pShmNode->nRef>0 || unixMutexHeld() );
+
+ /* Assert that the parameters are within expected range and that the
+ ** correct mutex or mutexes are held. */
+ assert( pShmNode->nRef>=0 );
+ assert( (ofst==UNIX_SHM_DMS && n==1)
+ || (ofst>=UNIX_SHM_BASE && ofst+n<=(UNIX_SHM_BASE+SQLITE_SHM_NLOCK))
+ );
+ if( ofst==UNIX_SHM_DMS ){
+ assert( pShmNode->nRef>0 || unixMutexHeld() );
+ assert( pShmNode->nRef==0 || sqlcipher_sqlite3_mutex_held(pShmNode->pShmMutex) );
+ }else{
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ int ii;
+ for(ii=ofst-UNIX_SHM_BASE; ii<ofst-UNIX_SHM_BASE+n; ii++){
+ assert( sqlcipher_sqlite3_mutex_held(pShmNode->aMutex[ii]) );
+ }
+#else
+ assert( sqlcipher_sqlite3_mutex_held(pShmNode->pShmMutex) );
+ assert( pShmNode->nRef>0 );
+#endif
+ }
/* Shared locks never span more than one byte */
assert( n==1 || lockType!=F_RDLCK );
/* Locks are within range */
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
+ assert( ofst>=UNIX_SHM_BASE && ofst<=(UNIX_SHM_DMS+SQLITE_SHM_NLOCK) );
if( pShmNode->hShm>=0 ){
int res;
@@ -39974,7 +42975,7 @@ static int unixShmSystemLock(
f.l_len = n;
res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
if( res==-1 ){
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && SQLITE_ENABLE_SETLK_TIMEOUT==1
rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
#else
rc = SQLITE_BUSY;
@@ -39982,39 +42983,28 @@ static int unixShmSystemLock(
}
}
- /* Update the global lock state and do debug tracing */
+ /* Do debug tracing */
#ifdef SQLITE_DEBUG
- { u16 mask;
OSTRACE(("SHM-LOCK "));
- mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<<ofst);
if( rc==SQLITE_OK ){
if( lockType==F_UNLCK ){
- OSTRACE(("unlock %d ok", ofst));
- pShmNode->exclMask &= ~mask;
- pShmNode->sharedMask &= ~mask;
+ OSTRACE(("unlock %d..%d ok\n", ofst, ofst+n-1));
}else if( lockType==F_RDLCK ){
- OSTRACE(("read-lock %d ok", ofst));
- pShmNode->exclMask &= ~mask;
- pShmNode->sharedMask |= mask;
+ OSTRACE(("read-lock %d..%d ok\n", ofst, ofst+n-1));
}else{
assert( lockType==F_WRLCK );
- OSTRACE(("write-lock %d ok", ofst));
- pShmNode->exclMask |= mask;
- pShmNode->sharedMask &= ~mask;
+ OSTRACE(("write-lock %d..%d ok\n", ofst, ofst+n-1));
}
}else{
if( lockType==F_UNLCK ){
- OSTRACE(("unlock %d failed", ofst));
+ OSTRACE(("unlock %d..%d failed\n", ofst, ofst+n-1));
}else if( lockType==F_RDLCK ){
- OSTRACE(("read-lock failed"));
+ OSTRACE(("read-lock %d..%d failed\n", ofst, ofst+n-1));
}else{
assert( lockType==F_WRLCK );
- OSTRACE(("write-lock %d failed", ofst));
+ OSTRACE(("write-lock %d..%d failed\n", ofst, ofst+n-1));
}
}
- OSTRACE((" - afterwards %03x,%03x\n",
- pShmNode->sharedMask, pShmNode->exclMask));
- }
#endif
return rc;
@@ -40051,6 +43041,11 @@ static void unixShmPurge(unixFile *pFd){
int i;
assert( p->pInode==pFd->pInode );
sqlcipher_sqlite3_mutex_free(p->pShmMutex);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ for(i=0; i<SQLITE_SHM_NLOCK; i++){
+ sqlcipher_sqlite3_mutex_free(p->aMutex[i]);
+ }
+#endif
for(i=0; i<p->nRegion; i+=nShmPerMap){
if( p->hShm>=0 ){
osMunmap(p->apRegion[i], p->szRegion);
@@ -40110,7 +43105,20 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
pShmNode->isUnlocked = 1;
rc = SQLITE_READONLY_CANTINIT;
}else{
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ /* Do not use a blocking lock here. If the lock cannot be obtained
+ ** immediately, it means some other connection is truncating the
+ ** *-shm file. And after it has done so, it will not release its
+ ** lock, but only downgrade it to a shared lock. So no point in
+ ** blocking here. The call below to obtain the shared DMS lock may
+ ** use a blocking lock. */
+ int iSaveTimeout = pDbFd->iBusyTimeout;
+ pDbFd->iBusyTimeout = 0;
+#endif
rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ pDbFd->iBusyTimeout = iSaveTimeout;
+#endif
/* The first connection to attach must truncate the -shm file. We
** truncate to 3 bytes (an arbitrary small number, less than the
** -shm header size) rather than 0 as a system debugging aid, to
@@ -40231,6 +43239,18 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
rc = SQLITE_NOMEM_BKPT;
goto shm_open_err;
}
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ {
+ int ii;
+ for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
+ pShmNode->aMutex[ii] = sqlcipher_sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->aMutex[ii]==0 ){
+ rc = SQLITE_NOMEM_BKPT;
+ goto shm_open_err;
+ }
+ }
+ }
+#endif
}
if( pInode->bProcessLock==0 ){
@@ -40452,9 +43472,11 @@ shmpage_out:
*/
#ifdef SQLITE_DEBUG
static int assertLockingArrayOk(unixShmNode *pShmNode){
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ return 1;
+#else
unixShm *pX;
int aLock[SQLITE_SHM_NLOCK];
- assert( sqlcipher_sqlite3_mutex_held(pShmNode->pShmMutex) );
memset(aLock, 0, sizeof(aLock));
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
@@ -40472,13 +43494,14 @@ static int assertLockingArrayOk(unixShmNode *pShmNode){
assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) );
return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0);
+#endif
}
#endif
/*
** Change the lock state for a shared-memory segment.
**
-** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
+** Note that the relationship between SHARED and EXCLUSIVE locks is a little
** different here than in posix. In xShmLock(), one can go from unlocked
** to shared and back or from unlocked to exclusive and back. But one may
** not go from shared to exclusive or from exclusive to shared.
@@ -40493,7 +43516,7 @@ static int unixShmLock(
unixShm *p; /* The shared memory being locked */
unixShmNode *pShmNode; /* The underlying file iNode */
int rc = SQLITE_OK; /* Result code */
- u16 mask; /* Mask of locks to take or release */
+ u16 mask = (1<<(ofst+n)) - (1<<ofst); /* Mask of locks to take or release */
int *aLock;
p = pDbFd->pShm;
@@ -40528,88 +43551,151 @@ static int unixShmLock(
** It is not permitted to block on the RECOVER lock.
*/
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
- (ofst!=2) /* not RECOVER */
- && (ofst!=1 || (p->exclMask|p->sharedMask)==0)
- && (ofst!=0 || (p->exclMask|p->sharedMask)<3)
- && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
- ));
+ {
+ u16 lockMask = (p->exclMask|p->sharedMask);
+ assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
+ (ofst!=2) /* not RECOVER */
+ && (ofst!=1 || lockMask==0 || lockMask==2)
+ && (ofst!=0 || lockMask<3)
+ && (ofst<3 || lockMask<(1<<ofst))
+ ));
+ }
#endif
- mask = (1<<(ofst+n)) - (1<<ofst);
- assert( n>1 || mask==(1<<ofst) );
- sqlcipher_sqlite3_mutex_enter(pShmNode->pShmMutex);
- assert( assertLockingArrayOk(pShmNode) );
- if( flags & SQLITE_SHM_UNLOCK ){
- if( (p->exclMask|p->sharedMask) & mask ){
- int ii;
- int bUnlock = 1;
+ /* Check if there is any work to do. There are three cases:
+ **
+ ** a) An unlock operation where there are locks to unlock,
+ ** b) An shared lock where the requested lock is not already held
+ ** c) An exclusive lock where the requested lock is not already held
+ **
+ ** The SQLite core never requests an exclusive lock that it already holds.
+ ** This is assert()ed below.
+ */
+ assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)
+ || 0==(p->exclMask & mask)
+ );
+ if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask))
+ || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask))
+ || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK))
+ ){
- for(ii=ofst; ii<ofst+n; ii++){
- if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){
- bUnlock = 0;
- }
+ /* Take the required mutexes. In SETLK_TIMEOUT mode (blocking locks), if
+ ** this is an attempt on an exclusive lock use sqlcipher_sqlite3_mutex_try(). If any
+ ** other thread is holding this mutex, then it is either holding or about
+ ** to hold a lock exclusive to the one being requested, and we may
+ ** therefore return SQLITE_BUSY to the caller.
+ **
+ ** Doing this prevents some deadlock scenarios. For example, thread 1 may
+ ** be a checkpointer blocked waiting on the WRITER lock. And thread 2
+ ** may be a normal SQL client upgrading to a write transaction. In this
+ ** case thread 2 does a non-blocking request for the WRITER lock. But -
+ ** if it were to use sqlcipher_sqlite3_mutex_enter() then it would effectively
+ ** become a (doomed) blocking request, as thread 2 would block until thread
+ ** 1 obtained WRITER and released the mutex. Since thread 2 already holds
+ ** a lock on a read-locking slot at this point, this breaks the
+ ** anti-deadlock rules (see above). */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ int iMutex;
+ for(iMutex=ofst; iMutex<ofst+n; iMutex++){
+ if( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) ){
+ rc = sqlcipher_sqlite3_mutex_try(pShmNode->aMutex[iMutex]);
+ if( rc!=SQLITE_OK ) goto leave_shmnode_mutexes;
+ }else{
+ sqlcipher_sqlite3_mutex_enter(pShmNode->aMutex[iMutex]);
}
+ }
+#else
+ sqlcipher_sqlite3_mutex_enter(pShmNode->pShmMutex);
+#endif
- if( bUnlock ){
- rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
- if( rc==SQLITE_OK ){
- memset(&aLock[ofst], 0, sizeof(int)*n);
+ if( ALWAYS(rc==SQLITE_OK) ){
+ if( flags & SQLITE_SHM_UNLOCK ){
+ /* Case (a) - unlock. */
+ int bUnlock = 1;
+ assert( (p->exclMask & p->sharedMask)==0 );
+ assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask );
+ assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask );
+
+ /* If this is a SHARED lock being unlocked, it is possible that other
+ ** clients within this process are holding the same SHARED lock. In
+ ** this case, set bUnlock to 0 so that the posix lock is not removed
+ ** from the file-descriptor below. */
+ if( flags & SQLITE_SHM_SHARED ){
+ assert( n==1 );
+ assert( aLock[ofst]>=1 );
+ if( aLock[ofst]>1 ){
+ bUnlock = 0;
+ aLock[ofst]--;
+ p->sharedMask &= ~mask;
+ }
}
- }else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
- assert( n==1 && aLock[ofst]>1 );
- aLock[ofst]--;
- }
- /* Undo the local locks */
- if( rc==SQLITE_OK ){
- p->exclMask &= ~mask;
- p->sharedMask &= ~mask;
- }
- }
- }else if( flags & SQLITE_SHM_SHARED ){
- assert( n==1 );
- assert( (p->exclMask & (1<<ofst))==0 );
- if( (p->sharedMask & mask)==0 ){
- if( aLock[ofst]<0 ){
- rc = SQLITE_BUSY;
- }else if( aLock[ofst]==0 ){
- rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
- }
+ if( bUnlock ){
+ rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
+ if( rc==SQLITE_OK ){
+ memset(&aLock[ofst], 0, sizeof(int)*n);
+ p->sharedMask &= ~mask;
+ p->exclMask &= ~mask;
+ }
+ }
+ }else if( flags & SQLITE_SHM_SHARED ){
+ /* Case (b) - a shared lock. */
- /* Get the local shared locks */
- if( rc==SQLITE_OK ){
- p->sharedMask |= mask;
- aLock[ofst]++;
- }
- }
- }else{
- /* Make sure no sibling connections hold locks that will block this
- ** lock. If any do, return SQLITE_BUSY right away. */
- int ii;
- for(ii=ofst; ii<ofst+n; ii++){
- assert( (p->sharedMask & mask)==0 );
- if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
- rc = SQLITE_BUSY;
- break;
- }
- }
+ if( aLock[ofst]<0 ){
+ /* An exclusive lock is held by some other connection. BUSY. */
+ rc = SQLITE_BUSY;
+ }else if( aLock[ofst]==0 ){
+ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
+ }
- /* Get the exclusive locks at the system level. Then if successful
- ** also update the in-memory values. */
- if( rc==SQLITE_OK ){
- rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
- if( rc==SQLITE_OK ){
+ /* Get the local shared locks */
+ if( rc==SQLITE_OK ){
+ p->sharedMask |= mask;
+ aLock[ofst]++;
+ }
+ }else{
+ /* Case (c) - an exclusive lock. */
+ int ii;
+
+ assert( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) );
assert( (p->sharedMask & mask)==0 );
- p->exclMask |= mask;
+ assert( (p->exclMask & mask)==0 );
+
+ /* Make sure no sibling connections hold locks that will block this
+ ** lock. If any do, return SQLITE_BUSY right away. */
for(ii=ofst; ii<ofst+n; ii++){
- aLock[ii] = -1;
+ if( aLock[ii] ){
+ rc = SQLITE_BUSY;
+ break;
+ }
+ }
+
+ /* Get the exclusive locks at the system level. Then if successful
+ ** also update the in-memory values. */
+ if( rc==SQLITE_OK ){
+ rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
+ if( rc==SQLITE_OK ){
+ p->exclMask |= mask;
+ for(ii=ofst; ii<ofst+n; ii++){
+ aLock[ii] = -1;
+ }
+ }
}
}
+ assert( assertLockingArrayOk(pShmNode) );
}
+
+ /* Drop the mutexes acquired above. */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ leave_shmnode_mutexes:
+ for(iMutex--; iMutex>=ofst; iMutex--){
+ sqlcipher_sqlite3_mutex_leave(pShmNode->aMutex[iMutex]);
+ }
+#else
+ sqlcipher_sqlite3_mutex_leave(pShmNode->pShmMutex);
+#endif
}
- assert( assertLockingArrayOk(pShmNode) );
- sqlcipher_sqlite3_mutex_leave(pShmNode->pShmMutex);
+
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
p->id, osGetpid(0), p->sharedMask, p->exclMask));
return rc;
@@ -40859,11 +43945,16 @@ static int unixFetch(sqlcipher_sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
#if SQLITE_MAX_MMAP_SIZE>0
if( pFd->mmapSizeMax>0 ){
+ /* Ensure that there is always at least a 256 byte buffer of addressable
+ ** memory following the returned page. If the database is corrupt,
+ ** SQLite may overread the page slightly (in practice only a few bytes,
+ ** but 256 is safe, round, number). */
+ const int nEofBuffer = 256;
if( pFd->pMapRegion==0 ){
int rc = unixMapfile(pFd, -1);
if( rc!=SQLITE_OK ) return rc;
}
- if( pFd->mmapSize >= iOff+nAmt ){
+ if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){
*pp = &((u8 *)pFd->pMapRegion)[iOff];
pFd->nFetchOut++;
}
@@ -41807,12 +44898,19 @@ static int unixOpen(
rc = SQLITE_READONLY_DIRECTORY;
}else if( errno!=EISDIR && isReadWrite ){
/* Failed to open the file for read/write access. Try read-only. */
+ UnixUnusedFd *pReadonly = 0;
flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
openFlags &= ~(O_RDWR|O_CREAT);
flags |= SQLITE_OPEN_READONLY;
openFlags |= O_RDONLY;
isReadonly = 1;
- fd = robust_open(zName, openFlags, openMode);
+ pReadonly = findReusableFd(zName, flags);
+ if( pReadonly ){
+ fd = pReadonly->fd;
+ sqlcipher_sqlite3_free(pReadonly);
+ }else{
+ fd = robust_open(zName, openFlags, openMode);
+ }
}
}
if( fd<0 ){
@@ -42039,12 +45137,10 @@ static void appendOnePathElement(
if( zName[0]=='.' ){
if( nName==1 ) return;
if( zName[1]=='.' && nName==2 ){
- if( pPath->nUsed<=1 ){
- pPath->rc = SQLITE_ERROR;
- return;
+ if( pPath->nUsed>1 ){
+ assert( pPath->zOut[0]=='/' );
+ while( pPath->zOut[--pPath->nUsed]!='/' ){}
}
- assert( pPath->zOut[0]=='/' );
- while( pPath->zOut[--pPath->nUsed]!='/' ){}
return;
}
}
@@ -42256,12 +45352,17 @@ static int unixRandomness(sqlcipher_sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
** than the argument.
*/
static int unixSleep(sqlcipher_sqlite3_vfs *NotUsed, int microseconds){
-#if OS_VXWORKS
+#if !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP+0
struct timespec sp;
-
sp.tv_sec = microseconds / 1000000;
sp.tv_nsec = (microseconds % 1000000) * 1000;
+
+ /* Almost all modern unix systems support nanosleep(). But if you are
+ ** compiling for one of the rare exceptions, you can use
+ ** -DHAVE_NANOSLEEP=0 (perhaps in conjuction with -DHAVE_USLEEP if
+ ** usleep() is available) in order to bypass the use of nanosleep() */
nanosleep(&sp, NULL);
+
UNUSED_PARAMETER(NotUsed);
return microseconds;
#elif defined(HAVE_USLEEP) && HAVE_USLEEP
@@ -43638,8 +46739,16 @@ SQLITE_API int sqlcipher_sqlite3_os_init(void){
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlcipher_sqlite3_vfs)); i++){
+#ifdef SQLITE_DEFAULT_UNIX_VFS
+ sqlcipher_sqlite3_vfs_register(&aVfs[i],
+ 0==strcmp(aVfs[i].zName,SQLITE_DEFAULT_UNIX_VFS));
+#else
sqlcipher_sqlite3_vfs_register(&aVfs[i], i==0);
+#endif
}
+#ifdef SQLITE_OS_KV_OPTIONAL
+ sqlcipher_sqlite3KvvfsInit();
+#endif
unixBigLock = sqlcipher_sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#ifndef SQLITE_OMIT_WAL
@@ -44843,7 +47952,7 @@ static struct win_syscall {
/*
** This is the xSetSystemCall() method of sqlcipher_sqlite3_vfs for all of the
-** "win32" VFSes. Return SQLITE_OK opon successfully updating the
+** "win32" VFSes. Return SQLITE_OK upon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
*/
@@ -46423,7 +49532,7 @@ static int winRead(
pFile->h, pBuf, amt, offset, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
+ /* Deal with as much of this read request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -46501,7 +49610,7 @@ static int winWrite(
pFile->h, pBuf, amt, offset, pFile->locktype));
#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
+ /* Deal with as much of this write request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -46611,7 +49720,7 @@ static int winTruncate(sqlcipher_sqlite3_file *id, sqlcipher_sqlite3_int64 nByte
** all references to memory-mapped content are closed. That is doable,
** but involves adding a few branches in the common write code path which
** could slow down normal operations slightly. Hence, we have decided for
- ** now to simply make trancations a no-op if there are pending reads. We
+ ** now to simply make transactions a no-op if there are pending reads. We
** can maybe revisit this decision in the future.
*/
return SQLITE_OK;
@@ -46670,7 +49779,7 @@ static int winTruncate(sqlcipher_sqlite3_file *id, sqlcipher_sqlite3_int64 nByte
#ifdef SQLITE_TEST
/*
** Count the number of fullsyncs and normal syncs. This is used to test
-** that syncs and fullsyncs are occuring at the right times.
+** that syncs and fullsyncs are occurring at the right times.
*/
SQLITE_API int sqlcipher_sqlite3_sync_count = 0;
SQLITE_API int sqlcipher_sqlite3_fullsync_count = 0;
@@ -47027,7 +50136,7 @@ static int winLock(sqlcipher_sqlite3_file *id, int locktype){
*/
if( locktype==EXCLUSIVE_LOCK && res ){
assert( pFile->locktype>=SHARED_LOCK );
- res = winUnlockReadLock(pFile);
+ (void)winUnlockReadLock(pFile);
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
SHARED_SIZE, 0);
if( res ){
@@ -48205,6 +51314,11 @@ static int winFetch(sqlcipher_sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
#if SQLITE_MAX_MMAP_SIZE>0
if( pFd->mmapSizeMax>0 ){
+ /* Ensure that there is always at least a 256 byte buffer of addressable
+ ** memory following the returned page. If the database is corrupt,
+ ** SQLite may overread the page slightly (in practice only a few bytes,
+ ** but 256 is safe, round, number). */
+ const int nEofBuffer = 256;
if( pFd->pMapRegion==0 ){
int rc = winMapfile(pFd, -1);
if( rc!=SQLITE_OK ){
@@ -48213,7 +51327,7 @@ static int winFetch(sqlcipher_sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
return rc;
}
}
- if( pFd->mmapSize >= iOff+nAmt ){
+ if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){
assert( pFd->pMapRegion!=0 );
*pp = &((u8 *)pFd->pMapRegion)[iOff];
pFd->nFetchOut++;
@@ -48409,9 +51523,10 @@ static int winMakeEndInDirSep(int nBuf, char *zBuf){
}
/*
-** If sqlcipher_sqlite3_temp_directory is not, take the mutex and return true.
+** If sqlcipher_sqlite3_temp_directory is defined, take the mutex and return true.
**
-** If sqlcipher_sqlite3_temp_directory is NULL, omit the mutex and return false.
+** If sqlcipher_sqlite3_temp_directory is NULL (undefined), omit the mutex and
+** return false.
*/
static int winTempDirDefined(void){
sqlcipher_sqlite3_mutex_enter(sqlcipher_sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
@@ -48430,6 +51545,7 @@ static int winGetTempname(sqlcipher_sqlite3_vfs *pVfs, char **pzBuf){
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
size_t i, j;
+ DWORD pid;
int nPre = sqlcipher_sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX);
int nMax, nBuf, nDir, nLen;
char *zBuf;
@@ -48642,7 +51758,10 @@ static int winGetTempname(sqlcipher_sqlite3_vfs *pVfs, char **pzBuf){
j = sqlcipher_sqlite3Strlen30(zBuf);
sqlcipher_sqlite3_randomness(15, &zBuf[j]);
+ pid = osGetCurrentProcessId();
for(i=0; i<15; i++, j++){
+ zBuf[j] += pid & 0xff;
+ pid >>= 8;
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
@@ -48880,7 +51999,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlcipher_sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlcipher_sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -48897,7 +52016,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlcipher_sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlcipher_sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -48917,7 +52036,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlcipher_sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlcipher_sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -49140,6 +52259,13 @@ static int winAccess(
OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
zFilename, flags, pResOut));
+ if( zFilename==0 ){
+ *pResOut = 0;
+ OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+ zFilename, pResOut, *pResOut));
+ return SQLITE_OK;
+ }
+
zConverted = winConvertFromUtf8Filename(zFilename);
if( zConverted==0 ){
OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
@@ -49447,7 +52573,8 @@ static int winFullPathname(
char *zFull /* Output buffer */
){
int rc;
- sqlcipher_sqlite3_mutex *pMutex = sqlcipher_sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR);
+ MUTEX_LOGIC( sqlcipher_sqlite3_mutex *pMutex; )
+ MUTEX_LOGIC( pMutex = sqlcipher_sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR); )
sqlcipher_sqlite3_mutex_enter(pMutex);
rc = winFullPathnameNoMutex(pVfs, zRelative, nFull, zFull);
sqlcipher_sqlite3_mutex_leave(pMutex);
@@ -49989,6 +53116,7 @@ static int memdbTruncate(sqlcipher_sqlite3_file*, sqlcipher_sqlite3_int64 size);
static int memdbSync(sqlcipher_sqlite3_file*, int flags);
static int memdbFileSize(sqlcipher_sqlite3_file*, sqlcipher_sqlite3_int64 *pSize);
static int memdbLock(sqlcipher_sqlite3_file*, int);
+static int memdbUnlock(sqlcipher_sqlite3_file*, int);
/* static int memdbCheckReservedLock(sqlcipher_sqlite3_file*, int *pResOut);// not used */
static int memdbFileControl(sqlcipher_sqlite3_file*, int op, void *pArg);
/* static int memdbSectorSize(sqlcipher_sqlite3_file*); // not used */
@@ -50047,7 +53175,7 @@ static const sqlcipher_sqlite3_io_methods memdb_io_methods = {
memdbSync, /* xSync */
memdbFileSize, /* xFileSize */
memdbLock, /* xLock */
- memdbLock, /* xUnlock - same as xLock in this case */
+ memdbUnlock, /* xUnlock */
0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */
memdbFileControl, /* xFileControl */
0, /* memdbSectorSize,*/ /* xSectorSize */
@@ -50248,39 +53376,81 @@ static int memdbLock(sqlcipher_sqlite3_file *pFile, int eLock){
MemFile *pThis = (MemFile*)pFile;
MemStore *p = pThis->pStore;
int rc = SQLITE_OK;
- if( eLock==pThis->eLock ) return SQLITE_OK;
+ if( eLock<=pThis->eLock ) return SQLITE_OK;
memdbEnter(p);
- if( eLock>SQLITE_LOCK_SHARED ){
- if( p->mFlags & SQLITE_DESERIALIZE_READONLY ){
- rc = SQLITE_READONLY;
- }else if( pThis->eLock<=SQLITE_LOCK_SHARED ){
- if( p->nWrLock ){
- rc = SQLITE_BUSY;
- }else{
- p->nWrLock = 1;
+
+ assert( p->nWrLock==0 || p->nWrLock==1 );
+ assert( pThis->eLock<=SQLITE_LOCK_SHARED || p->nWrLock==1 );
+ assert( pThis->eLock==SQLITE_LOCK_NONE || p->nRdLock>=1 );
+
+ if( eLock>SQLITE_LOCK_SHARED && (p->mFlags & SQLITE_DESERIALIZE_READONLY) ){
+ rc = SQLITE_READONLY;
+ }else{
+ switch( eLock ){
+ case SQLITE_LOCK_SHARED: {
+ assert( pThis->eLock==SQLITE_LOCK_NONE );
+ if( p->nWrLock>0 ){
+ rc = SQLITE_BUSY;
+ }else{
+ p->nRdLock++;
+ }
+ break;
+ };
+
+ case SQLITE_LOCK_RESERVED:
+ case SQLITE_LOCK_PENDING: {
+ assert( pThis->eLock>=SQLITE_LOCK_SHARED );
+ if( ALWAYS(pThis->eLock==SQLITE_LOCK_SHARED) ){
+ if( p->nWrLock>0 ){
+ rc = SQLITE_BUSY;
+ }else{
+ p->nWrLock = 1;
+ }
+ }
+ break;
+ }
+
+ default: {
+ assert( eLock==SQLITE_LOCK_EXCLUSIVE );
+ assert( pThis->eLock>=SQLITE_LOCK_SHARED );
+ if( p->nRdLock>1 ){
+ rc = SQLITE_BUSY;
+ }else if( pThis->eLock==SQLITE_LOCK_SHARED ){
+ p->nWrLock = 1;
+ }
+ break;
}
}
- }else if( eLock==SQLITE_LOCK_SHARED ){
- if( pThis->eLock > SQLITE_LOCK_SHARED ){
- assert( p->nWrLock==1 );
- p->nWrLock = 0;
- }else if( p->nWrLock ){
- rc = SQLITE_BUSY;
- }else{
- p->nRdLock++;
+ }
+ if( rc==SQLITE_OK ) pThis->eLock = eLock;
+ memdbLeave(p);
+ return rc;
+}
+
+/*
+** Unlock an memdb-file.
+*/
+static int memdbUnlock(sqlcipher_sqlite3_file *pFile, int eLock){
+ MemFile *pThis = (MemFile*)pFile;
+ MemStore *p = pThis->pStore;
+ if( eLock>=pThis->eLock ) return SQLITE_OK;
+ memdbEnter(p);
+
+ assert( eLock==SQLITE_LOCK_SHARED || eLock==SQLITE_LOCK_NONE );
+ if( eLock==SQLITE_LOCK_SHARED ){
+ if( ALWAYS(pThis->eLock>SQLITE_LOCK_SHARED) ){
+ p->nWrLock--;
}
}else{
- assert( eLock==SQLITE_LOCK_NONE );
if( pThis->eLock>SQLITE_LOCK_SHARED ){
- assert( p->nWrLock==1 );
- p->nWrLock = 0;
+ p->nWrLock--;
}
- assert( p->nRdLock>0 );
p->nRdLock--;
}
- if( rc==SQLITE_OK ) pThis->eLock = eLock;
+
+ pThis->eLock = eLock;
memdbLeave(p);
- return rc;
+ return SQLITE_OK;
}
#if 0
@@ -50390,7 +53560,7 @@ static int memdbOpen(
memset(pFile, 0, sizeof(*pFile));
szName = sqlcipher_sqlite3Strlen30(zName);
- if( szName>1 && zName[0]=='/' ){
+ if( szName>1 && (zName[0]=='/' || zName[0]=='\\') ){
int i;
#ifndef SQLITE_MUTEX_OMIT
sqlcipher_sqlite3_mutex *pVfsMutex = sqlcipher_sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
@@ -50636,6 +53806,14 @@ SQLITE_API unsigned char *sqlcipher_sqlite3_serialize(
pOut = 0;
}else{
sz = sqlcipher_sqlite3_column_int64(pStmt, 0)*szPage;
+ if( sz==0 ){
+ sqlcipher_sqlite3_reset(pStmt);
+ sqlcipher_sqlite3_exec(db, "BEGIN IMMEDIATE; COMMIT;", 0, 0, 0);
+ rc = sqlcipher_sqlite3_step(pStmt);
+ if( rc==SQLITE_ROW ){
+ sz = sqlcipher_sqlite3_column_int64(pStmt, 0)*szPage;
+ }
+ }
if( piSize ) *piSize = sz;
if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
pOut = 0;
@@ -50738,6 +53916,13 @@ end_deserialize:
}
/*
+** Return true if the VFS is the memvfs.
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3IsMemdb(const sqlcipher_sqlite3_vfs *pVfs){
+ return pVfs==&memdb_vfs;
+}
+
+/*
** This routine is called when the extension is loaded.
** Register the new VFS.
*/
@@ -50949,7 +54134,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BitvecSet(Bitvec *p, u32 i){
h = BITVEC_HASH(i++);
/* if there wasn't a hash collision, and this doesn't */
/* completely fill the hash, then just add it without */
- /* worring about sub-dividing and re-hashing. */
+ /* worrying about sub-dividing and re-hashing. */
if( !p->u.aHash[h] ){
if (p->nSet<(BITVEC_NINT-1)) {
goto bitvec_set_end;
@@ -51216,7 +54401,7 @@ bitvec_end:
struct PCache {
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
PgHdr *pSynced; /* Last synced page in dirty page list */
- int nRefSum; /* Sum of ref counts over all pages */
+ i64 nRefSum; /* Sum of ref counts over all pages */
int szCache; /* Configured cache size */
int szSpill; /* Size before spilling occurs */
int szPage; /* Size of every page in this cache */
@@ -51241,12 +54426,24 @@ struct PCache {
int sqlcipher_sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
int sqlcipher_sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
# define pcacheTrace(X) if(sqlcipher_sqlite3PcacheTrace){sqlcipher_sqlite3DebugPrintf X;}
- void pcacheDump(PCache *pCache){
- int N;
- int i, j;
- sqlcipher_sqlite3_pcache_page *pLower;
+ static void pcachePageTrace(int i, sqlcipher_sqlite3_pcache_page *pLower){
PgHdr *pPg;
unsigned char *a;
+ int j;
+ if( pLower==0 ){
+ printf("%3d: NULL\n", i);
+ }else{
+ pPg = (PgHdr*)pLower->pExtra;
+ printf("%3d: nRef %2lld flgs %02x data ", i, pPg->nRef, pPg->flags);
+ a = (unsigned char *)pLower->pBuf;
+ for(j=0; j<12; j++) printf("%02x", a[j]);
+ printf(" ptr %p\n", pPg);
+ }
+ }
+ static void pcacheDump(PCache *pCache){
+ int N;
+ int i;
+ sqlcipher_sqlite3_pcache_page *pLower;
if( sqlcipher_sqlite3PcacheTrace<2 ) return;
if( pCache->pCache==0 ) return;
@@ -51254,23 +54451,43 @@ struct PCache {
if( N>sqlcipher_sqlite3PcacheMxDump ) N = sqlcipher_sqlite3PcacheMxDump;
for(i=1; i<=N; i++){
pLower = sqlcipher_sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
- if( pLower==0 ) continue;
- pPg = (PgHdr*)pLower->pExtra;
- printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
- a = (unsigned char *)pLower->pBuf;
- for(j=0; j<12; j++) printf("%02x", a[j]);
- printf("\n");
- if( pPg->pPage==0 ){
+ pcachePageTrace(i, pLower);
+ if( pLower && ((PgHdr*)pLower)->pPage==0 ){
sqlcipher_sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
}
}
}
- #else
+#else
# define pcacheTrace(X)
+# define pcachePageTrace(PGNO, X)
# define pcacheDump(X)
#endif
/*
+** Return 1 if pPg is on the dirty list for pCache. Return 0 if not.
+** This routine runs inside of assert() statements only.
+*/
+#if defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
+static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
+ PgHdr *p;
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){
+ if( p==pPg ) return 1;
+ }
+ return 0;
+}
+static int pageNotOnDirtyList(PCache *pCache, PgHdr *pPg){
+ PgHdr *p;
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){
+ if( p==pPg ) return 0;
+ }
+ return 1;
+}
+#else
+# define pageOnDirtyList(A,B) 1
+# define pageNotOnDirtyList(A,B) 1
+#endif
+
+/*
** Check invariants on a PgHdr entry. Return true if everything is OK.
** Return false if any invariant is violated.
**
@@ -51288,8 +54505,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PcachePageSanity(PgHdr *pPg){
assert( pCache!=0 ); /* Every page has an associated PCache */
if( pPg->flags & PGHDR_CLEAN ){
assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
- assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */
- assert( pCache->pDirtyTail!=pPg );
+ assert( pageNotOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirtylist */
+ }else{
+ assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */
+ assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg );
+ assert( pPg->pDirtyPrev==0 || pPg->pDirtyPrev->pDirtyNext==pPg );
+ assert( pPg->pDirtyPrev!=0 || pCache->pDirty==pPg );
+ assert( pageOnDirtyList(pCache, pPg) );
}
/* WRITEABLE pages must also be DIRTY */
if( pPg->flags & PGHDR_WRITEABLE ){
@@ -51419,7 +54641,7 @@ static int numberOfCachePages(PCache *p){
return p->szCache;
}else{
i64 n;
- /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
+ /* IMPLEMENTATION-OF: R-59858-46238 If the argument N is negative, then the
** number of cache pages is adjusted to be a number of pages that would
** use approximately abs(N*1024) bytes of memory based on the current
** page size. */
@@ -51563,8 +54785,9 @@ SQLITE_PRIVATE sqlcipher_sqlite3_pcache_page *sqlcipher_sqlite3PcacheFetch(
assert( createFlag==0 || pCache->eCreate==eCreate );
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
pRes = sqlcipher_sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
- pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno,
+ pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno,
createFlag?" create":"",pRes));
+ pcachePageTrace(pgno, pRes);
return pRes;
}
@@ -51692,6 +54915,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlcipher_sqlite3PcacheRelease(PgHdr *p){
pcacheUnpin(p);
}else{
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
+ assert( sqlcipher_sqlite3PcachePageSanity(p) );
}
}
}
@@ -51735,6 +54959,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3PcacheMakeDirty(PgHdr *p){
pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
+ assert( sqlcipher_sqlite3PcachePageSanity(p) );
}
assert( sqlcipher_sqlite3PcachePageSanity(p) );
}
@@ -51904,7 +55129,7 @@ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
}
/*
-** Sort the list of pages in accending order by pgno. Pages are
+** Sort the list of pages in ascending order by pgno. Pages are
** connected by pDirty pointers. The pDirtyPrev pointers are
** corrupted by this sort.
**
@@ -51963,14 +55188,14 @@ SQLITE_PRIVATE PgHdr *sqlcipher_sqlite3PcacheDirtyList(PCache *pCache){
** This is not the total number of pages referenced, but the sum of the
** reference count for all pages.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3PcacheRefCount(PCache *pCache){
+SQLITE_PRIVATE i64 sqlcipher_sqlite3PcacheRefCount(PCache *pCache){
return pCache->nRefSum;
}
/*
** Return the number of references to the page supplied as an argument.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3PcachePageRefcount(PgHdr *p){
+SQLITE_PRIVATE i64 sqlcipher_sqlite3PcachePageRefcount(PgHdr *p){
return p->nRef;
}
@@ -52112,12 +55337,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3PcacheIterateDirty(PCache *pCache, void (*x
** size can vary according to architecture, compile-time options, and
** SQLite library version number.
**
-** If SQLITE_PCACHE_SEPARATE_HEADER is defined, then the extension is obtained
-** using a separate memory allocation from the database page content. This
-** seeks to overcome the "clownshoe" problem (also called "internal
-** fragmentation" in academic literature) of allocating a few bytes more
-** than a power of two with the memory allocator rounding up to the next
-** power of two, and leaving the rounded-up space unused.
+** Historical note: It used to be that if the SQLITE_PCACHE_SEPARATE_HEADER
+** was defined, then the page content would be held in a separate memory
+** allocation from the PgHdr1. This was intended to avoid clownshoe memory
+** allocations. However, the btree layer needs a small (16-byte) overrun
+** area after the page content buffer. The header serves as that overrun
+** area. Therefore SQLITE_PCACHE_SEPARATE_HEADER was discontinued to avoid
+** any possibility of a memory error.
**
** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates
** with this module. Information is passed back and forth as PgHdr1 pointers.
@@ -52143,7 +55369,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3PcacheIterateDirty(PCache *pCache, void (*x
** If N is positive, then N pages worth of memory are allocated using a single
** sqlcipher_sqlite3Malloc() call and that memory is used for the first N pages allocated.
** Or if N is negative, then -1024*N bytes of memory are allocated and used
-** for as many pages as can be accomodated.
+** for as many pages as can be accommodated.
**
** Only one of (2) or (3) can be used. Once the memory available to (2) or
** (3) is exhausted, subsequent allocations fail over to the general-purpose
@@ -52162,30 +55388,40 @@ typedef struct PGroup PGroup;
/*
** Each cache entry is represented by an instance of the following
-** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
-** PgHdr1.pCache->szPage bytes is allocated directly before this structure
-** in memory.
+** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
+** directly before this structure and is used to cache the page content.
+**
+** When reading a corrupt database file, it is possible that SQLite might
+** read a few bytes (no more than 16 bytes) past the end of the page buffer.
+** It will only read past the end of the page buffer, never write. This
+** object is positioned immediately after the page buffer to serve as an
+** overrun area, so that overreads are harmless.
**
-** Note: Variables isBulkLocal and isAnchor were once type "u8". That works,
+** Variables isBulkLocal and isAnchor were once type "u8". That works,
** but causes a 2-byte gap in the structure for most architectures (since
** pointers must be either 4 or 8-byte aligned). As this structure is located
** in memory directly after the associated page data, if the database is
** corrupt, code at the b-tree layer may overread the page buffer and
** read part of this structure before the corruption is detected. This
-** can cause a valgrind error if the unitialized gap is accessed. Using u16
-** ensures there is no such gap, and therefore no bytes of unitialized memory
-** in the structure.
+** can cause a valgrind error if the uninitialized gap is accessed. Using u16
+** ensures there is no such gap, and therefore no bytes of uninitialized
+** memory in the structure.
+**
+** The pLruNext and pLruPrev pointers form a double-linked circular list
+** of all pages that are unpinned. The PGroup.lru element (which should be
+** the only element on the list with PgHdr1.isAnchor set to 1) forms the
+** beginning and the end of the list.
*/
struct PgHdr1 {
- sqlcipher_sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
- unsigned int iKey; /* Key value (page number) */
- u16 isBulkLocal; /* This page from bulk local storage */
- u16 isAnchor; /* This is the PGroup.lru element */
- PgHdr1 *pNext; /* Next in hash table chain */
- PCache1 *pCache; /* Cache that currently owns this page */
- PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
- PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
- /* NB: pLruPrev is only valid if pLruNext!=0 */
+ sqlcipher_sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
+ unsigned int iKey; /* Key value (page number) */
+ u16 isBulkLocal; /* This page from bulk local storage */
+ u16 isAnchor; /* This is the PGroup.lru element */
+ PgHdr1 *pNext; /* Next in hash table chain */
+ PCache1 *pCache; /* Cache that currently owns this page */
+ PgHdr1 *pLruNext; /* Next in circular LRU list of unpinned pages */
+ PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
+ /* NB: pLruPrev is only valid if pLruNext!=0 */
};
/*
@@ -52511,25 +55747,13 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
pcache1LeaveMutex(pCache->pGroup);
#endif
if( benignMalloc ){ sqlcipher_sqlite3BeginBenignMalloc(); }
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- pPg = pcache1Alloc(pCache->szPage);
- p = sqlcipher_sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
- if( !pPg || !p ){
- pcache1Free(pPg);
- sqlcipher_sqlite3_free(p);
- pPg = 0;
- }
-#else
pPg = pcache1Alloc(pCache->szAlloc);
-#endif
if( benignMalloc ){ sqlcipher_sqlite3EndBenignMalloc(); }
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
pcache1EnterMutex(pCache->pGroup);
#endif
if( pPg==0 ) return 0;
-#ifndef SQLITE_PCACHE_SEPARATE_HEADER
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
-#endif
p->page.pBuf = pPg;
p->page.pExtra = &p[1];
p->isBulkLocal = 0;
@@ -52553,9 +55777,6 @@ static void pcache1FreePage(PgHdr1 *p){
pCache->pFree = p;
}else{
pcache1Free(p->page.pBuf);
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- sqlcipher_sqlite3_free(p);
-#endif
}
(*pCache->pnPurgeable)--;
}
@@ -53322,9 +56543,6 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PcacheReleaseMemory(int nReq){
&& p->isAnchor==0
){
nFree += pcache1MemSize(p->page.pBuf);
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- nFree += sqlcipher_sqlite3MemSize(p);
-#endif
assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
@@ -53405,7 +56623,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3PcacheStats(
** The TEST primitive includes a "batch" number. The TEST primitive
** will only see elements that were inserted before the last change
** in the batch number. In other words, if an INSERT occurs between
-** two TESTs where the TESTs have the same batch nubmer, then the
+** two TESTs where the TESTs have the same batch number, then the
** value added by the INSERT will not be visible to the second TEST.
** The initial batch number is zero, so if the very first TEST contains
** a non-zero batch number, it will see all prior INSERTs.
@@ -53937,6 +57155,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlc
# define sqlcipher_sqlite3WalFramesize(z) 0
# define sqlcipher_sqlite3WalFindFrame(x,y,z) 0
# define sqlcipher_sqlite3WalFile(x) 0
+# undef SQLITE_USE_SEH
#else
#define WAL_SAVEPOINT_NDATA 4
@@ -54043,6 +57262,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalWriteLock(Wal *pWal, int bLock);
SQLITE_PRIVATE void sqlcipher_sqlite3WalDb(Wal *pWal, sqlcipher_sqlite3 *db);
#endif
+#ifdef SQLITE_USE_SEH
+SQLITE_PRIVATE int sqlcipher_sqlite3WalSystemErrno(Wal*);
+#endif
+
#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* SQLITE_WAL_H */
@@ -54328,7 +57551,7 @@ int sqlcipher_sqlite3PagerTrace=1; /* True to enable tracing */
** outstanding transactions have been abandoned, the pager is able to
** transition back to OPEN state, discarding the contents of the
** page-cache and any other in-memory state at the same time. Everything
-** is reloaded from disk (and, if necessary, hot-journal rollback peformed)
+** is reloaded from disk (and, if necessary, hot-journal rollback performed)
** when a read-transaction is next opened on the pager (transitioning
** the pager into READER state). At that point the system has recovered
** from the error.
@@ -54731,7 +57954,7 @@ struct Pager {
char *zJournal; /* Name of the journal file */
int (*xBusyHandler)(void*); /* Function to call when busy */
void *pBusyHandlerArg; /* Context argument for xBusyHandler */
- int aStat[4]; /* Total cache hits, misses, writes, spills */
+ u32 aStat[4]; /* Total cache hits, misses, writes, spills */
#ifdef SQLITE_TEST
int nRead; /* Database pages read */
#endif
@@ -54874,9 +58097,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
#ifndef SQLITE_OMIT_WAL
if( pPager->pWal ){
u32 iRead = 0;
- int rc;
- rc = sqlcipher_sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
- return (rc==SQLITE_OK && iRead==0);
+ (void)sqlcipher_sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
+ return iRead==0;
}
#endif
return 1;
@@ -55554,9 +58776,32 @@ static int writeJournalHdr(Pager *pPager){
memset(zHeader, 0, sizeof(aJournalMagic)+4);
}
+
+
/* The random check-hash initializer */
- sqlcipher_sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
+ if( pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){
+ sqlcipher_sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
+ }
+#ifdef SQLITE_DEBUG
+ else{
+ /* The Pager.cksumInit variable is usually randomized above to protect
+ ** against there being existing records in the journal file. This is
+ ** dangerous, as following a crash they may be mistaken for records
+ ** written by the current transaction and rolled back into the database
+ ** file, causing corruption. The following assert statements verify
+ ** that this is not required in "journal_mode=memory" mode, as in that
+ ** case the journal file is always 0 bytes in size at this point.
+ ** It is advantageous to avoid the sqlcipher_sqlite3_randomness() call if possible
+ ** as it takes the global PRNG mutex. */
+ i64 sz = 0;
+ sqlcipher_sqlite3OsFileSize(pPager->jfd, &sz);
+ assert( sz==0 );
+ assert( pPager->journalOff==journalHdrOffset(pPager) );
+ assert( sqlcipher_sqlite3JournalIsInMemory(pPager->jfd) );
+ }
+#endif
put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
+
/* The initial database size */
put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbOrigSize);
/* The assumed sector size for this process */
@@ -55736,7 +58981,7 @@ static int readJournalHdr(
** + 4 bytes: super-journal name checksum.
** + 8 bytes: aJournalMagic[].
**
-** The super-journal page checksum is the sum of the bytes in thesuper-journal
+** The super-journal page checksum is the sum of the bytes in the super-journal
** name, where each byte is interpreted as a signed 8-bit integer.
**
** If zSuper is a NULL pointer (occurs for a single database transaction),
@@ -55789,7 +59034,7 @@ static int writeSuperJournal(Pager *pPager, const char *zSuper){
}
pPager->journalOff += (nSuper+20);
- /* If the pager is in peristent-journal mode, then the physical
+ /* If the pager is in persistent-journal mode, then the physical
** journal-file may extend past the end of the super-journal name
** and 8 bytes of magic data just written to the file. This is
** dangerous because the code to rollback a hot-journal file
@@ -55959,7 +59204,7 @@ static void pager_unlock(Pager *pPager){
/*
** This function is called whenever an IOERR or FULL error that requires
-** the pager to transition into the ERROR state may ahve occurred.
+** the pager to transition into the ERROR state may have occurred.
** The first argument is a pointer to the pager structure, the second
** the error-code about to be returned by a pager API function. The
** value returned is a copy of the second argument to this function.
@@ -56200,6 +59445,9 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
return (rc==SQLITE_OK?rc2:rc);
}
+/* Forward reference */
+static int pager_playback(Pager *pPager, int isHot);
+
/*
** Execute a rollback if a transaction is active and unlock the
** database file.
@@ -56228,13 +59476,28 @@ static void pagerUnlockAndRollback(Pager *pPager){
assert( pPager->eState==PAGER_READER );
pager_end_transaction(pPager, 0, 0);
}
+ }else if( pPager->eState==PAGER_ERROR
+ && pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+ && isOpen(pPager->jfd)
+ ){
+ /* Special case for a ROLLBACK due to I/O error with an in-memory
+ ** journal: We have to rollback immediately, before the journal is
+ ** closed, because once it is closed, all content is forgotten. */
+ int errCode = pPager->errCode;
+ u8 eLock = pPager->eLock;
+ pPager->eState = PAGER_OPEN;
+ pPager->errCode = SQLITE_OK;
+ pPager->eLock = EXCLUSIVE_LOCK;
+ pager_playback(pPager, 1);
+ pPager->errCode = errCode;
+ pPager->eLock = eLock;
}
pager_unlock(pPager);
}
/*
** Parameter aData must point to a buffer of pPager->pageSize bytes
-** of data. Compute and return a checksum based ont the contents of the
+** of data. Compute and return a checksum based on the contents of the
** page of data and the current value of pPager->cksumInit.
**
** This is not a real checksum. It is really just the sum of the
@@ -56733,6 +59996,8 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
int rc = SQLITE_OK;
assert( pPager->eState!=PAGER_ERROR );
assert( pPager->eState!=PAGER_READER );
+ PAGERTRACE(("Truncate %d npage %u\n", PAGERID(pPager), nPage));
+
if( isOpen(pPager->fd)
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
@@ -57063,7 +60328,7 @@ end_playback:
** see if it is possible to delete the super-journal.
*/
assert( zSuper==&pPager->pTmpSpace[4] );
- memset(&zSuper[-4], 0, 4);
+ memset(pPager->pTmpSpace, 0, 4);
rc = pager_delsuper(pPager, zSuper);
testcase( rc!=SQLITE_OK );
}
@@ -57266,7 +60531,7 @@ static int pagerWalFrames(
assert( pPager->pWal );
assert( pList );
#ifdef SQLITE_DEBUG
- /* Verify that the page list is in accending order */
+ /* Verify that the page list is in ascending order */
for(p=pList; p && p->pDirty; p=p->pDirty){
assert( p->pgno < p->pDirty->pgno );
}
@@ -57397,7 +60662,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
#ifndef SQLITE_OMIT_WAL
/*
** Check if the *-wal file that corresponds to the database opened by pPager
-** exists if the database is not empy, or verify that the *-wal file does
+** exists if the database is not empty, or verify that the *-wal file does
** not exist (by deleting it) if the database file is empty.
**
** If the database is not empty and the *-wal file exists, open the pager
@@ -57686,7 +60951,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3PagerShrink(Pager *pPager){
** Numeric values associated with these states are OFF==1, NORMAL=2,
** and FULL=3.
*/
-#ifndef SQLITE_OMIT_PAGER_PRAGMAS
SQLITE_PRIVATE void sqlcipher_sqlite3PagerSetFlags(
Pager *pPager, /* The pager to set safety level for */
unsigned pgFlags /* Various flags */
@@ -57721,7 +60985,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3PagerSetFlags(
pPager->doNotSpill |= SPILLFLAG_OFF;
}
}
-#endif
/*
** The following global variable is incremented whenever the library
@@ -58826,11 +62089,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerOpen(
int rc = SQLITE_OK; /* Return code */
int tempFile = 0; /* True for temp files (incl. in-memory files) */
int memDb = 0; /* True if this is an in-memory file */
-#ifndef SQLITE_OMIT_DESERIALIZE
int memJM = 0; /* Memory journal mode */
-#else
-# define memJM 0
-#endif
int readOnly = 0; /* True if this is a read-only file */
int journalFileSize; /* Bytes to allocate for each journal fd */
char *zPathname = 0; /* Full path to database file */
@@ -58840,7 +62099,6 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerOpen(
u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */
const char *zUri = 0; /* URI args to copy */
int nUriByte = 1; /* Number of bytes of URI args at *zUri */
- int nUri = 0; /* Number of URI parameters */
/* Figure out how much space is required for each journal file-handle
** (there are two of them, the main journal and the sub-journal). */
@@ -58888,7 +62146,6 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerOpen(
while( *z ){
z += strlen(z)+1;
z += strlen(z)+1;
- nUri++;
}
nUriByte = (int)(&z[1] - zUri);
assert( nUriByte>=1 );
@@ -58951,12 +62208,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerOpen(
** specific formatting and order of the various filenames, so if the format
** changes here, be sure to change it there as well.
*/
+ assert( SQLITE_PTRSIZE==sizeof(Pager*) );
pPtr = (u8 *)sqlcipher_sqlite3MallocZero(
ROUND8(sizeof(*pPager)) + /* Pager structure */
ROUND8(pcacheSize) + /* PCache object */
ROUND8(pVfs->szOsFile) + /* The main db file */
journalFileSize * 2 + /* The two journal files */
- sizeof(pPager) + /* Space to hold a pointer */
+ SQLITE_PTRSIZE + /* Space to hold a pointer */
4 + /* Database prefix */
nPathname + 1 + /* database filename */
nUriByte + /* query parameters */
@@ -58977,7 +62235,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerOpen(
pPager->sjfd = (sqlcipher_sqlite3_file*)pPtr; pPtr += journalFileSize;
pPager->jfd = (sqlcipher_sqlite3_file*)pPtr; pPtr += journalFileSize;
assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );
- memcpy(pPtr, &pPager, sizeof(pPager)); pPtr += sizeof(pPager);
+ memcpy(pPtr, &pPager, SQLITE_PTRSIZE); pPtr += SQLITE_PTRSIZE;
/* Fill in the Pager.zFilename and pPager.zQueryParam fields */
pPtr += 4; /* Skip zero prefix */
@@ -59031,9 +62289,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerOpen(
int fout = 0; /* VFS flags returned by xOpen() */
rc = sqlcipher_sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
assert( !memDb );
-#ifndef SQLITE_OMIT_DESERIALIZE
pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
-#endif
readOnly = (fout&SQLITE_OPEN_READONLY)!=0;
/* If the file was successfully opened for read/write access,
@@ -59144,18 +62400,7 @@ act_like_temp_file:
pPager->memDb = (u8)memDb;
pPager->readOnly = (u8)readOnly;
assert( useJournal || pPager->tempFile );
- pPager->noSync = pPager->tempFile;
- if( pPager->noSync ){
- assert( pPager->fullSync==0 );
- assert( pPager->extraSync==0 );
- assert( pPager->syncFlags==0 );
- assert( pPager->walSyncFlags==0 );
- }else{
- pPager->fullSync = 1;
- pPager->extraSync = 0;
- pPager->syncFlags = SQLITE_SYNC_NORMAL;
- pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2);
- }
+ sqlcipher_sqlite3PagerSetFlags(pPager, (SQLITE_DEFAULT_SYNCHRONOUS+1)|PAGER_CACHESPILL);
/* pPager->pFirst = 0; */
/* pPager->pFirstSynced = 0; */
/* pPager->pLast = 0; */
@@ -59181,15 +62426,18 @@ act_like_temp_file:
/*
** Return the sqlcipher_sqlite3_file for the main database given the name
-** of the corresonding WAL or Journal name as passed into
+** of the corresponding WAL or Journal name as passed into
** xOpen.
*/
SQLITE_API sqlcipher_sqlite3_file *sqlcipher_sqlite3_database_file_object(const char *zName){
Pager *pPager;
+ const char *p;
while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){
zName--;
}
- pPager = *(Pager**)(zName - 4 - sizeof(Pager*));
+ p = zName - 4 - sizeof(Pager*);
+ assert( EIGHT_BYTE_ALIGNMENT(p) );
+ pPager = *(Pager**)p;
return pPager->fd;
}
@@ -59684,6 +62932,10 @@ static int getPageNormal(
if( !isOpen(pPager->fd) || pPager->dbSize<pgno || noContent ){
if( pgno>pPager->mxPgno ){
rc = SQLITE_FULL;
+ if( pgno<=pPager->dbSize ){
+ sqlcipher_sqlite3PcacheRelease(pPg);
+ pPg = 0;
+ }
goto pager_acquire_err;
}
if( noContent ){
@@ -59824,8 +63076,20 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerGet(
DbPage **ppPage, /* Write a pointer to the page here */
int flags /* PAGER_GET_XXX flags */
){
- /* printf("PAGE %u\n", pgno); fflush(stdout); */
+#if 0 /* Trace page fetch by setting to 1 */
+ int rc;
+ printf("PAGE %u\n", pgno);
+ fflush(stdout);
+ rc = pPager->xGet(pPager, pgno, ppPage, flags);
+ if( rc ){
+ printf("PAGE %u failed with 0x%02x\n", pgno, rc);
+ fflush(stdout);
+ }
+ return rc;
+#else
+ /* Normal, high-speed version of sqlcipher_sqlite3PagerGet() */
return pPager->xGet(pPager, pgno, ppPage, flags);
+#endif
}
/*
@@ -59853,10 +63117,12 @@ SQLITE_PRIVATE DbPage *sqlcipher_sqlite3PagerLookup(Pager *pPager, Pgno pgno){
/*
** Release a page reference.
**
-** The sqlcipher_sqlite3PagerUnref() and sqlcipher_sqlite3PagerUnrefNotNull() may only be
-** used if we know that the page being released is not the last page.
+** The sqlcipher_sqlite3PagerUnref() and sqlcipher_sqlite3PagerUnrefNotNull() may only be used
+** if we know that the page being released is not the last reference to page1.
** The btree layer always holds page1 open until the end, so these first
-** to routines can be used to release any page other than BtShared.pPage1.
+** two routines can be used to release any page other than BtShared.pPage1.
+** The assert() at tag-20230419-2 proves that this constraint is always
+** honored.
**
** Use sqlcipher_sqlite3PagerUnrefPageOne() to release page1. This latter routine
** checks the total number of outstanding pages and if the number of
@@ -59872,7 +63138,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3PagerUnrefNotNull(DbPage *pPg){
sqlcipher_sqlite3PcacheRelease(pPg);
}
/* Do not use this routine to release the last reference to page1 */
- assert( sqlcipher_sqlite3PcacheRefCount(pPager->pPCache)>0 );
+ assert( sqlcipher_sqlite3PcacheRefCount(pPager->pPCache)>0 ); /* tag-20230419-2 */
}
SQLITE_PRIVATE void sqlcipher_sqlite3PagerUnref(DbPage *pPg){
if( pPg ) sqlcipher_sqlite3PagerUnrefNotNull(pPg);
@@ -59938,6 +63204,7 @@ static int pager_open_journal(Pager *pPager){
if( pPager->tempFile ){
flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
+ flags |= SQLITE_OPEN_EXCLUSIVE;
nSpill = sqlcipher_sqlite3Config.nStmtSpill;
}else{
flags |= SQLITE_OPEN_MAIN_JOURNAL;
@@ -60420,7 +63687,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
# define DIRECT_MODE isDirectMode
#endif
- if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){
+ if( !pPager->changeCountDone && pPager->dbSize>0 ){
PgHdr *pPgHdr; /* Reference to page 1 */
assert( !pPager->tempFile && isOpen(pPager->fd) );
@@ -60698,6 +63965,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerCommitPhaseOne(
rc = sqlcipher_sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
if( rc==SQLITE_OK ){
rc = pager_write_pagelist(pPager, pList);
+ if( rc==SQLITE_OK && pPager->dbSize>pPager->dbFileSize ){
+ char *pTmp = pPager->pTmpSpace;
+ int szPage = (int)pPager->pageSize;
+ memset(pTmp, 0, szPage);
+ rc = sqlcipher_sqlite3OsWrite(pPager->fd, pTmp, szPage,
+ ((i64)pPager->dbSize*pPager->pageSize)-szPage);
+ }
if( rc==SQLITE_OK ){
rc = sqlcipher_sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
}
@@ -60932,11 +64206,11 @@ SQLITE_PRIVATE int *sqlcipher_sqlite3PagerStats(Pager *pPager){
a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize;
a[4] = pPager->eState;
a[5] = pPager->errCode;
- a[6] = pPager->aStat[PAGER_STAT_HIT];
- a[7] = pPager->aStat[PAGER_STAT_MISS];
+ a[6] = (int)pPager->aStat[PAGER_STAT_HIT] & 0x7fffffff;
+ a[7] = (int)pPager->aStat[PAGER_STAT_MISS] & 0x7fffffff;
a[8] = 0; /* Used to be pPager->nOvfl */
a[9] = pPager->nRead;
- a[10] = pPager->aStat[PAGER_STAT_WRITE];
+ a[10] = (int)pPager->aStat[PAGER_STAT_WRITE] & 0x7fffffff;
return a;
}
#endif
@@ -60952,7 +64226,7 @@ SQLITE_PRIVATE int *sqlcipher_sqlite3PagerStats(Pager *pPager){
** reset parameter is non-zero, the cache hit or miss count is zeroed before
** returning.
*/
-SQLITE_PRIVATE void sqlcipher_sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
+SQLITE_PRIVATE void sqlcipher_sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, u64 *pnVal){
assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
|| eStat==SQLITE_DBSTATUS_CACHE_MISS
@@ -61160,7 +64434,11 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerSavepoint(Pager *pPager, int op, int iS
*/
SQLITE_PRIVATE const char *sqlcipher_sqlite3PagerFilename(const Pager *pPager, int nullIfMemDb){
static const char zFake[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
- return (nullIfMemDb && pPager->memDb) ? &zFake[4] : pPager->zFilename;
+ if( nullIfMemDb && (pPager->memDb || sqlcipher_sqlite3IsMemdb(pPager->pVfs)) ){
+ return &zFake[4];
+ }else{
+ return pPager->zFilename;
+ }
}
/*
@@ -61184,7 +64462,7 @@ SQLITE_PRIVATE sqlcipher_sqlite3_file *sqlcipher_sqlite3PagerFile(Pager *pPager)
** This will be either the rollback journal or the WAL file.
*/
SQLITE_PRIVATE sqlcipher_sqlite3_file *sqlcipher_sqlite3PagerJrnlFile(Pager *pPager){
-#if SQLITE_OMIT_WAL
+#ifdef SQLITE_OMIT_WAL
return pPager->jfd;
#else
return pPager->pWal ? sqlcipher_sqlite3WalFile(pPager->pWal) : pPager->jfd;
@@ -61503,7 +64781,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerSetJournalMode(Pager *pPager, int eMode
assert( pPager->eState!=PAGER_ERROR );
pPager->journalMode = (u8)eMode;
- /* When transistioning from TRUNCATE or PERSIST to any other journal
+ /* When transitioning from TRUNCATE or PERSIST to any other journal
** mode except WAL, unless the pager is in locking_mode=exclusive mode,
** delete the journal file.
*/
@@ -61548,7 +64826,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerSetJournalMode(Pager *pPager, int eMode
}
assert( state==pPager->eState );
}
- }else if( eMode==PAGER_JOURNALMODE_OFF ){
+ }else if( eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_MEMORY ){
sqlcipher_sqlite3OsClose(pPager->jfd);
}
}
@@ -61572,7 +64850,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerGetJournalMode(Pager *pPager){
SQLITE_PRIVATE int sqlcipher_sqlite3PagerOkToChangeJournalMode(Pager *pPager){
assert( assert_pager_state(pPager) );
if( pPager->eState>=PAGER_WRITER_CACHEMOD ) return 0;
- if( isOpen(pPager->jfd) && pPager->journalOff>0 ) return 0;
+ if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0;
return 1;
}
@@ -61670,13 +64948,15 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerWalSupported(Pager *pPager){
*/
static int pagerExclusiveLock(Pager *pPager){
int rc; /* Return code */
+ u8 eOrigLock; /* Original lock */
- assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
+ assert( pPager->eLock>=SHARED_LOCK );
+ eOrigLock = pPager->eLock;
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
/* If the attempt to grab the exclusive lock failed, release the
** pending lock that may have been obtained instead. */
- pagerUnlockDb(pPager, SHARED_LOCK);
+ pagerUnlockDb(pPager, eOrigLock);
}
return rc;
@@ -61929,6 +65209,12 @@ SQLITE_PRIVATE int sqlcipher_sqlite3PagerWalFramesize(Pager *pPager){
}
#endif
+#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
+SQLITE_PRIVATE int sqlcipher_sqlite3PagerWalSystemErrno(Pager *pPager){
+ return sqlcipher_sqlite3WalSystemErrno(pPager->pWal);
+}
+#endif
+
#endif /* SQLITE_OMIT_DISKIO */
/* BEGIN SQLCIPHER */
@@ -62240,7 +65526,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalTrace = 0;
**
** Technically, the various VFSes are free to implement these locks however
** they see fit. However, compatibility is encouraged so that VFSes can
-** interoperate. The standard implemention used on both unix and windows
+** interoperate. The standard implementation used on both unix and windows
** is for the index number to indicate a byte offset into the
** WalCkptInfo.aLock[] array in the wal-index header. In other words, all
** locks are on the shm file. The WALINDEX_LOCK_OFFSET constant (which
@@ -62316,7 +65602,7 @@ struct WalIndexHdr {
** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
** for any aReadMark[] means that entry is unused. aReadMark[0] is
** a special case; its value is never used and it exists as a place-holder
-** to avoid having to offset aReadMark[] indexs by one. Readers holding
+** to avoid having to offset aReadMark[] indexes by one. Readers holding
** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
** directly from the database.
**
@@ -62484,7 +65770,15 @@ struct Wal {
u32 iReCksum; /* On commit, recalculate checksums from here */
const char *zWalName; /* Name of WAL file */
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
+#ifdef SQLITE_USE_SEH
+ u32 lockMask; /* Mask of locks held */
+ void *pFree; /* Pointer to sqlcipher_sqlite3_free() if exception thrown */
+ u32 *pWiValue; /* Value to write into apWiData[iWiPg] */
+ int iWiPg; /* Write pWiValue into apWiData[iWiPg] */
+ int iSysErrno; /* System error code following exception */
+#endif
#ifdef SQLITE_DEBUG
+ int nSehTry; /* Number of nested SEH_TRY{} blocks */
u8 lockError; /* True if a locking error has occurred */
#endif
#ifdef SQLITE_ENABLE_SNAPSHOT
@@ -62567,6 +65861,113 @@ struct WalIterator {
)
/*
+** Structured Exception Handling (SEH) is a Windows-specific technique
+** for catching exceptions raised while accessing memory-mapped files.
+**
+** The -DSQLITE_USE_SEH compile-time option means to use SEH to catch and
+** deal with system-level errors that arise during WAL -shm file processing.
+** Without this compile-time option, any system-level faults that appear
+** while accessing the memory-mapped -shm file will cause a process-wide
+** signal to be deliver, which will more than likely cause the entire
+** process to exit.
+*/
+#ifdef SQLITE_USE_SEH
+#include <Windows.h>
+
+/* Beginning of a block of code in which an exception might occur */
+# define SEH_TRY __try { \
+ assert( walAssertLockmask(pWal) && pWal->nSehTry==0 ); \
+ VVA_ONLY(pWal->nSehTry++);
+
+/* The end of a block of code in which an exception might occur */
+# define SEH_EXCEPT(X) \
+ VVA_ONLY(pWal->nSehTry--); \
+ assert( pWal->nSehTry==0 ); \
+ } __except( sehExceptionFilter(pWal, GetExceptionCode(), GetExceptionInformation() ) ){ X }
+
+/* Simulate a memory-mapping fault in the -shm file for testing purposes */
+# define SEH_INJECT_FAULT sehInjectFault(pWal)
+
+/*
+** The second argument is the return value of GetExceptionCode() for the
+** current exception. Return EXCEPTION_EXECUTE_HANDLER if the exception code
+** indicates that the exception may have been caused by accessing the *-shm
+** file mapping. Or EXCEPTION_CONTINUE_SEARCH otherwise.
+*/
+static int sehExceptionFilter(Wal *pWal, int eCode, EXCEPTION_POINTERS *p){
+ VVA_ONLY(pWal->nSehTry--);
+ if( eCode==EXCEPTION_IN_PAGE_ERROR ){
+ if( p && p->ExceptionRecord && p->ExceptionRecord->NumberParameters>=3 ){
+ /* From MSDN: For this type of exception, the first element of the
+ ** ExceptionInformation[] array is a read-write flag - 0 if the exception
+ ** was thrown while reading, 1 if while writing. The second element is
+ ** the virtual address being accessed. The "third array element specifies
+ ** the underlying NTSTATUS code that resulted in the exception". */
+ pWal->iSysErrno = (int)p->ExceptionRecord->ExceptionInformation[2];
+ }
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+/*
+** If one is configured, invoke the xTestCallback callback with 650 as
+** the argument. If it returns true, throw the same exception that is
+** thrown by the system if the *-shm file mapping is accessed after it
+** has been invalidated.
+*/
+static void sehInjectFault(Wal *pWal){
+ int res;
+ assert( pWal->nSehTry>0 );
+
+ res = sqlcipher_sqlite3FaultSim(650);
+ if( res!=0 ){
+ ULONG_PTR aArg[3];
+ aArg[0] = 0;
+ aArg[1] = 0;
+ aArg[2] = (ULONG_PTR)res;
+ RaiseException(EXCEPTION_IN_PAGE_ERROR, 0, 3, (const ULONG_PTR*)aArg);
+ }
+}
+
+/*
+** There are two ways to use this macro. To set a pointer to be freed
+** if an exception is thrown:
+**
+** SEH_FREE_ON_ERROR(0, pPtr);
+**
+** and to cancel the same:
+**
+** SEH_FREE_ON_ERROR(pPtr, 0);
+**
+** In the first case, there must not already be a pointer registered to
+** be freed. In the second case, pPtr must be the registered pointer.
+*/
+#define SEH_FREE_ON_ERROR(X,Y) \
+ assert( (X==0 || Y==0) && pWal->pFree==X ); pWal->pFree = Y
+
+/*
+** There are two ways to use this macro. To arrange for pWal->apWiData[iPg]
+** to be set to pValue if an exception is thrown:
+**
+** SEH_SET_ON_ERROR(iPg, pValue);
+**
+** and to cancel the same:
+**
+** SEH_SET_ON_ERROR(0, 0);
+*/
+#define SEH_SET_ON_ERROR(X,Y) pWal->iWiPg = X; pWal->pWiValue = Y
+
+#else
+# define SEH_TRY VVA_ONLY(pWal->nSehTry++);
+# define SEH_EXCEPT(X) VVA_ONLY(pWal->nSehTry--); assert( pWal->nSehTry==0 );
+# define SEH_INJECT_FAULT assert( pWal->nSehTry>0 );
+# define SEH_FREE_ON_ERROR(X,Y)
+# define SEH_SET_ON_ERROR(X,Y)
+#endif /* ifdef SQLITE_USE_SEH */
+
+
+/*
** Obtain a pointer to the iPage'th page of the wal-index. The wal-index
** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are
** numbered from zero.
@@ -62638,6 +66039,7 @@ static int walIndexPage(
int iPage, /* The page we seek */
volatile u32 **ppPage /* Write the page pointer here */
){
+ SEH_INJECT_FAULT;
if( pWal->nWiData<=iPage || (*ppPage = pWal->apWiData[iPage])==0 ){
return walIndexPageRealloc(pWal, iPage, ppPage);
}
@@ -62649,6 +66051,7 @@ static int walIndexPage(
*/
static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ SEH_INJECT_FAULT;
return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
}
@@ -62657,6 +66060,7 @@ static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
*/
static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ SEH_INJECT_FAULT;
return (volatile WalIndexHdr*)pWal->apWiData[0];
}
@@ -62702,19 +66106,40 @@ static void walChecksumBytes(
assert( nByte>=8 );
assert( (nByte&0x00000007)==0 );
assert( nByte<=65536 );
+ assert( nByte%4==0 );
- if( nativeCksum ){
+ if( !nativeCksum ){
do {
+ s1 += BYTESWAP32(aData[0]) + s2;
+ s2 += BYTESWAP32(aData[1]) + s1;
+ aData += 2;
+ }while( aData<aEnd );
+ }else if( nByte%64==0 ){
+ do {
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
s1 += *aData++ + s2;
s2 += *aData++ + s1;
}while( aData<aEnd );
}else{
do {
- s1 += BYTESWAP32(aData[0]) + s2;
- s2 += BYTESWAP32(aData[1]) + s1;
- aData += 2;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
}while( aData<aEnd );
}
+ assert( aData==aEnd );
aOut[0] = s1;
aOut[1] = s2;
@@ -62825,7 +66250,7 @@ static int walDecodeFrame(
return 0;
}
- /* A frame is only valid if the page number is creater than zero.
+ /* A frame is only valid if the page number is greater than zero.
*/
pgno = sqlcipher_sqlite3Get4byte(&aFrame[0]);
if( pgno==0 ){
@@ -62833,7 +66258,7 @@ static int walDecodeFrame(
}
/* A frame is only valid if a checksum of the WAL header,
- ** all prior frams, the first 16 bytes of this frame-header,
+ ** all prior frames, the first 16 bytes of this frame-header,
** and the frame-data matches the checksum in the last 8
** bytes of this frame-header.
*/
@@ -62893,12 +66318,18 @@ static int walLockShared(Wal *pWal, int lockIdx){
WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
walLockName(lockIdx), rc ? "failed" : "ok"));
VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
+#ifdef SQLITE_USE_SEH
+ if( rc==SQLITE_OK ) pWal->lockMask |= (1 << lockIdx);
+#endif
return rc;
}
static void walUnlockShared(Wal *pWal, int lockIdx){
if( pWal->exclusiveMode ) return;
(void)sqlcipher_sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
+#ifdef SQLITE_USE_SEH
+ pWal->lockMask &= ~(1 << lockIdx);
+#endif
WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
}
static int walLockExclusive(Wal *pWal, int lockIdx, int n){
@@ -62909,12 +66340,20 @@ static int walLockExclusive(Wal *pWal, int lockIdx, int n){
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&0xFF)!=SQLITE_BUSY); )
+#ifdef SQLITE_USE_SEH
+ if( rc==SQLITE_OK ){
+ pWal->lockMask |= (((1<<n)-1) << (SQLITE_SHM_NLOCK+lockIdx));
+ }
+#endif
return rc;
}
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
if( pWal->exclusiveMode ) return;
(void)sqlcipher_sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
+#ifdef SQLITE_USE_SEH
+ pWal->lockMask &= ~(((1<<n)-1) << (SQLITE_SHM_NLOCK+lockIdx));
+#endif
WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
walLockName(lockIdx), n));
}
@@ -63006,6 +66445,7 @@ static int walFramePage(u32 iFrame){
*/
static u32 walFramePgno(Wal *pWal, u32 iFrame){
int iHash = walFramePage(iFrame);
+ SEH_INJECT_FAULT;
if( iHash==0 ){
return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
}
@@ -63265,6 +66705,7 @@ static int walIndexRecover(Wal *pWal){
/* Malloc a buffer to read frames into. */
szFrame = szPage + WAL_FRAME_HDRSIZE;
aFrame = (u8 *)sqlcipher_sqlite3_malloc64(szFrame + WALINDEX_PGSZ);
+ SEH_FREE_ON_ERROR(0, aFrame);
if( !aFrame ){
rc = SQLITE_NOMEM_BKPT;
goto recovery_error;
@@ -63283,6 +66724,7 @@ static int walIndexRecover(Wal *pWal){
rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare);
assert( aShare!=0 || rc!=SQLITE_OK );
if( aShare==0 ) break;
+ SEH_SET_ON_ERROR(iPg, aShare);
pWal->apWiData[iPg] = aPrivate;
for(iFrame=iFirst; iFrame<=iLast; iFrame++){
@@ -63310,6 +66752,7 @@ static int walIndexRecover(Wal *pWal){
}
}
pWal->apWiData[iPg] = aShare;
+ SEH_SET_ON_ERROR(0,0);
nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0);
nHdr32 = nHdr / sizeof(u32);
#ifndef SQLITE_SAFER_WALINDEX_RECOVERY
@@ -63340,9 +66783,11 @@ static int walIndexRecover(Wal *pWal){
}
}
#endif
+ SEH_INJECT_FAULT;
if( iFrame<=iLast ) break;
}
+ SEH_FREE_ON_ERROR(aFrame, 0);
sqlcipher_sqlite3_free(aFrame);
}
@@ -63370,6 +66815,7 @@ finished:
}else{
pInfo->aReadMark[i] = READMARK_NOT_USED;
}
+ SEH_INJECT_FAULT;
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
}else if( rc!=SQLITE_BUSY ){
goto recovery_error;
@@ -63527,7 +66973,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalOpen(
}
/*
-** Change the size to which the WAL file is trucated on each reset.
+** Change the size to which the WAL file is truncated on each reset.
*/
SQLITE_PRIVATE void sqlcipher_sqlite3WalLimit(Wal *pWal, i64 iLimit){
if( pWal ) pWal->mxWalSize = iLimit;
@@ -63753,23 +67199,16 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
nByte = sizeof(WalIterator)
+ (nSegment-1)*sizeof(struct WalSegment)
+ iLast*sizeof(ht_slot);
- p = (WalIterator *)sqlcipher_sqlite3_malloc64(nByte);
+ p = (WalIterator *)sqlcipher_sqlite3_malloc64(nByte
+ + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
+ );
if( !p ){
return SQLITE_NOMEM_BKPT;
}
memset(p, 0, nByte);
p->nSegment = nSegment;
-
- /* Allocate temporary space used by the merge-sort routine. This block
- ** of memory will be freed before this function returns.
- */
- aTmp = (ht_slot *)sqlcipher_sqlite3_malloc64(
- sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
- );
- if( !aTmp ){
- rc = SQLITE_NOMEM_BKPT;
- }
-
+ aTmp = (ht_slot*)&(((u8*)p)[nByte]);
+ SEH_FREE_ON_ERROR(0, p);
for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && i<nSegment; i++){
WalHashLoc sLoc;
@@ -63797,9 +67236,8 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
p->aSegment[i].aPgno = (u32 *)sLoc.aPgno;
}
}
- sqlcipher_sqlite3_free(aTmp);
-
if( rc!=SQLITE_OK ){
+ SEH_FREE_ON_ERROR(p, 0);
walIteratorFree(p);
p = 0;
}
@@ -63808,6 +67246,19 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
}
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+
+
+/*
+** Attempt to enable blocking locks that block for nMs ms. Return 1 if
+** blocking locks are successfully enabled, or 0 otherwise.
+*/
+static int walEnableBlockingMs(Wal *pWal, int nMs){
+ int rc = sqlcipher_sqlite3OsFileControl(
+ pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&nMs
+ );
+ return (rc==SQLITE_OK);
+}
+
/*
** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
** they are supported by the VFS, and (b) the database handle is configured
@@ -63819,11 +67270,7 @@ static int walEnableBlocking(Wal *pWal){
if( pWal->db ){
int tmout = pWal->db->busyTimeout;
if( tmout ){
- int rc;
- rc = sqlcipher_sqlite3OsFileControl(
- pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
- );
- res = (rc==SQLITE_OK);
+ res = walEnableBlockingMs(pWal, tmout);
}
}
return res;
@@ -63872,20 +67319,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WalDb(Wal *pWal, sqlcipher_sqlite3 *db){
pWal->db = db;
}
-/*
-** Take an exclusive WRITE lock. Blocking if so configured.
-*/
-static int walLockWriter(Wal *pWal){
- int rc;
- walEnableBlocking(pWal);
- rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
- walDisableBlocking(pWal);
- return rc;
-}
#else
# define walEnableBlocking(x) 0
# define walDisableBlocking(x)
-# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
+# define walEnableBlockingMs(pWal, ms) 0
# define sqlcipher_sqlite3WalDb(pWal, db)
#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
@@ -64025,13 +67462,13 @@ static int walCheckpoint(
mxSafeFrame = pWal->hdr.mxFrame;
mxPage = pWal->hdr.nPage;
for(i=1; i<WAL_NREADER; i++){
- u32 y = AtomicLoad(pInfo->aReadMark+i);
+ u32 y = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
if( mxSafeFrame>y ){
assert( y<=pWal->hdr.mxFrame );
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
if( rc==SQLITE_OK ){
u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
- AtomicStore(pInfo->aReadMark+i, iMark);
+ AtomicStore(pInfo->aReadMark+i, iMark); SEH_INJECT_FAULT;
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
}else if( rc==SQLITE_BUSY ){
mxSafeFrame = y;
@@ -64052,8 +67489,7 @@ static int walCheckpoint(
&& (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK
){
u32 nBackfill = pInfo->nBackfill;
-
- pInfo->nBackfillAttempted = mxSafeFrame;
+ pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT;
/* Sync the WAL to disk */
rc = sqlcipher_sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
@@ -64084,6 +67520,7 @@ static int walCheckpoint(
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
i64 iOffset;
assert( walFramePgno(pWal, iFrame)==iDbpage );
+ SEH_INJECT_FAULT;
if( AtomicLoad(&db->u1.isInterrupted) ){
rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
break;
@@ -64113,7 +67550,7 @@ static int walCheckpoint(
}
}
if( rc==SQLITE_OK ){
- AtomicStore(&pInfo->nBackfill, mxSafeFrame);
+ AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT;
}
}
@@ -64135,6 +67572,7 @@ static int walCheckpoint(
*/
if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
assert( pWal->writeLock );
+ SEH_INJECT_FAULT;
if( pInfo->nBackfill<pWal->hdr.mxFrame ){
rc = SQLITE_BUSY;
}else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
@@ -64166,6 +67604,7 @@ static int walCheckpoint(
}
walcheckpoint_out:
+ SEH_FREE_ON_ERROR(pIter, 0);
walIteratorFree(pIter);
return rc;
}
@@ -64188,6 +67627,93 @@ static void walLimitSize(Wal *pWal, i64 nMax){
}
}
+#ifdef SQLITE_USE_SEH
+/*
+** This is the "standard" exception handler used in a few places to handle
+** an exception thrown by reading from the *-shm mapping after it has become
+** invalid in SQLITE_USE_SEH builds. It is used as follows:
+**
+** SEH_TRY { ... }
+** SEH_EXCEPT( rc = walHandleException(pWal); )
+**
+** This function does three things:
+**
+** 1) Determines the locks that should be held, based on the contents of
+** the Wal.readLock, Wal.writeLock and Wal.ckptLock variables. All other
+** held locks are assumed to be transient locks that would have been
+** released had the exception not been thrown and are dropped.
+**
+** 2) Frees the pointer at Wal.pFree, if any, using sqlcipher_sqlite3_free().
+**
+** 3) Set pWal->apWiData[pWal->iWiPg] to pWal->pWiValue if not NULL
+**
+** 4) Returns SQLITE_IOERR.
+*/
+static int walHandleException(Wal *pWal){
+ if( pWal->exclusiveMode==0 ){
+ static const int S = 1;
+ static const int E = (1<<SQLITE_SHM_NLOCK);
+ int ii;
+ u32 mUnlock = pWal->lockMask & ~(
+ (pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock)))
+ | (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0)
+ | (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0)
+ );
+ for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
+ if( (S<<ii) & mUnlock ) walUnlockShared(pWal, ii);
+ if( (E<<ii) & mUnlock ) walUnlockExclusive(pWal, ii, 1);
+ }
+ }
+ sqlcipher_sqlite3_free(pWal->pFree);
+ pWal->pFree = 0;
+ if( pWal->pWiValue ){
+ pWal->apWiData[pWal->iWiPg] = pWal->pWiValue;
+ pWal->pWiValue = 0;
+ }
+ return SQLITE_IOERR_IN_PAGE;
+}
+
+/*
+** Assert that the Wal.lockMask mask, which indicates the locks held
+** by the connenction, is consistent with the Wal.readLock, Wal.writeLock
+** and Wal.ckptLock variables. To be used as:
+**
+** assert( walAssertLockmask(pWal) );
+*/
+static int walAssertLockmask(Wal *pWal){
+ if( pWal->exclusiveMode==0 ){
+ static const int S = 1;
+ static const int E = (1<<SQLITE_SHM_NLOCK);
+ u32 mExpect = (
+ (pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock)))
+ | (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0)
+ | (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0)
+#ifdef SQLITE_ENABLE_SNAPSHOT
+ | (pWal->pSnapshot ? (pWal->lockMask & (1 << WAL_CKPT_LOCK)) : 0)
+#endif
+ );
+ assert( mExpect==pWal->lockMask );
+ }
+ return 1;
+}
+
+/*
+** Return and zero the "system error" field set when an
+** EXCEPTION_IN_PAGE_ERROR exception is caught.
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3WalSystemErrno(Wal *pWal){
+ int iRet = 0;
+ if( pWal ){
+ iRet = pWal->iSysErrno;
+ pWal->iSysErrno = 0;
+ }
+ return iRet;
+}
+
+#else
+# define walAssertLockmask(x) 1
+#endif /* ifdef SQLITE_USE_SEH */
+
/*
** Close a connection to a log file.
*/
@@ -64202,6 +67728,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalClose(
if( pWal ){
int isDelete = 0; /* True to unlink wal and wal-index files */
+ assert( walAssertLockmask(pWal) );
+
/* 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
@@ -64226,7 +67754,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalClose(
);
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
+ ** fsynced (rc==SQLITE_OK) and if we are not in persistent-wal
** mode (!bPersist) */
isDelete = 1;
}else if( pWal->mxWalSize>=0 ){
@@ -64293,7 +67821,7 @@ static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){
** give false-positive warnings about these accesses because the tools do not
** account for the double-read and the memory barrier. The use of mutexes
** here would be problematic as the memory being accessed is potentially
- ** shared among multiple processes and not all mutex implementions work
+ ** shared among multiple processes and not all mutex implementations work
** reliably in that environment.
*/
aHdr = walIndexHdr(pWal);
@@ -64395,7 +67923,9 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
}
}else{
int bWriteLock = pWal->writeLock;
- if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
+ if( bWriteLock
+ || SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1))
+ ){
pWal->writeLock = 1;
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
badHdr = walIndexTryHdr(pWal, pChanged);
@@ -64403,7 +67933,8 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
/* 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.
- */
+ ** Disable blocking locks first. */
+ walDisableBlocking(pWal);
rc = walIndexRecover(pWal);
*pChanged = 1;
}
@@ -64614,6 +68145,37 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
}
/*
+** The final argument passed to walTryBeginRead() is of type (int*). The
+** caller should invoke walTryBeginRead as follows:
+**
+** int cnt = 0;
+** do {
+** rc = walTryBeginRead(..., &cnt);
+** }while( rc==WAL_RETRY );
+**
+** The final value of "cnt" is of no use to the caller. It is used by
+** the implementation of walTryBeginRead() as follows:
+**
+** + Each time walTryBeginRead() is called, it is incremented. Once
+** it reaches WAL_RETRY_PROTOCOL_LIMIT - indicating that walTryBeginRead()
+** has many times been invoked and failed with WAL_RETRY - walTryBeginRead()
+** returns SQLITE_PROTOCOL.
+**
+** + If SQLITE_ENABLE_SETLK_TIMEOUT is defined and walTryBeginRead() failed
+** because a blocking lock timed out (SQLITE_BUSY_TIMEOUT from the OS
+** layer), the WAL_RETRY_BLOCKED_MASK bit is set in "cnt". In this case
+** the next invocation of walTryBeginRead() may omit an expected call to
+** sqlcipher_sqlite3OsSleep(). There has already been a delay when the previous call
+** waited on a lock.
+*/
+#define WAL_RETRY_PROTOCOL_LIMIT 100
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+# define WAL_RETRY_BLOCKED_MASK 0x10000000
+#else
+# define WAL_RETRY_BLOCKED_MASK 0
+#endif
+
+/*
** 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.
@@ -64663,13 +68225,16 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
** 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){
+static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
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 */
u32 mxFrame; /* Wal frame to lock to */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ int nBlockTmout = 0;
+#endif
assert( pWal->readLock<0 ); /* Not currently locked */
@@ -64693,14 +68258,34 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** so that on the 100th (and last) RETRY we delay for 323 milliseconds.
** The total delay time before giving up is less than 10 seconds.
*/
- if( cnt>5 ){
+ (*pCnt)++;
+ if( *pCnt>5 ){
int nDelay = 1; /* Pause time in microseconds */
- if( cnt>100 ){
+ int cnt = (*pCnt & ~WAL_RETRY_BLOCKED_MASK);
+ if( cnt>WAL_RETRY_PROTOCOL_LIMIT ){
VVA_ONLY( pWal->lockError = 1; )
return SQLITE_PROTOCOL;
}
- if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
+ if( *pCnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ /* In SQLITE_ENABLE_SETLK_TIMEOUT builds, configure the file-descriptor
+ ** to block for locks for approximately nDelay us. This affects three
+ ** locks: (a) the shared lock taken on the DMS slot in os_unix.c (if
+ ** using os_unix.c), (b) the WRITER lock taken in walIndexReadHdr() if the
+ ** first attempted read fails, and (c) the shared lock taken on the
+ ** read-mark.
+ **
+ ** If the previous call failed due to an SQLITE_BUSY_TIMEOUT error,
+ ** then sleep for the minimum of 1us. The previous call already provided
+ ** an extra delay while it was blocking on the lock.
+ */
+ nBlockTmout = (nDelay+998) / 1000;
+ if( !useWal && walEnableBlockingMs(pWal, nBlockTmout) ){
+ if( *pCnt & WAL_RETRY_BLOCKED_MASK ) nDelay = 1;
+ }
+#endif
sqlcipher_sqlite3OsSleep(pWal->pVfs, nDelay);
+ *pCnt &= ~WAL_RETRY_BLOCKED_MASK;
}
if( !useWal ){
@@ -64708,6 +68293,13 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
if( pWal->bShmUnreliable==0 ){
rc = walIndexReadHdr(pWal, pChanged);
}
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ walDisableBlocking(pWal);
+ if( rc==SQLITE_BUSY_TIMEOUT ){
+ rc = SQLITE_BUSY;
+ *pCnt |= WAL_RETRY_BLOCKED_MASK;
+ }
+#endif
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
@@ -64744,6 +68336,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
assert( pWal->nWiData>0 );
assert( pWal->apWiData[0]!=0 );
pInfo = walCkptInfo(pWal);
+ SEH_INJECT_FAULT;
if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
#ifdef SQLITE_ENABLE_SNAPSHOT
&& (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
@@ -64793,7 +68386,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}
#endif
for(i=1; i<WAL_NREADER; i++){
- u32 thisMark = AtomicLoad(pInfo->aReadMark+i);
+ u32 thisMark = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
if( mxReadMark<=thisMark && thisMark<=mxFrame ){
assert( thisMark!=READMARK_NOT_USED );
mxReadMark = thisMark;
@@ -64821,9 +68414,19 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
}
+ (void)walEnableBlockingMs(pWal, nBlockTmout);
rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+ walDisableBlocking(pWal);
if( rc ){
- return rc==SQLITE_BUSY ? WAL_RETRY : rc;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( rc==SQLITE_BUSY_TIMEOUT ){
+ *pCnt |= WAL_RETRY_BLOCKED_MASK;
+ }
+#else
+ assert( rc!=SQLITE_BUSY_TIMEOUT );
+#endif
+ assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT );
+ return (rc&0xFF)==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
@@ -64859,7 +68462,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** we can guarantee that the checkpointer that set nBackfill could not
** see any pages past pWal->hdr.mxFrame, this problem does not come up.
*/
- pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1;
+ pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; SEH_INJECT_FAULT;
walShmBarrier(pWal);
if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark
|| memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
@@ -64875,6 +68478,54 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
#ifdef SQLITE_ENABLE_SNAPSHOT
/*
+** This function does the work of sqlcipher_sqlite3WalSnapshotRecover().
+*/
+static int walSnapshotRecover(
+ Wal *pWal, /* WAL handle */
+ void *pBuf1, /* Temp buffer pWal->szPage bytes in size */
+ void *pBuf2 /* Temp buffer pWal->szPage bytes in size */
+){
+ int szPage = (int)pWal->szPage;
+ int rc;
+ i64 szDb; /* Size of db file in bytes */
+
+ rc = sqlcipher_sqlite3OsFileSize(pWal->pDbFd, &szDb);
+ if( rc==SQLITE_OK ){
+ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+ u32 i = pInfo->nBackfillAttempted;
+ for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
+ WalHashLoc sLoc; /* Hash table location */
+ u32 pgno; /* Page number in db file */
+ i64 iDbOff; /* Offset of db file entry */
+ i64 iWalOff; /* Offset of wal file entry */
+
+ rc = walHashGet(pWal, walFramePage(i), &sLoc);
+ if( rc!=SQLITE_OK ) break;
+ assert( i - sLoc.iZero - 1 >=0 );
+ pgno = sLoc.aPgno[i-sLoc.iZero-1];
+ iDbOff = (i64)(pgno-1) * szPage;
+
+ if( iDbOff+szPage<=szDb ){
+ iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
+ rc = sqlcipher_sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
+
+ if( rc==SQLITE_OK ){
+ rc = sqlcipher_sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
+ }
+
+ if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
+ break;
+ }
+ }
+
+ pInfo->nBackfillAttempted = i-1;
+ }
+ }
+
+ return rc;
+}
+
+/*
** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted
** variable so that older snapshots can be accessed. To do this, loop
** through all wal frames from nBackfillAttempted to (nBackfill+1),
@@ -64899,50 +68550,21 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalSnapshotRecover(Wal *pWal){
assert( pWal->readLock>=0 );
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
if( rc==SQLITE_OK ){
- volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
- int szPage = (int)pWal->szPage;
- i64 szDb; /* Size of db file in bytes */
-
- rc = sqlcipher_sqlite3OsFileSize(pWal->pDbFd, &szDb);
- if( rc==SQLITE_OK ){
- void *pBuf1 = sqlcipher_sqlite3_malloc(szPage);
- void *pBuf2 = sqlcipher_sqlite3_malloc(szPage);
- if( pBuf1==0 || pBuf2==0 ){
- rc = SQLITE_NOMEM;
- }else{
- u32 i = pInfo->nBackfillAttempted;
- for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
- WalHashLoc sLoc; /* Hash table location */
- u32 pgno; /* Page number in db file */
- i64 iDbOff; /* Offset of db file entry */
- i64 iWalOff; /* Offset of wal file entry */
-
- rc = walHashGet(pWal, walFramePage(i), &sLoc);
- if( rc!=SQLITE_OK ) break;
- assert( i - sLoc.iZero - 1 >=0 );
- pgno = sLoc.aPgno[i-sLoc.iZero-1];
- iDbOff = (i64)(pgno-1) * szPage;
-
- if( iDbOff+szPage<=szDb ){
- iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
- rc = sqlcipher_sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
-
- if( rc==SQLITE_OK ){
- rc = sqlcipher_sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
- }
-
- if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
- break;
- }
- }
-
- pInfo->nBackfillAttempted = i-1;
- }
+ void *pBuf1 = sqlcipher_sqlite3_malloc(pWal->szPage);
+ void *pBuf2 = sqlcipher_sqlite3_malloc(pWal->szPage);
+ if( pBuf1==0 || pBuf2==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pWal->ckptLock = 1;
+ SEH_TRY {
+ rc = walSnapshotRecover(pWal, pBuf1, pBuf2);
}
-
- sqlcipher_sqlite3_free(pBuf1);
- sqlcipher_sqlite3_free(pBuf2);
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+ pWal->ckptLock = 0;
}
+
+ sqlcipher_sqlite3_free(pBuf1);
+ sqlcipher_sqlite3_free(pBuf2);
walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
}
@@ -64951,28 +68573,20 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalSnapshotRecover(Wal *pWal){
#endif /* SQLITE_ENABLE_SNAPSHOT */
/*
-** Begin a read transaction on the database.
-**
-** This routine used to be called sqlcipher_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 its cache is stale and
-** needs to be flushed.
+** This function does the work of sqlcipher_sqlite3WalBeginReadTransaction() (see
+** below). That function simply calls this one inside an SEH_TRY{...} block.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+static int walBeginReadTransaction(Wal *pWal, int *pChanged){
int rc; /* Return code */
int cnt = 0; /* Number of TryBeginRead attempts */
#ifdef SQLITE_ENABLE_SNAPSHOT
+ int ckptLock = 0;
int bChanged = 0;
WalIndexHdr *pSnapshot = pWal->pSnapshot;
#endif
assert( pWal->ckptLock==0 );
+ assert( pWal->nSehTry>0 );
#ifdef SQLITE_ENABLE_SNAPSHOT
if( pSnapshot ){
@@ -64995,12 +68609,12 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalBeginReadTransaction(Wal *pWal, int *pCha
if( rc!=SQLITE_OK ){
return rc;
}
- pWal->ckptLock = 1;
+ ckptLock = 1;
}
#endif
do{
- rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
+ rc = walTryBeginRead(pWal, pChanged, 0, &cnt);
}while( rc==WAL_RETRY );
testcase( (rc&0xff)==SQLITE_BUSY );
testcase( (rc&0xff)==SQLITE_IOERR );
@@ -65059,16 +68673,38 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalBeginReadTransaction(Wal *pWal, int *pCha
}
/* Release the shared CKPT lock obtained above. */
- if( pWal->ckptLock ){
+ if( ckptLock ){
assert( pSnapshot );
walUnlockShared(pWal, WAL_CKPT_LOCK);
- pWal->ckptLock = 0;
}
#endif
return rc;
}
/*
+** Begin a read transaction on the database.
+**
+** This routine used to be called sqlcipher_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 its cache is stale and
+** needs to be flushed.
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+ int rc;
+ SEH_TRY {
+ rc = walBeginReadTransaction(pWal, pChanged);
+ }
+ SEH_EXCEPT( rc = walHandleException(pWal); )
+ return rc;
+}
+
+/*
** Finish with a read transaction. All this does is release the
** read-lock.
*/
@@ -65088,7 +68724,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WalEndReadTransaction(Wal *pWal){
** Return SQLITE_OK if successful, or an error code if an error occurs. If an
** error does occur, the final value of *piRead is undefined.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3WalFindFrame(
+static int walFindFrame(
Wal *pWal, /* WAL handle */
Pgno pgno, /* Database page number to read data for */
u32 *piRead /* OUT: Frame number (or zero) */
@@ -65151,6 +68787,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalFindFrame(
}
nCollide = HASHTABLE_NSLOT;
iKey = walHash(pgno);
+ SEH_INJECT_FAULT;
while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
u32 iFrame = iH + sLoc.iZero;
if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){
@@ -65158,6 +68795,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalFindFrame(
iRead = iFrame;
}
if( (nCollide--)==0 ){
+ *piRead = 0;
return SQLITE_CORRUPT_BKPT;
}
iKey = walNextHash(iKey);
@@ -65188,6 +68826,30 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalFindFrame(
}
/*
+** Search the wal file for page pgno. If found, set *piRead to the frame that
+** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
+** to zero.
+**
+** Return SQLITE_OK if successful, or an error code if an error occurs. If an
+** error does occur, the final value of *piRead is undefined.
+**
+** The difference between this function and walFindFrame() is that this
+** function wraps walFindFrame() in an SEH_TRY{...} block.
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3WalFindFrame(
+ Wal *pWal, /* WAL handle */
+ Pgno pgno, /* Database page number to read data for */
+ u32 *piRead /* OUT: Frame number (or zero) */
+){
+ int rc;
+ SEH_TRY {
+ rc = walFindFrame(pWal, pgno, piRead);
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+ return rc;
+}
+
+/*
** Read the contents of frame iRead from the wal file into buffer pOut
** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
** error code otherwise.
@@ -65268,12 +68930,17 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalBeginWriteTransaction(Wal *pWal){
** time the read transaction on this connection was started, then
** the write is disallowed.
*/
- if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+ SEH_TRY {
+ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+ rc = SQLITE_BUSY_SNAPSHOT;
+ }
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+
+ if( rc!=SQLITE_OK ){
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
pWal->writeLock = 0;
- rc = SQLITE_BUSY_SNAPSHOT;
}
-
return rc;
}
@@ -65309,30 +68976,33 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno
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.
+ SEH_TRY {
+ /* Restore the clients cache of the wal-index header to the state it
+ ** was in before the client began writing to the database.
*/
- assert( walFramePgno(pWal, iFrame)!=1 );
- rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+ 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( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
}
- if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
}
return rc;
}
@@ -65376,7 +69046,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
pWal->hdr.mxFrame = aWalData[0];
pWal->hdr.aFrameCksum[0] = aWalData[1];
pWal->hdr.aFrameCksum[1] = aWalData[2];
- walCleanupHash(pWal);
+ SEH_TRY {
+ walCleanupHash(pWal);
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
}
return rc;
@@ -65426,7 +69099,7 @@ static int walRestartLog(Wal *pWal){
cnt = 0;
do{
int notUsed;
- rc = walTryBeginRead(pWal, &notUsed, 1, ++cnt);
+ rc = walTryBeginRead(pWal, &notUsed, 1, &cnt);
}while( rc==WAL_RETRY );
assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
testcase( (rc&0xff)==SQLITE_IOERR );
@@ -65561,7 +69234,7 @@ static int walRewriteChecksums(Wal *pWal, u32 iLast){
** Write a set of frames to the log. The caller must hold the write-lock
** on the log file (obtained using sqlcipher_sqlite3WalBeginWriteTransaction()).
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3WalFrames(
+static int walFrames(
Wal *pWal, /* Wal handle to write to */
int szPage, /* Database page-size in bytes */
PgHdr *pList, /* List of dirty pages to write */
@@ -65649,7 +69322,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalFrames(
if( rc ) return rc;
}
}
- assert( (int)pWal->szPage==szPage );
+ if( (int)pWal->szPage!=szPage ){
+ return SQLITE_CORRUPT_BKPT; /* TH3 test case: cov1/corrupt155.test */
+ }
/* Setup information needed to write frames into the WAL */
w.pWal = pWal;
@@ -65670,7 +69345,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalFrames(
** checksums must be recomputed when the transaction is committed. */
if( iFirst && (p->pDirty || isCommit==0) ){
u32 iWrite = 0;
- VVA_ONLY(rc =) sqlcipher_sqlite3WalFindFrame(pWal, p->pgno, &iWrite);
+ VVA_ONLY(rc =) walFindFrame(pWal, p->pgno, &iWrite);
assert( rc==SQLITE_OK || iWrite==0 );
if( iWrite>=iFirst ){
i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
@@ -65794,6 +69469,29 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalFrames(
}
/*
+** Write a set of frames to the log. The caller must hold the write-lock
+** on the log file (obtained using sqlcipher_sqlite3WalBeginWriteTransaction()).
+**
+** The difference between this function and walFrames() is that this
+** function wraps walFrames() in an SEH_TRY{...} block.
+*/
+SQLITE_PRIVATE int sqlcipher_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;
+ SEH_TRY {
+ rc = walFrames(pWal, szPage, pList, nTruncate, isCommit, sync_flags);
+ }
+ SEH_EXCEPT( rc = walHandleException(pWal); )
+ return rc;
+}
+
+/*
** This routine is called to implement sqlcipher_sqlite3_wal_checkpoint() and
** related interfaces.
**
@@ -65830,10 +69528,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalCheckpoint(
if( pWal->readOnly ) return SQLITE_READONLY;
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
- /* Enable blocking locks, if possible. If blocking locks are successfully
- ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
+ /* Enable blocking locks, if possible. */
sqlcipher_sqlite3WalDb(pWal, db);
- (void)walEnableBlocking(pWal);
+ if( xBusy2 ) (void)walEnableBlocking(pWal);
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
** "checkpoint" lock on the database file.
@@ -65872,30 +69569,38 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalCheckpoint(
/* Read the wal-index header. */
- if( rc==SQLITE_OK ){
- walDisableBlocking(pWal);
- rc = walIndexReadHdr(pWal, &isChanged);
- (void)walEnableBlocking(pWal);
- if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
- sqlcipher_sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+ SEH_TRY {
+ if( rc==SQLITE_OK ){
+ /* For a passive checkpoint, do not re-enable blocking locks after
+ ** reading the wal-index header. A passive checkpoint should not block
+ ** or invoke the busy handler. The only lock such a checkpoint may
+ ** attempt to obtain is a lock on a read-slot, and it should give up
+ ** immediately and do a partial checkpoint if it cannot obtain it. */
+ walDisableBlocking(pWal);
+ rc = walIndexReadHdr(pWal, &isChanged);
+ if( eMode2!=SQLITE_CHECKPOINT_PASSIVE ) (void)walEnableBlocking(pWal);
+ if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
+ sqlcipher_sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+ }
}
- }
-
- /* 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, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
- }
+ /* 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, db, eMode2, xBusy2, pBusyArg, sync_flags,zBuf);
+ }
- /* If no error occurred, set the output variables. */
- if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
- if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
- if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+ /* If no error occurred, set the output variables. */
+ if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
+ if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
+ SEH_INJECT_FAULT;
+ if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+ }
}
}
+ SEH_EXCEPT( rc = walHandleException(pWal); )
if( isChanged ){
/* If a new wal-index header was loaded before the checkpoint was
@@ -65972,7 +69677,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalExclusiveMode(Wal *pWal, int op){
** locks are taken in this case). Nor should the pager attempt to
** upgrade to exclusive-mode following such an error.
*/
+#ifndef SQLITE_USE_SEH
assert( pWal->readLock>=0 || pWal->lockError );
+#endif
assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
if( op==0 ){
@@ -66073,16 +69780,19 @@ SQLITE_API int sqlcipher_sqlite3_snapshot_cmp(sqlcipher_sqlite3_snapshot *p1, sq
*/
SQLITE_PRIVATE int sqlcipher_sqlite3WalSnapshotCheck(Wal *pWal, sqlcipher_sqlite3_snapshot *pSnapshot){
int rc;
- rc = walLockShared(pWal, WAL_CKPT_LOCK);
- if( rc==SQLITE_OK ){
- WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
- if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
- || pNew->mxFrame<walCkptInfo(pWal)->nBackfillAttempted
- ){
- rc = SQLITE_ERROR_SNAPSHOT;
- walUnlockShared(pWal, WAL_CKPT_LOCK);
+ SEH_TRY {
+ rc = walLockShared(pWal, WAL_CKPT_LOCK);
+ if( rc==SQLITE_OK ){
+ WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
+ if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
+ || pNew->mxFrame<walCkptInfo(pWal)->nBackfillAttempted
+ ){
+ rc = SQLITE_ERROR_SNAPSHOT;
+ walUnlockShared(pWal, WAL_CKPT_LOCK);
+ }
}
}
+ SEH_EXCEPT( rc = walHandleException(pWal); )
return rc;
}
@@ -66205,7 +69915,7 @@ SQLITE_PRIVATE sqlcipher_sqlite3_file *sqlcipher_sqlite3WalFile(Wal *pWal){
** 22 1 Min embedded payload fraction (must be 32)
** 23 1 Min leaf payload fraction (must be 32)
** 24 4 File change counter
-** 28 4 Reserved for future use
+** 28 4 The size of the database in pages
** 32 4 First freelist page
** 36 4 Number of freelist pages in the file
** 40 60 15 4-byte meta values passed to higher layers
@@ -66313,7 +70023,7 @@ SQLITE_PRIVATE sqlcipher_sqlite3_file *sqlcipher_sqlite3WalFile(Wal *pWal){
** byte are used. The integer consists of all bytes that have bit 8 set and
** the first byte with bit 8 clear. The most significant byte of the integer
** appears first. A variable-length integer may not be more than 9 bytes long.
-** As a special case, all 8 bytes of the 9th byte are used as data. This
+** As a special case, all 8 bits of the 9th byte are used as data. This
** allows a 64-bit integer to be encoded in 9 bytes.
**
** 0x00 becomes 0x00000000
@@ -66321,7 +70031,7 @@ SQLITE_PRIVATE sqlcipher_sqlite3_file *sqlcipher_sqlite3WalFile(Wal *pWal){
** 0x81 0x00 becomes 0x00000080
** 0x82 0x00 becomes 0x00000100
** 0x80 0x7f becomes 0x0000007f
-** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
+** 0x81 0x91 0xd1 0xac 0x78 becomes 0x12345678
** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
**
** Variable length integers are used for rowids and to hold the number of
@@ -66404,7 +70114,7 @@ typedef struct CellInfo CellInfo;
** page that has been loaded into memory. The information in this object
** is derived from the raw on-disk page content.
**
-** As each database page is loaded into memory, the pager allocats an
+** As each database page is loaded into memory, the pager allocates an
** instance of this object and zeros the first 8 bytes. (This is the
** "extra" information associated with each page of the pager.)
**
@@ -66697,7 +70407,7 @@ struct BtCursor {
#define BTCF_WriteFlag 0x01 /* True if a write cursor */
#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
-#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
+#define BTCF_AtLast 0x08 /* Cursor is pointing to the last entry */
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
#define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */
#define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */
@@ -66815,15 +70525,15 @@ struct BtCursor {
** So, this macro is defined instead.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
-#define ISAUTOVACUUM (pBt->autoVacuum)
+#define ISAUTOVACUUM(pBt) (pBt->autoVacuum)
#else
-#define ISAUTOVACUUM 0
+#define ISAUTOVACUUM(pBt) 0
#endif
/*
-** This structure is passed around through all the sanity checking routines
-** in order to keep track of some global state information.
+** This structure is passed around through all the PRAGMA integrity_check
+** 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
@@ -66836,16 +70546,19 @@ 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 */
+ Pgno nCkPage; /* Pages in the database. 0 for partial check */
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
- int bOomFault; /* A memory allocation error has occurred */
+ int rc; /* SQLITE_OK, SQLITE_NOMEM, or SQLITE_INTERRUPT */
+ u32 nStep; /* Number of steps into the integrity_check process */
const char *zPfx; /* Error message prefix */
- Pgno v1; /* Value for first %u substitution in zPfx */
- int v2; /* Value for second %d substitution in zPfx */
+ Pgno v0; /* Value for first %u substitution in zPfx (root page) */
+ Pgno v1; /* Value for second %u substitution in zPfx (current pg) */
+ int v2; /* Value for third %d substitution in zPfx */
StrAccum errMsg; /* Accumulate the error message text here */
u32 *heap; /* Min-heap used for analyzing cell coverage */
sqlcipher_sqlite3 *db; /* Database connection running the check */
+ i64 nRow; /* Number of rows visited in current tree */
};
/*
@@ -66858,7 +70571,7 @@ struct IntegrityCk {
/*
** get2byteAligned(), unlike get2byte(), requires that its argument point to a
-** two-byte aligned address. get2bytea() is only used for accessing the
+** two-byte aligned address. get2byteAligned() is only used for accessing the
** cell addresses in a btree header.
*/
#if SQLITE_BYTEORDER==4321
@@ -67035,7 +70748,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeHoldsMutex(Btree *p){
**
** There is a corresponding leave-all procedures.
**
-** Enter the mutexes in accending order by BtShared pointer address
+** Enter the mutexes in ascending order by BtShared pointer address
** to avoid the possibility of deadlock when two threads with
** two or more btrees in common both try to lock all their btrees
** at the same instant.
@@ -67109,6 +70822,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeHoldsAllMutexes(sqlcipher_sqlite3 *db){
SQLITE_PRIVATE int sqlcipher_sqlite3SchemaMutexHeld(sqlcipher_sqlite3 *db, int iDb, Schema *pSchema){
Btree *p;
assert( db!=0 );
+ if( db->pVfs==0 && db->nDb==0 ) return 1;
if( pSchema ) iDb = sqlcipher_sqlite3SchemaToIndex(db, pSchema);
assert( iDb>=0 && iDb<db->nDb );
if( !sqlcipher_sqlite3_mutex_held(db->mutex) ) return 0;
@@ -67304,8 +71018,8 @@ SQLITE_PRIVATE sqlcipher_sqlite3_uint64 sqlcipher_sqlite3BtreeSeekCount(Btree *p
int corruptPageError(int lineno, MemPage *p){
char *zMsg;
sqlcipher_sqlite3BeginBenignMalloc();
- zMsg = sqlcipher_sqlite3_mprintf("database corruption page %d of %s",
- (int)p->pgno, sqlcipher_sqlite3PagerFilename(p->pBt->pPager, 0)
+ zMsg = sqlcipher_sqlite3_mprintf("database corruption page %u of %s",
+ p->pgno, sqlcipher_sqlite3PagerFilename(p->pBt->pPager, 0)
);
sqlcipher_sqlite3EndBenignMalloc();
if( zMsg ){
@@ -67319,8 +71033,47 @@ int corruptPageError(int lineno, MemPage *p){
# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno)
#endif
+/* Default value for SHARED_LOCK_TRACE macro if shared-cache is disabled
+** or if the lock tracking is disabled. This is always the value for
+** release builds.
+*/
+#define SHARED_LOCK_TRACE(X,MSG,TAB,TYPE) /*no-op*/
+
#ifndef SQLITE_OMIT_SHARED_CACHE
+#if 0
+/* ^---- Change to 1 and recompile to enable shared-lock tracing
+** for debugging purposes.
+**
+** Print all shared-cache locks on a BtShared. Debugging use only.
+*/
+static void sharedLockTrace(
+ BtShared *pBt,
+ const char *zMsg,
+ int iRoot,
+ int eLockType
+){
+ BtLock *pLock;
+ if( iRoot>0 ){
+ printf("%s-%p %u%s:", zMsg, pBt, iRoot, eLockType==READ_LOCK?"R":"W");
+ }else{
+ printf("%s-%p:", zMsg, pBt);
+ }
+ for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){
+ printf(" %p/%u%s", pLock->pBtree, pLock->iTable,
+ pLock->eLock==READ_LOCK ? "R" : "W");
+ while( pLock->pNext && pLock->pBtree==pLock->pNext->pBtree ){
+ pLock = pLock->pNext;
+ printf(",%u%s", pLock->iTable, pLock->eLock==READ_LOCK ? "R" : "W");
+ }
+ }
+ printf("\n");
+ fflush(stdout);
+}
+#undef SHARED_LOCK_TRACE
+#define SHARED_LOCK_TRACE(X,MSG,TAB,TYPE) sharedLockTrace(X,MSG,TAB,TYPE)
+#endif /* Shared-lock tracing */
+
#ifdef SQLITE_DEBUG
/*
**** This function is only used as part of an assert() statement. ***
@@ -67397,6 +71150,8 @@ static int hasSharedCacheTableLock(
iTab = iRoot;
}
+ SHARED_LOCK_TRACE(pBtree->pBt,"hasLock",iRoot,eLockType);
+
/* Search for the required lock. Either a write-lock on root-page iTab, a
** write-lock on the schema table, or (if the client is reading) a
** read-lock on iTab will suffice. Return 1 if any of these are found. */
@@ -67530,6 +71285,8 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
BtLock *pLock = 0;
BtLock *pIter;
+ SHARED_LOCK_TRACE(pBt,"setLock", iTable, eLock);
+
assert( sqlcipher_sqlite3BtreeHoldsMutex(p) );
assert( eLock==READ_LOCK || eLock==WRITE_LOCK );
assert( p->db!=0 );
@@ -67597,6 +71354,8 @@ static void clearAllSharedCacheTableLocks(Btree *p){
assert( p->sharable || 0==*ppIter );
assert( p->inTrans>0 );
+ SHARED_LOCK_TRACE(pBt, "clearAllLocks", 0, 0);
+
while( *ppIter ){
BtLock *pLock = *ppIter;
assert( (pBt->btsFlags & BTS_EXCLUSIVE)==0 || pBt->pWriter==pLock->pBtree );
@@ -67635,6 +71394,9 @@ static void clearAllSharedCacheTableLocks(Btree *p){
*/
static void downgradeAllSharedCacheTableLocks(Btree *p){
BtShared *pBt = p->pBt;
+
+ SHARED_LOCK_TRACE(pBt, "downgradeLocks", 0, 0);
+
if( pBt->pWriter==p ){
BtLock *pLock;
pBt->pWriter = 0;
@@ -68114,8 +71876,25 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDif
*/
SQLITE_PRIVATE void sqlcipher_sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){
/* Used only by system that substitute their own storage engine */
+#ifdef SQLITE_DEBUG
+ if( ALWAYS(eHintType==BTREE_HINT_RANGE) ){
+ va_list ap;
+ Expr *pExpr;
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = sqlcipher_sqlite3CursorRangeHintExprCheck;
+ va_start(ap, eHintType);
+ pExpr = va_arg(ap, Expr*);
+ w.u.aMem = va_arg(ap, Mem*);
+ va_end(ap);
+ assert( pExpr!=0 );
+ assert( w.u.aMem!=0 );
+ sqlcipher_sqlite3WalkExpr(&w, pExpr);
+ }
+#endif /* SQLITE_DEBUG */
}
-#endif
+#endif /* SQLITE_ENABLE_CURSOR_HINTS */
+
/*
** Provide flag hints to the cursor.
@@ -68200,7 +71979,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
pPtrmap = (u8 *)sqlcipher_sqlite3PagerGetData(pDbPage);
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
- TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
+ TRACE(("PTRMAP_UPDATE: %u->(%u,%u)\n", key, eType, parent));
*pRC= rc = sqlcipher_sqlite3PagerWrite(pDbPage);
if( rc==SQLITE_OK ){
pPtrmap[offset] = eType;
@@ -68399,27 +72178,31 @@ static void btreeParseCellPtr(
iKey = *pIter;
if( iKey>=0x80 ){
u8 x;
- iKey = ((iKey&0x7f)<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x =*++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x10204000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<8) | (*++pIter);
+ iKey = (iKey<<8) ^ 0x8000 ^ (*++pIter);
}
}
}
}
}
+ }else{
+ iKey ^= 0x204000;
}
+ }else{
+ iKey ^= 0x4000;
}
}
pIter++;
@@ -68496,10 +72279,53 @@ static void btreeParseCell(
**
** cellSizePtrNoPayload() => table internal nodes
** cellSizePtrTableLeaf() => table leaf nodes
-** cellSizePtr() => all index nodes & table leaf nodes
+** cellSizePtr() => index internal nodes
+** cellSizeIdxLeaf() => index leaf nodes
*/
static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
- u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */
+ u8 *pIter = pCell + 4; /* For looping over bytes of pCell */
+ u8 *pEnd; /* End mark for a varint */
+ u32 nSize; /* Size value to return */
+
+#ifdef SQLITE_DEBUG
+ /* The value returned by this function should always be the same as
+ ** the (CellInfo.nSize) value found by doing a full parse of the
+ ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
+ ** this function verifies that this invariant is not violated. */
+ CellInfo debuginfo;
+ pPage->xParseCell(pPage, pCell, &debuginfo);
+#endif
+
+ assert( pPage->childPtrSize==4 );
+ nSize = *pIter;
+ if( nSize>=0x80 ){
+ pEnd = &pIter[8];
+ nSize &= 0x7f;
+ do{
+ nSize = (nSize<<7) | (*++pIter & 0x7f);
+ }while( *(pIter)>=0x80 && pIter<pEnd );
+ }
+ pIter++;
+ testcase( nSize==pPage->maxLocal );
+ testcase( nSize==(u32)pPage->maxLocal+1 );
+ if( nSize<=pPage->maxLocal ){
+ nSize += (u32)(pIter - pCell);
+ assert( nSize>4 );
+ }else{
+ int minLocal = pPage->minLocal;
+ nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4);
+ testcase( nSize==pPage->maxLocal );
+ testcase( nSize==(u32)pPage->maxLocal+1 );
+ if( nSize>pPage->maxLocal ){
+ nSize = minLocal;
+ }
+ nSize += 4 + (u16)(pIter - pCell);
+ }
+ assert( nSize==debuginfo.nSize || CORRUPT_DB );
+ return (u16)nSize;
+}
+static u16 cellSizePtrIdxLeaf(MemPage *pPage, u8 *pCell){
+ u8 *pIter = pCell; /* For looping over bytes of pCell */
u8 *pEnd; /* End mark for a varint */
u32 nSize; /* Size value to return */
@@ -68512,6 +72338,7 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
pPage->xParseCell(pPage, pCell, &debuginfo);
#endif
+ assert( pPage->childPtrSize==0 );
nSize = *pIter;
if( nSize>=0x80 ){
pEnd = &pIter[8];
@@ -68636,7 +72463,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){
pPage->xParseCell(pPage, pCell, &info);
if( info.nLocal<info.nPayload ){
Pgno ovfl;
- if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){
+ if( SQLITE_OVERFLOW(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){
testcase( pSrc!=pPage );
*pRC = SQLITE_CORRUPT_BKPT;
return;
@@ -68681,8 +72508,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
assert( pPage->nOverflow==0 );
assert( sqlcipher_sqlite3_mutex_held(pPage->pBt->mutex) );
- temp = 0;
- src = data = pPage->aData;
+ data = pPage->aData;
hdr = pPage->hdrOffset;
cellOffset = pPage->cellOffset;
nCell = pPage->nCell;
@@ -68736,39 +72562,38 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
cbrk = usableSize;
iCellLast = usableSize - 4;
iCellStart = get2byte(&data[hdr+5]);
- for(i=0; i<nCell; i++){
- u8 *pAddr; /* The i-th cell pointer */
- pAddr = &data[cellOffset + i*2];
- pc = get2byte(pAddr);
- testcase( pc==iCellFirst );
- testcase( pc==iCellLast );
- /* These conditions have already been verified in btreeInitPage()
- ** if PRAGMA cell_size_check=ON.
- */
- if( pc<iCellStart || pc>iCellLast ){
- return SQLITE_CORRUPT_PAGE(pPage);
- }
- assert( pc>=iCellStart && pc<=iCellLast );
- size = pPage->xCellSize(pPage, &src[pc]);
- cbrk -= size;
- if( cbrk<iCellStart || pc+size>usableSize ){
- return SQLITE_CORRUPT_PAGE(pPage);
- }
- assert( cbrk+size<=usableSize && cbrk>=iCellStart );
- testcase( cbrk+size==usableSize );
- testcase( pc+size==usableSize );
- put2byte(pAddr, cbrk);
- if( temp==0 ){
- if( cbrk==pc ) continue;
- temp = sqlcipher_sqlite3PagerTempSpace(pPage->pBt->pPager);
- memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
- src = temp;
+ if( nCell>0 ){
+ temp = sqlcipher_sqlite3PagerTempSpace(pPage->pBt->pPager);
+ memcpy(temp, data, usableSize);
+ src = temp;
+ for(i=0; i<nCell; i++){
+ u8 *pAddr; /* The i-th cell pointer */
+ pAddr = &data[cellOffset + i*2];
+ pc = get2byte(pAddr);
+ testcase( pc==iCellFirst );
+ testcase( pc==iCellLast );
+ /* These conditions have already been verified in btreeInitPage()
+ ** if PRAGMA cell_size_check=ON.
+ */
+ if( pc>iCellLast ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ assert( pc>=0 && pc<=iCellLast );
+ size = pPage->xCellSize(pPage, &src[pc]);
+ cbrk -= size;
+ if( cbrk<iCellStart || pc+size>usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ assert( cbrk+size<=usableSize && cbrk>=iCellStart );
+ testcase( cbrk+size==usableSize );
+ testcase( pc+size==usableSize );
+ put2byte(pAddr, cbrk);
+ memcpy(&data[cbrk], &src[pc], size);
}
- memcpy(&data[cbrk], &src[pc], size);
}
data[hdr+7] = 0;
- defragment_out:
+defragment_out:
assert( pPage->nFree>=0 );
if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
return SQLITE_CORRUPT_PAGE(pPage);
@@ -68825,7 +72650,6 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
** fragmented bytes within the page. */
memcpy(&aData[iAddr], &aData[pc], 2);
aData[hdr+7] += (u8)x;
- testcase( pc+x>maxPC );
return &aData[pc];
}else if( x+pc > maxPC ){
/* This slot extends off the end of the usable part of the page */
@@ -68841,9 +72665,9 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
iAddr = pc;
pTmp = &aData[pc];
pc = get2byte(pTmp);
- if( pc<=iAddr+size ){
+ if( pc<=iAddr ){
if( pc ){
- /* The next slot in the chain is not past the end of the current slot */
+ /* The next slot in the chain comes before the current slot */
*pRc = SQLITE_CORRUPT_PAGE(pPg);
}
return 0;
@@ -68869,7 +72693,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
** allocation is being made in order to insert a new cell, so we will
** also end up needing a new cell pointer.
*/
-static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
+static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */
u8 * const data = pPage->aData; /* Local cache of pPage->aData */
int top; /* First byte of cell content area */
@@ -68895,13 +72719,14 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
** integer, so a value of 0 is used in its place. */
pTmp = &data[hdr+5];
top = get2byte(pTmp);
- assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */
if( gap>top ){
if( top==0 && pPage->pBt->usableSize==65536 ){
top = 65536;
}else{
return SQLITE_CORRUPT_PAGE(pPage);
}
+ }else if( top>(int)pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
}
/* If there is enough space between gap and top for one more cell pointer,
@@ -68963,7 +72788,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
**
** Even though the freeblock list was checked by btreeComputeFreeSpace(),
** that routine will not detect overlap between cells or freeblocks. Nor
-** does it detect cells or freeblocks that encrouch into the reserved bytes
+** does it detect cells or freeblocks that encroach into the reserved bytes
** at the end of the page. So do additional corruption checks inside this
** routine and return SQLITE_CORRUPT if any problems are found.
*/
@@ -68984,7 +72809,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
assert( sqlcipher_sqlite3_mutex_held(pPage->pBt->mutex) );
assert( iSize>=4 ); /* Minimum cell size is 4 */
- assert( iStart<=pPage->pBt->usableSize-4 );
+ assert( CORRUPT_DB || iStart<=pPage->pBt->usableSize-4 );
/* The list of freeblocks must be in ascending order. Find the
** spot on the list where iStart should be inserted.
@@ -68995,7 +72820,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */
}else{
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
- if( iFreeBlk<iPtr+4 ){
+ if( iFreeBlk<=iPtr ){
if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */
return SQLITE_CORRUPT_PAGE(pPage);
}
@@ -69041,6 +72866,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}
pTmp = &data[hdr+5];
x = get2byte(pTmp);
+ if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
+ /* Overwrite deleted information with zeros when the secure_delete
+ ** option is enabled */
+ memset(&data[iStart], 0, iSize);
+ }
if( iStart<=x ){
/* The new freeblock is at the beginning of the cell content area,
** so just extend the cell content area rather than create another
@@ -69052,14 +72882,9 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}else{
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
+ put2byte(&data[iStart], iFreeBlk);
+ put2byte(&data[iStart+2], iSize);
}
- if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
- /* Overwrite deleted information with zeros when the secure_delete
- ** option is enabled */
- memset(&data[iStart], 0, iSize);
- }
- put2byte(&data[iStart], iFreeBlk);
- put2byte(&data[iStart+2], iSize);
pPage->nFree += iOrigSize;
return SQLITE_OK;
}
@@ -69071,62 +72896,67 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
** Only the following combinations are supported. Anything different
** indicates a corrupt database files:
**
-** PTF_ZERODATA
-** PTF_ZERODATA | PTF_LEAF
-** PTF_LEAFDATA | PTF_INTKEY
-** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF
+** PTF_ZERODATA (0x02, 2)
+** PTF_LEAFDATA | PTF_INTKEY (0x05, 5)
+** PTF_ZERODATA | PTF_LEAF (0x0a, 10)
+** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF (0x0d, 13)
*/
static int decodeFlags(MemPage *pPage, int flagByte){
BtShared *pBt; /* A copy of pPage->pBt */
assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
assert( sqlcipher_sqlite3_mutex_held(pPage->pBt->mutex) );
- pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 );
- flagByte &= ~PTF_LEAF;
- pPage->childPtrSize = 4-4*pPage->leaf;
pBt = pPage->pBt;
- if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
- /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an
- ** interior table b-tree page. */
- assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
- /* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a
- ** leaf table b-tree page. */
- assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
- pPage->intKey = 1;
- if( pPage->leaf ){
+ pPage->max1bytePayload = pBt->max1bytePayload;
+ if( flagByte>=(PTF_ZERODATA | PTF_LEAF) ){
+ pPage->childPtrSize = 0;
+ pPage->leaf = 1;
+ if( flagByte==(PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF) ){
pPage->intKeyLeaf = 1;
pPage->xCellSize = cellSizePtrTableLeaf;
pPage->xParseCell = btreeParseCellPtr;
+ pPage->intKey = 1;
+ pPage->maxLocal = pBt->maxLeaf;
+ pPage->minLocal = pBt->minLeaf;
+ }else if( flagByte==(PTF_ZERODATA | PTF_LEAF) ){
+ pPage->intKey = 0;
+ pPage->intKeyLeaf = 0;
+ pPage->xCellSize = cellSizePtrIdxLeaf;
+ pPage->xParseCell = btreeParseCellPtrIndex;
+ pPage->maxLocal = pBt->maxLocal;
+ pPage->minLocal = pBt->minLocal;
}else{
+ pPage->intKey = 0;
+ pPage->intKeyLeaf = 0;
+ pPage->xCellSize = cellSizePtrIdxLeaf;
+ pPage->xParseCell = btreeParseCellPtrIndex;
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ }else{
+ pPage->childPtrSize = 4;
+ pPage->leaf = 0;
+ if( flagByte==(PTF_ZERODATA) ){
+ pPage->intKey = 0;
+ pPage->intKeyLeaf = 0;
+ pPage->xCellSize = cellSizePtr;
+ pPage->xParseCell = btreeParseCellPtrIndex;
+ pPage->maxLocal = pBt->maxLocal;
+ pPage->minLocal = pBt->minLocal;
+ }else if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
pPage->intKeyLeaf = 0;
pPage->xCellSize = cellSizePtrNoPayload;
pPage->xParseCell = btreeParseCellPtrNoPayload;
+ pPage->intKey = 1;
+ pPage->maxLocal = pBt->maxLeaf;
+ pPage->minLocal = pBt->minLeaf;
+ }else{
+ pPage->intKey = 0;
+ pPage->intKeyLeaf = 0;
+ pPage->xCellSize = cellSizePtr;
+ pPage->xParseCell = btreeParseCellPtrIndex;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
- pPage->maxLocal = pBt->maxLeaf;
- pPage->minLocal = pBt->minLeaf;
- }else if( flagByte==PTF_ZERODATA ){
- /* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an
- ** interior index b-tree page. */
- assert( (PTF_ZERODATA)==2 );
- /* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a
- ** leaf index b-tree page. */
- assert( (PTF_ZERODATA|PTF_LEAF)==10 );
- pPage->intKey = 0;
- pPage->intKeyLeaf = 0;
- pPage->xCellSize = cellSizePtr;
- pPage->xParseCell = btreeParseCellPtrIndex;
- pPage->maxLocal = pBt->maxLocal;
- pPage->minLocal = pBt->minLocal;
- }else{
- /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
- ** an error. */
- pPage->intKey = 0;
- pPage->intKeyLeaf = 0;
- pPage->xCellSize = cellSizePtr;
- pPage->xParseCell = btreeParseCellPtrIndex;
- return SQLITE_CORRUPT_PAGE(pPage);
}
- pPage->max1bytePayload = pBt->max1bytePayload;
return SQLITE_OK;
}
@@ -69417,70 +73247,41 @@ SQLITE_PRIVATE Pgno sqlcipher_sqlite3BtreeLastPage(Btree *p){
/*
** Get a page from the pager and initialize it.
-**
-** If pCur!=0 then the page is being fetched as part of a moveToChild()
-** call. Do additional sanity checking on the page in this case.
-** And if the fetch fails, this routine must decrement pCur->iPage.
-**
-** The page is fetched as read-write unless pCur is not NULL and is
-** a read-only cursor.
-**
-** If an error occurs, then *ppPage is undefined. It
-** may remain unchanged, or it may be set to an invalid value.
*/
static int getAndInitPage(
BtShared *pBt, /* The database file */
Pgno pgno, /* Number of the page to get */
MemPage **ppPage, /* Write the page pointer here */
- BtCursor *pCur, /* Cursor to receive the page, or NULL */
int bReadOnly /* True for a read-only page */
){
int rc;
DbPage *pDbPage;
+ MemPage *pPage;
assert( sqlcipher_sqlite3_mutex_held(pBt->mutex) );
- assert( pCur==0 || ppPage==&pCur->pPage );
- assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
- assert( pCur==0 || pCur->iPage>0 );
if( pgno>btreePagecount(pBt) ){
- rc = SQLITE_CORRUPT_BKPT;
- goto getAndInitPage_error1;
+ *ppPage = 0;
+ return SQLITE_CORRUPT_BKPT;
}
rc = sqlcipher_sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
if( rc ){
- goto getAndInitPage_error1;
+ *ppPage = 0;
+ return rc;
}
- *ppPage = (MemPage*)sqlcipher_sqlite3PagerGetExtra(pDbPage);
- if( (*ppPage)->isInit==0 ){
+ pPage = (MemPage*)sqlcipher_sqlite3PagerGetExtra(pDbPage);
+ if( pPage->isInit==0 ){
btreePageFromDbPage(pDbPage, pgno, pBt);
- rc = btreeInitPage(*ppPage);
+ rc = btreeInitPage(pPage);
if( rc!=SQLITE_OK ){
- goto getAndInitPage_error2;
+ releasePage(pPage);
+ *ppPage = 0;
+ return rc;
}
}
- assert( (*ppPage)->pgno==pgno || CORRUPT_DB );
- assert( (*ppPage)->aData==sqlcipher_sqlite3PagerGetData(pDbPage) );
-
- /* If obtaining a child page for a cursor, we must verify that the page is
- ** compatible with the root page. */
- if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
- rc = SQLITE_CORRUPT_PGNO(pgno);
- goto getAndInitPage_error2;
- }
+ assert( pPage->pgno==pgno || CORRUPT_DB );
+ assert( pPage->aData==sqlcipher_sqlite3PagerGetData(pDbPage) );
+ *ppPage = pPage;
return SQLITE_OK;
-
-getAndInitPage_error2:
- releasePage(*ppPage);
-getAndInitPage_error1:
- if( pCur ){
- pCur->iPage--;
- pCur->pPage = pCur->apPage[pCur->iPage];
- }
- testcase( pgno==0 );
- assert( pgno!=0 || rc==SQLITE_CORRUPT
- || rc==SQLITE_IOERR_NOMEM
- || rc==SQLITE_NOMEM );
- return rc;
}
/*
@@ -69563,7 +73364,7 @@ static void pageReinit(DbPage *pData){
** call to btreeInitPage() will likely return SQLITE_CORRUPT.
** But no harm is done by this. And it is very important that
** btreeInitPage() be called on every btree page so we make
- ** the call for every page that comes in for re-initing. */
+ ** the call for every page that comes in for re-initializing. */
btreeInitPage(pPage);
}
}
@@ -69742,6 +73543,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeOpen(
assert( sizeof(u16)==2 );
assert( sizeof(Pgno)==4 );
+ /* Suppress false-positive compiler warning from PVS-Studio */
+ memset(&zDbHeader[16], 0, 8);
+
pBt = sqlcipher_sqlite3MallocZero( sizeof(*pBt) );
if( pBt==0 ){
rc = SQLITE_NOMEM_BKPT;
@@ -69958,7 +73762,7 @@ static SQLITE_NOINLINE int allocateTempSpace(BtShared *pBt){
** can mean that fillInCell() only initializes the first 2 or 3
** bytes of pTmpSpace, but that the first 4 bytes are copied from
** it into a database page. This is not actually a problem, but it
- ** does cause a valgrind error when the 1 or 2 bytes of unitialized
+ ** does cause a valgrind error when the 1 or 2 bytes of uninitialized
** data is passed to system call write(). So to avoid this error,
** zero the first 4 bytes of temp space here.
**
@@ -70193,7 +73997,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeGetReserveNoMutex(Btree *p){
/*
** Return the number of bytes of space at the end of every page that
-** are intentually left unused. This is the "reserved" space that is
+** are intentionally left unused. This is the "reserved" space that is
** sometimes used by extensions.
**
** The value returned is the larger of the current reserve size and
@@ -70440,7 +74244,6 @@ static int lockBtree(BtShared *pBt){
){
goto page1_init_failed;
}
- pBt->btsFlags |= BTS_PAGESIZE_FIXED;
assert( (pageSize & 7)==0 );
/* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte
** integer at offset 20 is the number of bytes of space at the end of
@@ -70460,6 +74263,7 @@ static int lockBtree(BtShared *pBt){
releasePageOne(pPage1);
pBt->usableSize = usableSize;
pBt->pageSize = pageSize;
+ pBt->btsFlags |= BTS_PAGESIZE_FIXED;
freeTempSpace(pBt);
rc = sqlcipher_sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize,
pageSize-usableSize);
@@ -70479,6 +74283,7 @@ static int lockBtree(BtShared *pBt){
if( usableSize<480 ){
goto page1_init_failed;
}
+ pBt->btsFlags |= BTS_PAGESIZE_FIXED;
pBt->pageSize = pageSize;
pBt->usableSize = usableSize;
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -70657,7 +74462,11 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeNewDb(Btree *p){
** when A already has a read lock, we encourage A to give up and let B
** proceed.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
+static SQLITE_NOINLINE int btreeBeginTrans(
+ Btree *p, /* The btree in which to start the transaction */
+ int wrflag, /* True to start a write transaction */
+ int *pSchemaVersion /* Put schema version number here, if not NULL */
+){
BtShared *pBt = p->pBt;
Pager *pPager = pBt->pPager;
int rc = SQLITE_OK;
@@ -70829,6 +74638,28 @@ trans_begun:
sqlcipher_sqlite3BtreeLeave(p);
return rc;
}
+SQLITE_PRIVATE int sqlcipher_sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
+ BtShared *pBt;
+ if( p->sharable
+ || p->inTrans==TRANS_NONE
+ || (p->inTrans==TRANS_READ && wrflag!=0)
+ ){
+ return btreeBeginTrans(p,wrflag,pSchemaVersion);
+ }
+ pBt = p->pBt;
+ if( pSchemaVersion ){
+ *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]);
+ }
+ if( wrflag ){
+ /* This call makes sure that the pager has the correct number of
+ ** open savepoints. If the second parameter is greater than 0 and
+ ** the sub-journal is not already open, then it will be opened here.
+ */
+ return sqlcipher_sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
+ }else{
+ return SQLITE_OK;
+ }
+}
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -70915,6 +74746,9 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
}
}
}else{
+ if( pCell+4 > pPage->aData+pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
if( get4byte(pCell)==iFrom ){
put4byte(pCell, iTo);
break;
@@ -70963,7 +74797,7 @@ static int relocatePage(
if( iDbPage<3 ) return SQLITE_CORRUPT_BKPT;
/* Move page iDbPage from its current location to page number iFreePage */
- TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
+ TRACE(("AUTOVACUUM: Moving %u to free page %u (ptr page %u type %u)\n",
iDbPage, iFreePage, iPtrPage, eType));
rc = sqlcipher_sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit);
if( rc!=SQLITE_OK ){
@@ -71921,7 +75755,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3BtreeCursorUnpin(BtCursor *pCur){
pCur->curFlags &= ~BTCF_Pinned;
}
-#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
/*
** Return the offset into the database file for the start of the
** payload to which the cursor is pointing.
@@ -71933,7 +75766,6 @@ SQLITE_PRIVATE i64 sqlcipher_sqlite3BtreeOffset(BtCursor *pCur){
return (i64)pCur->pBt->pageSize*((i64)pCur->pPage->pgno - 1) +
(i64)(pCur->info.pPayload - pCur->pPage->aData);
}
-#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
/*
** Return the number of bytes of payload for the entry that pCur is
@@ -71959,7 +75791,7 @@ SQLITE_PRIVATE u32 sqlcipher_sqlite3BtreePayloadSize(BtCursor *pCur){
** routine always returns 2147483647 (which is the largest record
** that SQLite can handle) or more. But returning a smaller value might
** prevent large memory allocations when trying to interpret a
-** corrupt datrabase.
+** corrupt database.
**
** The current implementation merely returns the size of the underlying
** database file.
@@ -72178,9 +76010,12 @@ static int accessPayload(
if( pCur->aOverflow==0
|| nOvfl*(int)sizeof(Pgno) > sqlcipher_sqlite3MallocSize(pCur->aOverflow)
){
- Pgno *aNew = (Pgno*)sqlcipher_sqlite3Realloc(
- pCur->aOverflow, nOvfl*2*sizeof(Pgno)
- );
+ Pgno *aNew;
+ if( sqlcipher_sqlite3FaultSim(413) ){
+ aNew = 0;
+ }else{
+ aNew = (Pgno*)sqlcipher_sqlite3Realloc(pCur->aOverflow, nOvfl*2*sizeof(Pgno));
+ }
if( aNew==0 ){
return SQLITE_NOMEM_BKPT;
}else{
@@ -72190,6 +76025,12 @@ static int accessPayload(
memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
pCur->curFlags |= BTCF_ValidOvfl;
}else{
+ /* Sanity check the validity of the overflow page cache */
+ assert( pCur->aOverflow[0]==nextPage
+ || pCur->aOverflow[0]==0
+ || CORRUPT_DB );
+ assert( pCur->aOverflow[0]!=0 || pCur->aOverflow[offset/ovflSize]==0 );
+
/* If the overflow page-list cache has been allocated and the
** entry for the first required overflow page is valid, skip
** directly to it.
@@ -72259,7 +76100,6 @@ static int accessPayload(
assert( aWrite>=pBufStart ); /* due to (6) */
memcpy(aSave, aWrite, 4);
rc = sqlcipher_sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
- if( rc && nextPage>pBt->nPage ) rc = SQLITE_CORRUPT_BKPT;
nextPage = get4byte(aWrite);
memcpy(aWrite, aSave, 4);
}else
@@ -72421,8 +76261,7 @@ SQLITE_PRIVATE const void *sqlcipher_sqlite3BtreePayloadFetch(BtCursor *pCur, u3
** vice-versa).
*/
static int moveToChild(BtCursor *pCur, u32 newPgno){
- BtShared *pBt = pCur->pBt;
-
+ int rc;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
@@ -72436,7 +76275,18 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
pCur->apPage[pCur->iPage] = pCur->pPage;
pCur->ix = 0;
pCur->iPage++;
- return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags);
+ rc = getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur->curPagerFlags);
+ assert( pCur->pPage!=0 || rc!=SQLITE_OK );
+ if( rc==SQLITE_OK
+ && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey)
+ ){
+ releasePage(pCur->pPage);
+ rc = SQLITE_CORRUPT_PGNO(newPgno);
+ }
+ if( rc ){
+ pCur->pPage = pCur->apPage[--pCur->iPage];
+ }
+ return rc;
}
#ifdef SQLITE_DEBUG
@@ -72542,8 +76392,8 @@ static int moveToRoot(BtCursor *pCur){
}
sqlcipher_sqlite3BtreeClearCursor(pCur);
}
- rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage,
- 0, pCur->curPagerFlags);
+ rc = getAndInitPage(pCur->pBt, pCur->pgnoRoot, &pCur->pPage,
+ pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
@@ -72655,42 +76505,36 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
*pRes = 0;
rc = moveToLeftmost(pCur);
}else if( rc==SQLITE_EMPTY ){
- assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ assert( pCur->pgnoRoot==0 || (pCur->pPage!=0 && pCur->pPage->nCell==0) );
*pRes = 1;
rc = SQLITE_OK;
}
return rc;
}
+#ifdef SQLITE_DEBUG
+/* The cursors is CURSOR_VALID and has BTCF_AtLast set. Verify that
+** this flags are true for a consistent database.
+**
+** This routine is is called from within assert() statements only.
+** It is an internal verification routine and does not appear in production
+** builds.
+*/
+static int cursorIsAtLastEntry(BtCursor *pCur){
+ int ii;
+ for(ii=0; ii<pCur->iPage; ii++){
+ if( pCur->aiIdx[ii]!=pCur->apPage[ii]->nCell ) return 0;
+ }
+ return pCur->ix==pCur->pPage->nCell-1 && pCur->pPage->leaf!=0;
+}
+#endif
+
/* Move the cursor to the last entry in the table. Return SQLITE_OK
** on success. Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3BtreeLast(BtCursor *pCur, int *pRes){
- int rc;
-
- assert( cursorOwnsBtShared(pCur) );
- assert( sqlcipher_sqlite3_mutex_held(pCur->pBtree->db->mutex) );
-
- /* If the cursor already points to the last entry, this is a no-op. */
- if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
-#ifdef SQLITE_DEBUG
- /* This block serves to assert() that the cursor really does point
- ** to the last entry in the b-tree. */
- int ii;
- for(ii=0; ii<pCur->iPage; ii++){
- assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
- }
- assert( pCur->ix==pCur->pPage->nCell-1 || CORRUPT_DB );
- testcase( pCur->ix!=pCur->pPage->nCell-1 );
- /* ^-- dbsqlfuzz b92b72e4de80b5140c30ab71372ca719b8feb618 */
- assert( pCur->pPage->leaf );
-#endif
- *pRes = 0;
- return SQLITE_OK;
- }
-
- rc = moveToRoot(pCur);
+static SQLITE_NOINLINE int btreeLast(BtCursor *pCur, int *pRes){
+ int rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_VALID );
*pRes = 0;
@@ -72707,6 +76551,18 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeLast(BtCursor *pCur, int *pRes){
}
return rc;
}
+SQLITE_PRIVATE int sqlcipher_sqlite3BtreeLast(BtCursor *pCur, int *pRes){
+ assert( cursorOwnsBtShared(pCur) );
+ assert( sqlcipher_sqlite3_mutex_held(pCur->pBtree->db->mutex) );
+
+ /* If the cursor already points to the last entry, this is a no-op. */
+ if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
+ assert( cursorIsAtLastEntry(pCur) || CORRUPT_DB );
+ *pRes = 0;
+ return SQLITE_OK;
+ }
+ return btreeLast(pCur, pRes);
+}
/* Move the cursor so that it points to an entry in a table (a.k.a INTKEY)
** table near the key intKey. Return a success code.
@@ -72754,13 +76610,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeTableMoveto(
}
if( pCur->info.nKey<intKey ){
if( (pCur->curFlags & BTCF_AtLast)!=0 ){
+ assert( cursorIsAtLastEntry(pCur) || CORRUPT_DB );
*pRes = -1;
return SQLITE_OK;
}
/* If the requested key is one more than the previous key, then
** try to get there using sqlcipher_sqlite3BtreeNext() rather than a full
** binary search. This is an optimization only. The correct answer
- ** is still obtained without this case, only a little more slowely */
+ ** is still obtained without this case, only a little more slowly. */
if( pCur->info.nKey+1==intKey ){
*pRes = 0;
rc = sqlcipher_sqlite3BtreeNext(pCur, 0);
@@ -73156,10 +77013,36 @@ bypass_moveto_root:
}else{
chldPg = get4byte(findCell(pPage, lwr));
}
- pCur->ix = (u16)lwr;
- rc = moveToChild(pCur, chldPg);
- if( rc ) break;
- }
+
+ /* This block is similar to an in-lined version of:
+ **
+ ** pCur->ix = (u16)lwr;
+ ** rc = moveToChild(pCur, chldPg);
+ ** if( rc ) break;
+ */
+ pCur->info.nSize = 0;
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
+ if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ pCur->aiIdx[pCur->iPage] = (u16)lwr;
+ pCur->apPage[pCur->iPage] = pCur->pPage;
+ pCur->ix = 0;
+ pCur->iPage++;
+ rc = getAndInitPage(pCur->pBt, chldPg, &pCur->pPage, pCur->curPagerFlags);
+ if( rc==SQLITE_OK
+ && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey)
+ ){
+ releasePage(pCur->pPage);
+ rc = SQLITE_CORRUPT_PGNO(chldPg);
+ }
+ if( rc ){
+ pCur->pPage = pCur->apPage[--pCur->iPage];
+ break;
+ }
+ /*
+ ***** End of in-lined moveToChild() call */
+ }
moveto_index_finish:
pCur->info.nSize = 0;
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
@@ -73194,10 +77077,10 @@ SQLITE_PRIVATE i64 sqlcipher_sqlite3BtreeRowCountEst(BtCursor *pCur){
assert( cursorOwnsBtShared(pCur) );
assert( sqlcipher_sqlite3_mutex_held(pCur->pBtree->db->mutex) );
- /* Currently this interface is only called by the OP_IfSmaller
- ** opcode, and it that case the cursor will always be valid and
- ** will always point to a leaf node. */
- if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
+ /* Currently this interface is only called by the OP_IfSizeBetween
+ ** opcode and the OP_Count opcode with P3=1. In either case,
+ ** the cursor will always be valid unless the btree is empty. */
+ if( pCur->eState!=CURSOR_VALID ) return 0;
if( NEVER(pCur->pPage->leaf==0) ) return -1;
n = pCur->pPage->nCell;
@@ -73250,14 +77133,8 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
pPage = pCur->pPage;
idx = ++pCur->ix;
- if( !pPage->isInit || sqlcipher_sqlite3FaultSim(412) ){
- /* The only known way for this to happen is for there to be a
- ** recursive SQL function that does a DELETE operation as part of a
- ** SELECT which deletes content out from under an active cursor
- ** in a corrupt database file where the table being DELETE-ed from
- ** has pages in common with the table being queried. See TH3
- ** module cov1/btree78.test testcase 220 (2018-06-08) for an
- ** example. */
+ if( sqlcipher_sqlite3FaultSim(412) ) pPage->isInit = 0;
+ if( !pPage->isInit ){
return SQLITE_CORRUPT_BKPT;
}
@@ -73349,7 +77226,10 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
}
pPage = pCur->pPage;
- assert( pPage->isInit );
+ if( sqlcipher_sqlite3FaultSim(412) ) pPage->isInit = 0;
+ if( !pPage->isInit ){
+ return SQLITE_CORRUPT_BKPT;
+ }
if( !pPage->leaf ){
int idx = pCur->ix;
rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
@@ -73433,8 +77313,8 @@ static int allocateBtreePage(
assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
pPage1 = pBt->pPage1;
mxPage = btreePagecount(pBt);
- /* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36
- ** stores stores the total number of pages on the freelist. */
+ /* EVIDENCE-OF: R-21003-45125 The 4-byte big-endian integer at offset 36
+ ** stores the total number of pages on the freelist. */
n = get4byte(&pPage1->aData[36]);
testcase( n==mxPage-1 );
if( n>=mxPage ){
@@ -73520,7 +77400,7 @@ static int allocateBtreePage(
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
*ppPage = pTrunk;
pTrunk = 0;
- TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
+ TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
}else if( k>(u32)(pBt->usableSize/4 - 2) ){
/* Value of k is out of range. Database corruption */
rc = SQLITE_CORRUPT_PGNO(iTrunk);
@@ -73586,7 +77466,7 @@ static int allocateBtreePage(
}
}
pTrunk = 0;
- TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
+ TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
#endif
}else if( k>0 ){
/* Extract a leaf from the trunk */
@@ -73631,8 +77511,8 @@ static int allocateBtreePage(
){
int noContent;
*pPgno = iPage;
- TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
- ": %d more free pages\n",
+ TRACE(("ALLOCATE: %u was leaf %u of %u on trunk %u"
+ ": %u more free pages\n",
*pPgno, closest+1, k, pTrunk->pgno, n-1));
rc = sqlcipher_sqlite3PagerWrite(pTrunk->pDbPage);
if( rc ) goto end_allocate_page;
@@ -73688,7 +77568,7 @@ static int allocateBtreePage(
** becomes a new pointer-map page, the second is used by the caller.
*/
MemPage *pPg = 0;
- TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
+ TRACE(("ALLOCATE: %u from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetUnusedPage(pBt, pBt->nPage, &pPg, bNoContent);
if( rc==SQLITE_OK ){
@@ -73711,7 +77591,7 @@ static int allocateBtreePage(
releasePage(*ppPage);
*ppPage = 0;
}
- TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
+ TRACE(("ALLOCATE: %u from end of file\n", *pPgno));
}
assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) );
@@ -73779,7 +77659,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
/* If the database supports auto-vacuum, write an entry in the pointer-map
** to indicate that the page is free.
*/
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, iPage, PTRMAP_FREEPAGE, 0, &rc);
if( rc ) goto freepage_out;
}
@@ -73839,7 +77719,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
}
rc = btreeSetHasContent(pBt, iPage);
}
- TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
+ TRACE(("FREE-PAGE: %u leaf on trunk page %u\n",pPage->pgno,pTrunk->pgno));
goto freepage_out;
}
}
@@ -73860,7 +77740,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
put4byte(pPage->aData, iTrunk);
put4byte(&pPage->aData[4], 0);
put4byte(&pPage1->aData[32], iPage);
- TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", pPage->pgno, iTrunk));
+ TRACE(("FREE-PAGE: %u new trunk page replacing %u\n", pPage->pgno, iTrunk));
freepage_out:
if( pPage ){
@@ -73949,7 +77829,7 @@ static SQLITE_NOINLINE int clearCellOverflow(
/* Call xParseCell to compute the size of a cell. If the cell contains
** overflow, then invoke cellClearOverflow to clear out that overflow.
-** STore the result code (SQLITE_OK or some error code) in rc.
+** Store the result code (SQLITE_OK or some error code) in rc.
**
** Implemented as macro to force inlining for performance.
*/
@@ -74022,7 +77902,10 @@ static int fillInCell(
n = nHeader + nPayload;
testcase( n==3 );
testcase( n==4 );
- if( n<4 ) n = 4;
+ if( n<4 ){
+ n = 4;
+ pPayload[nPayload] = 0;
+ }
*pnSize = n;
assert( nSrc<=nPayload );
testcase( nSrc<nPayload );
@@ -74183,12 +78066,6 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
assert( pPage->pBt->usableSize > (u32)(ptr-data) );
pc = get2byte(ptr);
hdr = pPage->hdrOffset;
-#if 0 /* Not required. Omit for efficiency */
- if( pc<hdr+pPage->nCell*2 ){
- *pRC = SQLITE_CORRUPT_BKPT;
- return;
- }
-#endif
testcase( pc==(u32)get2byte(&data[hdr+5]) );
testcase( pc+sz==pPage->pBt->usableSize );
if( pc+sz > pPage->pBt->usableSize ){
@@ -74226,23 +78103,27 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
**
-** *pRC must be SQLITE_OK when this routine is called.
+** The insertCellFast() routine below works exactly the same as
+** insertCell() except that it lacks the pTemp and iChild parameters
+** which are assumed zero. Other than that, the two routines are the
+** same.
+**
+** Fixes or enhancements to this routine should be reflected in
+** insertCellFast()!
*/
-static void insertCell(
+static int insertCell(
MemPage *pPage, /* Page into which we are copying */
int i, /* New cell becomes the i-th cell of the page */
u8 *pCell, /* Content of the new cell */
int sz, /* Bytes of content in pCell */
u8 *pTemp, /* Temp storage space for pCell, if needed */
- Pgno iChild, /* If non-zero, replace first 4 bytes with this value */
- int *pRC /* Read and write return code from here */
+ Pgno iChild /* If non-zero, replace first 4 bytes with this value */
){
int idx = 0; /* Where to write new cell content in data[] */
int j; /* Loop counter */
u8 *data; /* The content of the whole page */
u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
- assert( *pRC==SQLITE_OK );
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
assert( MX_CELL(pPage->pBt)<=10921 );
assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
@@ -74251,14 +78132,103 @@ static void insertCell(
assert( sqlcipher_sqlite3_mutex_held(pPage->pBt->mutex) );
assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
assert( pPage->nFree>=0 );
+ assert( iChild>0 );
if( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){
memcpy(pTemp, pCell, sz);
pCell = pTemp;
}
- if( iChild ){
- put4byte(pCell, iChild);
+ put4byte(pCell, iChild);
+ j = pPage->nOverflow++;
+ /* Comparison against ArraySize-1 since we hold back one extra slot
+ ** as a contingency. In other words, never need more than 3 overflow
+ ** slots but 4 are allocated, just to be safe. */
+ assert( j < ArraySize(pPage->apOvfl)-1 );
+ pPage->apOvfl[j] = pCell;
+ pPage->aiOvfl[j] = (u16)i;
+
+ /* When multiple overflows occur, they are always sequential and in
+ ** sorted order. This invariants arise because multiple overflows can
+ ** only occur when inserting divider cells into the parent page during
+ ** balancing, and the dividers are adjacent and sorted.
+ */
+ assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */
+ assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */
+ }else{
+ int rc = sqlcipher_sqlite3PagerWrite(pPage->pDbPage);
+ if( NEVER(rc!=SQLITE_OK) ){
+ return rc;
}
+ assert( sqlcipher_sqlite3PagerIswriteable(pPage->pDbPage) );
+ data = pPage->aData;
+ assert( &data[pPage->cellOffset]==pPage->aCellIdx );
+ rc = allocateSpace(pPage, sz, &idx);
+ if( rc ){ return rc; }
+ /* The allocateSpace() routine guarantees the following properties
+ ** if it returns successfully */
+ assert( idx >= 0 );
+ assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
+ assert( idx+sz <= (int)pPage->pBt->usableSize );
+ pPage->nFree -= (u16)(2 + sz);
+ /* In a corrupt database where an entry in the cell index section of
+ ** a btree page has a value of 3 or less, the pCell value might point
+ ** as many as 4 bytes in front of the start of the aData buffer for
+ ** the source page. Make sure this does not cause problems by not
+ ** reading the first 4 bytes */
+ memcpy(&data[idx+4], pCell+4, sz-4);
+ put4byte(&data[idx], iChild);
+ pIns = pPage->aCellIdx + i*2;
+ memmove(pIns+2, pIns, 2*(pPage->nCell - i));
+ put2byte(pIns, idx);
+ pPage->nCell++;
+ /* increment the cell count */
+ if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++;
+ assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB );
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pPage->pBt->autoVacuum ){
+ int rc2 = SQLITE_OK;
+ /* The cell may contain a pointer to an overflow page. If so, write
+ ** the entry for the overflow page into the pointer map.
+ */
+ ptrmapPutOvflPtr(pPage, pPage, pCell, &rc2);
+ if( rc2 ) return rc2;
+ }
+#endif
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This variant of insertCell() assumes that the pTemp and iChild
+** parameters are both zero. Use this variant in sqlcipher_sqlite3BtreeInsert()
+** for performance improvement, and also so that this variant is only
+** called from that one place, and is thus inlined, and thus runs must
+** faster.
+**
+** Fixes or enhancements to this routine should be reflected into
+** the insertCell() routine.
+*/
+static int insertCellFast(
+ MemPage *pPage, /* Page into which we are copying */
+ int i, /* New cell becomes the i-th cell of the page */
+ u8 *pCell, /* Content of the new cell */
+ int sz /* Bytes of content in pCell */
+){
+ int idx = 0; /* Where to write new cell content in data[] */
+ int j; /* Loop counter */
+ u8 *data; /* The content of the whole page */
+ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
+
+ assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
+ assert( MX_CELL(pPage->pBt)<=10921 );
+ assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
+ assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
+ assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
+ assert( sqlcipher_sqlite3_mutex_held(pPage->pBt->mutex) );
+ assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
+ assert( pPage->nFree>=0 );
+ assert( pPage->nOverflow==0 );
+ if( sz+2>pPage->nFree ){
j = pPage->nOverflow++;
/* Comparison against ArraySize-1 since we hold back one extra slot
** as a contingency. In other words, never need more than 3 overflow
@@ -74277,31 +78247,20 @@ static void insertCell(
}else{
int rc = sqlcipher_sqlite3PagerWrite(pPage->pDbPage);
if( rc!=SQLITE_OK ){
- *pRC = rc;
- return;
+ return rc;
}
assert( sqlcipher_sqlite3PagerIswriteable(pPage->pDbPage) );
data = pPage->aData;
assert( &data[pPage->cellOffset]==pPage->aCellIdx );
rc = allocateSpace(pPage, sz, &idx);
- if( rc ){ *pRC = rc; return; }
+ if( rc ){ return rc; }
/* The allocateSpace() routine guarantees the following properties
** if it returns successfully */
assert( idx >= 0 );
assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
assert( idx+sz <= (int)pPage->pBt->usableSize );
pPage->nFree -= (u16)(2 + sz);
- if( iChild ){
- /* In a corrupt database where an entry in the cell index section of
- ** a btree page has a value of 3 or less, the pCell value might point
- ** as many as 4 bytes in front of the start of the aData buffer for
- ** the source page. Make sure this does not cause problems by not
- ** reading the first 4 bytes */
- memcpy(&data[idx+4], pCell+4, sz-4);
- put4byte(&data[idx], iChild);
- }else{
- memcpy(&data[idx], pCell, sz);
- }
+ memcpy(&data[idx], pCell, sz);
pIns = pPage->aCellIdx + i*2;
memmove(pIns+2, pIns, 2*(pPage->nCell - i));
put2byte(pIns, idx);
@@ -74311,13 +78270,16 @@ static void insertCell(
assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB );
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pPage->pBt->autoVacuum ){
+ int rc2 = SQLITE_OK;
/* The cell may contain a pointer to an overflow page. If so, write
** the entry for the overflow page into the pointer map.
*/
- ptrmapPutOvflPtr(pPage, pPage, pCell, pRC);
+ ptrmapPutOvflPtr(pPage, pPage, pCell, &rc2);
+ if( rc2 ) return rc2;
}
#endif
}
+ return SQLITE_OK;
}
/*
@@ -74418,14 +78380,16 @@ struct CellArray {
** computed.
*/
static void populateCellCache(CellArray *p, int idx, int N){
+ MemPage *pRef = p->pRef;
+ u16 *szCell = p->szCell;
assert( idx>=0 && idx+N<=p->nCell );
while( N>0 ){
assert( p->apCell[idx]!=0 );
- if( p->szCell[idx]==0 ){
- p->szCell[idx] = p->pRef->xCellSize(p->pRef, p->apCell[idx]);
+ if( szCell[idx]==0 ){
+ szCell[idx] = pRef->xCellSize(pRef, p->apCell[idx]);
}else{
assert( CORRUPT_DB ||
- p->szCell[idx]==p->pRef->xCellSize(p->pRef, p->apCell[idx]) );
+ szCell[idx]==pRef->xCellSize(pRef, p->apCell[idx]) );
}
idx++;
N--;
@@ -74479,12 +78443,13 @@ static int rebuildPage(
int k; /* Current slot in pCArray->apEnd[] */
u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */
+ assert( nCell>0 );
assert( i<iEnd );
j = get2byte(&aData[hdr+5]);
if( j>(u32)usableSize ){ j = 0; }
memcpy(&pTmp[j], &aData[j], usableSize - j);
- for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
+ for(k=0; ALWAYS(k<NB*2) && pCArray->ixNx[k]<=i; k++){}
pSrcEnd = pCArray->apEnd[k];
pData = pEnd;
@@ -74547,7 +78512,7 @@ static int rebuildPage(
** Finally, argument pBegin points to the byte immediately following the
** end of the space required by this page for the cell-pointer area (for
** all cells - not just those inserted by the current call). If the content
-** area must be extended to before this point in order to accomodate all
+** area must be extended to before this point in order to accommodate all
** cells in apCell[], then the cells do not fit and non-zero is returned.
*/
static int pageInsertArray(
@@ -74567,7 +78532,7 @@ static int pageInsertArray(
u8 *pEnd; /* Maximum extent of cell data */
assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
if( iEnd<=iFirst ) return 0;
- for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
+ for(k=0; ALWAYS(k<NB*2) && pCArray->ixNx[k]<=i ; k++){}
pEnd = pCArray->apEnd[k];
while( 1 /*Exit by break*/ ){
int sz, rc;
@@ -74625,39 +78590,50 @@ static int pageFreeArray(
u8 * const pEnd = &aData[pPg->pBt->usableSize];
u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize];
int nRet = 0;
- int i;
+ int i, j;
int iEnd = iFirst + nCell;
- u8 *pFree = 0;
- int szFree = 0;
+ int nFree = 0;
+ int aOfst[10];
+ int aAfter[10];
for(i=iFirst; i<iEnd; i++){
u8 *pCell = pCArray->apCell[i];
if( SQLITE_WITHIN(pCell, pStart, pEnd) ){
int sz;
+ int iAfter;
+ int iOfst;
/* No need to use cachedCellSize() here. The sizes of all cells that
** are to be freed have already been computing while deciding which
** cells need freeing */
sz = pCArray->szCell[i]; assert( sz>0 );
- if( pFree!=(pCell + sz) ){
- if( pFree ){
- assert( pFree>aData && (pFree - aData)<65536 );
- freeSpace(pPg, (u16)(pFree - aData), szFree);
- }
- pFree = pCell;
- szFree = sz;
- if( pFree+sz>pEnd ){
- return 0;
+ iOfst = (u16)(pCell - aData);
+ iAfter = iOfst+sz;
+ for(j=0; j<nFree; j++){
+ if( aOfst[j]==iAfter ){
+ aOfst[j] = iOfst;
+ break;
+ }else if( aAfter[j]==iOfst ){
+ aAfter[j] = iAfter;
+ break;
}
- }else{
- pFree = pCell;
- szFree += sz;
+ }
+ if( j>=nFree ){
+ if( nFree>=(int)(sizeof(aOfst)/sizeof(aOfst[0])) ){
+ for(j=0; j<nFree; j++){
+ freeSpace(pPg, aOfst[j], aAfter[j]-aOfst[j]);
+ }
+ nFree = 0;
+ }
+ aOfst[nFree] = iOfst;
+ aAfter[nFree] = iAfter;
+ if( &aData[iAfter]>pEnd ) return 0;
+ nFree++;
}
nRet++;
}
}
- if( pFree ){
- assert( pFree>aData && (pFree - aData)<65536 );
- freeSpace(pPg, (u16)(pFree - aData), szFree);
+ for(j=0; j<nFree; j++){
+ freeSpace(pPg, aOfst[j], aAfter[j]-aOfst[j]);
}
return nRet;
}
@@ -74710,9 +78686,9 @@ static int editPage(
nCell -= nTail;
}
- pData = &aData[get2byteNotZero(&aData[hdr+5])];
+ pData = &aData[get2byte(&aData[hdr+5])];
if( pData<pBegin ) goto editpage_fail;
- if( pData>pPg->aDataEnd ) goto editpage_fail;
+ if( NEVER(pData>pPg->aDataEnd) ) goto editpage_fail;
/* Add cells to the start of the page */
if( iNew<iOld ){
@@ -74774,6 +78750,7 @@ static int editPage(
return SQLITE_OK;
editpage_fail:
/* Unable to edit this page. Rebuild it from scratch instead. */
+ if( nNew<1 ) return SQLITE_CORRUPT_BKPT;
populateCellCache(pCArray, iNew, nNew);
return rebuildPage(pCArray, iNew, nNew, pPg);
}
@@ -74851,12 +78828,12 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
** with entries for the new page, and any pointer from the
** cell on the page to an overflow page. If either of these
** operations fails, the return code is set, but the contents
- ** of the parent page are still manipulated by thh code below.
+ ** of the parent page are still manipulated by the code below.
** That is Ok, at this point the parent page is guaranteed to
** be marked as dirty. Returning an error code will cause a
** rollback, undoing any changes made to the parent page.
*/
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc);
if( szCell>pNew->minLocal ){
ptrmapPutOvflPtr(pNew, pNew, pCell, &rc);
@@ -74884,8 +78861,8 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
/* Insert the new divider cell into pParent. */
if( rc==SQLITE_OK ){
- insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
- 0, pPage->pgno, &rc);
+ rc = insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
+ 0, pPage->pgno);
}
/* Set the right-child pointer of pParent to point to the new page. */
@@ -74994,7 +78971,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
/* If this is an auto-vacuum database, update the pointer-map entries
** for any b-tree or overflow pages that pTo now contains the pointers to.
*/
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
*pRC = setChildPtrmaps(pTo);
}
}
@@ -75127,7 +79104,7 @@ static int balance_nonroot(
pgno = get4byte(pRight);
while( 1 ){
if( rc==SQLITE_OK ){
- rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0);
+ rc = getAndInitPage(pBt, pgno, &apOld[i], 0);
}
if( rc ){
memset(apOld, 0, (i+1)*sizeof(MemPage*));
@@ -75234,7 +79211,7 @@ static int balance_nonroot(
** table-interior, index-leaf, or index-interior).
*/
if( pOld->aData[0]!=apOld[0]->aData[0] ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PAGE(pOld);
goto balance_cleanup;
}
@@ -75258,7 +79235,7 @@ static int balance_nonroot(
memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow));
if( pOld->nOverflow>0 ){
if( NEVER(limit<pOld->aiOvfl[0]) ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PAGE(pOld);
goto balance_cleanup;
}
limit = pOld->aiOvfl[0];
@@ -75418,15 +79395,17 @@ static int balance_nonroot(
d = r + 1 - leafData;
(void)cachedCellSize(&b, d);
do{
+ int szR, szD;
assert( d<nMaxCells );
assert( r<nMaxCells );
- (void)cachedCellSize(&b, r);
+ szR = cachedCellSize(&b, r);
+ szD = b.szCell[d];
if( szRight!=0
- && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){
+ && (bBulk || szRight+szD+2 > szLeft-(szR+(i==k-1?0:2)))){
break;
}
- szRight += b.szCell[d] + 2;
- szLeft -= b.szCell[r] + 2;
+ szRight += szD + 2;
+ szLeft -= szR + 2;
cntNew[i-1] = r;
r--;
d--;
@@ -75439,7 +79418,7 @@ static int balance_nonroot(
}
}
- /* Sanity check: For a non-corrupt database file one of the follwing
+ /* Sanity check: For a non-corrupt database file one of the following
** must be true:
** (1) We found one or more cells (cntNew[0])>0), or
** (2) pPage is a virtual root page. A virtual root page is when
@@ -75447,7 +79426,7 @@ static int balance_nonroot(
** that page.
*/
assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB);
- TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\n",
+ TRACE(("BALANCE: old: %u(nc=%u) %u(nc=%u) %u(nc=%u)\n",
apOld[0]->pgno, apOld[0]->nCell,
nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0,
nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0
@@ -75480,7 +79459,7 @@ static int balance_nonroot(
cntOld[i] = b.nCell;
/* Set the pointer-map entry for the new sibling page. */
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno, &rc);
if( rc!=SQLITE_OK ){
goto balance_cleanup;
@@ -75531,8 +79510,8 @@ static int balance_nonroot(
}
}
- TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) "
- "%d(%d nc=%d) %d(%d nc=%d)\n",
+ TRACE(("BALANCE: new: %u(%u nc=%u) %u(%u nc=%u) %u(%u nc=%u) "
+ "%u(%u nc=%u) %u(%u nc=%u)\n",
apNew[0]->pgno, szNew[0], cntNew[0],
nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0,
nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0,
@@ -75573,7 +79552,7 @@ static int balance_nonroot(
** updated. This happens below, after the sibling pages have been
** populated, not here.
*/
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
MemPage *pOld;
MemPage *pNew = pOld = apNew[0];
int cntOldNext = pNew->nCell + pNew->nOverflow;
@@ -75664,13 +79643,13 @@ static int balance_nonroot(
iOvflSpace += sz;
assert( sz<=pBt->maxLocal+23 );
assert( iOvflSpace <= (int)pBt->pageSize );
- for(k=0; b.ixNx[k]<=j && ALWAYS(k<NB*2); k++){}
+ for(k=0; ALWAYS(k<NB*2) && b.ixNx[k]<=j; k++){}
pSrcEnd = b.apEnd[k];
- if( SQLITE_WITHIN(pSrcEnd, pCell, pCell+sz) ){
+ if( SQLITE_OVERFLOW(pSrcEnd, pCell, pCell+sz) ){
rc = SQLITE_CORRUPT_BKPT;
goto balance_cleanup;
}
- insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc);
+ rc = insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno);
if( rc!=SQLITE_OK ) goto balance_cleanup;
assert( sqlcipher_sqlite3PagerIswriteable(pParent->pDbPage) );
}
@@ -75700,6 +79679,8 @@ static int balance_nonroot(
for(i=1-nNew; i<nNew; i++){
int iPg = i<0 ? -i : i;
assert( iPg>=0 && iPg<nNew );
+ assert( iPg>=1 || i>=0 );
+ assert( iPg<ArraySize(cntOld) );
if( abDone[iPg] ) continue; /* Skip pages already processed */
if( i>=0 /* On the upwards pass, or... */
|| cntOld[iPg-1]>=cntNew[iPg-1] /* Condition (1) is true */
@@ -75766,7 +79747,7 @@ static int balance_nonroot(
);
copyNodeContent(apNew[0], pParent, &rc);
freePage(apNew[0], &rc);
- }else if( ISAUTOVACUUM && !leafCorrection ){
+ }else if( ISAUTOVACUUM(pBt) && !leafCorrection ){
/* Fix the pointer map entries associated with the right-child of each
** sibling page. All other pointer map entries have already been taken
** care of. */
@@ -75777,7 +79758,7 @@ static int balance_nonroot(
}
assert( pParent->isInit );
- TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n",
+ TRACE(("BALANCE: finished: old=%u new=%u cells=%u\n",
nOld, nNew, b.nCell));
/* Free any old pages that were not reused as new pages.
@@ -75787,7 +79768,7 @@ static int balance_nonroot(
}
#if 0
- if( ISAUTOVACUUM && rc==SQLITE_OK && apNew[0]->isInit ){
+ if( ISAUTOVACUUM(pBt) && rc==SQLITE_OK && apNew[0]->isInit ){
/* The ptrmapCheckPages() contains assert() statements that verify that
** all pointer map pages are set correctly. This is helpful while
** debugging. This is usually disabled because a corrupt database may
@@ -75849,7 +79830,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
if( rc==SQLITE_OK ){
rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0);
copyNodeContent(pRoot, pChild, &rc);
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc);
}
}
@@ -75862,7 +79843,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
assert( sqlcipher_sqlite3PagerIswriteable(pRoot->pDbPage) );
assert( pChild->nCell==pRoot->nCell || CORRUPT_DB );
- TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));
+ TRACE(("BALANCE: copy root %u into %u\n", pRoot->pgno, pChild->pgno));
/* Copy the overflow cells from pRoot to pChild */
memcpy(pChild->aiOvfl, pRoot->aiOvfl,
@@ -75897,7 +79878,7 @@ static int anotherValidCursor(BtCursor *pCur){
&& pOther->eState==CURSOR_VALID
&& pOther->pPage==pCur->pPage
){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pCur->pPage);
}
}
return SQLITE_OK;
@@ -75953,6 +79934,11 @@ static int balance(BtCursor *pCur){
}else{
break;
}
+ }else if( sqlcipher_sqlite3PagerPageRefcount(pPage->pDbPage)>1 ){
+ /* The page being written is not a root page, and there is currently
+ ** more than one reference to it. This only happens if the page is one
+ ** of its own ancestor pages. Corruption. */
+ rc = SQLITE_CORRUPT_PAGE(pPage);
}else{
MemPage * const pParent = pCur->apPage[iPage-1];
int const iIdx = pCur->aiIdx[iPage-1];
@@ -76051,7 +80037,7 @@ static int btreeOverwriteContent(
){
int nData = pX->nData - iOffset;
if( nData<=0 ){
- /* Overwritting with zeros */
+ /* Overwriting with zeros */
int i;
for(i=0; i<iAmt && pDest[i]==0; i++){}
if( i<iAmt ){
@@ -76083,9 +80069,13 @@ static int btreeOverwriteContent(
/*
** Overwrite the cell that cursor pCur is pointing to with fresh content
-** contained in pX.
+** contained in pX. In this variant, pCur is pointing to an overflow
+** cell.
*/
-static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
+static SQLITE_NOINLINE int btreeOverwriteOverflowCell(
+ BtCursor *pCur, /* Cursor pointing to cell to overwrite */
+ const BtreePayload *pX /* Content to write into the cell */
+){
int iOffset; /* Next byte of pX->pData to write */
int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */
int rc; /* Return code */
@@ -76094,16 +80084,12 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
Pgno ovflPgno; /* Next overflow page to write */
u32 ovflPageSize; /* Size to write on overflow page */
- if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
- || pCur->info.pPayload < pPage->aData + pPage->cellOffset
- ){
- return SQLITE_CORRUPT_BKPT;
- }
+ assert( pCur->info.nLocal<nTotal ); /* pCur is an overflow cell */
+
/* Overwrite the local portion first */
rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX,
0, pCur->info.nLocal);
if( rc ) return rc;
- if( pCur->info.nLocal==nTotal ) return SQLITE_OK;
/* Now overwrite the overflow pages */
iOffset = pCur->info.nLocal;
@@ -76116,7 +80102,7 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
rc = btreeGetPage(pBt, ovflPgno, &pPage, 0);
if( rc ) return rc;
if( sqlcipher_sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PAGE(pPage);
}else{
if( iOffset+ovflPageSize<(u32)nTotal ){
ovflPgno = get4byte(pPage->aData);
@@ -76133,6 +80119,29 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
return SQLITE_OK;
}
+/*
+** Overwrite the cell that cursor pCur is pointing to with fresh content
+** contained in pX.
+*/
+static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
+ int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */
+ MemPage *pPage = pCur->pPage; /* Page being written */
+
+ if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
+ || pCur->info.pPayload < pPage->aData + pPage->cellOffset
+ ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ if( pCur->info.nLocal==nTotal ){
+ /* The entire cell is local */
+ return btreeOverwriteContent(pPage, pCur->info.pPayload, pX,
+ 0, pCur->info.nLocal);
+ }else{
+ /* The cell contains overflow content */
+ return btreeOverwriteOverflowCell(pCur, pX);
+ }
+}
+
/*
** Insert a new record into the BTree. The content of the new record
@@ -76176,7 +80185,6 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeInsert(
int idx;
MemPage *pPage;
Btree *p = pCur->pBtree;
- BtShared *pBt = p->pBt;
unsigned char *oldCell;
unsigned char *newCell = 0;
@@ -76195,7 +80203,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeInsert(
** not to clear the cursor here.
*/
if( pCur->curFlags & BTCF_Multiple ){
- rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
+ rc = saveAllCursors(p->pBt, pCur->pgnoRoot, pCur);
if( rc ) return rc;
if( loc && pCur->iPage<0 ){
/* This can only happen if the schema is corrupt such that there is more
@@ -76203,7 +80211,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeInsert(
** Which can only happen if the SQLITE_NoSchemaError flag was set when
** the schema was loaded. This cannot be asserted though, as a user might
** set the flag, load the schema, and then unset the flag. */
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot);
}
}
@@ -76219,8 +80227,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeInsert(
assert( cursorOwnsBtShared(pCur) );
assert( (pCur->curFlags & BTCF_WriteFlag)!=0
- && pBt->inTransaction==TRANS_WRITE
- && (pBt->btsFlags & BTS_READ_ONLY)==0 );
+ && p->pBt->inTransaction==TRANS_WRITE
+ && (p->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
@@ -76318,7 +80326,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeInsert(
}
}
assert( pCur->eState==CURSOR_VALID
- || (pCur->eState==CURSOR_INVALID && loc) );
+ || (pCur->eState==CURSOR_INVALID && loc) || CORRUPT_DB );
pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );
@@ -76326,43 +80334,49 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeInsert(
if( pPage->nFree<0 ){
if( NEVER(pCur->eState>CURSOR_INVALID) ){
/* ^^^^^--- due to the moveToRoot() call above */
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PAGE(pPage);
}else{
rc = btreeComputeFreeSpace(pPage);
}
if( rc ) return rc;
}
- TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
+ TRACE(("INSERT: table=%u nkey=%lld ndata=%u page=%u %s\n",
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit || CORRUPT_DB );
- newCell = pBt->pTmpSpace;
+ newCell = p->pBt->pTmpSpace;
assert( newCell!=0 );
+ assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT );
if( flags & BTREE_PREFORMAT ){
rc = SQLITE_OK;
- szNew = pBt->nPreformatSize;
- if( szNew<4 ) szNew = 4;
- if( ISAUTOVACUUM && szNew>pPage->maxLocal ){
+ szNew = p->pBt->nPreformatSize;
+ if( szNew<4 ){
+ szNew = 4;
+ newCell[3] = 0;
+ }
+ if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
CellInfo info;
pPage->xParseCell(pPage, newCell, &info);
if( info.nPayload!=info.nLocal ){
Pgno ovfl = get4byte(&newCell[szNew-4]);
- ptrmapPut(pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
+ ptrmapPut(p->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
+ if( NEVER(rc) ) goto end_insert;
}
}
}else{
rc = fillInCell(pPage, newCell, pX, &szNew);
+ if( rc ) goto end_insert;
}
- if( rc ) goto end_insert;
assert( szNew==pPage->xCellSize(pPage, newCell) );
- assert( szNew <= MX_CELL_SIZE(pBt) );
+ assert( szNew <= MX_CELL_SIZE(p->pBt) );
idx = pCur->ix;
+ pCur->info.nSize = 0;
if( loc==0 ){
CellInfo info;
assert( idx>=0 );
if( idx>=pPage->nCell ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
rc = sqlcipher_sqlite3PagerWrite(pPage->pDbPage);
if( rc ){
@@ -76376,7 +80390,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeInsert(
testcase( pCur->curFlags & BTCF_ValidOvfl );
invalidateOverflowCache(pCur);
if( info.nSize==szNew && info.nLocal==info.nPayload
- && (!ISAUTOVACUUM || szNew<pPage->minLocal)
+ && (!ISAUTOVACUUM(p->pBt) || szNew<pPage->minLocal)
){
/* Overwrite the old cell with the new if they are the same size.
** We could also try to do this if the old cell is smaller, then add
@@ -76389,10 +80403,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeInsert(
** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */
assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */
if( oldCell < pPage->aData+pPage->hdrOffset+10 ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
if( oldCell+szNew > pPage->aDataEnd ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
memcpy(oldCell, newCell, szNew);
return SQLITE_OK;
@@ -76402,11 +80416,11 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeInsert(
}else if( loc<0 && pPage->nCell>0 ){
assert( pPage->leaf );
idx = ++pCur->ix;
- pCur->curFlags &= ~BTCF_ValidNKey;
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
}else{
assert( pPage->leaf );
}
- insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
+ rc = insertCellFast(pPage, idx, newCell, szNew);
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
@@ -76430,10 +80444,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeInsert(
** larger than the largest existing key, it is possible to insert the
** row without seeking the cursor. This can be a big performance boost.
*/
- pCur->info.nSize = 0;
if( pPage->nOverflow ){
assert( rc==SQLITE_OK );
- pCur->curFlags &= ~(BTCF_ValidNKey);
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
rc = balance(pCur);
/* Must make sure nOverflow is reset to zero even if the balance()
@@ -76479,7 +80492,6 @@ end_insert:
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
*/
SQLITE_PRIVATE int sqlcipher_sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
- int rc = SQLITE_OK;
BtShared *pBt = pDest->pBt;
u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */
const u8 *aIn; /* Pointer to next input buffer */
@@ -76496,13 +80508,15 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *
nIn = pSrc->info.nLocal;
aIn = pSrc->info.pPayload;
if( aIn+nIn>pSrc->pPage->aDataEnd ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pSrc->pPage);
}
nRem = pSrc->info.nPayload;
if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
memcpy(aOut, aIn, nIn);
pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace);
+ return SQLITE_OK;
}else{
+ int rc = SQLITE_OK;
Pager *pSrcPager = pSrc->pBt->pPager;
u8 *pPgnoOut = 0;
Pgno ovflIn = 0;
@@ -76519,7 +80533,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *
if( nRem>nIn ){
if( aIn+nIn+4>pSrc->pPage->aDataEnd ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pSrc->pPage);
}
ovflIn = get4byte(&pSrc->info.pPayload[nIn]);
}
@@ -76554,7 +80568,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *
MemPage *pNew = 0;
rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
put4byte(pPgnoOut, pgnoNew);
- if( ISAUTOVACUUM && pPageOut ){
+ if( ISAUTOVACUUM(pBt) && pPageOut ){
ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc);
}
releasePage(pPageOut);
@@ -76570,9 +80584,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *
releasePage(pPageOut);
sqlcipher_sqlite3PagerUnref(pPageIn);
+ return rc;
}
-
- return rc;
}
/*
@@ -76616,7 +80629,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID );
if( rc || pCur->eState!=CURSOR_VALID ) return rc;
}else{
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot);
}
}
assert( pCur->eState==CURSOR_VALID );
@@ -76625,11 +80638,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
iCellIdx = pCur->ix;
pPage = pCur->pPage;
if( pPage->nCell<=iCellIdx ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
pCell = findCell(pPage, iCellIdx);
if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ if( pCell<&pPage->aCellIdx[pPage->nCell] ){
+ return SQLITE_CORRUPT_PAGE(pPage);
}
/* If the BTREE_SAVEPOSITION bit is on, then the cursor position must
@@ -76720,14 +80736,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
n = pCur->pPage->pgno;
}
pCell = findCell(pLeaf, pLeaf->nCell-1);
- if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
+ if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_PAGE(pLeaf);
nCell = pLeaf->xCellSize(pLeaf, pCell);
assert( MX_CELL_SIZE(pBt) >= nCell );
pTmp = pBt->pTmpSpace;
assert( pTmp!=0 );
rc = sqlcipher_sqlite3PagerWrite(pLeaf->pDbPage);
if( rc==SQLITE_OK ){
- insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
+ rc = insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n);
}
dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
if( rc ) return rc;
@@ -76807,7 +80823,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
MemPage *pRoot;
Pgno pgnoRoot;
int rc;
- int ptfFlags; /* Page-type flage for the root page of new table */
+ int ptfFlags; /* Page-type flags for the root page of new table */
assert( sqlcipher_sqlite3BtreeHoldsMutex(p) );
assert( pBt->inTransaction==TRANS_WRITE );
@@ -76836,7 +80852,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
*/
sqlcipher_sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot);
if( pgnoRoot>btreePagecount(pBt) ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pgnoRoot);
}
pgnoRoot++;
@@ -76884,7 +80900,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
}
rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage);
if( eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(pgnoRoot);
}
if( rc!=SQLITE_OK ){
releasePage(pRoot);
@@ -76974,14 +80990,14 @@ static int clearDatabasePage(
assert( sqlcipher_sqlite3_mutex_held(pBt->mutex) );
if( pgno>btreePagecount(pBt) ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pgno);
}
- rc = getAndInitPage(pBt, pgno, &pPage, 0, 0);
+ rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc;
if( (pBt->openFlags & BTREE_SINGLE)==0
&& sqlcipher_sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1))
){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PAGE(pPage);
goto cleardatabasepage_out;
}
hdr = pPage->hdrOffset;
@@ -77085,7 +81101,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
assert( p->inTrans==TRANS_WRITE );
assert( iTable>=2 );
if( iTable>btreePagecount(pBt) ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(iTable);
}
rc = sqlcipher_sqlite3BtreeClearTable(p, iTable, 0);
@@ -77327,6 +81343,41 @@ SQLITE_PRIVATE Pager *sqlcipher_sqlite3BtreePager(Btree *p){
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
/*
+** Record an OOM error during integrity_check
+*/
+static void checkOom(IntegrityCk *pCheck){
+ pCheck->rc = SQLITE_NOMEM;
+ pCheck->mxErr = 0; /* Causes integrity_check processing to stop */
+ if( pCheck->nErr==0 ) pCheck->nErr++;
+}
+
+/*
+** Invoke the progress handler, if appropriate. Also check for an
+** interrupt.
+*/
+static void checkProgress(IntegrityCk *pCheck){
+ sqlcipher_sqlite3 *db = pCheck->db;
+ if( AtomicLoad(&db->u1.isInterrupted) ){
+ pCheck->rc = SQLITE_INTERRUPT;
+ pCheck->nErr++;
+ pCheck->mxErr = 0;
+ }
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ if( db->xProgress ){
+ assert( db->nProgressOps>0 );
+ pCheck->nStep++;
+ if( (pCheck->nStep % db->nProgressOps)==0
+ && db->xProgress(db->pProgressArg)
+ ){
+ pCheck->rc = SQLITE_INTERRUPT;
+ pCheck->nErr++;
+ pCheck->mxErr = 0;
+ }
+ }
+#endif
+}
+
+/*
** Append a message to the error message string.
*/
static void checkAppendMsg(
@@ -77335,6 +81386,7 @@ static void checkAppendMsg(
...
){
va_list ap;
+ checkProgress(pCheck);
if( !pCheck->mxErr ) return;
pCheck->mxErr--;
pCheck->nErr++;
@@ -77343,12 +81395,13 @@ static void checkAppendMsg(
sqlcipher_sqlite3_str_append(&pCheck->errMsg, "\n", 1);
}
if( pCheck->zPfx ){
- sqlcipher_sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2);
+ sqlcipher_sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx,
+ pCheck->v0, pCheck->v1, pCheck->v2);
}
sqlcipher_sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
va_end(ap);
if( pCheck->errMsg.accError==SQLITE_NOMEM ){
- pCheck->bOomFault = 1;
+ checkOom(pCheck);
}
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -77360,7 +81413,8 @@ static void checkAppendMsg(
** corresponds to page iPg is already set.
*/
static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){
- assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 );
+ assert( pCheck->aPgRef!=0 );
+ assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 );
return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07)));
}
@@ -77368,7 +81422,8 @@ static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){
** 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 );
+ assert( pCheck->aPgRef!=0 );
+ assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 );
pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07));
}
@@ -77382,15 +81437,14 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
** Also check that the page number is in bounds.
*/
static int checkRef(IntegrityCk *pCheck, Pgno iPage){
- if( iPage>pCheck->nPage || iPage==0 ){
- checkAppendMsg(pCheck, "invalid page number %d", iPage);
+ if( iPage>pCheck->nCkPage || iPage==0 ){
+ checkAppendMsg(pCheck, "invalid page number %u", iPage);
return 1;
}
if( getPageReferenced(pCheck, iPage) ){
- checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
+ checkAppendMsg(pCheck, "2nd reference to page %u", iPage);
return 1;
}
- if( AtomicLoad(&pCheck->db->u1.isInterrupted) ) return 1;
setPageReferenced(pCheck, iPage);
return 0;
}
@@ -77413,14 +81467,14 @@ static void checkPtrmap(
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
if( rc!=SQLITE_OK ){
- if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->bOomFault = 1;
- checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) checkOom(pCheck);
+ checkAppendMsg(pCheck, "Failed to read ptrmap key=%u", iChild);
return;
}
if( ePtrmapType!=eType || iPtrmapParent!=iParent ){
checkAppendMsg(pCheck,
- "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)",
+ "Bad ptr map entry key=%u expected=(%u,%u) got=(%u,%u)",
iChild, eType, iParent, ePtrmapType, iPtrmapParent);
}
}
@@ -77445,7 +81499,7 @@ static void checkList(
if( checkRef(pCheck, iPage) ) break;
N--;
if( sqlcipher_sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
- checkAppendMsg(pCheck, "failed to get page %d", iPage);
+ checkAppendMsg(pCheck, "failed to get page %u", iPage);
break;
}
pOvflData = (unsigned char *)sqlcipher_sqlite3PagerGetData(pOvflPage);
@@ -77458,7 +81512,7 @@ static void checkList(
#endif
if( n>pCheck->pBt->usableSize/4-2 ){
checkAppendMsg(pCheck,
- "freelist leaf count too big on page %d", iPage);
+ "freelist leaf count too big on page %u", iPage);
N--;
}else{
for(i=0; i<(int)n; i++){
@@ -77490,7 +81544,7 @@ static void checkList(
}
if( N && nErrAtStart==pCheck->nErr ){
checkAppendMsg(pCheck,
- "%s is %d but should be %d",
+ "%s is %u but should be %u",
isFreeList ? "size" : "overflow list length",
expected-N, expected);
}
@@ -77520,7 +81574,9 @@ static void checkList(
** lower 16 bits are the index of the last byte of that range.
*/
static void btreeHeapInsert(u32 *aHeap, u32 x){
- u32 j, i = ++aHeap[0];
+ u32 j, i;
+ assert( aHeap!=0 );
+ i = ++aHeap[0];
aHeap[i] = x;
while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){
x = aHeap[j];
@@ -77597,15 +81653,18 @@ static int checkTreePage(
/* Check that the page exists
*/
+ checkProgress(pCheck);
+ if( pCheck->mxErr==0 ) goto end_of_check;
pBt = pCheck->pBt;
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage) ) return 0;
- pCheck->zPfx = "Page %u: ";
+ pCheck->zPfx = "Tree %u page %u: ";
pCheck->v1 = iPage;
if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck,
"unable to get the page. error code=%d", rc);
+ if( rc==SQLITE_IOERR_NOMEM ) pCheck->rc = SQLITE_NOMEM;
goto end_of_check;
}
@@ -77628,7 +81687,7 @@ static int checkTreePage(
hdr = pPage->hdrOffset;
/* Set up for cell analysis */
- pCheck->zPfx = "On tree page %u cell %d: ";
+ pCheck->zPfx = "Tree %u page %u cell %u: ";
contentOffset = get2byteNotZero(&data[hdr+5]);
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
@@ -77636,6 +81695,9 @@ static int checkTreePage(
** number of cells on the page. */
nCell = get2byte(&data[hdr+3]);
assert( pPage->nCell==nCell );
+ if( pPage->leaf || pPage->intKey==0 ){
+ pCheck->nRow += nCell;
+ }
/* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
** immediately follows the b-tree page header. */
@@ -77648,7 +81710,7 @@ static int checkTreePage(
pgno = get4byte(&data[hdr+8]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
- pCheck->zPfx = "On page %u at right child: ";
+ pCheck->zPfx = "Tree %u page %u right child: ";
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
@@ -77672,7 +81734,7 @@ static int checkTreePage(
pc = get2byteAligned(pCellIdx);
pCellIdx -= 2;
if( pc<contentOffset || pc>usableSize-4 ){
- checkAppendMsg(pCheck, "Offset %d out of range %d..%d",
+ checkAppendMsg(pCheck, "Offset %u out of range %u..%u",
pc, contentOffset, usableSize-4);
doCoverageCheck = 0;
continue;
@@ -77747,6 +81809,7 @@ static int checkTreePage(
btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
}
}
+ assert( heap!=0 );
/* Add the freeblocks to the min-heap
**
** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
@@ -77804,7 +81867,7 @@ static int checkTreePage(
*/
if( heap[0]==0 && nFrag!=data[hdr+7] ){
checkAppendMsg(pCheck,
- "Fragmentation of %d bytes reported as %d on page %u",
+ "Fragmentation of %u bytes reported as %u on page %u",
nFrag, data[hdr+7], iPage);
}
}
@@ -77842,13 +81905,15 @@ end_of_check:
** the unverified btrees. Except, if aRoot[1] is 1, then the freelist
** checks are still performed.
*/
-SQLITE_PRIVATE char *sqlcipher_sqlite3BtreeIntegrityCheck(
+SQLITE_PRIVATE int sqlcipher_sqlite3BtreeIntegrityCheck(
sqlcipher_sqlite3 *db, /* Database connection that is running the check */
Btree *p, /* The btree to be checked */
Pgno *aRoot, /* An array of root pages numbers for individual trees */
+ Mem *aCnt, /* Memory cells to write counts for each tree to */
int nRoot, /* Number of entries in aRoot[] */
int mxErr, /* Stop reporting errors after this many */
- int *pnErr /* Write number of errors seen to this variable */
+ int *pnErr, /* OUT: Write number of errors seen to this variable */
+ char **pzOut /* OUT: Write the error message string here */
){
Pgno i;
IntegrityCk sCheck;
@@ -77858,7 +81923,9 @@ SQLITE_PRIVATE char *sqlcipher_sqlite3BtreeIntegrityCheck(
int bPartial = 0; /* True if not checking all btrees */
int bCkFreelist = 1; /* True to scan the freelist */
VVA_ONLY( int nRef );
+
assert( nRoot>0 );
+ assert( aCnt!=0 );
/* aRoot[0]==0 means this is a partial check */
if( aRoot[0]==0 ){
@@ -77871,42 +81938,36 @@ SQLITE_PRIVATE char *sqlcipher_sqlite3BtreeIntegrityCheck(
assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
VVA_ONLY( nRef = sqlcipher_sqlite3PagerRefcount(pBt->pPager) );
assert( nRef>=0 );
+ memset(&sCheck, 0, sizeof(sCheck));
sCheck.db = db;
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
- sCheck.nPage = btreePagecount(sCheck.pBt);
+ sCheck.nCkPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
- sCheck.nErr = 0;
- sCheck.bOomFault = 0;
- sCheck.zPfx = 0;
- sCheck.v1 = 0;
- sCheck.v2 = 0;
- sCheck.aPgRef = 0;
- sCheck.heap = 0;
sqlcipher_sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL;
- if( sCheck.nPage==0 ){
+ if( sCheck.nCkPage==0 ){
goto integrity_ck_cleanup;
}
- sCheck.aPgRef = sqlcipher_sqlite3MallocZero((sCheck.nPage / 8)+ 1);
+ sCheck.aPgRef = sqlcipher_sqlite3MallocZero((sCheck.nCkPage / 8)+ 1);
if( !sCheck.aPgRef ){
- sCheck.bOomFault = 1;
+ checkOom(&sCheck);
goto integrity_ck_cleanup;
}
sCheck.heap = (u32*)sqlcipher_sqlite3PageMalloc( pBt->pageSize );
if( sCheck.heap==0 ){
- sCheck.bOomFault = 1;
+ checkOom(&sCheck);
goto integrity_ck_cleanup;
}
i = PENDING_BYTE_PAGE(pBt);
- if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
+ if( i<=sCheck.nCkPage ) setPageReferenced(&sCheck, i);
/* Check the integrity of the freelist
*/
if( bCkFreelist ){
- sCheck.zPfx = "Main freelist: ";
+ sCheck.zPfx = "Freelist: ";
checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
get4byte(&pBt->pPage1->aData[36]));
sCheck.zPfx = 0;
@@ -77923,7 +81984,7 @@ SQLITE_PRIVATE char *sqlcipher_sqlite3BtreeIntegrityCheck(
mxInHdr = get4byte(&pBt->pPage1->aData[52]);
if( mx!=mxInHdr ){
checkAppendMsg(&sCheck,
- "max rootpage (%d) disagrees with header (%d)",
+ "max rootpage (%u) disagrees with header (%u)",
mx, mxInHdr
);
}
@@ -77937,24 +81998,28 @@ SQLITE_PRIVATE char *sqlcipher_sqlite3BtreeIntegrityCheck(
testcase( pBt->db->flags & SQLITE_CellSizeCk );
pBt->db->flags &= ~(u64)SQLITE_CellSizeCk;
for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
- i64 notUsed;
- if( aRoot[i]==0 ) continue;
+ sCheck.nRow = 0;
+ if( aRoot[i] ){
+ i64 notUsed;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
- checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
- }
+ if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
+ checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
+ }
#endif
- checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
+ sCheck.v0 = aRoot[i];
+ checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
+ }
+ sqlcipher_sqlite3MemSetArrayInt64(aCnt, i, sCheck.nRow);
}
pBt->db->flags = savedDbFlags;
/* Make sure every page in the file is referenced
*/
if( !bPartial ){
- for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
+ for(i=1; i<=sCheck.nCkPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
if( getPageReferenced(&sCheck, i)==0 ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %u: never used", i);
}
#else
/* If the database supports auto-vacuum, make sure no tables contain
@@ -77962,11 +82027,11 @@ SQLITE_PRIVATE char *sqlcipher_sqlite3BtreeIntegrityCheck(
*/
if( getPageReferenced(&sCheck, i)==0 &&
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %u: never used", i);
}
if( getPageReferenced(&sCheck, i)!=0 &&
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
+ checkAppendMsg(&sCheck, "Page %u: pointer map referenced", i);
}
#endif
}
@@ -77977,16 +82042,17 @@ SQLITE_PRIVATE char *sqlcipher_sqlite3BtreeIntegrityCheck(
integrity_ck_cleanup:
sqlcipher_sqlite3PageFree(sCheck.heap);
sqlcipher_sqlite3_free(sCheck.aPgRef);
- if( sCheck.bOomFault ){
+ *pnErr = sCheck.nErr;
+ if( sCheck.nErr==0 ){
sqlcipher_sqlite3_str_reset(&sCheck.errMsg);
- sCheck.nErr++;
+ *pzOut = 0;
+ }else{
+ *pzOut = sqlcipher_sqlite3StrAccumFinish(&sCheck.errMsg);
}
- *pnErr = sCheck.nErr;
- if( sCheck.nErr==0 ) sqlcipher_sqlite3_str_reset(&sCheck.errMsg);
/* Make sure this analysis did not leave any unref() pages. */
assert( nRef==sqlcipher_sqlite3PagerRefcount(pBt->pPager) );
sqlcipher_sqlite3BtreeLeave(p);
- return sqlcipher_sqlite3StrAccumFinish(&sCheck.errMsg);
+ return sCheck.rc;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -78251,6 +82317,17 @@ SQLITE_PRIVATE int sqlcipher_sqlite3BtreeIsReadonly(Btree *p){
*/
SQLITE_PRIVATE int sqlcipher_sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
+/*
+** If no transaction is active and the database is not a temp-db, clear
+** the in-memory pager cache.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3BtreeClearCache(Btree *p){
+ BtShared *pBt = p->pBt;
+ if( pBt->inTransaction==TRANS_NONE ){
+ sqlcipher_sqlite3PagerClearCache(pBt->pPager);
+ }
+}
+
#if !defined(SQLITE_OMIT_SHARED_CACHE)
/*
** Return true if the Btree passed as the only argument is sharable.
@@ -78547,13 +82624,7 @@ static int backupOnePage(
assert( !isFatalError(p->rc) );
assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
assert( zSrcData );
-
- /* Catch the case where the destination is an in-memory database and the
- ** page sizes of the source and destination differ.
- */
- if( nSrcPgsz!=nDestPgsz && sqlcipher_sqlite3PagerIsMemdb(pDestPager) ){
- rc = SQLITE_READONLY;
- }
+ assert( nSrcPgsz==nDestPgsz || sqlcipher_sqlite3PagerIsMemdb(pDestPager)==0 );
/* BEGIN SQLCIPHER */
#ifdef SQLITE_HAS_CODEC
@@ -78708,7 +82779,10 @@ SQLITE_API int sqlcipher_sqlite3_backup_step(sqlcipher_sqlite3_backup *p, int nP
pgszSrc = sqlcipher_sqlite3BtreeGetPageSize(p->pSrc);
pgszDest = sqlcipher_sqlite3BtreeGetPageSize(p->pDest);
destMode = sqlcipher_sqlite3PagerGetJournalMode(sqlcipher_sqlite3BtreePager(p->pDest));
- if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
+ if( SQLITE_OK==rc
+ && (destMode==PAGER_JOURNALMODE_WAL || sqlcipher_sqlite3PagerIsMemdb(pDestPager))
+ && pgszSrc!=pgszDest
+ ){
rc = SQLITE_READONLY;
}
@@ -79220,9 +83294,9 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
i64 x;
assert( (p->flags&MEM_Int)*2==sizeof(x) );
memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2);
- sqlcipher_sqlite3Int64ToText(x, zBuf);
+ p->n = sqlcipher_sqlite3Int64ToText(x, zBuf);
#else
- sqlcipher_sqlite3Int64ToText(p->u.i, zBuf);
+ p->n = sqlcipher_sqlite3Int64ToText(p->u.i, zBuf);
#endif
}else{
sqlcipher_sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
@@ -79230,6 +83304,7 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
(p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r);
assert( acc.zText==zBuf && acc.mxAlloc<=0 );
zBuf[acc.nChar] = 0; /* Fast version of sqlcipher_sqlite3StrAccumFinish(&acc) */
+ p->n = acc.nChar;
}
}
@@ -79257,10 +83332,12 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
** This routine is for use inside of assert() statements only.
*/
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMemValidStrRep(Mem *p){
+ Mem tmp;
char zBuf[100];
char *z;
int i, j, incr;
if( (p->flags & MEM_Str)==0 ) return 1;
+ if( p->db && p->db->mallocFailed ) return 1;
if( p->flags & MEM_Term ){
/* Insure that the string is properly zero-terminated. Pay particular
** attention to the case where p->n is odd */
@@ -79273,7 +83350,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMemValidStrRep(Mem *p){
assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 );
}
if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1;
- vdbeMemRenderNum(sizeof(zBuf), zBuf, p);
+ memcpy(&tmp, p, sizeof(tmp));
+ vdbeMemRenderNum(sizeof(zBuf), zBuf, &tmp);
z = p->z;
i = j = 0;
incr = 1;
@@ -79417,6 +83495,40 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
}
/*
+** If pMem is already a string, detect if it is a zero-terminated
+** string, or make it into one if possible, and mark it as such.
+**
+** This is an optimization. Correct operation continues even if
+** this routine is a no-op.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){
+ if( (pMem->flags & (MEM_Str|MEM_Term|MEM_Ephem|MEM_Static))!=MEM_Str ){
+ /* pMem must be a string, and it cannot be an ephemeral or static string */
+ return;
+ }
+ if( pMem->enc!=SQLITE_UTF8 ) return;
+ if( NEVER(pMem->z==0) ) return;
+ if( pMem->flags & MEM_Dyn ){
+ if( pMem->xDel==sqlcipher_sqlite3_free
+ && sqlcipher_sqlite3_msize(pMem->z) >= (u64)(pMem->n+1)
+ ){
+ pMem->z[pMem->n] = 0;
+ pMem->flags |= MEM_Term;
+ return;
+ }
+ if( pMem->xDel==sqlcipher_sqlite3RCStrUnref ){
+ /* Blindly assume that all RCStr objects are zero-terminated */
+ pMem->flags |= MEM_Term;
+ return;
+ }
+ }else if( pMem->szMalloc >= pMem->n+1 ){
+ pMem->z[pMem->n] = 0;
+ pMem->flags |= MEM_Term;
+ return;
+ }
+}
+
+/*
** It is already known that pMem contains an unterminated string.
** Add the zero terminator.
**
@@ -79542,7 +83654,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForc
vdbeMemRenderNum(nByte, pMem->z, pMem);
assert( pMem->z!=0 );
- pMem->n = sqlcipher_sqlite3Strlen30NN(pMem->z);
+ assert( pMem->n==(int)sqlcipher_sqlite3Strlen30NN(pMem->z) );
pMem->enc = SQLITE_UTF8;
pMem->flags |= MEM_Str|MEM_Term;
if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
@@ -79678,36 +83790,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeMemReleaseMalloc(Mem *p){
}
/*
-** Convert a 64-bit IEEE double into a 64-bit signed integer.
-** If the double is out of range of a 64-bit signed integer then
-** return the closest available 64-bit signed integer.
-*/
-static SQLITE_NOINLINE i64 doubleToInt64(double r){
-#ifdef SQLITE_OMIT_FLOATING_POINT
- /* When floating-point is omitted, double and int64 are the same thing */
- return r;
-#else
- /*
- ** Many compilers we encounter do not define constants for the
- ** minimum and maximum 64-bit integers, or they define them
- ** inconsistently. And many do not understand the "LL" notation.
- ** So we define our own static constants here using nothing
- ** larger than a 32-bit integer constant.
- */
- static const i64 maxInt = LARGEST_INT64;
- static const i64 minInt = SMALLEST_INT64;
-
- if( r<=(double)minInt ){
- return minInt;
- }else if( r>=(double)maxInt ){
- return maxInt;
- }else{
- return (i64)r;
- }
-#endif
-}
-
-/*
** Return some kind of integer value which is the best we can do
** at representing the value that *pMem describes as an integer.
** If pMem is an integer, then the value is exact. If pMem is
@@ -79733,7 +83815,7 @@ SQLITE_PRIVATE i64 sqlcipher_sqlite3VdbeIntValue(const Mem *pMem){
testcase( flags & MEM_IntReal );
return pMem->u.i;
}else if( flags & MEM_Real ){
- return doubleToInt64(pMem->u.r);
+ return sqlcipher_sqlite3RealToI64(pMem->u.r);
}else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){
return memIntValue(pMem);
}else{
@@ -79782,32 +83864,35 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){
}
/*
-** The MEM structure is already a MEM_Real. Try to also make it a
-** MEM_Int if we can.
+** The MEM structure is already a MEM_Real or MEM_IntReal. Try to
+** make it a MEM_Int if we can.
*/
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeIntegerAffinity(Mem *pMem){
- i64 ix;
assert( pMem!=0 );
- assert( pMem->flags & MEM_Real );
+ assert( pMem->flags & (MEM_Real|MEM_IntReal) );
assert( !sqlcipher_sqlite3VdbeMemIsRowSet(pMem) );
assert( pMem->db==0 || sqlcipher_sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
- ix = doubleToInt64(pMem->u.r);
-
- /* Only mark the value as an integer if
- **
- ** (1) the round-trip conversion real->int->real is a no-op, and
- ** (2) The integer is neither the largest nor the smallest
- ** possible integer (ticket #3922)
- **
- ** The second and third terms in the following conditional enforces
- ** the second condition under the assumption that addition overflow causes
- ** values to wrap around.
- */
- if( pMem->u.r==ix && ix>SMALLEST_INT64 && ix<LARGEST_INT64 ){
- pMem->u.i = ix;
+ if( pMem->flags & MEM_IntReal ){
MemSetTypeFlag(pMem, MEM_Int);
+ }else{
+ i64 ix = sqlcipher_sqlite3RealToI64(pMem->u.r);
+
+ /* Only mark the value as an integer if
+ **
+ ** (1) the round-trip conversion real->int->real is a no-op, and
+ ** (2) The integer is neither the largest nor the smallest
+ ** possible integer (ticket #3922)
+ **
+ ** The second and third terms in the following conditional enforces
+ ** the second condition under the assumption that addition overflow causes
+ ** values to wrap around.
+ */
+ if( pMem->u.r==ix && ix>SMALLEST_INT64 && ix<LARGEST_INT64 ){
+ pMem->u.i = ix;
+ MemSetTypeFlag(pMem, MEM_Int);
+ }
}
}
@@ -79855,6 +83940,16 @@ SQLITE_PRIVATE int sqlcipher_sqlite3RealSameAsInt(double r1, sqlcipher_sqlite3_i
&& i >= -2251799813685248LL && i < 2251799813685248LL);
}
+/* Convert a floating point value to its closest integer. Do so in
+** a way that avoids 'outside the range of representable values' warnings
+** from UBSAN.
+*/
+SQLITE_PRIVATE i64 sqlcipher_sqlite3RealToI64(double r){
+ if( r<-9223372036854774784.0 ) return SMALLEST_INT64;
+ if( r>+9223372036854774784.0 ) return LARGEST_INT64;
+ return (i64)r;
+}
+
/*
** Convert pMem so that it has type MEM_Real or MEM_Int.
** Invalidate any prior representations.
@@ -79876,7 +83971,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMemNumerify(Mem *pMem){
assert( pMem->db==0 || sqlcipher_sqlite3_mutex_held(pMem->db->mutex) );
rc = sqlcipher_sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
if( ((rc==0 || rc==1) && sqlcipher_sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
- || sqlcipher_sqlite3RealSameAsInt(pMem->u.r, (ix = (i64)pMem->u.r))
+ || sqlcipher_sqlite3RealSameAsInt(pMem->u.r, (ix = sqlcipher_sqlite3RealToI64(pMem->u.r)))
){
pMem->u.i = ix;
MemSetTypeFlag(pMem, MEM_Int);
@@ -79922,13 +84017,17 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
break;
}
default: {
+ int rc;
assert( aff==SQLITE_AFF_TEXT );
assert( MEM_Str==(MEM_Blob>>3) );
pMem->flags |= (pMem->flags&MEM_Blob)>>3;
sqlcipher_sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
- return sqlcipher_sqlite3VdbeChangeEncoding(pMem, encoding);
+ if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1;
+ rc = sqlcipher_sqlite3VdbeChangeEncoding(pMem, encoding);
+ if( rc ) return rc;
+ sqlcipher_sqlite3VdbeMemZeroTerminateIfAble(pMem);
}
}
return SQLITE_OK;
@@ -80024,6 +84123,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
}
}
+/*
+** Set the iIdx'th entry of array aMem[] to contain integer value val.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3MemSetArrayInt64(sqlcipher_sqlite3_value *aMem, int iIdx, i64 val){
+ sqlcipher_sqlite3VdbeMemSetInt64(&aMem[iIdx], val);
+}
+
/* A no-op destructor */
SQLITE_PRIVATE void sqlcipher_sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
@@ -80452,6 +84558,24 @@ SQLITE_PRIVATE const void *sqlcipher_sqlite3ValueText(sqlcipher_sqlite3_value* p
return valueToText(pVal, enc);
}
+/* Return true if sqlit3_value object pVal is a string or blob value
+** that uses the destructor specified in the second argument.
+**
+** TODO: Maybe someday promote this interface into a published API so
+** that third-party extensions can get access to it?
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3ValueIsOfClass(const sqlcipher_sqlite3_value *pVal, void(*xFree)(void*)){
+ if( ALWAYS(pVal!=0)
+ && ALWAYS((pVal->flags & (MEM_Str|MEM_Blob))!=0)
+ && (pVal->flags & MEM_Dyn)!=0
+ && pVal->xDel==xFree
+ ){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
/*
** Create a new sqlcipher_sqlite3_value object.
*/
@@ -80519,6 +84643,7 @@ static sqlcipher_sqlite3_value *valueNew(sqlcipher_sqlite3 *db, struct ValueNewS
}
pRec->nField = p->iVal+1;
+ sqlcipher_sqlite3VdbeMemSetNull(&pRec->aMem[p->iVal]);
return &pRec->aMem[p->iVal];
}
#else
@@ -80572,9 +84697,12 @@ static int valueFromFunction(
if( pList ) nVal = pList->nExpr;
assert( !ExprHasProperty(p, EP_IntValue) );
pFunc = sqlcipher_sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ if( pFunc==0 ) return SQLITE_OK;
+#endif
assert( pFunc );
if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
- || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
+ || (pFunc->funcFlags & (SQLITE_FUNC_NEEDCOLL|SQLITE_FUNC_RUNONLY))!=0
){
return SQLITE_OK;
}
@@ -80597,8 +84725,6 @@ static int valueFromFunction(
goto value_from_function_out;
}
- testcase( pCtx->pParse->rc==SQLITE_ERROR );
- testcase( pCtx->pParse->rc==SQLITE_OK );
memset(&ctx, 0, sizeof(ctx));
ctx.pOut = pVal;
ctx.pFunc = pFunc;
@@ -80611,16 +84737,16 @@ static int valueFromFunction(
sqlcipher_sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
assert( rc==SQLITE_OK );
rc = sqlcipher_sqlite3VdbeChangeEncoding(pVal, enc);
- if( rc==SQLITE_OK && sqlcipher_sqlite3VdbeMemTooBig(pVal) ){
+ if( NEVER(rc==SQLITE_OK && sqlcipher_sqlite3VdbeMemTooBig(pVal)) ){
rc = SQLITE_TOOBIG;
pCtx->pParse->nErr++;
}
}
- pCtx->pParse->rc = rc;
value_from_function_out:
if( rc!=SQLITE_OK ){
pVal = 0;
+ pCtx->pParse->rc = rc;
}
if( apVal ){
for(i=0; i<nVal; i++){
@@ -80678,6 +84804,13 @@ static int valueFromExpr(
rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
testcase( rc!=SQLITE_OK );
if( *ppVal ){
+#ifdef SQLITE_ENABLE_STAT4
+ rc = ExpandBlob(*ppVal);
+#else
+ /* zero-blobs only come from functions, not literal values. And
+ ** functions are only processed under STAT4 */
+ assert( (ppVal[0][0].flags & MEM_Zero)==0 );
+#endif
sqlcipher_sqlite3VdbeMemCast(*ppVal, aff, enc);
sqlcipher_sqlite3ValueApplyAffinity(*ppVal, affinity, enc);
}
@@ -80685,14 +84818,20 @@ static int valueFromExpr(
}
/* Handle negative integers in a single step. This is needed in the
- ** case when the value is -9223372036854775808.
- */
- if( op==TK_UMINUS
- && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){
- pExpr = pExpr->pLeft;
- op = pExpr->op;
- negInt = -1;
- zNeg = "-";
+ ** case when the value is -9223372036854775808. Except - do not do this
+ ** for hexadecimal literals. */
+ if( op==TK_UMINUS ){
+ Expr *pLeft = pExpr->pLeft;
+ if( (pLeft->op==TK_INTEGER || pLeft->op==TK_FLOAT) ){
+ if( ExprHasProperty(pLeft, EP_IntValue)
+ || pLeft->u.zToken[0]!='0' || (pLeft->u.zToken[1] & ~0x20)!='X'
+ ){
+ pExpr = pLeft;
+ op = pExpr->op;
+ negInt = -1;
+ zNeg = "-";
+ }
+ }
}
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
@@ -80701,12 +84840,26 @@ static int valueFromExpr(
if( ExprHasProperty(pExpr, EP_IntValue) ){
sqlcipher_sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt);
}else{
- zVal = sqlcipher_sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
- if( zVal==0 ) goto no_mem;
- sqlcipher_sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
+ i64 iVal;
+ if( op==TK_INTEGER && 0==sqlcipher_sqlite3DecOrHexToI64(pExpr->u.zToken, &iVal) ){
+ sqlcipher_sqlite3VdbeMemSetInt64(pVal, iVal*negInt);
+ }else{
+ zVal = sqlcipher_sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
+ if( zVal==0 ) goto no_mem;
+ sqlcipher_sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
+ }
}
- if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_BLOB ){
- sqlcipher_sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
+ if( affinity==SQLITE_AFF_BLOB ){
+ if( op==TK_FLOAT ){
+ assert( pVal && pVal->z && pVal->flags==(MEM_Str|MEM_Term) );
+ sqlcipher_sqlite3AtoF(pVal->z, &pVal->u.r, pVal->n, SQLITE_UTF8);
+ pVal->flags = MEM_Real;
+ }else if( op==TK_INTEGER ){
+ /* This case is required by -9223372036854775808 and other strings
+ ** that look like integers but cannot be handled by the
+ ** sqlcipher_sqlite3DecOrHexToI64() call above. */
+ sqlcipher_sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
+ }
}else{
sqlcipher_sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
}
@@ -80770,6 +84923,7 @@ static int valueFromExpr(
if( pVal ){
pVal->flags = MEM_Int;
pVal->u.i = pExpr->u.zToken[4]==0;
+ sqlcipher_sqlite3ValueApplyAffinity(pVal, affinity, enc);
}
}
@@ -80975,17 +85129,17 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Stat4Column(
sqlcipher_sqlite3_value **ppVal /* OUT: Extracted value */
){
u32 t = 0; /* a column type code */
- int nHdr; /* Size of the header in the record */
- int iHdr; /* Next unread header byte */
- int iField; /* Next unread data byte */
- int szField = 0; /* Size of the current data field */
+ u32 nHdr; /* Size of the header in the record */
+ u32 iHdr; /* Next unread header byte */
+ i64 iField; /* Next unread data byte */
+ u32 szField = 0; /* Size of the current data field */
int i; /* Column index */
u8 *a = (u8*)pRec; /* Typecast byte array */
Mem *pMem = *ppVal; /* Write result into this Mem object */
assert( iCol>0 );
iHdr = getVarint32(a, nHdr);
- if( nHdr>nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT;
+ if( nHdr>(u32)nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT;
iField = nHdr;
for(i=0; i<=iCol; i++){
iHdr += getVarint32(&a[iHdr], t);
@@ -81063,6 +85217,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ValueBytes(sqlcipher_sqlite3_value *pVal, u8
if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){
return p->n;
}
+ if( (p->flags & MEM_Str)!=0 && enc!=SQLITE_UTF8 && pVal->enc!=SQLITE_UTF8 ){
+ return p->n;
+ }
if( (p->flags & MEM_Blob)!=0 ){
if( p->flags & MEM_Zero ){
return p->n + p->u.nZero;
@@ -81108,10 +85265,10 @@ SQLITE_PRIVATE Vdbe *sqlcipher_sqlite3VdbeCreate(Parse *pParse){
memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp));
p->db = db;
if( db->pVdbe ){
- db->pVdbe->pPrev = p;
+ db->pVdbe->ppVPrev = &p->pVNext;
}
- p->pNext = db->pVdbe;
- p->pPrev = 0;
+ p->pVNext = db->pVdbe;
+ p->ppVPrev = &db->pVdbe;
db->pVdbe = p;
assert( p->eVdbeState==VDBE_INIT_STATE );
p->pParse = pParse;
@@ -81193,21 +85350,28 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeUsesDoubleQuotedString(
#endif
/*
-** Swap all content between two VDBE structures.
+** Swap byte-code between two VDBE structures.
+**
+** This happens after pB was previously run and returned
+** SQLITE_SCHEMA. The statement was then reprepared in pA.
+** This routine transfers the new bytecode in pA over to pB
+** so that pB can be run again. The old pB byte code is
+** moved back to pA so that it will be cleaned up when pA is
+** finalized.
*/
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
- Vdbe tmp, *pTmp;
+ Vdbe tmp, *pTmp, **ppTmp;
char *zTmp;
assert( pA->db==pB->db );
tmp = *pA;
*pA = *pB;
*pB = tmp;
- pTmp = pA->pNext;
- pA->pNext = pB->pNext;
- pB->pNext = pTmp;
- pTmp = pA->pPrev;
- pA->pPrev = pB->pPrev;
- pB->pPrev = pTmp;
+ pTmp = pA->pVNext;
+ pA->pVNext = pB->pVNext;
+ pB->pVNext = pTmp;
+ ppTmp = pA->ppVPrev;
+ pA->ppVPrev = pB->ppVPrev;
+ pB->ppVPrev = ppTmp;
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
@@ -81282,12 +85446,44 @@ static int growOpArray(Vdbe *v, int nOp){
** sqlcipher_sqlite3CantopenError(lineno)
*/
static void test_addop_breakpoint(int pc, Op *pOp){
- static int n = 0;
+ static u64 n = 0;
+ (void)pc;
+ (void)pOp;
n++;
+ if( n==LARGEST_UINT64 ) abort(); /* so that n is used, preventing a warning */
}
#endif
/*
+** Slow paths for sqlcipher_sqlite3VdbeAddOp3() and sqlcipher_sqlite3VdbeAddOp4Int() for the
+** unusual case when we need to increase the size of the Vdbe.aOp[] array
+** before adding the new opcode.
+*/
+static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
+ assert( p->nOpAlloc<=p->nOp );
+ if( growOpArray(p, 1) ) return 1;
+ assert( p->nOpAlloc>p->nOp );
+ return sqlcipher_sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+}
+static SQLITE_NOINLINE int addOp4IntSlow(
+ Vdbe *p, /* Add the opcode to this VM */
+ int op, /* The new opcode */
+ int p1, /* The P1 operand */
+ int p2, /* The P2 operand */
+ int p3, /* The P3 operand */
+ int p4 /* The P4 operand as an integer */
+){
+ int addr = sqlcipher_sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+ if( p->db->mallocFailed==0 ){
+ VdbeOp *pOp = &p->aOp[addr];
+ pOp->p4type = P4_INT32;
+ pOp->p4.i = p4;
+ }
+ return addr;
+}
+
+
+/*
** Add a new instruction to the list of instructions current in the
** VDBE. Return the address of the new instruction.
**
@@ -81297,17 +85493,16 @@ static void test_addop_breakpoint(int pc, Op *pOp){
**
** op The opcode for this instruction
**
-** p1, p2, p3 Operands
-**
-** Use the sqlcipher_sqlite3VdbeResolveLabel() function to fix an address and
-** the sqlcipher_sqlite3VdbeChangeP4() function to change the value of the P4
-** operand.
+** p1, p2, p3, p4 Operands
*/
-static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
- assert( p->nOpAlloc<=p->nOp );
- if( growOpArray(p, 1) ) return 1;
- assert( p->nOpAlloc>p->nOp );
- return sqlcipher_sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+SQLITE_PRIVATE int sqlcipher_sqlite3VdbeAddOp0(Vdbe *p, int op){
+ return sqlcipher_sqlite3VdbeAddOp3(p, op, 0, 0, 0);
+}
+SQLITE_PRIVATE int sqlcipher_sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){
+ return sqlcipher_sqlite3VdbeAddOp3(p, op, p1, 0, 0);
+}
+SQLITE_PRIVATE int sqlcipher_sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
+ return sqlcipher_sqlite3VdbeAddOp3(p, op, p1, p2, 0);
}
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
int i;
@@ -81330,32 +85525,78 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2,
pOp->p3 = p3;
pOp->p4.p = 0;
pOp->p4type = P4_NOTUSED;
+
+ /* Replicate this logic in sqlcipher_sqlite3VdbeAddOp4Int()
+ ** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
pOp->zComment = 0;
#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+ pOp->nExec = 0;
+ pOp->nCycle = 0;
+#endif
#ifdef SQLITE_DEBUG
if( p->db->flags & SQLITE_VdbeAddopTrace ){
sqlcipher_sqlite3VdbePrintOp(0, i, &p->aOp[i]);
test_addop_breakpoint(i, &p->aOp[i]);
}
#endif
-#ifdef VDBE_PROFILE
- pOp->cycles = 0;
- pOp->cnt = 0;
-#endif
#ifdef SQLITE_VDBE_COVERAGE
pOp->iSrcLine = 0;
#endif
+ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ** Replicate in sqlcipher_sqlite3VdbeAddOp4Int() */
+
return i;
}
-SQLITE_PRIVATE int sqlcipher_sqlite3VdbeAddOp0(Vdbe *p, int op){
- return sqlcipher_sqlite3VdbeAddOp3(p, op, 0, 0, 0);
-}
-SQLITE_PRIVATE int sqlcipher_sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){
- return sqlcipher_sqlite3VdbeAddOp3(p, op, p1, 0, 0);
-}
-SQLITE_PRIVATE int sqlcipher_sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
- return sqlcipher_sqlite3VdbeAddOp3(p, op, p1, p2, 0);
+SQLITE_PRIVATE int sqlcipher_sqlite3VdbeAddOp4Int(
+ Vdbe *p, /* Add the opcode to this VM */
+ int op, /* The new opcode */
+ int p1, /* The P1 operand */
+ int p2, /* The P2 operand */
+ int p3, /* The P3 operand */
+ int p4 /* The P4 operand as an integer */
+){
+ int i;
+ VdbeOp *pOp;
+
+ i = p->nOp;
+ if( p->nOpAlloc<=i ){
+ return addOp4IntSlow(p, op, p1, p2, p3, p4);
+ }
+ p->nOp++;
+ pOp = &p->aOp[i];
+ assert( pOp!=0 );
+ pOp->opcode = (u8)op;
+ pOp->p5 = 0;
+ pOp->p1 = p1;
+ pOp->p2 = p2;
+ pOp->p3 = p3;
+ pOp->p4.i = p4;
+ pOp->p4type = P4_INT32;
+
+ /* Replicate this logic in sqlcipher_sqlite3VdbeAddOp3()
+ ** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ pOp->zComment = 0;
+#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+ pOp->nExec = 0;
+ pOp->nCycle = 0;
+#endif
+#ifdef SQLITE_DEBUG
+ if( p->db->flags & SQLITE_VdbeAddopTrace ){
+ sqlcipher_sqlite3VdbePrintOp(0, i, &p->aOp[i]);
+ test_addop_breakpoint(i, &p->aOp[i]);
+ }
+#endif
+#ifdef SQLITE_VDBE_COVERAGE
+ pOp->iSrcLine = 0;
+#endif
+ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ** Replicate in sqlcipher_sqlite3VdbeAddOp3() */
+
+ return i;
}
/* Generate code for an unconditional jump to instruction iDest
@@ -81510,11 +85751,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExplainBreakpoint(const char *z1, const cha
** If the bPush flag is true, then make this opcode the parent for
** subsequent Explains until sqlcipher_sqlite3VdbeExplainPop() is called.
*/
-SQLITE_PRIVATE void sqlcipher_sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
-#ifndef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlcipher_sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
+ int addr = 0;
+#if !defined(SQLITE_DEBUG)
/* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined.
** But omit them (for performance) during production builds */
- if( pParse->explain==2 )
+ if( pParse->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
#endif
{
char *zMsg;
@@ -81526,13 +85768,15 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeExplain(Parse *pParse, u8 bPush, const
va_end(ap);
v = pParse->pVdbe;
iThis = v->nOp;
- sqlcipher_sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0,
+ addr = sqlcipher_sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0,
zMsg, P4_DYNAMIC);
- sqlcipher_sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlcipher_sqlite3VdbeGetOp(v,-1)->p4.z);
+ sqlcipher_sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlcipher_sqlite3VdbeGetLastOp(v)->p4.z);
if( bPush){
pParse->addrExplain = iThis;
}
+ sqlcipher_sqlite3VdbeScanStatus(v, iThis, -1, -1, 0, 0);
}
+ return addr;
}
/*
@@ -81560,26 +85804,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char
sqlcipher_sqlite3MayAbort(p->pParse);
}
-/*
-** Add an opcode that includes the p4 value as an integer.
-*/
-SQLITE_PRIVATE int sqlcipher_sqlite3VdbeAddOp4Int(
- Vdbe *p, /* Add the opcode to this VM */
- int op, /* The new opcode */
- int p1, /* The P1 operand */
- int p2, /* The P2 operand */
- int p3, /* The P3 operand */
- int p4 /* The P4 operand as an integer */
-){
- int addr = sqlcipher_sqlite3VdbeAddOp3(p, op, p1, p2, p3);
- if( p->db->mallocFailed==0 ){
- VdbeOp *pOp = &p->aOp[addr];
- pOp->p4type = P4_INT32;
- pOp->p4.i = p4;
- }
- return addr;
-}
-
/* Insert the end of a co-routine
*/
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){
@@ -81640,6 +85864,9 @@ static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){
int i;
for(i=p->nLabelAlloc; i<nNewSize; i++) p->aLabel[i] = -1;
#endif
+ if( nNewSize>=100 && (nNewSize/100)>(p->nLabelAlloc/100) ){
+ sqlcipher_sqlite3ProgressCheck(p);
+ }
p->nLabelAlloc = nNewSize;
p->aLabel[j] = v->nOp;
}
@@ -81883,11 +86110,13 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
Op *pOp;
Parse *pParse = p->pParse;
int *aLabel = pParse->aLabel;
+
+ assert( pParse->db->mallocFailed==0 ); /* tag-20230419-1 */
p->readOnly = 1;
p->bIsReader = 0;
pOp = &p->aOp[p->nOp-1];
- while(1){
-
+ assert( p->aOp[0].opcode==OP_Init );
+ while( 1 /* Loop terminates when it reaches the OP_Init opcode */ ){
/* Only JUMP opcodes and the short list of special opcodes in the switch
** below need to be considered. The mkopcodeh.tcl generator script groups
** all these opcodes together near the front of the opcode list. Skip
@@ -81916,6 +86145,10 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
p->bIsReader = 1;
break;
}
+ case OP_Init: {
+ assert( pOp->p2>=0 );
+ goto resolve_p2_values_loop_exit;
+ }
#ifndef SQLITE_OMIT_VIRTUALTABLE
case OP_VUpdate: {
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
@@ -81938,8 +86171,18 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
** have non-negative values for P2. */
assert( (sqlcipher_sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
assert( ADDR(pOp->p2)<-pParse->nLabel );
+ assert( aLabel!=0 ); /* True because of tag-20230419-1 */
pOp->p2 = aLabel[ADDR(pOp->p2)];
}
+
+ /* OPFLG_JUMP opcodes never have P2==0, though OPFLG_JUMP0 opcodes
+ ** might */
+ assert( pOp->p2>0
+ || (sqlcipher_sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP0)!=0 );
+
+ /* Jumps never go off the end of the bytecode array */
+ assert( pOp->p2<p->nOp
+ || (sqlcipher_sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)==0 );
break;
}
}
@@ -81948,11 +86191,12 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
** have non-negative values for P2. */
assert( (sqlcipher_sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
}
- if( pOp==p->aOp ) break;
+ assert( pOp>p->aOp );
pOp--;
}
+resolve_p2_values_loop_exit:
if( aLabel ){
- sqlcipher_sqlite3DbFreeNN(p->db, pParse->aLabel);
+ sqlcipher_sqlite3DbNNFreeNN(p->db, pParse->aLabel);
pParse->aLabel = 0;
}
pParse->nLabel = 0;
@@ -82003,6 +86247,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeNoJumpsOutsideSubrtn(
int iDest = pOp->p2; /* Jump destination */
if( iDest==0 ) continue;
if( pOp->opcode==OP_Gosub ) continue;
+ if( pOp->p3==20230325 && pOp->opcode==OP_NotNull ){
+ /* This is a deliberately taken illegal branch. tag-20230325-2 */
+ continue;
+ }
if( iDest<0 ){
int j = ADDR(iDest);
assert( j>=0 );
@@ -82180,20 +86428,83 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeScanStatus(
LogEst nEst, /* Estimated number of output rows */
const char *zName /* Name of table or index being scanned */
){
- sqlcipher_sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus);
- ScanStatus *aNew;
- aNew = (ScanStatus*)sqlcipher_sqlite3DbRealloc(p->db, p->aScan, nByte);
- if( aNew ){
- ScanStatus *pNew = &aNew[p->nScan++];
- pNew->addrExplain = addrExplain;
- pNew->addrLoop = addrLoop;
- pNew->addrVisit = addrVisit;
- pNew->nEst = nEst;
- pNew->zName = sqlcipher_sqlite3DbStrDup(p->db, zName);
- p->aScan = aNew;
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ sqlcipher_sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus);
+ ScanStatus *aNew;
+ aNew = (ScanStatus*)sqlcipher_sqlite3DbRealloc(p->db, p->aScan, nByte);
+ if( aNew ){
+ ScanStatus *pNew = &aNew[p->nScan++];
+ memset(pNew, 0, sizeof(ScanStatus));
+ pNew->addrExplain = addrExplain;
+ pNew->addrLoop = addrLoop;
+ pNew->addrVisit = addrVisit;
+ pNew->nEst = nEst;
+ pNew->zName = sqlcipher_sqlite3DbStrDup(p->db, zName);
+ p->aScan = aNew;
+ }
}
}
-#endif
+
+/*
+** Add the range of instructions from addrStart to addrEnd (inclusive) to
+** the set of those corresponding to the sqlcipher_sqlite3_stmt_scanstatus() counters
+** associated with the OP_Explain instruction at addrExplain. The
+** sum of the sqlcipher_sqlite3Hwtime() values for each of these instructions
+** will be returned for SQLITE_SCANSTAT_NCYCLE requests.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3VdbeScanStatusRange(
+ Vdbe *p,
+ int addrExplain,
+ int addrStart,
+ int addrEnd
+){
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ ScanStatus *pScan = 0;
+ int ii;
+ for(ii=p->nScan-1; ii>=0; ii--){
+ pScan = &p->aScan[ii];
+ if( pScan->addrExplain==addrExplain ) break;
+ pScan = 0;
+ }
+ if( pScan ){
+ if( addrEnd<0 ) addrEnd = sqlcipher_sqlite3VdbeCurrentAddr(p)-1;
+ for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
+ if( pScan->aAddrRange[ii]==0 ){
+ pScan->aAddrRange[ii] = addrStart;
+ pScan->aAddrRange[ii+1] = addrEnd;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*
+** Set the addresses for the SQLITE_SCANSTAT_NLOOP and SQLITE_SCANSTAT_NROW
+** counters for the query element associated with the OP_Explain at
+** addrExplain.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3VdbeScanStatusCounters(
+ Vdbe *p,
+ int addrExplain,
+ int addrLoop,
+ int addrVisit
+){
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ ScanStatus *pScan = 0;
+ int ii;
+ for(ii=p->nScan-1; ii>=0; ii--){
+ pScan = &p->aScan[ii];
+ if( pScan->addrExplain==addrExplain ) break;
+ pScan = 0;
+ }
+ if( pScan ){
+ if( addrLoop>0 ) pScan->addrLoop = addrLoop;
+ if( addrVisit>0 ) pScan->addrVisit = addrVisit;
+ }
+ }
+}
+#endif /* defined(SQLITE_ENABLE_STMT_SCANSTATUS) */
/*
@@ -82201,15 +86512,19 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeScanStatus(
** for a specific instruction.
*/
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeChangeOpcode(Vdbe *p, int addr, u8 iNewOpcode){
+ assert( addr>=0 );
sqlcipher_sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode;
}
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
+ assert( addr>=0 );
sqlcipher_sqlite3VdbeGetOp(p,addr)->p1 = val;
}
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
+ assert( addr>=0 || p->db->mallocFailed );
sqlcipher_sqlite3VdbeGetOp(p,addr)->p2 = val;
}
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
+ assert( addr>=0 );
sqlcipher_sqlite3VdbeGetOp(p,addr)->p3 = val;
}
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
@@ -82218,6 +86533,18 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
}
/*
+** If the previous opcode is an OP_Column that delivers results
+** into register iDest, then add the OPFLAG_TYPEOFARG flag to that
+** opcode.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){
+ VdbeOp *pOp = sqlcipher_sqlite3VdbeGetLastOp(p);
+ if( pOp->p3==iDest && pOp->opcode==OP_Column ){
+ pOp->p5 |= OPFLAG_TYPEOFARG;
+ }
+}
+
+/*
** Change the P2 operand of instruction addr so that it points to
** the address of the next instruction to be coded.
*/
@@ -82245,7 +86572,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
|| p->aOp[addr].opcode==OP_FkIfZero );
assert( p->aOp[addr].p4type==0 );
#ifdef SQLITE_VDBE_COVERAGE
- sqlcipher_sqlite3VdbeGetOp(p,-1)->iSrcLine = 0; /* Erase VdbeCoverage() macros */
+ sqlcipher_sqlite3VdbeGetLastOp(p)->iSrcLine = 0; /* Erase VdbeCoverage() macros */
#endif
p->nOp--;
}else{
@@ -82256,11 +86583,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
/*
** If the input FuncDef structure is ephemeral, then free it. If
-** the FuncDef is not ephermal, then do nothing.
+** the FuncDef is not ephemeral, then do nothing.
*/
static void freeEphemeralFunction(sqlcipher_sqlite3 *db, FuncDef *pDef){
+ assert( db!=0 );
if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
- sqlcipher_sqlite3DbFreeNN(db, pDef);
+ sqlcipher_sqlite3DbNNFreeNN(db, pDef);
}
}
@@ -82269,11 +86597,12 @@ static void freeEphemeralFunction(sqlcipher_sqlite3 *db, FuncDef *pDef){
*/
static SQLITE_NOINLINE void freeP4Mem(sqlcipher_sqlite3 *db, Mem *p){
if( p->szMalloc ) sqlcipher_sqlite3DbFree(db, p->zMalloc);
- sqlcipher_sqlite3DbFreeNN(db, p);
+ sqlcipher_sqlite3DbNNFreeNN(db, p);
}
static SQLITE_NOINLINE void freeP4FuncCtx(sqlcipher_sqlite3 *db, sqlcipher_sqlite3_context *p){
+ assert( db!=0 );
freeEphemeralFunction(db, p->pFunc);
- sqlcipher_sqlite3DbFreeNN(db, p);
+ sqlcipher_sqlite3DbNNFreeNN(db, p);
}
static void freeP4(sqlcipher_sqlite3 *db, int p4type, void *p4){
assert( db );
@@ -82286,7 +86615,7 @@ static void freeP4(sqlcipher_sqlite3 *db, int p4type, void *p4){
case P4_INT64:
case P4_DYNAMIC:
case P4_INTARRAY: {
- sqlcipher_sqlite3DbFree(db, p4);
+ if( p4 ) sqlcipher_sqlite3DbNNFreeNN(db, p4);
break;
}
case P4_KEYINFO: {
@@ -82315,6 +86644,10 @@ static void freeP4(sqlcipher_sqlite3 *db, int p4type, void *p4){
if( db->pnBytesFreed==0 ) sqlcipher_sqlite3VtabUnlock((VTable *)p4);
break;
}
+ case P4_TABLEREF: {
+ if( db->pnBytesFreed==0 ) sqlcipher_sqlite3DeleteTable(db, (Table*)p4);
+ break;
+ }
}
}
@@ -82325,6 +86658,7 @@ static void freeP4(sqlcipher_sqlite3 *db, int p4type, void *p4){
*/
static void vdbeFreeOpArray(sqlcipher_sqlite3 *db, Op *aOp, int nOp){
assert( nOp>=0 );
+ assert( db!=0 );
if( aOp ){
Op *pOp = &aOp[nOp-1];
while(1){ /* Exit via break */
@@ -82335,7 +86669,7 @@ static void vdbeFreeOpArray(sqlcipher_sqlite3 *db, Op *aOp, int nOp){
if( pOp==aOp ) break;
pOp--;
}
- sqlcipher_sqlite3DbFreeNN(db, aOp);
+ sqlcipher_sqlite3DbNNFreeNN(db, aOp);
}
}
@@ -82417,7 +86751,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeReleaseRegisters(
}
#endif /* SQLITE_DEBUG */
-
/*
** Change the value of the P4 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
@@ -82442,7 +86775,7 @@ static void SQLITE_NOINLINE vdbeChangeP4Full(
int n
){
if( pOp->p4type ){
- freeP4(p->db, pOp->p4type, pOp->p4.p);
+ assert( pOp->p4type > P4_FREE_IF_LE );
pOp->p4type = 0;
pOp->p4.p = 0;
}
@@ -82504,7 +86837,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){
if( p->db->mallocFailed ){
freeP4(p->db, n, pP4);
}else{
- assert( pP4!=0 );
+ assert( pP4!=0 || n==P4_DYNAMIC );
assert( p->nOp>0 );
pOp = &p->aOp[p->nOp-1];
assert( pOp->p4type==P4_NOTUSED );
@@ -82566,13 +86899,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeNoopComment(Vdbe *p, const char *zForma
** Set the value if the iSrcLine field for the previously coded instruction.
*/
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){
- sqlcipher_sqlite3VdbeGetOp(v,-1)->iSrcLine = iLine;
+ sqlcipher_sqlite3VdbeGetLastOp(v)->iSrcLine = iLine;
}
#endif /* SQLITE_VDBE_COVERAGE */
/*
-** Return the opcode for a given address. If the address is -1, then
-** return the most recently inserted opcode.
+** Return the opcode for a given address. The address must be non-negative.
+** See sqlcipher_sqlite3VdbeGetLastOp() to get the most recently added opcode.
**
** If a memory allocation error has occurred prior to the calling of this
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
@@ -82588,9 +86921,6 @@ SQLITE_PRIVATE VdbeOp *sqlcipher_sqlite3VdbeGetOp(Vdbe *p, int addr){
** zeros, which is correct. MSVC generates a warning, nevertheless. */
static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
assert( p->eVdbeState==VDBE_INIT_STATE );
- if( addr<0 ){
- addr = p->nOp - 1;
- }
assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
if( p->db->mallocFailed ){
return (VdbeOp*)&dummy;
@@ -82599,6 +86929,12 @@ SQLITE_PRIVATE VdbeOp *sqlcipher_sqlite3VdbeGetOp(Vdbe *p, int addr){
}
}
+/* Return the most recently added opcode
+*/
+SQLITE_PRIVATE VdbeOp *sqlcipher_sqlite3VdbeGetLastOp(Vdbe *p){
+ return sqlcipher_sqlite3VdbeGetOp(p, p->nOp - 1);
+}
+
#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
/*
** Return an integer value for one of the parameters to the opcode pOp
@@ -83086,7 +87422,7 @@ static void releaseMemArray(Mem *p, int N){
sqlcipher_sqlite3VdbeMemRelease(p);
p->flags = MEM_Undefined;
}else if( p->szMalloc ){
- sqlcipher_sqlite3DbFreeNN(db, p->zMalloc);
+ sqlcipher_sqlite3DbNNFreeNN(db, p->zMalloc);
p->szMalloc = 0;
p->flags = MEM_Undefined;
}
@@ -83300,7 +87636,6 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeList(
** sqlcipher_sqlite3_column_text16(), causing a translation to UTF-16 encoding.
*/
releaseMemArray(pMem, 8);
- p->pResultSet = 0;
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlcipher_sqlite3_column_text() or
@@ -83336,7 +87671,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeList(
sqlcipher_sqlite3VdbeMemSetInt64(pMem+1, pOp->p2);
sqlcipher_sqlite3VdbeMemSetInt64(pMem+2, pOp->p3);
sqlcipher_sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlcipher_sqlite3_free);
- p->nResColumn = 4;
+ assert( p->nResColumn==4 );
}else{
sqlcipher_sqlite3VdbeMemSetInt64(pMem+0, i);
sqlcipher_sqlite3VdbeMemSetStr(pMem+1, (char*)sqlcipher_sqlite3OpcodeName(pOp->opcode),
@@ -83355,9 +87690,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeList(
sqlcipher_sqlite3VdbeMemSetNull(pMem+7);
#endif
sqlcipher_sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlcipher_sqlite3_free);
- p->nResColumn = 8;
+ assert( p->nResColumn==8 );
}
- p->pResultSet = pMem;
+ p->pResultRow = pMem;
if( db->mallocFailed ){
p->rc = SQLITE_NOMEM;
rc = SQLITE_ERROR;
@@ -83468,7 +87803,7 @@ static void *allocSpace(
** running it.
*/
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeRewind(Vdbe *p){
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+#if defined(SQLITE_DEBUG)
int i;
#endif
assert( p!=0 );
@@ -83497,8 +87832,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeRewind(Vdbe *p){
p->nFkConstraint = 0;
#ifdef VDBE_PROFILE
for(i=0; i<p->nOp; i++){
- p->aOp[i].cnt = 0;
- p->aOp[i].cycles = 0;
+ p->aOp[i].nExec = 0;
+ p->aOp[i].nCycle = 0;
}
#endif
}
@@ -83569,26 +87904,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeMakeReady(
resolveP2Values(p, &nArg);
p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
if( pParse->explain ){
- static const char * const azColName[] = {
- "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
- "id", "parent", "notused", "detail"
- };
- int iFirst, mx, i;
if( nMem<10 ) nMem = 10;
p->explain = pParse->explain;
- if( pParse->explain==2 ){
- sqlcipher_sqlite3VdbeSetNumCols(p, 4);
- iFirst = 8;
- mx = 12;
- }else{
- sqlcipher_sqlite3VdbeSetNumCols(p, 8);
- iFirst = 0;
- mx = 8;
- }
- for(i=iFirst; i<mx; i++){
- sqlcipher_sqlite3VdbeSetColName(p, i-iFirst, COLNAME_NAME,
- azColName[i], SQLITE_STATIC);
- }
+ p->nResColumn = 12 - 4*p->explain;
}
p->expired = 0;
@@ -83607,9 +87925,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeMakeReady(
p->aVar = allocSpace(&x, 0, nVar*sizeof(Mem));
p->apArg = allocSpace(&x, 0, nArg*sizeof(Mem*));
p->apCsr = allocSpace(&x, 0, nCursor*sizeof(VdbeCursor*));
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- p->anExec = allocSpace(&x, 0, p->nOp*sizeof(i64));
-#endif
if( x.nNeeded ){
x.pSpace = p->pFree = sqlcipher_sqlite3DbMallocRawNN(db, x.nNeeded);
x.nFree = x.nNeeded;
@@ -83618,9 +87933,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeMakeReady(
p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
-#endif
}
}
@@ -83635,9 +87947,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeMakeReady(
p->nMem = nMem;
initMemArray(p->aMem, nMem, db, MEM_Undefined);
memset(p->apCsr, 0, nCursor*sizeof(VdbeCursor*));
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- memset(p->anExec, 0, p->nOp*sizeof(i64));
-#endif
}
sqlcipher_sqlite3VdbeRewind(p);
}
@@ -83649,7 +87958,23 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeMakeReady(
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx ) sqlcipher_sqlite3VdbeFreeCursorNN(p,pCx);
}
+static SQLITE_NOINLINE void freeCursorWithCache(Vdbe *p, VdbeCursor *pCx){
+ VdbeTxtBlbCache *pCache = pCx->pCache;
+ assert( pCx->colCache );
+ pCx->colCache = 0;
+ pCx->pCache = 0;
+ if( pCache->pCValue ){
+ sqlcipher_sqlite3RCStrUnref(pCache->pCValue);
+ pCache->pCValue = 0;
+ }
+ sqlcipher_sqlite3DbFree(p->db, pCache);
+ sqlcipher_sqlite3VdbeFreeCursorNN(p, pCx);
+}
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeFreeCursorNN(Vdbe *p, VdbeCursor *pCx){
+ if( pCx->colCache ){
+ freeCursorWithCache(p, pCx);
+ return;
+ }
switch( pCx->eCurType ){
case CURTYPE_SORTER: {
sqlcipher_sqlite3VdbeSorterClose(p->db, pCx);
@@ -83695,9 +88020,6 @@ static void closeCursorsInFrame(Vdbe *p){
SQLITE_PRIVATE int sqlcipher_sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
Vdbe *v = pFrame->v;
closeCursorsInFrame(v);
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- v->anExec = pFrame->anExec;
-#endif
v->aOp = pFrame->aOp;
v->nOp = pFrame->nOp;
v->aMem = pFrame->aMem;
@@ -83753,12 +88075,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
int n;
sqlcipher_sqlite3 *db = p->db;
- if( p->nResColumn ){
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ if( p->nResAlloc ){
+ releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N);
sqlcipher_sqlite3DbFree(db, p->aColName);
}
n = nResColumn*COLNAME_N;
- p->nResColumn = (u16)nResColumn;
+ p->nResColumn = p->nResAlloc = (u16)nResColumn;
p->aColName = (Mem*)sqlcipher_sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
initMemArray(p->aColName, n, db, MEM_Null);
@@ -83783,14 +88105,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeSetColName(
){
int rc;
Mem *pColName;
- assert( idx<p->nResColumn );
+ assert( idx<p->nResAlloc );
assert( var<COLNAME_N );
if( p->db->mallocFailed ){
assert( !zName || xDel!=SQLITE_DYNAMIC );
return SQLITE_NOMEM_BKPT;
}
assert( p->aColName!=0 );
- pColName = &(p->aColName[idx+var*p->nResColumn]);
+ pColName = &(p->aColName[idx+var*p->nResAlloc]);
rc = sqlcipher_sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, xDel);
assert( rc!=0 || !zName || (pColName->flags&MEM_Term)!=0 );
return rc;
@@ -84078,7 +88400,7 @@ static void checkActiveVdbeCnt(sqlcipher_sqlite3 *db){
if( p->readOnly==0 ) nWrite++;
if( p->bIsReader ) nRead++;
}
- p = p->pNext;
+ p = p->pVNext;
}
assert( cnt==db->nVdbeActive );
assert( nWrite==db->nVdbeWrite );
@@ -84268,7 +88590,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeHalt(Vdbe *p){
/* Check for immediate foreign key violations. */
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
- sqlcipher_sqlite3VdbeCheckFk(p, 0);
+ (void)sqlcipher_sqlite3VdbeCheckFk(p, 0);
}
/* If the auto-commit flag is set and this is the only active writer
@@ -84303,6 +88625,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeHalt(Vdbe *p){
sqlcipher_sqlite3VdbeLeave(p);
return SQLITE_BUSY;
}else if( rc!=SQLITE_OK ){
+ sqlcipher_sqlite3SystemError(db, rc);
p->rc = rc;
sqlcipher_sqlite3RollbackAll(db, SQLITE_OK);
p->nChange = 0;
@@ -84312,6 +88635,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeHalt(Vdbe *p){
db->flags &= ~(u64)SQLITE_DeferFKs;
sqlcipher_sqlite3CommitInternalChanges(db);
}
+ }else if( p->rc==SQLITE_SCHEMA && db->nVdbeActive>1 ){
+ p->nChange = 0;
}else{
sqlcipher_sqlite3RollbackAll(db, SQLITE_OK);
p->nChange = 0;
@@ -84501,7 +88826,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeReset(Vdbe *p){
sqlcipher_sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
- p->pResultSet = 0;
+ p->pResultRow = 0;
#ifdef SQLITE_DEBUG
p->nWrite = 0;
#endif
@@ -84529,10 +88854,12 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeReset(Vdbe *p){
}
for(i=0; i<p->nOp; i++){
char zHdr[100];
+ i64 cnt = p->aOp[i].nExec;
+ i64 cycles = p->aOp[i].nCycle;
sqlcipher_sqlite3_snprintf(sizeof(zHdr), zHdr, "%6u %12llu %8llu ",
- p->aOp[i].cnt,
- p->aOp[i].cycles,
- p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0
+ cnt,
+ cycles,
+ cnt>0 ? cycles/cnt : 0
);
fprintf(out, "%s", zHdr);
sqlcipher_sqlite3VdbePrintOp(out, i, &p->aOp[i]);
@@ -84607,10 +88934,11 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeDeleteAuxData(sqlcipher_sqlite3 *db, Au
*/
static void sqlcipher_sqlite3VdbeClearObject(sqlcipher_sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext;
+ assert( db!=0 );
assert( p->db==0 || p->db==db );
if( p->aColName ){
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
- sqlcipher_sqlite3DbFreeNN(db, p->aColName);
+ releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N);
+ sqlcipher_sqlite3DbNNFreeNN(db, p->aColName);
}
for(pSub=p->pProgram; pSub; pSub=pNext){
pNext = pSub->pNext;
@@ -84619,17 +88947,17 @@ static void sqlcipher_sqlite3VdbeClearObject(sqlcipher_sqlite3 *db, Vdbe *p){
}
if( p->eVdbeState!=VDBE_INIT_STATE ){
releaseMemArray(p->aVar, p->nVar);
- if( p->pVList ) sqlcipher_sqlite3DbFreeNN(db, p->pVList);
- if( p->pFree ) sqlcipher_sqlite3DbFreeNN(db, p->pFree);
+ if( p->pVList ) sqlcipher_sqlite3DbNNFreeNN(db, p->pVList);
+ if( p->pFree ) sqlcipher_sqlite3DbNNFreeNN(db, p->pFree);
}
vdbeFreeOpArray(db, p->aOp, p->nOp);
- sqlcipher_sqlite3DbFree(db, p->zSql);
+ if( p->zSql ) sqlcipher_sqlite3DbNNFreeNN(db, p->zSql);
#ifdef SQLITE_ENABLE_NORMALIZE
sqlcipher_sqlite3DbFree(db, p->zNormSql);
{
- DblquoteStr *pThis, *pNext;
- for(pThis=p->pDblStr; pThis; pThis=pNext){
- pNext = pThis->pNextStr;
+ DblquoteStr *pThis, *pNxt;
+ for(pThis=p->pDblStr; pThis; pThis=pNxt){
+ pNxt = pThis->pNextStr;
sqlcipher_sqlite3DbFree(db, pThis);
}
}
@@ -84653,20 +88981,17 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeDelete(Vdbe *p){
assert( p!=0 );
db = p->db;
+ assert( db!=0 );
assert( sqlcipher_sqlite3_mutex_held(db->mutex) );
sqlcipher_sqlite3VdbeClearObject(db, p);
if( db->pnBytesFreed==0 ){
- if( p->pPrev ){
- p->pPrev->pNext = p->pNext;
- }else{
- assert( db->pVdbe==p );
- db->pVdbe = p->pNext;
- }
- if( p->pNext ){
- p->pNext->pPrev = p->pPrev;
+ assert( p->ppVPrev!=0 );
+ *p->ppVPrev = p->pVNext;
+ if( p->pVNext ){
+ p->pVNext->ppVPrev = p->ppVPrev;
}
}
- sqlcipher_sqlite3DbFreeNN(db, p);
+ sqlcipher_sqlite3DbNNFreeNN(db, p);
}
/*
@@ -84979,6 +89304,23 @@ static void serialGet(
pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
}
}
+static int serialGet7(
+ const unsigned char *buf, /* Buffer to deserialize from */
+ Mem *pMem /* Memory cell to write value into */
+){
+ u64 x = FOUR_BYTE_UINT(buf);
+ u32 y = FOUR_BYTE_UINT(buf+4);
+ x = (x<<32) + y;
+ assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
+ swapMixedEndianFloat(x);
+ memcpy(&pMem->u.r, &x, sizeof(x));
+ if( IsNaN(x) ){
+ pMem->flags = MEM_Null;
+ return 1;
+ }
+ pMem->flags = MEM_Real;
+ return 0;
+}
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeSerialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
@@ -85212,6 +89554,15 @@ static int vdbeRecordCompareDebug(
if( d1+(u64)serial_type1+2>(u64)nKey1
&& d1+(u64)sqlcipher_sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1
){
+ if( serial_type1>=1
+ && serial_type1<=7
+ && d1+(u64)sqlcipher_sqlite3VdbeSerialTypeLen(serial_type1)<=(u64)nKey1+8
+ && CORRUPT_DB
+ ){
+ return 1; /* corrupt record not detected by
+ ** sqlcipher_sqlite3VdbeRecordCompareWithSkip(). Return true
+ ** to avoid firing the assert() */
+ }
break;
}
@@ -85380,32 +89731,44 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlcipher_sqlite3BlobCompare(const Mem *pB1,
return n1 - n2;
}
+/* The following two functions are used only within testcase() to prove
+** test coverage. These functions do no exist for production builds.
+** We must use separate SQLITE_NOINLINE functions here, since otherwise
+** optimizer code movement causes gcov to become very confused.
+*/
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
+static int SQLITE_NOINLINE doubleLt(double a, double b){ return a<b; }
+static int SQLITE_NOINLINE doubleEq(double a, double b){ return a==b; }
+#endif
+
/*
** Do a comparison between a 64-bit signed integer and a 64-bit floating-point
** number. Return negative, zero, or positive if the first (i64) is less than,
** equal to, or greater than the second (double).
*/
SQLITE_PRIVATE int sqlcipher_sqlite3IntFloatCompare(i64 i, double r){
- if( sizeof(LONGDOUBLE_TYPE)>8 ){
+ if( sqlcipher_sqlite3IsNaN(r) ){
+ /* SQLite considers NaN to be a NULL. And all integer values are greater
+ ** than NULL */
+ return 1;
+ }
+ if( sqlcipher_sqlite3Config.bUseLongDouble ){
LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
testcase( x<r );
testcase( x>r );
testcase( x==r );
- if( x<r ) return -1;
- if( x>r ) return +1; /*NO_TEST*/ /* work around bugs in gcov */
- return 0; /*NO_TEST*/ /* work around bugs in gcov */
+ return (x<r) ? -1 : (x>r);
}else{
i64 y;
- double s;
if( r<-9223372036854775808.0 ) return +1;
if( r>=9223372036854775808.0 ) return -1;
y = (i64)r;
if( i<y ) return -1;
if( i>y ) return +1;
- s = (double)i;
- if( s<r ) return -1;
- if( s>r ) return +1;
- return 0;
+ testcase( doubleLt(((double)i),r) );
+ testcase( doubleLt(r,((double)i)) );
+ testcase( doubleEq(r,((double)i)) );
+ return (((double)i)<r) ? -1 : (((double)i)>r);
}
}
@@ -85621,7 +89984,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeRecordCompareWithSkip(
assert( pPKey2->pKeyInfo->aSortFlags!=0 );
assert( pPKey2->pKeyInfo->nKeyField>0 );
assert( idx1<=szHdr1 || CORRUPT_DB );
- do{
+ while( 1 /*exit-by-break*/ ){
u32 serial_type;
/* RHS is an integer */
@@ -85631,11 +89994,11 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeRecordCompareWithSkip(
serial_type = aKey1[idx1];
testcase( serial_type==12 );
if( serial_type>=10 ){
- rc = +1;
+ rc = serial_type==10 ? -1 : +1;
}else if( serial_type==0 ){
rc = -1;
}else if( serial_type==7 ){
- sqlcipher_sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
+ serialGet7(&aKey1[d1], &mem1);
rc = -sqlcipher_sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
}else{
i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
@@ -85655,19 +90018,23 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeRecordCompareWithSkip(
/* Serial types 12 or greater are strings and blobs (greater than
** numbers). Types 10 and 11 are currently "reserved for future
** use", so it doesn't really matter what the results of comparing
- ** them to numberic values are. */
- rc = +1;
+ ** them to numeric values are. */
+ rc = serial_type==10 ? -1 : +1;
}else if( serial_type==0 ){
rc = -1;
}else{
- sqlcipher_sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
if( serial_type==7 ){
- if( mem1.u.r<pRhs->u.r ){
+ if( serialGet7(&aKey1[d1], &mem1) ){
+ rc = -1; /* mem1 is a NaN */
+ }else if( mem1.u.r<pRhs->u.r ){
rc = -1;
}else if( mem1.u.r>pRhs->u.r ){
rc = +1;
+ }else{
+ assert( rc==0 );
}
}else{
+ sqlcipher_sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
rc = sqlcipher_sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
}
}
@@ -85737,7 +90104,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeRecordCompareWithSkip(
/* RHS is null */
else{
serial_type = aKey1[idx1];
- rc = (serial_type!=0);
+ if( serial_type==0
+ || serial_type==10
+ || (serial_type==7 && serialGet7(&aKey1[d1], &mem1)!=0)
+ ){
+ assert( rc==0 );
+ }else{
+ rc = 1;
+ }
}
if( rc!=0 ){
@@ -85759,8 +90133,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeRecordCompareWithSkip(
if( i==pPKey2->nField ) break;
pRhs++;
d1 += sqlcipher_sqlite3VdbeSerialTypeLen(serial_type);
+ if( d1>(unsigned)nKey1 ) break;
idx1 += sqlcipher_sqlite3VarintLen(serial_type);
- }while( idx1<(unsigned)szHdr1 && d1<=(unsigned)nKey1 );
+ if( idx1>=(unsigned)szHdr1 ){
+ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
+ return 0; /* Corrupt index */
+ }
+ }
/* No memory allocation is ever used on mem1. Prove this using
** the following assert(). If the assert() fails, it indicates a
@@ -86161,7 +90540,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeCountChanges(Vdbe *v){
*/
SQLITE_PRIVATE void sqlcipher_sqlite3ExpirePreparedStatements(sqlcipher_sqlite3 *db, int iCode){
Vdbe *p;
- for(p = db->pVdbe; p; p=p->pNext){
+ for(p = db->pVdbe; p; p=p->pVNext){
p->expired = iCode+1;
}
}
@@ -86192,7 +90571,8 @@ SQLITE_PRIVATE sqlcipher_sqlite3_value *sqlcipher_sqlite3VdbeGetBoundValue(Vdbe
assert( iVar>0 );
if( v ){
Mem *pMem = &v->aVar[iVar-1];
- assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
+ assert( (v->db->flags & SQLITE_EnableQPSG)==0
+ || (v->db->mDbFlags & DBFLAG_InternalFunc)!=0 );
if( 0==(pMem->flags & MEM_Null) ){
sqlcipher_sqlite3_value *pRet = sqlcipher_sqlite3ValueNew(v->db);
if( pRet ){
@@ -86212,7 +90592,8 @@ SQLITE_PRIVATE sqlcipher_sqlite3_value *sqlcipher_sqlite3VdbeGetBoundValue(Vdbe
*/
SQLITE_PRIVATE void sqlcipher_sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
assert( iVar>0 );
- assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
+ assert( (v->db->flags & SQLITE_EnableQPSG)==0
+ || (v->db->mDbFlags & DBFLAG_InternalFunc)!=0 );
if( iVar>=32 ){
v->expmask |= 0x80000000;
}else{
@@ -86254,6 +90635,20 @@ SQLITE_PRIVATE int sqlcipher_sqlite3NotPureFunc(sqlcipher_sqlite3_context *pCtx)
return 1;
}
+#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
+/*
+** This Walker callback is used to help verify that calls to
+** sqlcipher_sqlite3BtreeCursorHint() with opcode BTREE_HINT_RANGE have
+** byte-code register values correctly initialized.
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_REGISTER ){
+ assert( (pWalker->u.aMem[pExpr->iTable].flags & MEM_Undefined)==0 );
+ }
+ return WRC_Continue;
+}
+#endif /* SQLITE_ENABLE_CURSOR_HINTS && SQLITE_DEBUG */
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Transfer error message text from an sqlcipher_sqlite3_vtab.zErrMsg (text stored
@@ -86282,13 +90677,14 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VtabImportErrmsg(Vdbe *p, sqlcipher_sqlite3
** the vdbeUnpackRecord() function found in vdbeapi.c.
*/
static void vdbeFreeUnpacked(sqlcipher_sqlite3 *db, int nField, UnpackedRecord *p){
+ assert( db!=0 );
if( p ){
int i;
for(i=0; i<nField; i++){
Mem *pMem = &p->aMem[i];
if( pMem->zMalloc ) sqlcipher_sqlite3VdbeMemReleaseMalloc(pMem);
}
- sqlcipher_sqlite3DbFreeNN(db, p);
+ sqlcipher_sqlite3DbNNFreeNN(db, p);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -86315,6 +90711,16 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbePreUpdateHook(
PreUpdate preupdate;
const char *zTbl = pTab->zName;
static const u8 fakeSortOrder = 0;
+#ifdef SQLITE_DEBUG
+ int nRealCol;
+ if( pTab->tabFlags & TF_WithoutRowid ){
+ nRealCol = sqlcipher_sqlite3PrimaryKeyIndex(pTab)->nColumn;
+ }else if( pTab->tabFlags & TF_HasVirtual ){
+ nRealCol = pTab->nNVCol;
+ }else{
+ nRealCol = pTab->nCol;
+ }
+#endif
assert( db->pPreUpdate==0 );
memset(&preupdate, 0, sizeof(PreUpdate));
@@ -86331,8 +90737,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbePreUpdateHook(
assert( pCsr!=0 );
assert( pCsr->eCurType==CURTYPE_BTREE );
- assert( pCsr->nField==pTab->nCol
- || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
+ assert( pCsr->nField==nRealCol
+ || (pCsr->nField==nRealCol+1 && op==SQLITE_DELETE && iReg==-1)
);
preupdate.v = v;
@@ -86359,7 +90765,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbePreUpdateHook(
for(i=0; i<pCsr->nField; i++){
sqlcipher_sqlite3VdbeMemRelease(&preupdate.aNew[i]);
}
- sqlcipher_sqlite3DbFreeNN(db, preupdate.aNew);
+ sqlcipher_sqlite3DbNNFreeNN(db, preupdate.aNew);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -86383,6 +90789,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbePreUpdateHook(
*/
/* #include "sqliteInt.h" */
/* #include "vdbeInt.h" */
+/* #include "opcodes.h" */
#ifndef SQLITE_OMIT_DEPRECATED
/*
@@ -86476,7 +90883,9 @@ SQLITE_API int sqlcipher_sqlite3_finalize(sqlcipher_sqlite3_stmt *pStmt){
if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
sqlcipher_sqlite3_mutex_enter(db->mutex);
checkProfileCallback(db, v);
- rc = sqlcipher_sqlite3VdbeFinalize(v);
+ assert( v->eVdbeState>=VDBE_READY_STATE );
+ rc = sqlcipher_sqlite3VdbeReset(v);
+ sqlcipher_sqlite3VdbeDelete(v);
rc = sqlcipher_sqlite3ApiExit(db, rc);
sqlcipher_sqlite3LeaveMutexAndCloseZombie(db);
}
@@ -86517,7 +90926,15 @@ SQLITE_API int sqlcipher_sqlite3_clear_bindings(sqlcipher_sqlite3_stmt *pStmt){
int rc = SQLITE_OK;
Vdbe *p = (Vdbe*)pStmt;
#if SQLITE_THREADSAFE
- sqlcipher_sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex;
+ sqlcipher_sqlite3_mutex *mutex;
+#endif
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pStmt==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+#if SQLITE_THREADSAFE
+ mutex = p->db->mutex;
#endif
sqlcipher_sqlite3_mutex_enter(mutex);
for(i=0; i<p->nVar; i++){
@@ -86636,7 +91053,7 @@ SQLITE_API int sqlcipher_sqlite3_value_type(sqlcipher_sqlite3_value* pVal){
SQLITE_NULL, /* 0x1f (not possible) */
SQLITE_FLOAT, /* 0x20 INTREAL */
SQLITE_NULL, /* 0x21 (not possible) */
- SQLITE_TEXT, /* 0x22 INTREAL + TEXT */
+ SQLITE_FLOAT, /* 0x22 INTREAL + TEXT */
SQLITE_NULL, /* 0x23 (not possible) */
SQLITE_FLOAT, /* 0x24 (not possible) */
SQLITE_NULL, /* 0x25 (not possible) */
@@ -86684,6 +91101,9 @@ SQLITE_API int sqlcipher_sqlite3_value_type(sqlcipher_sqlite3_value* pVal){
#endif
return aType[pVal->flags&MEM_AffMask];
}
+SQLITE_API int sqlcipher_sqlite3_value_encoding(sqlcipher_sqlite3_value *pVal){
+ return pVal->enc;
+}
/* Return true if a parameter to xUpdate represents an unchanged column */
SQLITE_API int sqlcipher_sqlite3_value_nochange(sqlcipher_sqlite3_value *pVal){
@@ -86737,7 +91157,7 @@ SQLITE_API void sqlcipher_sqlite3_value_free(sqlcipher_sqlite3_value *pOld){
** is too big or if an OOM occurs.
**
** The invokeValueDestructor(P,X) routine invokes destructor function X()
-** on value P is not going to be used and need to be destroyed.
+** on value P if P is not going to be used and need to be destroyed.
*/
static void setResultStrOrError(
sqlcipher_sqlite3_context *pCtx, /* Function context */
@@ -86767,7 +91187,7 @@ static void setResultStrOrError(
static int invokeValueDestructor(
const void *p, /* Value to destroy */
void (*xDel)(void*), /* The destructor */
- sqlcipher_sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */
+ sqlcipher_sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if not NULL */
){
assert( xDel!=SQLITE_DYNAMIC );
if( xDel==0 ){
@@ -86777,7 +91197,14 @@ static int invokeValueDestructor(
}else{
xDel((void*)p);
}
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx!=0 ){
+ sqlcipher_sqlite3_result_error_toobig(pCtx);
+ }
+#else
+ assert( pCtx!=0 );
sqlcipher_sqlite3_result_error_toobig(pCtx);
+#endif
return SQLITE_TOOBIG;
}
SQLITE_API void sqlcipher_sqlite3_result_blob(
@@ -86786,6 +91213,12 @@ SQLITE_API void sqlcipher_sqlite3_result_blob(
int n,
void (*xDel)(void *)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 || n<0 ){
+ invokeValueDestructor(z, xDel, pCtx);
+ return;
+ }
+#endif
assert( n>=0 );
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, 0, xDel);
@@ -86796,8 +91229,14 @@ SQLITE_API void sqlcipher_sqlite3_result_blob64(
sqlcipher_sqlite3_uint64 n,
void (*xDel)(void *)
){
- assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
assert( xDel!=SQLITE_DYNAMIC );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
+ assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
if( n>0x7fffffff ){
(void)invokeValueDestructor(z, xDel, pCtx);
}else{
@@ -86805,30 +91244,48 @@ SQLITE_API void sqlcipher_sqlite3_result_blob64(
}
}
SQLITE_API void sqlcipher_sqlite3_result_double(sqlcipher_sqlite3_context *pCtx, double rVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlcipher_sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
}
SQLITE_API void sqlcipher_sqlite3_result_error(sqlcipher_sqlite3_context *pCtx, const char *z, int n){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
sqlcipher_sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API void sqlcipher_sqlite3_result_error16(sqlcipher_sqlite3_context *pCtx, const void *z, int n){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
sqlcipher_sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
SQLITE_API void sqlcipher_sqlite3_result_int(sqlcipher_sqlite3_context *pCtx, int iVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlcipher_sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal);
}
SQLITE_API void sqlcipher_sqlite3_result_int64(sqlcipher_sqlite3_context *pCtx, i64 iVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlcipher_sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
}
SQLITE_API void sqlcipher_sqlite3_result_null(sqlcipher_sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlcipher_sqlite3VdbeMemSetNull(pCtx->pOut);
}
@@ -86838,14 +91295,37 @@ SQLITE_API void sqlcipher_sqlite3_result_pointer(
const char *zPType,
void (*xDestructor)(void*)
){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(pPtr, xDestructor, 0);
+ return;
+ }
+#endif
+ pOut = pCtx->pOut;
assert( sqlcipher_sqlite3_mutex_held(pOut->db->mutex) );
sqlcipher_sqlite3VdbeMemRelease(pOut);
pOut->flags = MEM_Null;
sqlcipher_sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor);
}
SQLITE_API void sqlcipher_sqlite3_result_subtype(sqlcipher_sqlite3_context *pCtx, unsigned int eSubtype){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
+#if defined(SQLITE_STRICT_SUBTYPE) && SQLITE_STRICT_SUBTYPE+0!=0
+ if( pCtx->pFunc!=0
+ && (pCtx->pFunc->funcFlags & SQLITE_RESULT_SUBTYPE)==0
+ ){
+ char zErr[200];
+ sqlcipher_sqlite3_snprintf(sizeof(zErr), zErr,
+ "misuse of sqlcipher_sqlite3_result_subtype() by %s()",
+ pCtx->pFunc->zName);
+ sqlcipher_sqlite3_result_error(pCtx, zErr, -1);
+ return;
+ }
+#endif /* SQLITE_STRICT_SUBTYPE */
+ pOut = pCtx->pOut;
assert( sqlcipher_sqlite3_mutex_held(pOut->db->mutex) );
pOut->eSubtype = eSubtype & 0xff;
pOut->flags |= MEM_Subtype;
@@ -86856,6 +91336,12 @@ SQLITE_API void sqlcipher_sqlite3_result_text(
int n,
void (*xDel)(void *)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
}
@@ -86866,13 +91352,23 @@ SQLITE_API void sqlcipher_sqlite3_result_text64(
void (*xDel)(void *),
unsigned char enc
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
assert( xDel!=SQLITE_DYNAMIC );
- if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ if( enc!=SQLITE_UTF8 ){
+ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ n &= ~(u64)1;
+ }
if( n>0x7fffffff ){
(void)invokeValueDestructor(z, xDel, pCtx);
}else{
setResultStrOrError(pCtx, z, (int)n, enc, xDel);
+ sqlcipher_sqlite3VdbeMemZeroTerminateIfAble(pCtx->pOut);
}
}
#ifndef SQLITE_OMIT_UTF16
@@ -86883,7 +91379,7 @@ SQLITE_API void sqlcipher_sqlite3_result_text16(
void (*xDel)(void *)
){
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
+ setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16NATIVE, xDel);
}
SQLITE_API void sqlcipher_sqlite3_result_text16be(
sqlcipher_sqlite3_context *pCtx,
@@ -86892,7 +91388,7 @@ SQLITE_API void sqlcipher_sqlite3_result_text16be(
void (*xDel)(void *)
){
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
+ setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16BE, xDel);
}
SQLITE_API void sqlcipher_sqlite3_result_text16le(
sqlcipher_sqlite3_context *pCtx,
@@ -86901,11 +91397,20 @@ SQLITE_API void sqlcipher_sqlite3_result_text16le(
void (*xDel)(void *)
){
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel);
+ setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16LE, xDel);
}
#endif /* SQLITE_OMIT_UTF16 */
SQLITE_API void sqlcipher_sqlite3_result_value(sqlcipher_sqlite3_context *pCtx, sqlcipher_sqlite3_value *pValue){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+ if( pValue==0 ){
+ sqlcipher_sqlite3_result_null(pCtx);
+ return;
+ }
+#endif
+ pOut = pCtx->pOut;
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlcipher_sqlite3VdbeMemCopy(pOut, pValue);
sqlcipher_sqlite3VdbeChangeEncoding(pOut, pCtx->enc);
@@ -86917,7 +91422,12 @@ SQLITE_API void sqlcipher_sqlite3_result_zeroblob(sqlcipher_sqlite3_context *pCt
sqlcipher_sqlite3_result_zeroblob64(pCtx, n>0 ? n : 0);
}
SQLITE_API int sqlcipher_sqlite3_result_zeroblob64(sqlcipher_sqlite3_context *pCtx, u64 n){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ pOut = pCtx->pOut;
assert( sqlcipher_sqlite3_mutex_held(pOut->db->mutex) );
if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlcipher_sqlite3_result_error_toobig(pCtx);
@@ -86931,6 +91441,9 @@ SQLITE_API int sqlcipher_sqlite3_result_zeroblob64(sqlcipher_sqlite3_context *pC
#endif
}
SQLITE_API void sqlcipher_sqlite3_result_error_code(sqlcipher_sqlite3_context *pCtx, int errCode){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
pCtx->isError = errCode ? errCode : -1;
#ifdef SQLITE_DEBUG
if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
@@ -86943,6 +91456,9 @@ SQLITE_API void sqlcipher_sqlite3_result_error_code(sqlcipher_sqlite3_context *p
/* Force an SQLITE_TOOBIG error. */
SQLITE_API void sqlcipher_sqlite3_result_error_toobig(sqlcipher_sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_TOOBIG;
sqlcipher_sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1,
@@ -86951,6 +91467,9 @@ SQLITE_API void sqlcipher_sqlite3_result_error_toobig(sqlcipher_sqlite3_context
/* An SQLITE_NOMEM error. */
SQLITE_API void sqlcipher_sqlite3_result_error_nomem(sqlcipher_sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlcipher_sqlite3VdbeMemSetNull(pCtx->pOut);
pCtx->isError = SQLITE_NOMEM_BKPT;
@@ -87112,7 +91631,7 @@ static int sqlcipher_sqlite3Step(Vdbe *p){
/* If the statement completed successfully, invoke the profile callback */
checkProfileCallback(db, p);
#endif
-
+ p->pResultRow = 0;
if( rc==SQLITE_DONE && db->autoCommit ){
assert( p->rc==SQLITE_OK );
p->rc = doWalCallbacks(db);
@@ -87203,6 +91722,9 @@ SQLITE_API int sqlcipher_sqlite3_step(sqlcipher_sqlite3_stmt *pStmt){
** pointer to it.
*/
SQLITE_API void *sqlcipher_sqlite3_user_data(sqlcipher_sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#endif
assert( p && p->pFunc );
return p->pFunc->pUserData;
}
@@ -87218,7 +91740,11 @@ SQLITE_API void *sqlcipher_sqlite3_user_data(sqlcipher_sqlite3_context *p){
** application defined function.
*/
SQLITE_API sqlcipher_sqlite3 *sqlcipher_sqlite3_context_db_handle(sqlcipher_sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#else
assert( p && p->pOut );
+#endif
return p->pOut->db;
}
@@ -87237,11 +91763,26 @@ SQLITE_API sqlcipher_sqlite3 *sqlcipher_sqlite3_context_db_handle(sqlcipher_sqli
** value, as a signal to the xUpdate routine that the column is unchanged.
*/
SQLITE_API int sqlcipher_sqlite3_vtab_nochange(sqlcipher_sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#else
assert( p );
+#endif
return sqlcipher_sqlite3_value_nochange(p->pOut);
}
/*
+** The destructor function for a ValueList object. This needs to be
+** a separate function, unknowable to the application, to ensure that
+** calls to sqlcipher_sqlite3_vtab_in_first()/sqlcipher_sqlite3_vtab_in_next() that are not
+** preceded by activation of IN processing via sqlcipher_sqlite3_vtab_int() do not
+** try to access a fake ValueList object inserted by a hostile extension.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3VdbeValueListFree(void *pToDelete){
+ sqlcipher_sqlite3_free(pToDelete);
+}
+
+/*
** Implementation of sqlcipher_sqlite3_vtab_in_first() (if bNext==0) and
** sqlcipher_sqlite3_vtab_in_next() (if bNext!=0).
*/
@@ -87254,9 +91795,16 @@ static int valueFromValueList(
ValueList *pRhs;
*ppOut = 0;
- if( pVal==0 ) return SQLITE_MISUSE;
- pRhs = (ValueList*)sqlcipher_sqlite3_value_pointer(pVal, "ValueList");
- if( pRhs==0 ) return SQLITE_MISUSE;
+ if( pVal==0 ) return SQLITE_MISUSE_BKPT;
+ if( (pVal->flags & MEM_Dyn)==0 || pVal->xDel!=sqlcipher_sqlite3VdbeValueListFree ){
+ return SQLITE_ERROR;
+ }else{
+ assert( (pVal->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) ==
+ (MEM_Null|MEM_Term|MEM_Subtype) );
+ assert( pVal->eSubtype=='p' );
+ assert( pVal->u.zPType!=0 && strcmp(pVal->u.zPType,"ValueList")==0 );
+ pRhs = (ValueList*)pVal->z;
+ }
if( bNext ){
rc = sqlcipher_sqlite3BtreeNext(pRhs->pCsr, 0);
}else{
@@ -87378,6 +91926,9 @@ SQLITE_API void *sqlcipher_sqlite3_aggregate_context(sqlcipher_sqlite3_context *
SQLITE_API void *sqlcipher_sqlite3_get_auxdata(sqlcipher_sqlite3_context *pCtx, int iArg){
AuxData *pAuxData;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return 0;
+#endif
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
#if SQLITE_ENABLE_STAT4
if( pCtx->pVdbe==0 ) return 0;
@@ -87410,8 +91961,12 @@ SQLITE_API void sqlcipher_sqlite3_set_auxdata(
void (*xDelete)(void*)
){
AuxData *pAuxData;
- Vdbe *pVdbe = pCtx->pVdbe;
+ Vdbe *pVdbe;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
+ pVdbe= pCtx->pVdbe;
assert( sqlcipher_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
#ifdef SQLITE_ENABLE_STAT4
if( pVdbe==0 ) goto failed;
@@ -87467,7 +92022,8 @@ SQLITE_API int sqlcipher_sqlite3_aggregate_count(sqlcipher_sqlite3_context *p){
*/
SQLITE_API int sqlcipher_sqlite3_column_count(sqlcipher_sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
- return pVm ? pVm->nResColumn : 0;
+ if( pVm==0 ) return 0;
+ return pVm->nResColumn;
}
/*
@@ -87476,7 +92032,7 @@ SQLITE_API int sqlcipher_sqlite3_column_count(sqlcipher_sqlite3_stmt *pStmt){
*/
SQLITE_API int sqlcipher_sqlite3_data_count(sqlcipher_sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
- if( pVm==0 || pVm->pResultSet==0 ) return 0;
+ if( pVm==0 || pVm->pResultRow==0 ) return 0;
return pVm->nResColumn;
}
@@ -87531,8 +92087,8 @@ static Mem *columnMem(sqlcipher_sqlite3_stmt *pStmt, int i){
if( pVm==0 ) return (Mem*)columnNullValue();
assert( pVm->db );
sqlcipher_sqlite3_mutex_enter(pVm->db->mutex);
- if( pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
- pOut = &pVm->pResultSet[i];
+ if( pVm->pResultRow!=0 && i<pVm->nResColumn && i>=0 ){
+ pOut = &pVm->pResultRow[i];
}else{
sqlcipher_sqlite3Error(pVm->db, SQLITE_RANGE);
pOut = (Mem*)columnNullValue();
@@ -87556,7 +92112,7 @@ static Mem *columnMem(sqlcipher_sqlite3_stmt *pStmt, int i){
** sqlcipher_sqlite3_column_real()
** sqlcipher_sqlite3_column_bytes()
** sqlcipher_sqlite3_column_bytes16()
-** sqiite3_column_blob()
+** sqlcipher_sqlite3_column_blob()
*/
static void columnMallocFailure(sqlcipher_sqlite3_stmt *pStmt)
{
@@ -87641,6 +92197,32 @@ SQLITE_API int sqlcipher_sqlite3_column_type(sqlcipher_sqlite3_stmt *pStmt, int
}
/*
+** Column names appropriate for EXPLAIN or EXPLAIN QUERY PLAN.
+*/
+static const char * const azExplainColNames8[] = {
+ "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", /* EXPLAIN */
+ "id", "parent", "notused", "detail" /* EQP */
+};
+static const u16 azExplainColNames16data[] = {
+ /* 0 */ 'a', 'd', 'd', 'r', 0,
+ /* 5 */ 'o', 'p', 'c', 'o', 'd', 'e', 0,
+ /* 12 */ 'p', '1', 0,
+ /* 15 */ 'p', '2', 0,
+ /* 18 */ 'p', '3', 0,
+ /* 21 */ 'p', '4', 0,
+ /* 24 */ 'p', '5', 0,
+ /* 27 */ 'c', 'o', 'm', 'm', 'e', 'n', 't', 0,
+ /* 35 */ 'i', 'd', 0,
+ /* 38 */ 'p', 'a', 'r', 'e', 'n', 't', 0,
+ /* 45 */ 'n', 'o', 't', 'u', 's', 'e', 'd', 0,
+ /* 53 */ 'd', 'e', 't', 'a', 'i', 'l', 0
+};
+static const u8 iExplainColNames16[] = {
+ 0, 5, 12, 15, 18, 21, 24, 27,
+ 35, 38, 45, 53
+};
+
+/*
** Convert the N-th element of pStmt->pColName[] into a string using
** xFunc() then return that string. If N is out of range, return 0.
**
@@ -87672,15 +92254,29 @@ static const void *columnName(
return 0;
}
#endif
+ if( N<0 ) return 0;
ret = 0;
p = (Vdbe *)pStmt;
db = p->db;
assert( db!=0 );
- n = sqlcipher_sqlite3_column_count(pStmt);
- if( N<n && N>=0 ){
+ sqlcipher_sqlite3_mutex_enter(db->mutex);
+
+ if( p->explain ){
+ if( useType>0 ) goto columnName_end;
+ n = p->explain==1 ? 8 : 4;
+ if( N>=n ) goto columnName_end;
+ if( useUtf16 ){
+ int i = iExplainColNames16[N + 8*p->explain - 8];
+ ret = (void*)&azExplainColNames16data[i];
+ }else{
+ ret = (void*)azExplainColNames8[N + 8*p->explain - 8];
+ }
+ goto columnName_end;
+ }
+ n = p->nResColumn;
+ if( N<n ){
+ u8 prior_mallocFailed = db->mallocFailed;
N += useType*n;
- sqlcipher_sqlite3_mutex_enter(db->mutex);
- assert( db->mallocFailed==0 );
#ifndef SQLITE_OMIT_UTF16
if( useUtf16 ){
ret = sqlcipher_sqlite3_value_text16((sqlcipher_sqlite3_value*)&p->aColName[N]);
@@ -87692,12 +92288,14 @@ static const void *columnName(
/* A malloc may have failed inside of the _text() call. If this
** is the case, clear the mallocFailed flag and return NULL.
*/
- if( db->mallocFailed ){
+ assert( db->mallocFailed==0 || db->mallocFailed==1 );
+ if( db->mallocFailed > prior_mallocFailed ){
sqlcipher_sqlite3OomClear(db);
ret = 0;
}
- sqlcipher_sqlite3_mutex_leave(db->mutex);
}
+columnName_end:
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
return ret;
}
@@ -87790,7 +92388,7 @@ SQLITE_API const void *sqlcipher_sqlite3_column_origin_name16(sqlcipher_sqlite3_
/*
** Unbind the value bound to variable i in virtual machine p. This is the
** the same as binding a NULL value to the column. If the "i" parameter is
-** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK.
+** out of range, then SQLITE_RANGE is returned. Otherwise SQLITE_OK.
**
** A successful evaluation of this routine acquires the mutex on p.
** the mutex is released if any kind of error occurs.
@@ -87798,25 +92396,24 @@ SQLITE_API const void *sqlcipher_sqlite3_column_origin_name16(sqlcipher_sqlite3_
** The error code stored in database p->db is overwritten with the return
** value in any case.
*/
-static int vdbeUnbind(Vdbe *p, int i){
+static int vdbeUnbind(Vdbe *p, unsigned int i){
Mem *pVar;
if( vdbeSafetyNotNull(p) ){
return SQLITE_MISUSE_BKPT;
}
sqlcipher_sqlite3_mutex_enter(p->db->mutex);
if( p->eVdbeState!=VDBE_READY_STATE ){
- sqlcipher_sqlite3Error(p->db, SQLITE_MISUSE);
+ sqlcipher_sqlite3Error(p->db, SQLITE_MISUSE_BKPT);
sqlcipher_sqlite3_mutex_leave(p->db->mutex);
sqlcipher_sqlite3_log(SQLITE_MISUSE,
"bind on a busy prepared statement: [%s]", p->zSql);
return SQLITE_MISUSE_BKPT;
}
- if( i<1 || i>p->nVar ){
+ if( i>=(unsigned int)p->nVar ){
sqlcipher_sqlite3Error(p->db, SQLITE_RANGE);
sqlcipher_sqlite3_mutex_leave(p->db->mutex);
return SQLITE_RANGE;
}
- i--;
pVar = &p->aVar[i];
sqlcipher_sqlite3VdbeMemRelease(pVar);
pVar->flags = MEM_Null;
@@ -87853,7 +92450,7 @@ static int bindText(
Mem *pVar;
int rc;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
if( zData!=0 ){
pVar = &p->aVar[i-1];
@@ -87902,7 +92499,7 @@ SQLITE_API int sqlcipher_sqlite3_bind_blob64(
SQLITE_API int sqlcipher_sqlite3_bind_double(sqlcipher_sqlite3_stmt *pStmt, int i, double rValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlcipher_sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
sqlcipher_sqlite3_mutex_leave(p->db->mutex);
@@ -87915,7 +92512,7 @@ SQLITE_API int sqlcipher_sqlite3_bind_int(sqlcipher_sqlite3_stmt *p, int i, int
SQLITE_API int sqlcipher_sqlite3_bind_int64(sqlcipher_sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlcipher_sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
sqlcipher_sqlite3_mutex_leave(p->db->mutex);
@@ -87925,7 +92522,7 @@ SQLITE_API int sqlcipher_sqlite3_bind_int64(sqlcipher_sqlite3_stmt *pStmt, int i
SQLITE_API int sqlcipher_sqlite3_bind_null(sqlcipher_sqlite3_stmt *pStmt, int i){
int rc;
Vdbe *p = (Vdbe*)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlcipher_sqlite3_mutex_leave(p->db->mutex);
}
@@ -87940,7 +92537,7 @@ SQLITE_API int sqlcipher_sqlite3_bind_pointer(
){
int rc;
Vdbe *p = (Vdbe*)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlcipher_sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
sqlcipher_sqlite3_mutex_leave(p->db->mutex);
@@ -87967,7 +92564,10 @@ SQLITE_API int sqlcipher_sqlite3_bind_text64(
unsigned char enc
){
assert( xDel!=SQLITE_DYNAMIC );
- if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ if( enc!=SQLITE_UTF8 ){
+ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ nData &= ~(u16)1;
+ }
return bindText(pStmt, i, zData, nData, xDel, enc);
}
#ifndef SQLITE_OMIT_UTF16
@@ -87975,10 +92575,10 @@ SQLITE_API int sqlcipher_sqlite3_bind_text16(
sqlcipher_sqlite3_stmt *pStmt,
int i,
const void *zData,
- int nData,
+ int n,
void (*xDel)(void*)
){
- return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
+ return bindText(pStmt, i, zData, n & ~(u64)1, xDel, SQLITE_UTF16NATIVE);
}
#endif /* SQLITE_OMIT_UTF16 */
SQLITE_API int sqlcipher_sqlite3_bind_value(sqlcipher_sqlite3_stmt *pStmt, int i, const sqlcipher_sqlite3_value *pValue){
@@ -88018,7 +92618,7 @@ SQLITE_API int sqlcipher_sqlite3_bind_value(sqlcipher_sqlite3_stmt *pStmt, int i
SQLITE_API int sqlcipher_sqlite3_bind_zeroblob(sqlcipher_sqlite3_stmt *pStmt, int i, int n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_INCRBLOB
sqlcipher_sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
@@ -88032,6 +92632,9 @@ SQLITE_API int sqlcipher_sqlite3_bind_zeroblob(sqlcipher_sqlite3_stmt *pStmt, in
SQLITE_API int sqlcipher_sqlite3_bind_zeroblob64(sqlcipher_sqlite3_stmt *pStmt, int i, sqlcipher_sqlite3_uint64 n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return SQLITE_MISUSE_BKPT;
+#endif
sqlcipher_sqlite3_mutex_enter(p->db->mutex);
if( n>(u64)p->db->aLimit[SQLITE_LIMIT_LENGTH] ){
rc = SQLITE_TOOBIG;
@@ -88153,6 +92756,42 @@ SQLITE_API int sqlcipher_sqlite3_stmt_isexplain(sqlcipher_sqlite3_stmt *pStmt){
}
/*
+** Set the explain mode for a statement.
+*/
+SQLITE_API int sqlcipher_sqlite3_stmt_explain(sqlcipher_sqlite3_stmt *pStmt, int eMode){
+ Vdbe *v = (Vdbe*)pStmt;
+ int rc;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pStmt==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ sqlcipher_sqlite3_mutex_enter(v->db->mutex);
+ if( ((int)v->explain)==eMode ){
+ rc = SQLITE_OK;
+ }else if( eMode<0 || eMode>2 ){
+ rc = SQLITE_ERROR;
+ }else if( (v->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){
+ rc = SQLITE_ERROR;
+ }else if( v->eVdbeState!=VDBE_READY_STATE ){
+ rc = SQLITE_BUSY;
+ }else if( v->nMem>=10 && (eMode!=2 || v->haveEqpOps) ){
+ /* No reprepare necessary */
+ v->explain = eMode;
+ rc = SQLITE_OK;
+ }else{
+ v->explain = eMode;
+ rc = sqlcipher_sqlite3Reprepare(v);
+ v->haveEqpOps = eMode==2;
+ }
+ if( v->explain ){
+ v->nResColumn = 12 - 4*v->explain;
+ }else{
+ v->nResColumn = v->nResAlloc;
+ }
+ sqlcipher_sqlite3_mutex_leave(v->db->mutex);
+ return rc;
+}
+
+/*
** Return true if the prepared statement is in need of being reset.
*/
SQLITE_API int sqlcipher_sqlite3_stmt_busy(sqlcipher_sqlite3_stmt *pStmt){
@@ -88178,7 +92817,7 @@ SQLITE_API sqlcipher_sqlite3_stmt *sqlcipher_sqlite3_next_stmt(sqlcipher_sqlite3
if( pStmt==0 ){
pNext = (sqlcipher_sqlite3_stmt*)pDb->pVdbe;
}else{
- pNext = (sqlcipher_sqlite3_stmt*)((Vdbe*)pStmt)->pNext;
+ pNext = (sqlcipher_sqlite3_stmt*)((Vdbe*)pStmt)->pVNext;
}
sqlcipher_sqlite3_mutex_leave(pDb->mutex);
return pNext;
@@ -88203,8 +92842,11 @@ SQLITE_API int sqlcipher_sqlite3_stmt_status(sqlcipher_sqlite3_stmt *pStmt, int
sqlcipher_sqlite3_mutex_enter(db->mutex);
v = 0;
db->pnBytesFreed = (int*)&v;
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
+ db->lookaside.pEnd = db->lookaside.pStart;
sqlcipher_sqlite3VdbeDelete(pVdbe);
db->pnBytesFreed = 0;
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
sqlcipher_sqlite3_mutex_leave(db->mutex);
}else{
v = pVdbe->aCounter[op];
@@ -88288,10 +92930,16 @@ static UnpackedRecord *vdbeUnpackRecord(
** a field of the row currently being updated or deleted.
*/
SQLITE_API int sqlcipher_sqlite3_preupdate_old(sqlcipher_sqlite3 *db, int iIdx, sqlcipher_sqlite3_value **ppValue){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
Mem *pMem;
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 || ppValue==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ p = db->pPreUpdate;
/* Test that this call is being made from within an SQLITE_DELETE or
** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
if( !p || p->op==SQLITE_INSERT ){
@@ -88352,7 +93000,12 @@ SQLITE_API int sqlcipher_sqlite3_preupdate_old(sqlcipher_sqlite3 *db, int iIdx,
** the number of columns in the row being updated, deleted or inserted.
*/
SQLITE_API int sqlcipher_sqlite3_preupdate_count(sqlcipher_sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->keyinfo.nKeyField : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -88370,7 +93023,12 @@ SQLITE_API int sqlcipher_sqlite3_preupdate_count(sqlcipher_sqlite3 *db){
** or SET DEFAULT action is considered a trigger.
*/
SQLITE_API int sqlcipher_sqlite3_preupdate_depth(sqlcipher_sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->v->nFrame : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -88381,7 +93039,12 @@ SQLITE_API int sqlcipher_sqlite3_preupdate_depth(sqlcipher_sqlite3 *db){
** only.
*/
SQLITE_API int sqlcipher_sqlite3_preupdate_blobwrite(sqlcipher_sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->iBlobWrite : -1);
}
#endif
@@ -88392,10 +93055,16 @@ SQLITE_API int sqlcipher_sqlite3_preupdate_blobwrite(sqlcipher_sqlite3 *db){
** a field of the row currently being updated or inserted.
*/
SQLITE_API int sqlcipher_sqlite3_preupdate_new(sqlcipher_sqlite3 *db, int iIdx, sqlcipher_sqlite3_value **ppValue){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
int rc = SQLITE_OK;
Mem *pMem;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 || ppValue==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ p = db->pPreUpdate;
if( !p || p->op==SQLITE_DELETE ){
rc = SQLITE_MISUSE_BKPT;
goto preupdate_new_out;
@@ -88466,23 +93135,79 @@ SQLITE_API int sqlcipher_sqlite3_preupdate_new(sqlcipher_sqlite3 *db, int iIdx,
/*
** Return status data for a single loop within query pStmt.
*/
-SQLITE_API int sqlcipher_sqlite3_stmt_scanstatus(
+SQLITE_API int sqlcipher_sqlite3_stmt_scanstatus_v2(
sqlcipher_sqlite3_stmt *pStmt, /* Prepared statement being queried */
- int idx, /* Index of loop to report on */
+ int iScan, /* Index of loop to report on */
int iScanStatusOp, /* Which metric to return */
+ int flags,
void *pOut /* OUT: Write the answer here */
){
Vdbe *p = (Vdbe*)pStmt;
- ScanStatus *pScan;
- if( idx<0 || idx>=p->nScan ) return 1;
+ VdbeOp *aOp;
+ int nOp;
+ ScanStatus *pScan = 0;
+ int idx;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 || pOut==0
+ || iScanStatusOp<SQLITE_SCANSTAT_NLOOP
+ || iScanStatusOp>SQLITE_SCANSTAT_NCYCLE ){
+ return 1;
+ }
+#endif
+ aOp = p->aOp;
+ nOp = p->nOp;
+ if( p->pFrame ){
+ VdbeFrame *pFrame;
+ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
+ aOp = pFrame->aOp;
+ nOp = pFrame->nOp;
+ }
+
+ if( iScan<0 ){
+ int ii;
+ if( iScanStatusOp==SQLITE_SCANSTAT_NCYCLE ){
+ i64 res = 0;
+ for(ii=0; ii<nOp; ii++){
+ res += aOp[ii].nCycle;
+ }
+ *(i64*)pOut = res;
+ return 0;
+ }
+ return 1;
+ }
+ if( flags & SQLITE_SCANSTAT_COMPLEX ){
+ idx = iScan;
+ }else{
+ /* If the COMPLEX flag is clear, then this function must ignore any
+ ** ScanStatus structures with ScanStatus.addrLoop set to 0. */
+ for(idx=0; idx<p->nScan; idx++){
+ pScan = &p->aScan[idx];
+ if( pScan->zName ){
+ iScan--;
+ if( iScan<0 ) break;
+ }
+ }
+ }
+ if( idx>=p->nScan ) return 1;
+ assert( pScan==0 || pScan==&p->aScan[idx] );
pScan = &p->aScan[idx];
+
switch( iScanStatusOp ){
case SQLITE_SCANSTAT_NLOOP: {
- *(sqlcipher_sqlite3_int64*)pOut = p->anExec[pScan->addrLoop];
+ if( pScan->addrLoop>0 ){
+ *(sqlcipher_sqlite3_int64*)pOut = aOp[pScan->addrLoop].nExec;
+ }else{
+ *(sqlcipher_sqlite3_int64*)pOut = -1;
+ }
break;
}
case SQLITE_SCANSTAT_NVISIT: {
- *(sqlcipher_sqlite3_int64*)pOut = p->anExec[pScan->addrVisit];
+ if( pScan->addrVisit>0 ){
+ *(sqlcipher_sqlite3_int64*)pOut = aOp[pScan->addrVisit].nExec;
+ }else{
+ *(sqlcipher_sqlite3_int64*)pOut = -1;
+ }
break;
}
case SQLITE_SCANSTAT_EST: {
@@ -88501,7 +93226,7 @@ SQLITE_API int sqlcipher_sqlite3_stmt_scanstatus(
}
case SQLITE_SCANSTAT_EXPLAIN: {
if( pScan->addrExplain ){
- *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z;
+ *(const char**)pOut = aOp[ pScan->addrExplain ].p4.z;
}else{
*(const char**)pOut = 0;
}
@@ -88509,12 +93234,51 @@ SQLITE_API int sqlcipher_sqlite3_stmt_scanstatus(
}
case SQLITE_SCANSTAT_SELECTID: {
if( pScan->addrExplain ){
- *(int*)pOut = p->aOp[ pScan->addrExplain ].p1;
+ *(int*)pOut = aOp[ pScan->addrExplain ].p1;
+ }else{
+ *(int*)pOut = -1;
+ }
+ break;
+ }
+ case SQLITE_SCANSTAT_PARENTID: {
+ if( pScan->addrExplain ){
+ *(int*)pOut = aOp[ pScan->addrExplain ].p2;
}else{
*(int*)pOut = -1;
}
break;
}
+ case SQLITE_SCANSTAT_NCYCLE: {
+ i64 res = 0;
+ if( pScan->aAddrRange[0]==0 ){
+ res = -1;
+ }else{
+ int ii;
+ for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
+ int iIns = pScan->aAddrRange[ii];
+ int iEnd = pScan->aAddrRange[ii+1];
+ if( iIns==0 ) break;
+ if( iIns>0 ){
+ while( iIns<=iEnd ){
+ res += aOp[iIns].nCycle;
+ iIns++;
+ }
+ }else{
+ int iOp;
+ for(iOp=0; iOp<nOp; iOp++){
+ Op *pOp = &aOp[iOp];
+ if( pOp->p1!=iEnd ) continue;
+ if( (sqlcipher_sqlite3OpcodeProperty[pOp->opcode] & OPFLG_NCYCLE)==0 ){
+ continue;
+ }
+ res += aOp[iOp].nCycle;
+ }
+ }
+ }
+ }
+ *(i64*)pOut = res;
+ break;
+ }
default: {
return 1;
}
@@ -88523,11 +93287,28 @@ SQLITE_API int sqlcipher_sqlite3_stmt_scanstatus(
}
/*
+** Return status data for a single loop within query pStmt.
+*/
+SQLITE_API int sqlcipher_sqlite3_stmt_scanstatus(
+ sqlcipher_sqlite3_stmt *pStmt, /* Prepared statement being queried */
+ int iScan, /* Index of loop to report on */
+ int iScanStatusOp, /* Which metric to return */
+ void *pOut /* OUT: Write the answer here */
+){
+ return sqlcipher_sqlite3_stmt_scanstatus_v2(pStmt, iScan, iScanStatusOp, 0, pOut);
+}
+
+/*
** Zero all counters associated with the sqlcipher_sqlite3_stmt_scanstatus() data.
*/
SQLITE_API void sqlcipher_sqlite3_stmt_scanstatus_reset(sqlcipher_sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
- memset(p->anExec, 0, p->nOp * sizeof(i64));
+ int ii;
+ for(ii=0; p!=0 && ii<p->nOp; ii++){
+ Op *pOp = &p->aOp[ii];
+ pOp->nExec = 0;
+ pOp->nCycle = 0;
+ }
}
#endif /* SQLITE_ENABLE_STMT_SCANSTATUS */
@@ -88862,8 +93643,12 @@ SQLITE_API int sqlcipher_sqlite3_found_count = 0;
** sqlcipher_sqlite3CantopenError(lineno)
*/
static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){
- static int n = 0;
+ static u64 n = 0;
+ (void)pc;
+ (void)pOp;
+ (void)v;
n++;
+ if( n==LARGEST_UINT64 ) abort(); /* So that n is used, preventing a warning */
}
#endif
@@ -89044,7 +93829,8 @@ static VdbeCursor *allocateCursor(
** return false.
*/
static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){
- i64 iValue = (double)rValue;
+ i64 iValue;
+ iValue = sqlcipher_sqlite3RealToI64(rValue);
if( sqlcipher_sqlite3RealSameAsInt(rValue,iValue) ){
*piValue = iValue;
return 1;
@@ -89100,6 +93886,10 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
** always preferred, even if the affinity is REAL, because
** an integer representation is more space efficient on disk.
**
+** SQLITE_AFF_FLEXNUM:
+** If the value is text, then try to convert it into a number of
+** some kind (integer or real) but do not make any other changes.
+**
** SQLITE_AFF_TEXT:
** Convert pRec to a text representation.
**
@@ -89114,11 +93904,11 @@ static void applyAffinity(
){
if( affinity>=SQLITE_AFF_NUMERIC ){
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
- || affinity==SQLITE_AFF_NUMERIC );
+ || affinity==SQLITE_AFF_NUMERIC || affinity==SQLITE_AFF_FLEXNUM );
if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/
- if( (pRec->flags & MEM_Real)==0 ){
+ if( (pRec->flags & (MEM_Real|MEM_IntReal))==0 ){
if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1);
- }else{
+ }else if( affinity<=SQLITE_AFF_REAL ){
sqlcipher_sqlite3VdbeIntegerAffinity(pRec);
}
}
@@ -89206,17 +93996,18 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
** But it does set pMem->u.r and pMem->u.i appropriately.
*/
static u16 numericType(Mem *pMem){
- if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal) ){
+ assert( (pMem->flags & MEM_Null)==0
+ || pMem->db==0 || pMem->db->mallocFailed );
+ if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null) ){
testcase( pMem->flags & MEM_Int );
testcase( pMem->flags & MEM_Real );
testcase( pMem->flags & MEM_IntReal );
- return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal);
- }
- if( pMem->flags & (MEM_Str|MEM_Blob) ){
- testcase( pMem->flags & MEM_Str );
- testcase( pMem->flags & MEM_Blob );
- return computeNumericType(pMem);
+ return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null);
}
+ assert( pMem->flags & (MEM_Str|MEM_Blob) );
+ testcase( pMem->flags & MEM_Str );
+ testcase( pMem->flags & MEM_Blob );
+ return computeNumericType(pMem);
return 0;
}
@@ -89277,6 +94068,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pSt
sqlcipher_sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.');
}
sqlcipher_sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]);
+ if( f & MEM_Term ){
+ sqlcipher_sqlite3_str_appendf(pStr, "(0-term)");
+ }
}
}
#endif
@@ -89345,17 +94139,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VdbeRegisterDump(Vdbe *v){
# define REGISTER_TRACE(R,M)
#endif
-
-#ifdef VDBE_PROFILE
-
-/*
-** hwtime.h contains inline assembler code for implementing
-** high-performance timing routines.
-*/
-/* #include "hwtime.h" */
-
-#endif
-
#ifndef NDEBUG
/*
** This function is only called from within an assert() expression. It
@@ -89415,13 +94198,102 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){
}else if( p->flags & MEM_Real ){
h += sqlcipher_sqlite3VdbeIntValue(p);
}else if( p->flags & (MEM_Str|MEM_Blob) ){
- h += p->n;
- if( p->flags & MEM_Zero ) h += p->u.nZero;
+ /* All strings have the same hash and all blobs have the same hash,
+ ** though, at least, those hashes are different from each other and
+ ** from NULL. */
+ h += 4093 + (p->flags & (MEM_Str|MEM_Blob));
}
}
return h;
}
+
+/*
+** For OP_Column, factor out the case where content is loaded from
+** overflow pages, so that the code to implement this case is separate
+** the common case where all content fits on the page. Factoring out
+** the code reduces register pressure and helps the common case
+** to run faster.
+*/
+static SQLITE_NOINLINE int vdbeColumnFromOverflow(
+ VdbeCursor *pC, /* The BTree cursor from which we are reading */
+ int iCol, /* The column to read */
+ int t, /* The serial-type code for the column value */
+ i64 iOffset, /* Offset to the start of the content value */
+ u32 cacheStatus, /* Current Vdbe.cacheCtr value */
+ u32 colCacheCtr, /* Current value of the column cache counter */
+ Mem *pDest /* Store the value into this register. */
+){
+ int rc;
+ sqlcipher_sqlite3 *db = pDest->db;
+ int encoding = pDest->enc;
+ int len = sqlcipher_sqlite3VdbeSerialTypeLen(t);
+ assert( pC->eCurType==CURTYPE_BTREE );
+ if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) return SQLITE_TOOBIG;
+ if( len > 4000 && pC->pKeyInfo==0 ){
+ /* Cache large column values that are on overflow pages using
+ ** an RCStr (reference counted string) so that if they are reloaded,
+ ** that do not have to be copied a second time. The overhead of
+ ** creating and managing the cache is such that this is only
+ ** profitable for larger TEXT and BLOB values.
+ **
+ ** Only do this on table-btrees so that writes to index-btrees do not
+ ** need to clear the cache. This buys performance in the common case
+ ** in exchange for generality.
+ */
+ VdbeTxtBlbCache *pCache;
+ char *pBuf;
+ if( pC->colCache==0 ){
+ pC->pCache = sqlcipher_sqlite3DbMallocZero(db, sizeof(VdbeTxtBlbCache) );
+ if( pC->pCache==0 ) return SQLITE_NOMEM;
+ pC->colCache = 1;
+ }
+ pCache = pC->pCache;
+ if( pCache->pCValue==0
+ || pCache->iCol!=iCol
+ || pCache->cacheStatus!=cacheStatus
+ || pCache->colCacheCtr!=colCacheCtr
+ || pCache->iOffset!=sqlcipher_sqlite3BtreeOffset(pC->uc.pCursor)
+ ){
+ if( pCache->pCValue ) sqlcipher_sqlite3RCStrUnref(pCache->pCValue);
+ pBuf = pCache->pCValue = sqlcipher_sqlite3RCStrNew( len+3 );
+ if( pBuf==0 ) return SQLITE_NOMEM;
+ rc = sqlcipher_sqlite3BtreePayload(pC->uc.pCursor, iOffset, len, pBuf);
+ if( rc ) return rc;
+ pBuf[len] = 0;
+ pBuf[len+1] = 0;
+ pBuf[len+2] = 0;
+ pCache->iCol = iCol;
+ pCache->cacheStatus = cacheStatus;
+ pCache->colCacheCtr = colCacheCtr;
+ pCache->iOffset = sqlcipher_sqlite3BtreeOffset(pC->uc.pCursor);
+ }else{
+ pBuf = pCache->pCValue;
+ }
+ assert( t>=12 );
+ sqlcipher_sqlite3RCStrRef(pBuf);
+ if( t&1 ){
+ rc = sqlcipher_sqlite3VdbeMemSetStr(pDest, pBuf, len, encoding,
+ sqlcipher_sqlite3RCStrUnref);
+ pDest->flags |= MEM_Term;
+ }else{
+ rc = sqlcipher_sqlite3VdbeMemSetStr(pDest, pBuf, len, 0,
+ sqlcipher_sqlite3RCStrUnref);
+ }
+ }else{
+ rc = sqlcipher_sqlite3VdbeMemFromBtree(pC->uc.pCursor, iOffset, len, pDest);
+ if( rc ) return rc;
+ sqlcipher_sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
+ if( (t&1)!=0 && encoding==SQLITE_UTF8 ){
+ pDest->z[len] = 0;
+ pDest->flags |= MEM_Term;
+ }
+ }
+ pDest->flags &= ~MEM_Ephem;
+ return rc;
+}
+
+
/*
** Return the symbolic name for the data type of a pMem
*/
@@ -89445,11 +94317,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeExec(
){
Op *aOp = p->aOp; /* Copy of p->aOp */
Op *pOp = aOp; /* Current operation */
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
- Op *pOrigOp; /* Value of pOp at the top of the loop */
-#endif
#ifdef SQLITE_DEBUG
+ Op *pOrigOp; /* Value of pOp at the top of the loop */
int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */
+ u8 iCompareIsInit = 0; /* iCompare is initialized */
#endif
int rc = SQLITE_OK; /* Value to return */
sqlcipher_sqlite3 *db = p->db; /* The database */
@@ -89465,13 +94336,17 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeExec(
Mem *pIn2 = 0; /* 2nd input operand */
Mem *pIn3 = 0; /* 3rd input operand */
Mem *pOut = 0; /* Output operand */
-#ifdef VDBE_PROFILE
- u64 start; /* CPU clock count at start of opcode */
+ u32 colCacheCtr = 0; /* Column cache counter */
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+ u64 *pnCycle = 0;
+ int bStmtScanStatus = IS_STMT_SCANSTATUS(db)!=0;
#endif
/*** INSERT STACK UNION HERE ***/
assert( p->eVdbeState==VDBE_RUN_STATE ); /* sqlcipher_sqlite3_step() verifies this */
- sqlcipher_sqlite3VdbeEnter(p);
+ if( DbMaskNonZero(p->lockMask) ){
+ sqlcipher_sqlite3VdbeEnter(p);
+ }
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
if( db->xProgress ){
u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
@@ -89492,7 +94367,6 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeExec(
assert( p->bIsReader || p->readOnly!=0 );
p->iCurrentTime = 0;
assert( p->explain==0 );
- p->pResultSet = 0;
db->busyHandler.nBusy = 0;
if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt;
sqlcipher_sqlite3VdbeIOTraceSql(p);
@@ -89529,12 +94403,18 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeExec(
assert( rc==SQLITE_OK );
assert( pOp>=aOp && pOp<&aOp[p->nOp]);
-#ifdef VDBE_PROFILE
- start = sqlcipher_sqlite3NProfileCnt ? sqlcipher_sqlite3NProfileCnt : sqlcipher_sqlite3Hwtime();
-#endif
nVmStep++;
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- if( p->anExec ) p->anExec[(int)(pOp-aOp)]++;
+
+#if defined(VDBE_PROFILE)
+ pOp->nExec++;
+ pnCycle = &pOp->nCycle;
+ if( sqlcipher_sqlite3NProfileCnt==0 ) *pnCycle -= sqlcipher_sqlite3Hwtime();
+#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ if( bStmtScanStatus ){
+ pOp->nExec++;
+ pnCycle = &pOp->nCycle;
+ *pnCycle -= sqlcipher_sqlite3Hwtime();
+ }
#endif
/* Only allow tracing if SQLITE_DEBUG is defined.
@@ -89596,7 +94476,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeExec(
}
}
#endif
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+#ifdef SQLITE_DEBUG
pOrigOp = pOp;
#endif
@@ -89652,8 +94532,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeExec(
case OP_Goto: { /* jump */
#ifdef SQLITE_DEBUG
- /* In debuggging mode, when the p5 flags is set on an OP_Goto, that
- ** means we should really jump back to the preceeding OP_ReleaseReg
+ /* In debugging mode, when the p5 flags is set on an OP_Goto, that
+ ** means we should really jump back to the preceding OP_ReleaseReg
** instruction. */
if( pOp->p5 ){
assert( pOp->p2 < (int)(pOp - aOp) );
@@ -89760,7 +94640,7 @@ case OP_Return: { /* in1 */
**
** See also: EndCoroutine
*/
-case OP_InitCoroutine: { /* jump */
+case OP_InitCoroutine: { /* jump0 */
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
assert( pOp->p2>=0 && pOp->p2<p->nOp );
assert( pOp->p3>=0 && pOp->p3<p->nOp );
@@ -89783,7 +94663,9 @@ jump_to_p2:
**
** The instruction at the address in register P1 is a Yield.
** Jump to the P2 parameter of that Yield.
-** After the jump, register P1 becomes undefined.
+** After the jump, the value register P1 is left with a value
+** such that subsequent OP_Yields go back to the this same
+** OP_EndCoroutine instruction.
**
** See also: InitCoroutine
*/
@@ -89795,8 +94677,8 @@ case OP_EndCoroutine: { /* in1 */
pCaller = &aOp[pIn1->u.i];
assert( pCaller->opcode==OP_Yield );
assert( pCaller->p2>=0 && pCaller->p2<p->nOp );
+ pIn1->u.i = (int)(pOp - p->aOp) - 1;
pOp = &aOp[pCaller->p2 - 1];
- pIn1->flags = MEM_Undefined;
break;
}
@@ -89813,7 +94695,7 @@ case OP_EndCoroutine: { /* in1 */
**
** See also: InitCoroutine
*/
-case OP_Yield: { /* in1, jump */
+case OP_Yield: { /* in1, jump0 */
int pcDest;
pIn1 = &aMem[pOp->p1];
assert( VdbeMemDynamic(pIn1)==0 );
@@ -89861,7 +94743,7 @@ case OP_HaltIfNull: { /* in3 */
** P5 is a value between 0 and 4, inclusive, that modifies the P4 string.
**
** 0: (no change)
-** 1: NOT NULL contraint failed: P4
+** 1: NOT NULL constraint failed: P4
** 2: UNIQUE constraint failed: P4
** 3: CHECK constraint failed: P4
** 4: FOREIGN KEY constraint failed: P4
@@ -89880,6 +94762,12 @@ case OP_Halt: {
#ifdef SQLITE_DEBUG
if( pOp->p2==OE_Abort ){ sqlcipher_sqlite3VdbeAssertAbortable(p); }
#endif
+
+ /* A deliberately coded "OP_Halt SQLITE_INTERNAL * * * *" opcode indicates
+ ** something is wrong with the code generator. Raise an assertion in order
+ ** to bring this to the attention of fuzzers and other testing tools. */
+ assert( pOp->p1!=SQLITE_INTERNAL );
+
if( p->pFrame && pOp->p1==SQLITE_OK ){
/* Halt the sub-program. Return control to the parent frame. */
pFrame = p->pFrame;
@@ -90137,19 +95025,15 @@ case OP_Blob: { /* out2 */
break;
}
-/* Opcode: Variable P1 P2 * P4 *
-** Synopsis: r[P2]=parameter(P1,P4)
+/* Opcode: Variable P1 P2 * * *
+** Synopsis: r[P2]=parameter(P1)
**
** Transfer the values of bound parameter P1 into register P2
-**
-** If the parameter is named, then its name appears in P4.
-** The P4 value is used by sqlcipher_sqlite3_bind_parameter_name().
*/
case OP_Variable: { /* out2 */
Mem *pVar; /* Value being transferred */
assert( pOp->p1>0 && pOp->p1<=p->nVar );
- assert( pOp->p4.z==0 || pOp->p4.z==sqlcipher_sqlite3VListNumToName(p->pVList,pOp->p1) );
pVar = &p->aVar[pOp->p1 - 1];
if( sqlcipher_sqlite3VdbeMemTooBig(pVar) ){
goto too_big;
@@ -90321,10 +95205,10 @@ case OP_ResultRow: {
assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
p->cacheCtr = (p->cacheCtr + 2)|1;
- p->pResultSet = &aMem[pOp->p1];
+ p->pResultRow = &aMem[pOp->p1];
#ifdef SQLITE_DEBUG
{
- Mem *pMem = p->pResultSet;
+ Mem *pMem = p->pResultRow;
int i;
for(i=0; i<pOp->p2; i++){
assert( memIsValid(&pMem[i]) );
@@ -90461,7 +95345,6 @@ 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 */
- u16 flags; /* Combined MEM_* flags from both inputs */
u16 type1; /* Numeric type of left operand */
u16 type2; /* Numeric type of right operand */
i64 iA; /* Integer value of left operand */
@@ -90470,12 +95353,12 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
double rB; /* Real value of right operand */
pIn1 = &aMem[pOp->p1];
- type1 = numericType(pIn1);
+ type1 = pIn1->flags;
pIn2 = &aMem[pOp->p2];
- type2 = numericType(pIn2);
+ type2 = pIn2->flags;
pOut = &aMem[pOp->p3];
- flags = pIn1->flags | pIn2->flags;
if( (type1 & type2 & MEM_Int)!=0 ){
+int_math:
iA = pIn1->u.i;
iB = pIn2->u.i;
switch( pOp->opcode ){
@@ -90497,9 +95380,12 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
}
pOut->u.i = iB;
MemSetTypeFlag(pOut, MEM_Int);
- }else if( (flags & MEM_Null)!=0 ){
+ }else if( ((type1 | type2) & MEM_Null)!=0 ){
goto arithmetic_result_is_null;
}else{
+ type1 = numericType(pIn1);
+ type2 = numericType(pIn2);
+ if( (type1 & type2 & MEM_Int)!=0 ) goto int_math;
fp_math:
rA = sqlcipher_sqlite3VdbeRealValue(pIn1);
rB = sqlcipher_sqlite3VdbeRealValue(pIn2);
@@ -90657,7 +95543,7 @@ case OP_AddImm: { /* in1 */
pIn1 = &aMem[pOp->p1];
memAboutToChange(p, pIn1);
sqlcipher_sqlite3VdbeMemIntegerify(pIn1);
- pIn1->u.i += pOp->p2;
+ *(u64*)&pIn1->u.i += (u64)pOp->p2;
break;
}
@@ -90668,7 +95554,7 @@ case OP_AddImm: { /* in1 */
** without data loss, then jump immediately to P2, or if P2==0
** raise an SQLITE_MISMATCH exception.
*/
-case OP_MustBeInt: { /* jump, in1 */
+case OP_MustBeInt: { /* jump0, in1 */
pIn1 = &aMem[pOp->p1];
if( (pIn1->flags & MEM_Int)==0 ){
applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
@@ -90709,7 +95595,7 @@ case OP_RealAffinity: { /* in1 */
}
#endif
-#ifndef SQLITE_OMIT_CAST
+#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE)
/* Opcode: Cast P1 P2 * * *
** Synopsis: affinity(r[P1])
**
@@ -90852,7 +95738,6 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
flags1 = pIn1->flags;
flags3 = pIn3->flags;
if( (flags1 & flags3 & MEM_Int)!=0 ){
- assert( (pOp->p5 & SQLITE_AFF_MASK)!=SQLITE_AFF_TEXT || CORRUPT_DB );
/* Common case of comparison of two integers */
if( pIn3->u.i > pIn1->u.i ){
if( sqlcipher_sqlite3aGTb[pOp->opcode] ){
@@ -90860,18 +95745,21 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
goto jump_to_p2;
}
iCompare = +1;
+ VVA_ONLY( iCompareIsInit = 1; )
}else if( pIn3->u.i < pIn1->u.i ){
if( sqlcipher_sqlite3aLTb[pOp->opcode] ){
VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
goto jump_to_p2;
}
iCompare = -1;
+ VVA_ONLY( iCompareIsInit = 1; )
}else{
if( sqlcipher_sqlite3aEQb[pOp->opcode] ){
VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
goto jump_to_p2;
}
iCompare = 0;
+ VVA_ONLY( iCompareIsInit = 1; )
}
VdbeBranchTaken(0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
break;
@@ -90903,6 +95791,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
goto jump_to_p2;
}
iCompare = 1; /* Operands are not equal */
+ VVA_ONLY( iCompareIsInit = 1; )
break;
}
}else{
@@ -90913,24 +95802,28 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
if( (flags1 | flags3)&MEM_Str ){
if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn1,0);
- testcase( flags3==pIn3->flags );
+ assert( flags3==pIn3->flags || CORRUPT_DB );
flags3 = pIn3->flags;
}
if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn3,0);
}
}
- }else if( affinity==SQLITE_AFF_TEXT ){
- if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
+ }else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){
+ if( (flags1 & MEM_Str)!=0 ){
+ pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
+ }else if( (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn1->flags & MEM_Int );
testcase( pIn1->flags & MEM_Real );
testcase( pIn1->flags & MEM_IntReal );
sqlcipher_sqlite3VdbeMemStringify(pIn1, encoding, 1);
testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
- if( pIn1==pIn3 ) flags3 = flags1 | MEM_Str;
+ if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str;
}
- if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
+ if( (flags3 & MEM_Str)!=0 ){
+ pIn3->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
+ }else if( (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn3->flags & MEM_Int );
testcase( pIn3->flags & MEM_Real );
testcase( pIn3->flags & MEM_IntReal );
@@ -90959,6 +95852,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
res2 = sqlcipher_sqlite3aGTb[pOp->opcode];
}
iCompare = res;
+ VVA_ONLY( iCompareIsInit = 1; )
/* Undo any changes made by applyAffinity() to the input registers. */
assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
@@ -90980,10 +95874,10 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** opcodes are allowed to occur between this instruction and the previous
** OP_Lt or OP_Gt.
**
-** If result of an OP_Eq comparison on the same two operands as the
-** prior OP_Lt or OP_Gt would have been true, then jump to P2.
-** If the result of an OP_Eq comparison on the two previous
-** operands would have been false or NULL, then fall through.
+** If the result of an OP_Eq comparison on the same two operands as
+** the prior OP_Lt or OP_Gt would have been true, then jump to P2. If
+** the result of an OP_Eq comparison on the two previous operands
+** would have been false or NULL, then fall through.
*/
case OP_ElseEq: { /* same as TK_ESCAPE, jump */
@@ -90997,6 +95891,7 @@ case OP_ElseEq: { /* same as TK_ESCAPE, jump */
break;
}
#endif /* SQLITE_DEBUG */
+ assert( iCompareIsInit );
VdbeBranchTaken(iCompare==0, 2);
if( iCompare==0 ) goto jump_to_p2;
break;
@@ -91091,6 +95986,7 @@ case OP_Compare: {
pColl = pKeyInfo->aColl[i];
bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC);
iCompare = sqlcipher_sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
+ VVA_ONLY( iCompareIsInit = 1; )
if( iCompare ){
if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL)
&& ((aMem[p1+idx].flags & MEM_Null) || (aMem[p2+idx].flags & MEM_Null))
@@ -91108,13 +96004,14 @@ case OP_Compare: {
/* Opcode: Jump P1 P2 P3 * *
**
** Jump to the instruction at address P1, P2, or P3 depending on whether
-** in the most recent OP_Compare instruction the P1 vector was less than
+** in the most recent OP_Compare instruction the P1 vector was less than,
** equal to, or greater than the P2 vector, respectively.
**
** This opcode must immediately follow an OP_Compare opcode.
*/
case OP_Jump: { /* jump */
assert( pOp>aOp && pOp[-1].opcode==OP_Compare );
+ assert( iCompareIsInit );
if( iCompare<0 ){
VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1];
}else if( iCompare==0 ){
@@ -91314,26 +96211,103 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
break;
}
-/* Opcode: IsNullOrType P1 P2 P3 * *
-** Synopsis: if typeof(r[P1]) IN (P3,5) goto P2
+/* Opcode: IsType P1 P2 P3 P4 P5
+** Synopsis: if typeof(P1.P3) in P5 goto P2
+**
+** Jump to P2 if the type of a column in a btree is one of the types specified
+** by the P5 bitmask.
+**
+** P1 is normally a cursor on a btree for which the row decode cache is
+** valid through at least column P3. In other words, there should have been
+** a prior OP_Column for column P3 or greater. If the cursor is not valid,
+** then this opcode might give spurious results.
+** The the btree row has fewer than P3 columns, then use P4 as the
+** datatype.
+**
+** If P1 is -1, then P3 is a register number and the datatype is taken
+** from the value in that register.
+**
+** P5 is a bitmask of data types. SQLITE_INTEGER is the least significant
+** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04.
+** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10.
+**
+** WARNING: This opcode does not reliably distinguish between NULL and REAL
+** when P1>=0. If the database contains a NaN value, this opcode will think
+** that the datatype is REAL when it should be NULL. When P1<0 and the value
+** is already stored in register P3, then this opcode does reliably
+** distinguish between NULL and REAL. The problem only arises then P1>=0.
+**
+** Take the jump to address P2 if and only if the datatype of the
+** value determined by P1 and P3 corresponds to one of the bits in the
+** P5 bitmask.
**
-** Jump to P2 if the value in register P1 is NULL or has a datatype P3.
-** P3 is an integer which should be one of SQLITE_INTEGER, SQLITE_FLOAT,
-** SQLITE_BLOB, SQLITE_NULL, or SQLITE_TEXT.
*/
-case OP_IsNullOrType: { /* jump, in1 */
- int doTheJump;
- pIn1 = &aMem[pOp->p1];
- doTheJump = (pIn1->flags & MEM_Null)!=0 || sqlcipher_sqlite3_value_type(pIn1)==pOp->p3;
- VdbeBranchTaken( doTheJump, 2);
- if( doTheJump ) goto jump_to_p2;
+case OP_IsType: { /* jump */
+ VdbeCursor *pC;
+ u16 typeMask;
+ u32 serialType;
+
+ assert( pOp->p1>=(-1) && pOp->p1<p->nCursor );
+ assert( pOp->p1>=0 || (pOp->p3>=0 && pOp->p3<=(p->nMem+1 - p->nCursor)) );
+ if( pOp->p1>=0 ){
+ pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
+ assert( pOp->p3>=0 );
+ if( pOp->p3<pC->nHdrParsed ){
+ serialType = pC->aType[pOp->p3];
+ if( serialType>=12 ){
+ if( serialType&1 ){
+ typeMask = 0x04; /* SQLITE_TEXT */
+ }else{
+ typeMask = 0x08; /* SQLITE_BLOB */
+ }
+ }else{
+ static const unsigned char aMask[] = {
+ 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2,
+ 0x01, 0x01, 0x10, 0x10
+ };
+ testcase( serialType==0 );
+ testcase( serialType==1 );
+ testcase( serialType==2 );
+ testcase( serialType==3 );
+ testcase( serialType==4 );
+ testcase( serialType==5 );
+ testcase( serialType==6 );
+ testcase( serialType==7 );
+ testcase( serialType==8 );
+ testcase( serialType==9 );
+ testcase( serialType==10 );
+ testcase( serialType==11 );
+ typeMask = aMask[serialType];
+ }
+ }else{
+ typeMask = 1 << (pOp->p4.i - 1);
+ testcase( typeMask==0x01 );
+ testcase( typeMask==0x02 );
+ testcase( typeMask==0x04 );
+ testcase( typeMask==0x08 );
+ testcase( typeMask==0x10 );
+ }
+ }else{
+ assert( memIsValid(&aMem[pOp->p3]) );
+ typeMask = 1 << (sqlcipher_sqlite3_value_type((sqlcipher_sqlite3_value*)&aMem[pOp->p3])-1);
+ testcase( typeMask==0x01 );
+ testcase( typeMask==0x02 );
+ testcase( typeMask==0x04 );
+ testcase( typeMask==0x08 );
+ testcase( typeMask==0x10 );
+ }
+ VdbeBranchTaken( (typeMask & pOp->p5)!=0, 2);
+ if( typeMask & pOp->p5 ){
+ goto jump_to_p2;
+ }
break;
}
/* Opcode: ZeroOrNull P1 P2 P3 * *
** Synopsis: r[P2] = 0 OR NULL
**
-** If all both registers P1 and P3 are NOT NULL, then store a zero in
+** If both registers P1 and P3 are NOT NULL, then store a zero in
** register P2. If either registers P1 or P3 are NULL then put
** a NULL in register P2.
*/
@@ -91369,11 +96343,14 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
** If it is, then set register P3 to NULL and jump immediately to P2.
** If P1 is not on a NULL row, then fall through without making any
** changes.
+**
+** If P1 is not an open cursor, then this opcode is a no-op.
*/
case OP_IfNullRow: { /* jump */
+ VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( p->apCsr[pOp->p1]!=0 );
- if( p->apCsr[pOp->p1]->nullRow ){
+ pC = p->apCsr[pOp->p1];
+ if( pC && pC->nullRow ){
sqlcipher_sqlite3VdbeMemSetNull(aMem + pOp->p3);
goto jump_to_p2;
}
@@ -91424,7 +96401,7 @@ case OP_Offset: { /* out3 */
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
** information about the format of the data.) Extract the P2-th column
-** from this record. If there are less that (P2+1)
+** from this record. If there are less than (P2+1)
** values in the record, extract a NULL.
**
** The value extracted is stored in register P3.
@@ -91433,12 +96410,14 @@ case OP_Offset: { /* out3 */
** if the P4 argument is a P4_MEM use the value of the P4 argument as
** the result.
**
-** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then
-** 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().
+** If the OPFLAG_LENGTHARG bit is set in P5 then the result is guaranteed
+** to only be used by the length() function or the equivalent. The content
+** of large blobs is not loaded, thus saving CPU cycles. If the
+** OPFLAG_TYPEOFARG bit is set then the result will only be used by the
+** typeof() function or the IS NULL or IS NOT NULL operators or the
+** equivalent. In this case, all content loading can be omitted.
*/
-case OP_Column: {
+case OP_Column: { /* ncycle */
u32 p2; /* column number to retrieve */
VdbeCursor *pC; /* The VDBE cursor */
BtCursor *pCrsr; /* The B-Tree cursor corresponding to pC */
@@ -91682,11 +96661,16 @@ op_column_restart:
pDest->flags = aFlag[t&1];
}
}else{
+ u8 p5;
pDest->enc = encoding;
+ assert( pDest->db==db );
/* This branch happens only when content is on overflow pages */
- if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
- && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
- || (len = sqlcipher_sqlite3VdbeSerialTypeLen(t))==0
+ if( ((p5 = (pOp->p5 & OPFLAG_BYTELENARG))!=0
+ && (p5==OPFLAG_TYPEOFARG
+ || (t>=12 && ((t&1)==0 || p5==OPFLAG_BYTELENARG))
+ )
+ )
+ || sqlcipher_sqlite3VdbeSerialTypeLen(t)==0
){
/* Content is irrelevant for
** 1. the typeof() function,
@@ -91703,11 +96687,13 @@ op_column_restart:
*/
sqlcipher_sqlite3VdbeSerialGet((u8*)sqlcipher_sqlite3CtypeMap, t, pDest);
}else{
- if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) goto too_big;
- rc = sqlcipher_sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
- sqlcipher_sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
- pDest->flags &= ~MEM_Ephem;
+ rc = vdbeColumnFromOverflow(pC, p2, t, aOffset[p2],
+ p->cacheCtr, colCacheCtr, pDest);
+ if( rc ){
+ if( rc==SQLITE_NOMEM ) goto no_mem;
+ if( rc==SQLITE_TOOBIG ) goto too_big;
+ goto abort_due_to_error;
+ }
}
}
@@ -91787,7 +96773,7 @@ case OP_TypeCheck: {
}
case COLTYPE_REAL: {
testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_Real );
- testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_IntReal );
+ assert( (pIn1->flags & MEM_IntReal)==0 );
if( pIn1->flags & MEM_Int ){
/* When applying REAL affinity, if the result is still an MEM_Int
** that will fit in 6 bytes, then change the type to MEM_IntReal
@@ -91866,7 +96852,7 @@ case OP_Affinity: {
}else{
pIn1->u.r = (double)pIn1->u.i;
pIn1->flags |= MEM_Real;
- pIn1->flags &= ~MEM_Int;
+ pIn1->flags &= ~(MEM_Int|MEM_Str);
}
}
REGISTER_TRACE((int)(pIn1-aMem), pIn1);
@@ -92169,7 +97155,6 @@ case OP_MakeRecord: {
/* NULL value. No change in zPayload */
}else{
u64 v;
- u32 i;
if( serial_type==7 ){
assert( sizeof(v)==sizeof(pRec->u.r) );
memcpy(&v, &pRec->u.r, sizeof(v));
@@ -92177,12 +97162,22 @@ case OP_MakeRecord: {
}else{
v = pRec->u.i;
}
- len = i = sqlcipher_sqlite3SmallTypeSizes[serial_type];
- assert( i>0 );
- while( 1 /*exit-by-break*/ ){
- zPayload[--i] = (u8)(v&0xFF);
- if( i==0 ) break;
- v >>= 8;
+ len = sqlcipher_sqlite3SmallTypeSizes[serial_type];
+ assert( len>=1 && len<=8 && len!=5 && len!=7 );
+ switch( len ){
+ default: zPayload[7] = (u8)(v&0xff); v >>= 8;
+ zPayload[6] = (u8)(v&0xff); v >>= 8;
+ /* no break */ deliberate_fall_through
+ case 6: zPayload[5] = (u8)(v&0xff); v >>= 8;
+ zPayload[4] = (u8)(v&0xff); v >>= 8;
+ /* no break */ deliberate_fall_through
+ case 4: zPayload[3] = (u8)(v&0xff); v >>= 8;
+ /* no break */ deliberate_fall_through
+ case 3: zPayload[2] = (u8)(v&0xff); v >>= 8;
+ /* no break */ deliberate_fall_through
+ case 2: zPayload[1] = (u8)(v&0xff); v >>= 8;
+ /* no break */ deliberate_fall_through
+ case 1: zPayload[0] = (u8)(v&0xff);
}
zPayload += len;
}
@@ -92790,7 +97785,7 @@ case OP_SetCookie: {
**
** See also: OP_OpenRead, OP_ReopenIdx
*/
-case OP_ReopenIdx: {
+case OP_ReopenIdx: { /* ncycle */
int nField;
KeyInfo *pKeyInfo;
u32 p2;
@@ -92811,7 +97806,7 @@ case OP_ReopenIdx: {
}
/* If the cursor is not currently open or is open on a different
** index, then fall through into OP_OpenRead to force a reopen */
-case OP_OpenRead:
+case OP_OpenRead: /* ncycle */
case OP_OpenWrite:
assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
@@ -92905,7 +97900,7 @@ open_cursor_set_hints:
**
** Duplicate ephemeral cursors are used for self-joins of materialized views.
*/
-case OP_OpenDup: {
+case OP_OpenDup: { /* ncycle */
VdbeCursor *pOrig; /* The original cursor to be duplicated */
VdbeCursor *pCx; /* The new cursor */
@@ -92967,8 +97962,8 @@ case OP_OpenDup: {
** by this opcode will be used for automatically created transient
** indices in joins.
*/
-case OP_OpenAutoindex:
-case OP_OpenEphemeral: {
+case OP_OpenAutoindex: /* ncycle */
+case OP_OpenEphemeral: { /* ncycle */
VdbeCursor *pCx;
KeyInfo *pKeyInfo;
@@ -92991,7 +97986,7 @@ case OP_OpenEphemeral: {
}
pCx = p->apCsr[pOp->p1];
if( pCx && !pCx->noReuse && ALWAYS(pOp->p2<=pCx->nField) ){
- /* If the ephermeral table is already open and has no duplicates from
+ /* If the ephemeral table is already open and has no duplicates from
** OP_OpenDup, then erase all existing content so that the table is
** empty again, rather than creating a new table. */
assert( pCx->isEphemeral );
@@ -93100,7 +98095,8 @@ case OP_SequenceTest: {
** is the only cursor opcode that works with a pseudo-table.
**
** P3 is the number of fields in the records that will be stored by
-** the pseudo-table.
+** the pseudo-table. If P2 is 0 or negative then the pseudo-cursor
+** will return NULL for every column.
*/
case OP_OpenPseudo: {
VdbeCursor *pCx;
@@ -93126,7 +98122,7 @@ case OP_OpenPseudo: {
** Close a cursor previously opened as P1. If P1 is not
** currently open, this instruction is a no-op.
*/
-case OP_Close: {
+case OP_Close: { /* ncycle */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
sqlcipher_sqlite3VdbeFreeCursor(p, p->apCsr[pOp->p1]);
p->apCsr[pOp->p1] = 0;
@@ -93243,10 +98239,10 @@ case OP_ColumnsUsed: {
**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
*/
-case OP_SeekLT: /* jump, in3, group */
-case OP_SeekLE: /* jump, in3, group */
-case OP_SeekGE: /* jump, in3, group */
-case OP_SeekGT: { /* jump, in3, group */
+case OP_SeekLT: /* jump0, in3, group, ncycle */
+case OP_SeekLE: /* jump0, in3, group, ncycle */
+case OP_SeekGE: /* jump0, in3, group, ncycle */
+case OP_SeekGT: { /* jump0, in3, group, ncycle */
int res; /* Comparison result */
int oc; /* Opcode */
VdbeCursor *pC; /* The cursor to seek */
@@ -93375,7 +98371,13 @@ case OP_SeekGT: { /* jump, in3, group */
r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
+ {
+ int i;
+ for(i=0; i<r.nField; i++){
+ assert( memIsValid(&r.aMem[i]) );
+ if( i>0 ) REGISTER_TRACE(pOp->p3+i, &r.aMem[i]);
+ }
+ }
#endif
r.eqSeen = 0;
rc = sqlcipher_sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res);
@@ -93438,7 +98440,7 @@ seek_not_found:
}
-/* Opcode: SeekScan P1 P2 * * *
+/* Opcode: SeekScan P1 P2 * * P5
** Synopsis: Scan-ahead up to P1 rows
**
** This opcode is a prefix opcode to OP_SeekGE. In other words, this
@@ -93448,8 +98450,8 @@ seek_not_found:
** This opcode uses the P1 through P4 operands of the subsequent
** OP_SeekGE. In the text that follows, the operands of the subsequent
** OP_SeekGE opcode are denoted as SeekOP.P1 through SeekOP.P4. Only
-** the P1 and P2 operands of this opcode are also used, and are called
-** This.P1 and This.P2.
+** the P1, P2 and P5 operands of this opcode are also used, and are called
+** This.P1, This.P2 and This.P5.
**
** This opcode helps to optimize IN operators on a multi-column index
** where the IN operator is on the later terms of the index by avoiding
@@ -93459,32 +98461,54 @@ seek_not_found:
**
** The SeekGE.P3 and SeekGE.P4 operands identify an unpacked key which
** is the desired entry that we want the cursor SeekGE.P1 to be pointing
-** to. Call this SeekGE.P4/P5 row the "target".
+** to. Call this SeekGE.P3/P4 row the "target".
**
** If the SeekGE.P1 cursor is not currently pointing to a valid row,
** then this opcode is a no-op and control passes through into the OP_SeekGE.
**
** If the SeekGE.P1 cursor is pointing to a valid row, then that row
** might be the target row, or it might be near and slightly before the
-** target row. This opcode attempts to position the cursor on the target
-** row by, perhaps by invoking sqlcipher_sqlite3BtreeStep() on the cursor
-** between 0 and This.P1 times.
-**
-** There are three possible outcomes from this opcode:<ol>
-**
-** <li> If after This.P1 steps, the cursor is still pointing to a place that
-** is earlier in the btree than the target row, then fall through
-** into the subsquence OP_SeekGE opcode.
-**
-** <li> If the cursor is successfully moved to the target row by 0 or more
-** sqlcipher_sqlite3BtreeNext() calls, then jump to This.P2, which will land just
-** past the OP_IdxGT or OP_IdxGE opcode that follows the OP_SeekGE.
-**
-** <li> If the cursor ends up past the target row (indicating the the target
-** row does not exist in the btree) then jump to SeekOP.P2.
+** target row, or it might be after the target row. If the cursor is
+** currently before the target row, then this opcode attempts to position
+** the cursor on or after the target row by invoking sqlcipher_sqlite3BtreeStep()
+** on the cursor between 1 and This.P1 times.
+**
+** The This.P5 parameter is a flag that indicates what to do if the
+** cursor ends up pointing at a valid row that is past the target
+** row. If This.P5 is false (0) then a jump is made to SeekGE.P2. If
+** This.P5 is true (non-zero) then a jump is made to This.P2. The P5==0
+** case occurs when there are no inequality constraints to the right of
+** the IN constraint. The jump to SeekGE.P2 ends the loop. The P5!=0 case
+** occurs when there are inequality constraints to the right of the IN
+** operator. In that case, the This.P2 will point either directly to or
+** to setup code prior to the OP_IdxGT or OP_IdxGE opcode that checks for
+** loop terminate.
+**
+** Possible outcomes from this opcode:<ol>
+**
+** <li> If the cursor is initially not pointed to any valid row, then
+** fall through into the subsequent OP_SeekGE opcode.
+**
+** <li> If the cursor is left pointing to a row that is before the target
+** row, even after making as many as This.P1 calls to
+** sqlcipher_sqlite3BtreeNext(), then also fall through into OP_SeekGE.
+**
+** <li> If the cursor is left pointing at the target row, either because it
+** was at the target row to begin with or because one or more
+** sqlcipher_sqlite3BtreeNext() calls moved the cursor to the target row,
+** then jump to This.P2..,
+**
+** <li> If the cursor started out before the target row and a call to
+** to sqlcipher_sqlite3BtreeNext() moved the cursor off the end of the index
+** (indicating that the target row definitely does not exist in the
+** btree) then jump to SeekGE.P2, ending the loop.
+**
+** <li> If the cursor ends up on a valid row that is past the target row
+** (indicating that the target row does not exist in the btree) then
+** jump to SeekOP.P2 if This.P5==0 or to This.P2 if This.P5>0.
** </ol>
*/
-case OP_SeekScan: {
+case OP_SeekScan: { /* ncycle */
VdbeCursor *pC;
int res;
int nStep;
@@ -93492,14 +98516,25 @@ case OP_SeekScan: {
assert( pOp[1].opcode==OP_SeekGE );
- /* pOp->p2 points to the first instruction past the OP_IdxGT that
- ** follows the OP_SeekGE. */
+ /* If pOp->p5 is clear, then pOp->p2 points to the first instruction past the
+ ** OP_IdxGT that follows the OP_SeekGE. Otherwise, it points to the first
+ ** opcode past the OP_SeekGE itself. */
assert( pOp->p2>=(int)(pOp-aOp)+2 );
- assert( aOp[pOp->p2-1].opcode==OP_IdxGT || aOp[pOp->p2-1].opcode==OP_IdxGE );
- testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
- assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
- assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
- assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
+#ifdef SQLITE_DEBUG
+ if( pOp->p5==0 ){
+ /* There are no inequality constraints following the IN constraint. */
+ assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
+ assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
+ assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
+ assert( aOp[pOp->p2-1].opcode==OP_IdxGT
+ || aOp[pOp->p2-1].opcode==OP_IdxGE );
+ testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
+ }else{
+ /* There are inequality constraints. */
+ assert( pOp->p2==(int)(pOp-aOp)+2 );
+ assert( aOp[pOp->p2-1].opcode==OP_SeekGE );
+ }
+#endif
assert( pOp->p1>0 );
pC = p->apCsr[pOp[1].p1];
@@ -93533,8 +98568,9 @@ case OP_SeekScan: {
while(1){
rc = sqlcipher_sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
if( rc ) goto abort_due_to_error;
- if( res>0 ){
+ if( res>0 && pOp->p5==0 ){
seekscan_search_fail:
+ /* Jump to SeekGE.P2, ending the loop */
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... %d steps and then skip\n", pOp->p1 - nStep);
@@ -93544,7 +98580,8 @@ case OP_SeekScan: {
pOp++;
goto jump_to_p2;
}
- if( res==0 ){
+ if( res>=0 ){
+ /* Jump to This.P2, bypassing the OP_SeekGE opcode */
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... %d steps and then success\n", pOp->p1 - nStep);
@@ -93564,6 +98601,7 @@ case OP_SeekScan: {
break;
}
nStep--;
+ pC->cacheStatus = CACHE_STALE;
rc = sqlcipher_sqlite3BtreeNext(pC->uc.pCursor, 0);
if( rc ){
if( rc==SQLITE_DONE ){
@@ -93593,7 +98631,7 @@ case OP_SeekScan: {
**
** P1 must be a valid b-tree cursor.
*/
-case OP_SeekHit: {
+case OP_SeekHit: { /* ncycle */
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
@@ -93620,12 +98658,16 @@ case OP_SeekHit: {
/* Opcode: IfNotOpen P1 P2 * * *
** Synopsis: if( !csr[P1] ) goto P2
**
-** If cursor P1 is not open, jump to instruction P2. Otherwise, fall through.
+** If cursor P1 is not open or if P1 is set to a NULL row using the
+** OP_NullRow opcode, then jump to instruction P2. Otherwise, fall through.
*/
case OP_IfNotOpen: { /* jump */
+ VdbeCursor *pCur;
+
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- VdbeBranchTaken(p->apCsr[pOp->p1]==0, 2);
- if( !p->apCsr[pOp->p1] ){
+ pCur = p->apCsr[pOp->p1];
+ VdbeBranchTaken(pCur==0 || pCur->nullRow, 2);
+ if( pCur==0 || pCur->nullRow ){
goto jump_to_p2_and_check_for_interrupt;
}
break;
@@ -93676,13 +98718,13 @@ case OP_IfNotOpen: { /* jump */
** operands to OP_NotFound and OP_IdxGT.
**
** This opcode is an optimization attempt only. If this opcode always
-** falls through, the correct answer is still obtained, but extra works
+** falls through, the correct answer is still obtained, but extra work
** is performed.
**
** A value of N in the seekHit flag of cursor P1 means that there exists
** a key P3:N that will match some record in the index. We want to know
** if it is possible for a record P3:P4 to match some record in the
-** index. If it is not possible, we can skips some work. So if seekHit
+** index. If it is not possible, we can skip some work. So if seekHit
** is less than P4, attempt to find out if a match is possible by running
** OP_NotFound.
**
@@ -93721,7 +98763,7 @@ case OP_IfNotOpen: { /* jump */
**
** See also: NotFound, Found, NotExists
*/
-case OP_IfNoHope: { /* jump, in3 */
+case OP_IfNoHope: { /* jump, in3, ncycle */
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
@@ -93735,9 +98777,9 @@ case OP_IfNoHope: { /* jump, in3 */
/* Fall through into OP_NotFound */
/* no break */ deliberate_fall_through
}
-case OP_NoConflict: /* jump, in3 */
-case OP_NotFound: /* jump, in3 */
-case OP_Found: { /* jump, in3 */
+case OP_NoConflict: /* jump, in3, ncycle */
+case OP_NotFound: /* jump, in3, ncycle */
+case OP_Found: { /* jump, in3, ncycle */
int alreadyExists;
int ii;
VdbeCursor *pC;
@@ -93867,7 +98909,7 @@ case OP_Found: { /* jump, in3 */
**
** See also: Found, NotFound, NoConflict, SeekRowid
*/
-case OP_SeekRowid: { /* jump, in3 */
+case OP_SeekRowid: { /* jump0, in3, ncycle */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
@@ -93892,7 +98934,7 @@ case OP_SeekRowid: { /* jump, in3 */
}
/* Fall through into OP_NotExists */
/* no break */ deliberate_fall_through
-case OP_NotExists: /* jump, in3 */
+case OP_NotExists: /* jump, in3, ncycle */
pIn3 = &aMem[pOp->p3];
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
@@ -94172,8 +99214,11 @@ case OP_Insert: {
if( pOp->p5 & OPFLAG_ISNOOP ) break;
#endif
- if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
- if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
+ assert( (pOp->p5 & OPFLAG_LASTROWID)==0 || (pOp->p5 & OPFLAG_NCHANGE)!=0 );
+ if( pOp->p5 & OPFLAG_NCHANGE ){
+ p->nChange++;
+ if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
+ }
assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 );
x.pData = pData->z;
x.nData = pData->n;
@@ -94184,12 +99229,14 @@ case OP_Insert: {
x.nZero = 0;
}
x.pKey = 0;
+ assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT );
rc = sqlcipher_sqlite3BtreeInsert(pC->uc.pCursor, &x,
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
seekResult
);
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
+ colCacheCtr++;
/* Invoke the update-hook if required. */
if( rc ) goto abort_due_to_error;
@@ -94243,13 +99290,18 @@ case OP_RowCell: {
** left in an undefined state.
**
** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this
-** delete one of several associated with deleting a table row and all its
-** associated index entries. Exactly one of those deletes is the "primary"
-** delete. The others are all on OPFLAG_FORDELETE cursors or else are
-** marked with the AUXDELETE flag.
+** delete is one of several associated with deleting a table row and
+** all its associated index entries. Exactly one of those deletes is
+** the "primary" delete. The others are all on OPFLAG_FORDELETE
+** cursors or else are marked with the AUXDELETE flag.
+**
+** If the OPFLAG_NCHANGE (0x01) flag of P2 (NB: P2 not P5) is set, then
+** the row change count is incremented (otherwise not).
**
-** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row
-** change count is incremented (otherwise not).
+** If the OPFLAG_ISNOOP (0x40) flag of P2 (not P5!) is set, then the
+** pre-update-hook for deletes is run, but the btree is otherwise unchanged.
+** This happens when the OP_Delete is to be shortly followed by an OP_Insert
+** with the same key, causing the btree entry to be overwritten.
**
** P1 must not be pseudo-table. It has to be a real table with
** multiple rows.
@@ -94350,6 +99402,7 @@ case OP_Delete: {
rc = sqlcipher_sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
pC->cacheStatus = CACHE_STALE;
+ colCacheCtr++;
pC->seekResult = 0;
if( rc ) goto abort_due_to_error;
@@ -94417,13 +99470,13 @@ case OP_SorterCompare: {
** Write into register P2 the current sorter data for sorter cursor P1.
** Then clear the column header cache on cursor P3.
**
-** This opcode is normally use to move a record out of the sorter and into
+** This opcode is normally used to move a record out of the sorter and into
** a register that is the source for a pseudo-table cursor created using
** OpenPseudo. That pseudo-table cursor is the one that is identified by
** parameter P3. Clearing the P3 column cache as part of this opcode saves
** us from having to issue a separate NullRow instruction to clear that cache.
*/
-case OP_SorterData: {
+case OP_SorterData: { /* ncycle */
VdbeCursor *pC;
pOut = &aMem[pOp->p2];
@@ -94515,7 +99568,7 @@ case OP_RowData: {
** be a separate OP_VRowid opcode for use with virtual tables, but this
** one opcode now works for both table types.
*/
-case OP_Rowid: { /* out2 */
+case OP_Rowid: { /* out2, ncycle */
VdbeCursor *pC;
i64 v;
sqlcipher_sqlite3_vtab *pVtab;
@@ -94614,8 +99667,8 @@ case OP_NullRow: {
** from the end toward the beginning. In other words, the cursor is
** configured to use Prev, not Next.
*/
-case OP_SeekEnd:
-case OP_Last: { /* jump */
+case OP_SeekEnd: /* ncycle */
+case OP_Last: { /* jump0, ncycle */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
@@ -94649,28 +99702,38 @@ case OP_Last: { /* jump */
break;
}
-/* Opcode: IfSmaller P1 P2 P3 * *
+/* Opcode: IfSizeBetween P1 P2 P3 P4 *
**
-** Estimate the number of rows in the table P1. Jump to P2 if that
-** estimate is less than approximately 2**(0.1*P3).
+** Let N be the approximate number of rows in the table or index
+** with cursor P1 and let X be 10*log2(N) if N is positive or -1
+** if N is zero.
+**
+** Jump to P2 if X is in between P3 and P4, inclusive.
*/
-case OP_IfSmaller: { /* jump */
+case OP_IfSizeBetween: { /* jump */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
i64 sz;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ assert( pOp->p4type==P4_INT32 );
+ assert( pOp->p3>=-1 && pOp->p3<=640*2 );
+ assert( pOp->p4.i>=-1 && pOp->p4.i<=640*2 );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
pCrsr = pC->uc.pCursor;
assert( pCrsr );
rc = sqlcipher_sqlite3BtreeFirst(pCrsr, &res);
if( rc ) goto abort_due_to_error;
- if( res==0 ){
+ if( res!=0 ){
+ sz = -1; /* -Infinity encoding */
+ }else{
sz = sqlcipher_sqlite3BtreeRowCountEst(pCrsr);
- if( ALWAYS(sz>=0) && sqlcipher_sqlite3LogEst((u64)sz)<pOp->p3 ) res = 1;
+ assert( sz>0 );
+ sz = sqlcipher_sqlite3LogEst((u64)sz);
}
+ res = sz>=pOp->p3 && sz<=pOp->p4.i;
VdbeBranchTaken(res!=0,2);
if( res ) goto jump_to_p2;
break;
@@ -94698,8 +99761,8 @@ case OP_IfSmaller: { /* jump */
** regression tests can determine whether or not the optimizer is
** correctly optimizing out sorts.
*/
-case OP_SorterSort: /* jump */
-case OP_Sort: { /* jump */
+case OP_SorterSort: /* jump ncycle */
+case OP_Sort: { /* jump ncycle */
#ifdef SQLITE_TEST
sqlcipher_sqlite3_sort_count++;
sqlcipher_sqlite3_search_count--;
@@ -94716,17 +99779,22 @@ case OP_Sort: { /* jump */
** If the table or index is not empty, fall through to the following
** instruction.
**
+** If P2 is zero, that is an assertion that the P1 table is never
+** empty and hence the jump will never be taken.
+**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end. In other words, the cursor is
** configured to use Next, not Prev.
*/
-case OP_Rewind: { /* jump */
+case OP_Rewind: { /* jump0, ncycle */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5==0 );
+ assert( pOp->p2>=0 && pOp->p2<p->nOp );
+
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
@@ -94746,9 +99814,10 @@ case OP_Rewind: { /* jump */
}
if( rc ) goto abort_due_to_error;
pC->nullRow = (u8)res;
- assert( pOp->p2>0 && pOp->p2<p->nOp );
- VdbeBranchTaken(res!=0,2);
- if( res ) goto jump_to_p2;
+ if( pOp->p2>0 ){
+ VdbeBranchTaken(res!=0,2);
+ if( res ) goto jump_to_p2;
+ }
break;
}
@@ -94814,9 +99883,11 @@ case OP_SorterNext: { /* jump */
rc = sqlcipher_sqlite3VdbeSorterNext(db, pC);
goto next_tail;
-case OP_Prev: /* jump */
+case OP_Prev: /* jump, ncycle */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( pOp->p5<ArraySize(p->aCounter) );
+ assert( pOp->p5==0
+ || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP
+ || pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX);
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
@@ -94827,9 +99898,11 @@ case OP_Prev: /* jump */
rc = sqlcipher_sqlite3BtreePrevious(pC->uc.pCursor, pOp->p3);
goto next_tail;
-case OP_Next: /* jump */
+case OP_Next: /* jump, ncycle */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( pOp->p5<ArraySize(p->aCounter) );
+ assert( pOp->p5==0
+ || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP
+ || pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX);
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
@@ -95017,8 +100090,8 @@ case OP_IdxDelete: {
**
** See also: Rowid, MakeRecord.
*/
-case OP_DeferredSeek:
-case OP_IdxRowid: { /* out2 */
+case OP_DeferredSeek: /* ncycle */
+case OP_IdxRowid: { /* out2, ncycle */
VdbeCursor *pC; /* The P1 index cursor */
VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */
i64 rowid; /* Rowid that P1 current points to */
@@ -95036,10 +100109,10 @@ case OP_IdxRowid: { /* out2 */
** of sqlcipher_sqlite3VdbeCursorRestore() and sqlcipher_sqlite3VdbeIdxRowid(). */
rc = sqlcipher_sqlite3VdbeCursorRestore(pC);
- /* sqlcipher_sqlite3VbeCursorRestore() can only fail if the record has been deleted
- ** out from under the cursor. That will never happens for an IdxRowid
- ** or Seek opcode */
- if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
+ /* sqlcipher_sqlite3VdbeCursorRestore() may fail if the cursor has been disturbed
+ ** since it was last positioned and an error (e.g. OOM or an IO error)
+ ** occurs while trying to reposition it. */
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
if( !pC->nullRow ){
rowid = 0; /* Not needed. Only used to silence a warning. */
@@ -95080,8 +100153,8 @@ case OP_IdxRowid: { /* out2 */
** seek operation now, without further delay. If the cursor seek has
** already occurred, this instruction is a no-op.
*/
-case OP_FinishSeek: {
- VdbeCursor *pC; /* The P1 index cursor */
+case OP_FinishSeek: { /* ncycle */
+ VdbeCursor *pC; /* The P1 index cursor */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
@@ -95136,10 +100209,10 @@ case OP_FinishSeek: {
** If the P1 index entry is less than or equal to the key value then jump
** to P2. Otherwise fall through to the next instruction.
*/
-case OP_IdxLE: /* jump */
-case OP_IdxGT: /* jump */
-case OP_IdxLT: /* jump */
-case OP_IdxGE: { /* jump */
+case OP_IdxLE: /* jump, ncycle */
+case OP_IdxGT: /* jump, ncycle */
+case OP_IdxLT: /* jump, ncycle */
+case OP_IdxGE: { /* jump, ncycle */
VdbeCursor *pC;
int res;
UnpackedRecord r;
@@ -95216,7 +100289,7 @@ case OP_IdxGE: { /* jump */
** file is given by P1.
**
** The table being destroyed is in the main database file if P3==0. If
-** P3==1 then the table to be clear is in the auxiliary database file
+** P3==1 then the table to be destroyed is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If AUTOVACUUM is enabled then it is possible that another root page
@@ -95276,8 +100349,8 @@ case OP_Destroy: { /* out2 */
** in the database file is given by P1. But, unlike Destroy, do not
** remove the table or index from the database file.
**
-** The table being clear is in the main database file if P2==0. If
-** P2==1 then the table to be clear is in the auxiliary database file
+** The table being cleared is in the main database file if P2==0. If
+** P2==1 then the table to be cleared is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If the P3 value is non-zero, then the row change count is incremented
@@ -95360,16 +100433,57 @@ case OP_CreateBtree: { /* out2 */
break;
}
-/* Opcode: SqlExec * * * P4 *
+/* Opcode: SqlExec P1 P2 * P4 *
**
** Run the SQL statement or statements specified in the P4 string.
+**
+** The P1 parameter is a bitmask of options:
+**
+** 0x0001 Disable Auth and Trace callbacks while the statements
+** in P4 are running.
+**
+** 0x0002 Set db->nAnalysisLimit to P2 while the statements in
+** P4 are running.
+**
*/
case OP_SqlExec: {
+ char *zErr;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ sqlcipher_sqlite3_xauth xAuth;
+#endif
+ u8 mTrace;
+ int savedAnalysisLimit;
+
sqlcipher_sqlite3VdbeIncrWriteCounter(p, 0);
db->nSqlExec++;
- rc = sqlcipher_sqlite3_exec(db, pOp->p4.z, 0, 0, 0);
+ zErr = 0;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ xAuth = db->xAuth;
+#endif
+ mTrace = db->mTrace;
+ savedAnalysisLimit = db->nAnalysisLimit;
+ if( pOp->p1 & 0x0001 ){
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = 0;
+#endif
+ db->mTrace = 0;
+ }
+ if( pOp->p1 & 0x0002 ){
+ db->nAnalysisLimit = pOp->p2;
+ }
+ rc = sqlcipher_sqlite3_exec(db, pOp->p4.z, 0, 0, &zErr);
db->nSqlExec--;
- if( rc ) goto abort_due_to_error;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = xAuth;
+#endif
+ db->mTrace = mTrace;
+ db->nAnalysisLimit = savedAnalysisLimit;
+ if( zErr || rc ){
+ sqlcipher_sqlite3VdbeError(p, "%s", zErr);
+ sqlcipher_sqlite3_free(zErr);
+ if( rc==SQLITE_NOMEM ) goto no_mem;
+ goto abort_due_to_error;
+ }
break;
}
@@ -95515,11 +100629,11 @@ case OP_DropTrigger: {
/* Opcode: IntegrityCk P1 P2 P3 P4 P5
**
** Do an analysis of the currently open database. Store in
-** register P1 the text of an error message describing any problems.
-** If no problems are found, store a NULL in register P1.
+** register (P1+1) the text of an error message describing any problems.
+** If no problems are found, store a NULL in register (P1+1).
**
-** The register P3 contains one less than the maximum number of allowed errors.
-** At most reg(P3) errors will be reported.
+** The register (P1) contains one less than the maximum number of allowed
+** errors. At most reg(P1) errors will be reported.
** In other words, the analysis stops as soon as reg(P1) errors are
** seen. Reg(P1) is updated with the number of errors remaining.
**
@@ -95539,24 +100653,27 @@ case OP_IntegrityCk: {
Mem *pnErr; /* Register keeping track of errors remaining */
assert( p->bIsReader );
+ assert( pOp->p4type==P4_INTARRAY );
nRoot = pOp->p2;
aRoot = pOp->p4.ai;
assert( nRoot>0 );
+ assert( aRoot!=0 );
assert( aRoot[0]==(Pgno)nRoot );
- assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
- pnErr = &aMem[pOp->p3];
+ assert( pOp->p1>0 && (pOp->p1+1)<=(p->nMem+1 - p->nCursor) );
+ pnErr = &aMem[pOp->p1];
assert( (pnErr->flags & MEM_Int)!=0 );
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
- pIn1 = &aMem[pOp->p1];
+ pIn1 = &aMem[pOp->p1+1];
assert( pOp->p5<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p5) );
- z = sqlcipher_sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
- (int)pnErr->u.i+1, &nErr);
+ rc = sqlcipher_sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1],
+ &aMem[pOp->p3], nRoot, (int)pnErr->u.i+1, &nErr, &z);
sqlcipher_sqlite3VdbeMemSetNull(pIn1);
if( nErr==0 ){
assert( z==0 );
- }else if( z==0 ){
- goto no_mem;
+ }else if( rc ){
+ sqlcipher_sqlite3_free(z);
+ goto abort_due_to_error;
}else{
pnErr->u.i -= nErr-1;
sqlcipher_sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlcipher_sqlite3_free);
@@ -95677,7 +100794,9 @@ case OP_RowSetTest: { /* jump, in1, in3 */
** P1 contains the address of the memory cell that contains the first memory
** cell in an array of values used as arguments to the sub-program. P2
** contains the address to jump to if the sub-program throws an IGNORE
-** exception using the RAISE() function. Register P3 contains the address
+** exception using the RAISE() function. P2 might be zero, if there is
+** no possibility that an IGNORE exception will be raised.
+** Register P3 contains the address
** of a memory cell in this (the parent) VM that is used to allocate the
** memory required by the sub-vdbe at runtime.
**
@@ -95685,7 +100804,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
**
** If P5 is non-zero, then recursive program invocation is enabled.
*/
-case OP_Program: { /* jump */
+case OP_Program: { /* jump0 */
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 */
@@ -95760,9 +100879,6 @@ case OP_Program: { /* jump */
pFrame->aOp = p->aOp;
pFrame->nOp = p->nOp;
pFrame->token = pProgram->token;
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- pFrame->anExec = p->anExec;
-#endif
#ifdef SQLITE_DEBUG
pFrame->iFrameMagic = SQLITE_FRAME_MAGIC;
#endif
@@ -95799,9 +100915,6 @@ case OP_Program: { /* jump */
memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8);
p->aOp = aOp = pProgram->aOp;
p->nOp = pProgram->nOp;
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- p->anExec = 0;
-#endif
#ifdef SQLITE_DEBUG
/* Verify that second and subsequent executions of the same trigger do not
** try to reuse register values from the first use. */
@@ -95941,7 +101054,7 @@ case OP_IfPos: { /* jump, in1 */
** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)
**
** This opcode performs a commonly used computation associated with
-** LIMIT and OFFSET process. r[P1] holds the limit counter. r[P3]
+** LIMIT and OFFSET processing. r[P1] holds the limit counter. r[P3]
** holds the offset counter. The opcode computes the combined value
** of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2]
** value computed is the total number of rows that will need to be
@@ -96108,7 +101221,7 @@ case OP_AggStep1: {
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
- ** reinitializes the relavant parts of the sqlcipher_sqlite3_context object */
+ ** reinitializes the relevant parts of the sqlcipher_sqlite3_context object */
if( pCtx->pMem != pMem ){
pCtx->pMem = pMem;
for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
@@ -96203,6 +101316,7 @@ case OP_AggFinal: {
}
sqlcipher_sqlite3VdbeChangeEncoding(pMem, encoding);
UPDATE_MAX_BLOBSIZE(pMem);
+ REGISTER_TRACE((int)(pMem-aMem), pMem);
break;
}
@@ -96558,7 +101672,7 @@ case OP_VDestroy: {
** P1 is a cursor number. This opcode opens a cursor to the virtual
** table and stores that cursor in P1.
*/
-case OP_VOpen: {
+case OP_VOpen: { /* ncycle */
VdbeCursor *pCur;
sqlcipher_sqlite3_vtab_cursor *pVCur;
sqlcipher_sqlite3_vtab *pVtab;
@@ -96595,6 +101709,52 @@ case OP_VOpen: {
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VCheck P1 P2 P3 P4 *
+**
+** P4 is a pointer to a Table object that is a virtual table in schema P1
+** that supports the xIntegrity() method. This opcode runs the xIntegrity()
+** method for that virtual table, using P3 as the integer argument. If
+** an error is reported back, the table name is prepended to the error
+** message and that message is stored in P2. If no errors are seen,
+** register P2 is set to NULL.
+*/
+case OP_VCheck: { /* out2 */
+ Table *pTab;
+ sqlcipher_sqlite3_vtab *pVtab;
+ const sqlcipher_sqlite3_module *pModule;
+ char *zErr = 0;
+
+ pOut = &aMem[pOp->p2];
+ sqlcipher_sqlite3VdbeMemSetNull(pOut); /* Innocent until proven guilty */
+ assert( pOp->p4type==P4_TABLEREF );
+ pTab = pOp->p4.pTab;
+ assert( pTab!=0 );
+ assert( pTab->nTabRef>0 );
+ assert( IsVirtual(pTab) );
+ if( pTab->u.vtab.p==0 ) break;
+ pVtab = pTab->u.vtab.p->pVtab;
+ assert( pVtab!=0 );
+ pModule = pVtab->pModule;
+ assert( pModule!=0 );
+ assert( pModule->iVersion>=4 );
+ assert( pModule->xIntegrity!=0 );
+ sqlcipher_sqlite3VtabLock(pTab->u.vtab.p);
+ assert( pOp->p1>=0 && pOp->p1<db->nDb );
+ rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName,
+ pOp->p3, &zErr);
+ sqlcipher_sqlite3VtabUnlock(pTab->u.vtab.p);
+ if( rc ){
+ sqlcipher_sqlite3_free(zErr);
+ goto abort_due_to_error;
+ }
+ if( zErr ){
+ sqlcipher_sqlite3VdbeMemSetStr(pOut, zErr, -1, SQLITE_UTF8, sqlcipher_sqlite3_free);
+ }
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VInitIn P1 P2 P3 * *
** Synopsis: r[P2]=ValueList(P1,P3)
**
@@ -96605,7 +101765,7 @@ case OP_VOpen: {
** cursor. Register P3 is used to hold the values returned by
** sqlcipher_sqlite3_vtab_in_first() and sqlcipher_sqlite3_vtab_in_next().
*/
-case OP_VInitIn: { /* out2 */
+case OP_VInitIn: { /* out2, ncycle */
VdbeCursor *pC; /* The cursor containing the RHS values */
ValueList *pRhs; /* New ValueList object to put in reg[P2] */
@@ -96616,7 +101776,7 @@ case OP_VInitIn: { /* out2 */
pRhs->pOut = &aMem[pOp->p3];
pOut = out2Prerelease(p, pOp);
pOut->flags = MEM_Null;
- sqlcipher_sqlite3VdbeMemSetPointer(pOut, pRhs, "ValueList", sqlcipher_sqlite3_free);
+ sqlcipher_sqlite3VdbeMemSetPointer(pOut, pRhs, "ValueList", sqlcipher_sqlite3VdbeValueListFree);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -96642,7 +101802,7 @@ case OP_VInitIn: { /* out2 */
**
** A jump is made to P2 if the result set after filtering would be empty.
*/
-case OP_VFilter: { /* jump */
+case OP_VFilter: { /* jump, ncycle */
int nArg;
int iQuery;
const sqlcipher_sqlite3_module *pModule;
@@ -96702,11 +101862,12 @@ case OP_VFilter: { /* jump */
** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are
** unused by OP_VColumn.
*/
-case OP_VColumn: {
+case OP_VColumn: { /* ncycle */
sqlcipher_sqlite3_vtab *pVtab;
const sqlcipher_sqlite3_module *pModule;
Mem *pDest;
sqlcipher_sqlite3_context sContext;
+ FuncDef nullFunc;
VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur!=0 );
@@ -96724,6 +101885,9 @@ case OP_VColumn: {
memset(&sContext, 0, sizeof(sContext));
sContext.pOut = pDest;
sContext.enc = encoding;
+ nullFunc.pUserData = 0;
+ nullFunc.funcFlags = SQLITE_RESULT_SUBTYPE;
+ sContext.pFunc = &nullFunc;
assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 );
if( pOp->p5 & OPFLAG_NOCHNG ){
sqlcipher_sqlite3VdbeMemSetNull(pDest);
@@ -96754,7 +101918,7 @@ case OP_VColumn: {
** jump to instruction P2. Or, if the virtual table has reached
** the end of its result set, then fall through to the next instruction.
*/
-case OP_VNext: { /* jump */
+case OP_VNext: { /* jump, ncycle */
sqlcipher_sqlite3_vtab *pVtab;
const sqlcipher_sqlite3_module *pModule;
int res;
@@ -96985,7 +102149,7 @@ case OP_MaxPgcnt: { /* out2 */
** This opcode works exactly like OP_Function. The only difference is in
** its name. This opcode is used in places where the function must be
** purely non-deterministic. Some built-in date/time functions can be
-** either determinitic of non-deterministic, depending on their arguments.
+** either deterministic of non-deterministic, depending on their arguments.
** When those function are used in a non-deterministic way, they will check
** to see if they were called using OP_PureFunc instead of OP_Function, and
** if they were, they throw an error.
@@ -97003,7 +102167,7 @@ case OP_Function: { /* group */
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
- ** reinitializes the relavant parts of the sqlcipher_sqlite3_context object */
+ ** reinitializes the relevant parts of the sqlcipher_sqlite3_context object */
pOut = &aMem[pOp->p3];
if( pCtx->pOut != pOut ){
pCtx->pVdbe = p;
@@ -97056,6 +102220,42 @@ case OP_ClrSubtype: { /* in1 */
break;
}
+/* Opcode: GetSubtype P1 P2 * * *
+** Synopsis: r[P2] = r[P1].subtype
+**
+** Extract the subtype value from register P1 and write that subtype
+** into register P2. If P1 has no subtype, then P1 gets a NULL.
+*/
+case OP_GetSubtype: { /* in1 out2 */
+ pIn1 = &aMem[pOp->p1];
+ pOut = &aMem[pOp->p2];
+ if( pIn1->flags & MEM_Subtype ){
+ sqlcipher_sqlite3VdbeMemSetInt64(pOut, pIn1->eSubtype);
+ }else{
+ sqlcipher_sqlite3VdbeMemSetNull(pOut);
+ }
+ break;
+}
+
+/* Opcode: SetSubtype P1 P2 * * *
+** Synopsis: r[P2].subtype = r[P1]
+**
+** Set the subtype value of register P2 to the integer from register P1.
+** If P1 is NULL, clear the subtype from p2.
+*/
+case OP_SetSubtype: { /* in1 out2 */
+ pIn1 = &aMem[pOp->p1];
+ pOut = &aMem[pOp->p2];
+ if( pIn1->flags & MEM_Null ){
+ pOut->flags &= ~MEM_Subtype;
+ }else{
+ assert( pIn1->flags & MEM_Int );
+ pOut->flags |= MEM_Subtype;
+ pOut->eSubtype = (u8)(pIn1->u.i & 0xff);
+ }
+ break;
+}
+
/* Opcode: FilterAdd P1 * P3 P4 *
** Synopsis: filter(P1) += key(P3@P4)
**
@@ -97079,7 +102279,7 @@ case OP_FilterAdd: {
printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
}
#endif
- h %= pIn1->n;
+ h %= (pIn1->n*8);
pIn1->z[h/8] |= 1<<(h&7);
break;
}
@@ -97115,7 +102315,7 @@ case OP_Filter: { /* jump */
printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
}
#endif
- h %= pIn1->n;
+ h %= (pIn1->n*8);
if( (pIn1->z[h/8] & (1<<(h&7)))==0 ){
VdbeBranchTaken(1, 2);
p->aCounter[SQLITE_STMTSTATUS_FILTER_HIT]++;
@@ -97153,7 +102353,7 @@ case OP_Filter: { /* jump */
** error is encountered.
*/
case OP_Trace:
-case OP_Init: { /* jump */
+case OP_Init: { /* jump0 */
int i;
#ifndef SQLITE_OMIT_TRACE
char *zTrace;
@@ -97337,11 +102537,13 @@ default: { /* This is really OP_Noop, OP_Explain */
*****************************************************************************/
}
-#ifdef VDBE_PROFILE
- {
- u64 endTime = sqlcipher_sqlite3NProfileCnt ? sqlcipher_sqlite3NProfileCnt : sqlcipher_sqlite3Hwtime();
- if( endTime>start ) pOrigOp->cycles += endTime - start;
- pOrigOp->cnt++;
+#if defined(VDBE_PROFILE)
+ *pnCycle += sqlcipher_sqlite3NProfileCnt ? sqlcipher_sqlite3NProfileCnt : sqlcipher_sqlite3Hwtime();
+ pnCycle = 0;
+#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ if( pnCycle ){
+ *pnCycle += sqlcipher_sqlite3Hwtime();
+ pnCycle = 0;
}
#endif
@@ -97365,7 +102567,7 @@ default: { /* This is really OP_Noop, OP_Explain */
}
if( opProperty==0xff ){
/* Never happens. This code exists to avoid a harmless linkage
- ** warning aboud sqlcipher_sqlite3VdbeRegisterDump() being defined but not
+ ** warning about sqlcipher_sqlite3VdbeRegisterDump() being defined but not
** used. */
sqlcipher_sqlite3VdbeRegisterDump(p);
}
@@ -97418,6 +102620,18 @@ abort_due_to_error:
** release the mutexes on btrees that were acquired at the
** top. */
vdbe_return:
+#if defined(VDBE_PROFILE)
+ if( pnCycle ){
+ *pnCycle += sqlcipher_sqlite3NProfileCnt ? sqlcipher_sqlite3NProfileCnt : sqlcipher_sqlite3Hwtime();
+ pnCycle = 0;
+ }
+#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ if( pnCycle ){
+ *pnCycle += sqlcipher_sqlite3Hwtime();
+ pnCycle = 0;
+ }
+#endif
+
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
while( nVmStep>=nProgressLimit && db->xProgress!=0 ){
nProgressLimit += db->nProgressOps;
@@ -97429,7 +102643,9 @@ vdbe_return:
}
#endif
p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
- sqlcipher_sqlite3VdbeLeave(p);
+ if( DbMaskNonZero(p->lockMask) ){
+ sqlcipher_sqlite3VdbeLeave(p);
+ }
assert( rc!=SQLITE_OK || nExtraDelete==0
|| sqlcipher_sqlite3_strlike("DELETE%",p->zSql,0)!=0
);
@@ -97524,8 +102740,7 @@ static int blobSeekToRow(Incrblob *p, sqlcipher_sqlite3_int64 iRow, char **pzErr
/* Set the value of register r[1] in the SQL statement to integer iRow.
** This is done directly as a performance optimization
*/
- v->aMem[1].flags = MEM_Int;
- v->aMem[1].u.i = iRow;
+ sqlcipher_sqlite3VdbeMemSetInt64(&v->aMem[1], iRow);
/* If the statement has been run before (and is paused at the OP_ResultRow)
** then back it up to the point where it does the OP_NotExists. This could
@@ -97608,7 +102823,7 @@ SQLITE_API int sqlcipher_sqlite3_blob_open(
#endif
*ppBlob = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlcipher_sqlite3SafetyCheckOk(db) || zTable==0 ){
+ if( !sqlcipher_sqlite3SafetyCheckOk(db) || zTable==0 || zColumn==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
@@ -97807,7 +103022,7 @@ blob_open_out:
if( pBlob && pBlob->pStmt ) sqlcipher_sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
sqlcipher_sqlite3DbFree(db, pBlob);
}
- sqlcipher_sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
+ sqlcipher_sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr);
sqlcipher_sqlite3DbFree(db, zErr);
sqlcipher_sqlite3ParseObjectReset(&sParse);
rc = sqlcipher_sqlite3ApiExit(db, rc);
@@ -97966,7 +103181,7 @@ SQLITE_API int sqlcipher_sqlite3_blob_reopen(sqlcipher_sqlite3_blob *pBlob, sqlc
((Vdbe*)p->pStmt)->rc = SQLITE_OK;
rc = blobSeekToRow(p, iRow, &zErr);
if( rc!=SQLITE_OK ){
- sqlcipher_sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
+ sqlcipher_sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr);
sqlcipher_sqlite3DbFree(db, zErr);
}
assert( rc!=SQLITE_SCHEMA );
@@ -98069,7 +103284,7 @@ SQLITE_API int sqlcipher_sqlite3_blob_reopen(sqlcipher_sqlite3_blob *pBlob, sqlc
** The threshold for the amount of main memory to use before flushing
** records to a PMA is roughly the same as the limit configured for the
** page-cache of the main database. Specifically, the threshold is set to
-** the value returned by "PRAGMA main.page_size" multipled by
+** the value returned by "PRAGMA main.page_size" multiplied by
** that returned by "PRAGMA main.cache_size", in bytes.
**
** If the sorter is running in single-threaded mode, then all PMAs generated
@@ -98092,7 +103307,7 @@ SQLITE_API int sqlcipher_sqlite3_blob_reopen(sqlcipher_sqlite3_blob *pBlob, sqlc
**
** If there are fewer than SORTER_MAX_MERGE_COUNT PMAs in total and the
** sorter is running in single-threaded mode, then these PMAs are merged
-** incrementally as keys are retreived from the sorter by the VDBE. The
+** incrementally as keys are retrieved from the sorter by the VDBE. The
** MergeEngine object, described in further detail below, performs this
** merge.
**
@@ -98170,7 +103385,7 @@ struct SorterFile {
struct SorterList {
SorterRecord *pList; /* Linked list of records */
u8 *aMemory; /* If non-NULL, bulk memory to hold pList */
- int szPMA; /* Size of pList as PMA in bytes */
+ i64 szPMA; /* Size of pList as PMA in bytes */
};
/*
@@ -98255,7 +103470,7 @@ struct MergeEngine {
**
** Essentially, this structure contains all those fields of the VdbeSorter
** structure for which each thread requires a separate instance. For example,
-** each thread requries its own UnpackedRecord object to unpack records in
+** each thread requeries its own UnpackedRecord object to unpack records in
** as part of comparison operations.
**
** Before a background thread is launched, variable bDone is set to 0. Then,
@@ -98279,10 +103494,10 @@ typedef int (*SorterCompare)(SortSubtask*,int*,const void*,int,const void*,int);
struct SortSubtask {
SQLiteThread *pThread; /* Background thread, if any */
int bDone; /* Set if thread is finished but not joined */
+ int nPMA; /* Number of PMAs currently in file */
VdbeSorter *pSorter; /* Sorter that owns this sub-task */
UnpackedRecord *pUnpacked; /* Space to unpack a record */
SorterList list; /* List for thread to write to a PMA */
- int nPMA; /* Number of PMAs currently in file */
SorterCompare xCompare; /* Compare function to use */
SorterFile file; /* Temp file for level-0 PMAs */
SorterFile file2; /* Space for other PMAs */
@@ -98327,7 +103542,7 @@ struct VdbeSorter {
** PMA, in sorted order. The next key to be read is cached in nKey/aKey.
** aKey might point into aMap or into aBuffer. If neither of those locations
** contain a contiguous representation of the key, then aAlloc is allocated
-** and the key is copied into aAlloc and aKey is made to poitn to aAlloc.
+** and the key is copied into aAlloc and aKey is made to point to aAlloc.
**
** pFd==0 at EOF.
*/
@@ -99698,7 +104913,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
** the background thread from a sub-tasks previous turn is still running,
** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy,
** fall back to using the final sub-task. The first (pSorter->nTask-1)
- ** sub-tasks are prefered as they use background threads - the final
+ ** sub-tasks are preferred as they use background threads - the final
** sub-task uses the main thread. */
for(i=0; i<nWorker; i++){
int iTest = (pSorter->iPrev + i + 1) % nWorker;
@@ -99756,8 +104971,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VdbeSorterWrite(
int rc = SQLITE_OK; /* Return Code */
SorterRecord *pNew; /* New list element */
int bFlush; /* True to flush contents of memory to PMA */
- int nReq; /* Bytes of memory required */
- int nPMA; /* Bytes of PMA space required */
+ i64 nReq; /* Bytes of memory required */
+ i64 nPMA; /* Bytes of PMA space required */
int t; /* serial type of first record field */
assert( pCsr->eCurType==CURTYPE_SORTER );
@@ -100182,7 +105397,7 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode);
- /* Set up the required files for pIncr. A multi-theaded IncrMerge object
+ /* Set up the required files for pIncr. A multi-threaded IncrMerge object
** requires two temp files to itself, whereas a single-threaded object
** only requires a region of pTask->file2. */
if( rc==SQLITE_OK ){
@@ -100822,6 +106037,8 @@ static int bytecodevtabConnect(
"p5 INT,"
"comment TEXT,"
"subprog TEXT,"
+ "nexec INT,"
+ "ncycle INT,"
"stmt HIDDEN"
");",
@@ -100836,6 +106053,9 @@ static int bytecodevtabConnect(
");"
};
+ (void)argc;
+ (void)argv;
+ (void)pzErr;
rc = sqlcipher_sqlite3_declare_vtab(db, azSchema[isTabUsed]);
if( rc==SQLITE_OK ){
pNew = sqlcipher_sqlite3_malloc( sizeof(*pNew) );
@@ -100981,7 +106201,7 @@ static int bytecodevtabColumn(
}
}
}
- i += 10;
+ i += 20;
}
}
switch( i ){
@@ -101031,16 +106251,31 @@ static int bytecodevtabColumn(
}
break;
}
- case 10: /* tables_used.type */
+
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ case 9: /* nexec */
+ sqlcipher_sqlite3_result_int64(ctx, pOp->nExec);
+ break;
+ case 10: /* ncycle */
+ sqlcipher_sqlite3_result_int64(ctx, pOp->nCycle);
+ break;
+#else
+ case 9: /* nexec */
+ case 10: /* ncycle */
+ sqlcipher_sqlite3_result_int(ctx, 0);
+ break;
+#endif
+
+ case 20: /* tables_used.type */
sqlcipher_sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
break;
- case 11: /* tables_used.schema */
+ case 21: /* tables_used.schema */
sqlcipher_sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
break;
- case 12: /* tables_used.name */
+ case 22: /* tables_used.name */
sqlcipher_sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
break;
- case 13: /* tables_used.wr */
+ case 23: /* tables_used.wr */
sqlcipher_sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
break;
}
@@ -101071,6 +106306,7 @@ static int bytecodevtabFilter(
bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor;
bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;
int rc = SQLITE_OK;
+ (void)idxStr;
bytecodevtabCursorClear(pCur);
pCur->iRowid = 0;
@@ -101113,7 +106349,7 @@ static int bytecodevtabBestIndex(
int rc = SQLITE_CONSTRAINT;
struct sqlcipher_sqlite3_index_constraint *p;
bytecodevtab *pVTab = (bytecodevtab*)tab;
- int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
+ int iBaseCol = pVTab->bTablesUsed ? 4 : 10;
pIdxInfo->estimatedCost = (double)100;
pIdxInfo->estimatedRows = 100;
pIdxInfo->idxNum = 0;
@@ -101160,7 +106396,8 @@ static sqlcipher_sqlite3_module bytecodevtabModule = {
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
- /* xShadowName */ 0
+ /* xShadowName */ 0,
+ /* xIntegrity */ 0
};
@@ -101539,6 +106776,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3JournalOpen(
){
MemJournal *p = (MemJournal*)pJfd;
+ assert( zName || nSpill<0 || (flags & SQLITE_OPEN_EXCLUSIVE) );
+
/* Zero the file-handle object. If nSpill was passed zero, initialize
** it using the sqlcipher_sqlite3OsOpen() function of the underlying VFS. In this
** case none of the code in this module is executed as a result of calls
@@ -101618,12 +106857,12 @@ SQLITE_PRIVATE int sqlcipher_sqlite3JournalSize(sqlcipher_sqlite3_vfs *pVfs){
}
/************** End of memjournal.c ******************************************/
-/************** Begin file crypto.c ******************************************/
+/************** Begin file sqlcipher.c ***************************************/
/*
** SQLCipher
-** http://sqlcipher.net
+** http://zetetic.net
**
-** Copyright (c) 2008 - 2013, ZETETIC LLC
+** Copyright (c) 2008-2024, ZETETIC LLC
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@@ -101652,8 +106891,39 @@ SQLITE_PRIVATE int sqlcipher_sqlite3JournalSize(sqlcipher_sqlite3_vfs *pVfs){
/* BEGIN SQLCIPHER */
#ifdef SQLITE_HAS_CODEC
+/* #include "sqliteInt.h" */
+/* #include "btreeInt.h" */
+/* #include "pager.h" */
+/* #include "vdbeInt.h" */
+
+#if !defined(SQLCIPHER_OMIT_LOG_DEVICE)
+#if defined(__ANDROID__)
+#include <android/log.h>
+#elif defined(__APPLE__)
+/* #include <TargetConditionals.h> */
+#include <os/log.h>
+#endif
+#endif
+
+/* #include <time.h> */
+
+#if defined(_WIN32) || defined(SQLITE_OS_WINRT)
+/* #include <windows.h> ** amalgamator: dontcache ** */
+#else
+/* #include <sys/time.h> ** amalgamator: dontcache ** */
+#endif
+
+#ifndef OMIT_MEMLOCK
+#if defined(__unix__) || defined(__APPLE__) || defined(_AIX)
+/* #include <errno.h> ** amalgamator: dontcache ** */
+/* #include <unistd.h> ** amalgamator: dontcache ** */
+#include <sys/resource.h> /* amalgamator: dontcache */
+/* #include <sys/mman.h> ** amalgamator: dontcache ** */
+#endif
+#endif
+
/* #include <assert.h> */
-/************** Include sqlcipher.h in the middle of crypto.c ****************/
+/************** Include sqlcipher.h in the middle of sqlcipher.c *************/
/************** Begin file sqlcipher.h ***************************************/
/*
** SQLCipher
@@ -101709,7 +106979,6 @@ SQLITE_PRIVATE int sqlcipher_sqlite3JournalSize(sqlcipher_sqlite3_vfs *pVfs){
#define SQLCIPHER_PBKDF2_HMAC_SHA512 2
#define SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL "PBKDF2_HMAC_SHA512"
-
typedef struct {
int (*activate)(void *ctx);
int (*deactivate)(void *ctx);
@@ -101730,10 +106999,16 @@ typedef struct {
const char* (*get_provider_version)(void *ctx);
} sqlcipher_provider;
+/* public interfaces called externally */
+void sqlcipher_init_memmethods(void);
+int sqlcipher_codec_pragma(sqlcipher_sqlite3*, int, Parse*, const char *, const char*);
+int sqlcipherCodecAttach(sqlcipher_sqlite3*, int, const void *, int);
+void sqlcipherCodecGetKey(sqlcipher_sqlite3*, int, void**, int*);
+void sqlcipher_exportFunc(sqlcipher_sqlite3_context *, int, sqlcipher_sqlite3_value **);
+int sqlcipher_find_db_index(sqlcipher_sqlite3 *, const char *);
+
/* utility functions */
void* sqlcipher_malloc(sqlite_uint64);
-void sqlcipher_mlock(void *, sqlite_uint64);
-void sqlcipher_munlock(void *, sqlite_uint64);
void* sqlcipher_memset(void *, unsigned char, sqlite_uint64);
int sqlcipher_ismemset(const void *, unsigned char, sqlite_uint64);
int sqlcipher_memcmp(const void *, const void *, int);
@@ -101754,79 +107029,49 @@ sqlcipher_provider* sqlcipher_get_provider(void);
sqlcipher_sqlite3_mutex* sqlcipher_mutex(int);
-#endif
-#endif
-/* END SQLCIPHER */
-
+#define SQLCIPHER_LOG_NONE 0
+#define SQLCIPHER_LOG_ANY 0xffffffff
-/************** End of sqlcipher.h *******************************************/
-/************** Continuing where we left off in crypto.c *********************/
-/************** Include crypto.h in the middle of crypto.c *******************/
-/************** Begin file crypto.h ******************************************/
-/*
-** SQLCipher
-** crypto.h developed by Stephen Lombardo (Zetetic LLC)
-** sjlombardo at zetetic dot net
-** http://zetetic.net
-**
-** Copyright (c) 2008, ZETETIC LLC
-** All rights reserved.
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in the
-** documentation and/or other materials provided with the distribution.
-** * Neither the name of the ZETETIC LLC nor the
-** names of its contributors may be used to endorse or promote products
-** derived from this software without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
-** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
-** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-**
-*/
-/* BEGIN SQLCIPHER */
-#ifdef SQLITE_HAS_CODEC
-#ifndef CRYPTO_H
-#define CRYPTO_H
+#define SQLCIPHER_LOG_ERROR (1<<0)
+#define SQLCIPHER_LOG_WARN (1<<1)
+#define SQLCIPHER_LOG_INFO (1<<2)
+#define SQLCIPHER_LOG_DEBUG (1<<3)
+#define SQLCIPHER_LOG_TRACE (1<<4)
-/* #include "sqliteInt.h" */
-/* #include "btreeInt.h" */
-/* #include "pager.h" */
-/* #include "vdbeInt.h" */
+#define SQLCIPHER_LOG_CORE (1<<0)
+#define SQLCIPHER_LOG_MEMORY (1<<1)
+#define SQLCIPHER_LOG_MUTEX (1<<2)
+#define SQLCIPHER_LOG_PROVIDER (1<<3)
-#ifdef __ANDROID__
-#include <android/log.h>
+#ifdef SQLCIPHER_OMIT_LOG
+#define sqlcipher_log(level, source, message, ...)
+#else
+void sqlcipher_log(unsigned int level, unsigned int source, const char *message, ...);
#endif
-/* #include <time.h> */
-
-#if defined(_WIN32) || defined(SQLITE_OS_WINRT)
-/* #include <windows.h> ** amalgamator: dontcache ** */
+#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
-/* #include <sys/time.h> ** amalgamator: dontcache ** */
+#define CODEC_HEXDUMP(DESC,BUFFER,LEN)
#endif
-#ifndef OMIT_MEMLOCK
-#if defined(__unix__) || defined(__APPLE__) || defined(_AIX)
-/* #include <errno.h> ** amalgamator: dontcache ** */
-/* #include <unistd.h> ** amalgamator: dontcache ** */
-#include <sys/resource.h> /* amalgamator: dontcache */
-/* #include <sys/mman.h> ** amalgamator: dontcache ** */
#endif
#endif
+/* END SQLCIPHER */
-/* #include "sqlcipher.h" */
+
+/************** End of sqlcipher.h *******************************************/
+/************** Continuing where we left off in sqlcipher.c ******************/
/* extensions defined in pager.c */
void *sqlcipherPagerGetCodec(Pager*);
@@ -101849,7 +107094,7 @@ SQLITE_API void sqlcipher_sqlite3pager_reset(Pager *pPager);
#define CIPHER_STR(s) #s
#ifndef CIPHER_VERSION_NUMBER
-#define CIPHER_VERSION_NUMBER 4.5.3
+#define CIPHER_VERSION_NUMBER 4.6.1
#endif
#ifndef CIPHER_VERSION_BUILD
@@ -101867,10 +107112,17 @@ SQLITE_API void sqlcipher_sqlite3pager_reset(Pager *pPager);
#define PBKDF2_ITER 256000
#endif
-/* possible flags for cipher_ctx->flags */
-#define CIPHER_FLAG_HMAC 0x01
-#define CIPHER_FLAG_LE_PGNO 0x02
-#define CIPHER_FLAG_BE_PGNO 0x04
+#define SQLCIPHER_FLAG_GET(FLAG,BIT) ((FLAG & BIT) != 0)
+#define SQLCIPHER_FLAG_SET(FLAG,BIT) FLAG |= BIT
+#define SQLCIPHER_FLAG_UNSET(FLAG,BIT) FLAG &= ~BIT
+
+/* possible flags for codec_ctx->flags */
+#define CIPHER_FLAG_HMAC (1 << 0)
+#define CIPHER_FLAG_LE_PGNO (1 << 1)
+#define CIPHER_FLAG_BE_PGNO (1 << 2)
+#define CIPHER_FLAG_KEY_USED (1 << 3)
+#define CIPHER_FLAG_HAS_KDF_SALT (1 << 4)
+
#ifndef DEFAULT_CIPHER_FLAGS
#define DEFAULT_CIPHER_FLAGS CIPHER_FLAG_HMAC | CIPHER_FLAG_LE_PGNO
@@ -101938,19 +107190,6 @@ static int cipher_isHex(const unsigned char *hex, int sz){
return 1;
}
-/* possible flags for simulating specific test conditions */
-#ifdef SQLCIPHER_TEST
-#define TEST_FAIL_ENCRYPT 0x01
-#define TEST_FAIL_DECRYPT 0x02
-#define TEST_FAIL_MIGRATE 0x04
-unsigned int sqlcipher_get_test_flags(void);
-void sqlcipher_set_test_flags(unsigned int);
-int sqlcipher_get_test_rand(void);
-void sqlcipher_set_test_rand(int);
-int sqlcipher_get_test_fail(void);
-#endif
-
-/* extensions defined in crypto_impl.c */
/* the default implementation of SQLCipher uses a cipher_ctx
to keep track of read / write state separately. The following
struct and associated functions are defined here */
@@ -101979,8 +107218,6 @@ typedef struct {
int plaintext_header_sz;
int hmac_algorithm;
int kdf_algorithm;
- unsigned int skip_read_hmac;
- unsigned int need_kdf_salt;
unsigned int flags;
unsigned char *kdf_salt;
unsigned char *hmac_kdf_salt;
@@ -101992,1417 +107229,17 @@ typedef struct {
void *provider_ctx;
} codec_ctx ;
-/* crypto.c functions */
-int sqlcipher_codec_pragma(sqlcipher_sqlite3*, int, Parse*, const char *, const char*);
-int sqlcipherCodecAttach(sqlcipher_sqlite3*, int, const void *, int);
-void sqlcipherCodecGetKey(sqlcipher_sqlite3*, int, void**, int*);
-void sqlcipher_exportFunc(sqlcipher_sqlite3_context *, int, sqlcipher_sqlite3_value **);
-
-/* crypto_impl.c functions */
-
-void sqlcipher_init_memmethods(void);
-
-/* activation and initialization */
-void sqlcipher_activate(void);
-void sqlcipher_deactivate(void);
-
-int sqlcipher_codec_ctx_init(codec_ctx **, Db *, Pager *, const void *, int);
-void sqlcipher_codec_ctx_free(codec_ctx **);
-int sqlcipher_codec_key_derive(codec_ctx *);
-int sqlcipher_codec_key_copy(codec_ctx *, int);
-
-/* page cipher implementation */
-int sqlcipher_page_cipher(codec_ctx *, int, Pgno, int, int, unsigned char *, unsigned char *);
-
-/* context setters & getters */
-void sqlcipher_codec_ctx_set_error(codec_ctx *, int);
-
-void sqlcipher_codec_get_pass(codec_ctx *, void **, int *);
-int sqlcipher_codec_ctx_set_pass(codec_ctx *, const void *, int, int);
-void sqlcipher_codec_get_keyspec(codec_ctx *, void **zKey, int *nKey);
-
-int sqlcipher_codec_ctx_set_pagesize(codec_ctx *, int);
-int sqlcipher_codec_ctx_get_pagesize(codec_ctx *);
-int sqlcipher_codec_ctx_get_reservesize(codec_ctx *);
-
-void sqlcipher_set_default_pagesize(int page_size);
-int sqlcipher_get_default_pagesize(void);
-
-void sqlcipher_set_default_kdf_iter(int iter);
-int sqlcipher_get_default_kdf_iter(void);
-int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *, int);
-int sqlcipher_codec_ctx_get_kdf_iter(codec_ctx *ctx);
-
-int sqlcipher_codec_ctx_set_kdf_salt(codec_ctx *ctx, unsigned char *salt, int sz);
-int sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx, void **salt);
-
-int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *, int);
-int sqlcipher_codec_ctx_get_fast_kdf_iter(codec_ctx *);
-
-const char* sqlcipher_codec_ctx_get_cipher(codec_ctx *ctx);
-
-void* sqlcipher_codec_ctx_get_data(codec_ctx *);
-
-void sqlcipher_set_default_use_hmac(int use);
-int sqlcipher_get_default_use_hmac(void);
-
-void sqlcipher_set_hmac_salt_mask(unsigned char mask);
-unsigned char sqlcipher_get_hmac_salt_mask(void);
-
-int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use);
-int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx);
-
-int sqlcipher_codec_ctx_set_flag(codec_ctx *ctx, unsigned int flag);
-int sqlcipher_codec_ctx_unset_flag(codec_ctx *ctx, unsigned int flag);
-int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag);
-
-const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx);
-int sqlcipher_codec_ctx_migrate(codec_ctx *ctx);
-int sqlcipher_codec_add_random(codec_ctx *ctx, const char *data, int random_sz);
-int sqlcipher_cipher_profile(sqlcipher_sqlite3 *db, const char *destination);
-int sqlcipher_codec_get_store_pass(codec_ctx *ctx);
-void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey);
-void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value);
-int sqlcipher_codec_fips_status(codec_ctx *ctx);
-const char* sqlcipher_codec_get_provider_version(codec_ctx *ctx);
-
-int sqlcipher_set_default_plaintext_header_size(int size);
-int sqlcipher_get_default_plaintext_header_size(void);
-int sqlcipher_codec_ctx_set_plaintext_header_size(codec_ctx *ctx, int size);
-int sqlcipher_codec_ctx_get_plaintext_header_size(codec_ctx *ctx);
-
-int sqlcipher_set_default_hmac_algorithm(int algorithm);
-int sqlcipher_get_default_hmac_algorithm(void);
-int sqlcipher_codec_ctx_set_hmac_algorithm(codec_ctx *ctx, int algorithm);
-int sqlcipher_codec_ctx_get_hmac_algorithm(codec_ctx *ctx);
-
-int sqlcipher_set_default_kdf_algorithm(int algorithm);
-int sqlcipher_get_default_kdf_algorithm(void);
-int sqlcipher_codec_ctx_set_kdf_algorithm(codec_ctx *ctx, int algorithm);
-int sqlcipher_codec_ctx_get_kdf_algorithm(codec_ctx *ctx);
-
-void sqlcipher_set_mem_security(int);
-int sqlcipher_get_mem_security(void);
-
-int sqlcipher_find_db_index(sqlcipher_sqlite3 *db, const char *zDb);
-int sqlcipher_codec_ctx_integrity_check(codec_ctx *, Parse *, char *);
-
-int sqlcipher_set_log(const char *destination);
-void sqlcipher_set_log_level(unsigned int level);
-void sqlcipher_log(unsigned int tag, const char *message, ...);
-
-#define SQLCIPHER_LOG_NONE 0x00
-#define SQLCIPHER_LOG_ERROR 0x01
-#define SQLCIPHER_LOG_WARN 0x02
-#define SQLCIPHER_LOG_INFO 0x04
-#define SQLCIPHER_LOG_DEBUG 0x08
-#define SQLCIPHER_LOG_TRACE 0x10
-#define SQLCIPHER_LOG_ALL 0xffffffff
-
-void sqlcipher_vdbe_return_string(Parse*, const char*, const char*, int);
-
-#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
-
-#endif
-#endif
-/* END SQLCIPHER */
-
-/************** End of crypto.h **********************************************/
-/************** Continuing where we left off in crypto.c *********************/
-
-#ifdef SQLCIPHER_EXT
-#include "sqlcipher_ext.h"
-#endif
-
-void sqlcipher_vdbe_return_string(Parse *pParse, const char *zLabel, const char *value, int value_type){
- Vdbe *v = sqlcipher_sqlite3GetVdbe(pParse);
- sqlcipher_sqlite3VdbeSetNumCols(v, 1);
- sqlcipher_sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC);
- sqlcipher_sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, value, value_type);
- sqlcipher_sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
-}
-
-static int codec_set_btree_to_codec_pagesize(sqlcipher_sqlite3 *db, Db *pDb, codec_ctx *ctx) {
- int rc, page_sz, reserve_sz;
-
- page_sz = sqlcipher_codec_ctx_get_pagesize(ctx);
- reserve_sz = sqlcipher_codec_ctx_get_reservesize(ctx);
-
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "codec_set_btree_to_codec_pagesize: sqlcipher_sqlite3BtreeSetPageSize() size=%d reserve=%d", page_sz, reserve_sz);
-
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "codec_set_btree_to_codec_pagesize: entering database mutex %p", db->mutex);
- sqlcipher_sqlite3_mutex_enter(db->mutex);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "codec_set_btree_to_codec_pagesize: entered database mutex %p", db->mutex);
- db->nextPagesize = page_sz;
-
- /* 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;
- rc = sqlcipher_sqlite3BtreeSetPageSize(pDb->pBt, page_sz, reserve_sz, 0);
-
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "codec_set_btree_to_codec_pagesize: sqlcipher_sqlite3BtreeSetPageSize returned %d", rc);
-
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "codec_set_btree_to_codec_pagesize: leaving database mutex %p", db->mutex);
- sqlcipher_sqlite3_mutex_leave(db->mutex);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "codec_set_btree_to_codec_pagesize: left database mutex %p", db->mutex);
-
- return rc;
-}
-
-static int codec_set_pass_key(sqlcipher_sqlite3* db, int nDb, const void *zKey, int nKey, int for_ctx) {
- struct Db *pDb = &db->aDb[nDb];
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "codec_set_pass_key: db=%p nDb=%d for_ctx=%d", db, nDb, for_ctx);
- if(pDb->pBt) {
- codec_ctx *ctx = (codec_ctx*) sqlcipherPagerGetCodec(pDb->pBt->pBt->pPager);
-
- if(ctx) {
- return sqlcipher_codec_ctx_set_pass(ctx, zKey, nKey, for_ctx);
- } else {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "codec_set_pass_key: error ocurred fetching codec from pager on db %d", nDb);
- return SQLITE_ERROR;
- }
- }
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "codec_set_pass_key: no btree present on db %d", nDb);
- return SQLITE_ERROR;
-}
-
-int sqlcipher_codec_pragma(sqlcipher_sqlite3* db, int iDb, Parse *pParse, const char *zLeft, const char *zRight) {
- struct Db *pDb = &db->aDb[iDb];
- codec_ctx *ctx = NULL;
- int rc;
-
- if(pDb->pBt) {
- ctx = (codec_ctx*) sqlcipherPagerGetCodec(pDb->pBt->pBt->pPager);
- }
-
- if(sqlcipher_sqlite3_stricmp(zLeft, "key") !=0 && sqlcipher_sqlite3_stricmp(zLeft, "rekey") != 0) {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_codec_pragma: db=%p iDb=%d pParse=%p zLeft=%s zRight=%s ctx=%p", db, iDb, pParse, zLeft, zRight, ctx);
- }
-
-#ifdef SQLCIPHER_EXT
- if(sqlcipher_ext_pragma(db, iDb, pParse, zLeft, zRight)) {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_codec_pragma: PRAGMA handled by sqlcipher_ext_pragma");
- } else
-#endif
-#ifdef SQLCIPHER_TEST
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_test_on")==0 ){
- if( zRight ) {
- unsigned int flags = sqlcipher_get_test_flags();
- if(sqlcipher_sqlite3_stricmp(zRight, "fail_encrypt")==0) {
- flags |= TEST_FAIL_ENCRYPT;
- } else
- if(sqlcipher_sqlite3_stricmp(zRight, "fail_decrypt")==0) {
- flags |= TEST_FAIL_DECRYPT;
- } else
- if(sqlcipher_sqlite3_stricmp(zRight, "fail_migrate")==0) {
- flags |= TEST_FAIL_MIGRATE;
- }
- sqlcipher_set_test_flags(flags);
- }
- } else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_test_off")==0 ){
- if( zRight ) {
- unsigned int flags = sqlcipher_get_test_flags();
- if(sqlcipher_sqlite3_stricmp(zRight, "fail_encrypt")==0) {
- flags &= ~TEST_FAIL_ENCRYPT;
- } else
- if(sqlcipher_sqlite3_stricmp(zRight, "fail_decrypt")==0) {
- flags &= ~TEST_FAIL_DECRYPT;
- } else
- if(sqlcipher_sqlite3_stricmp(zRight, "fail_migrate")==0) {
- flags &= ~TEST_FAIL_MIGRATE;
- }
- sqlcipher_set_test_flags(flags);
- }
- } else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_test")==0 ){
- char *flags = sqlcipher_sqlite3_mprintf("%u", sqlcipher_get_test_flags());
- sqlcipher_vdbe_return_string(pParse, "cipher_test", flags, P4_DYNAMIC);
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_test_rand")==0 ){
- if( zRight ) {
- int rand = atoi(zRight);
- sqlcipher_set_test_rand(rand);
- } else {
- char *rand = sqlcipher_sqlite3_mprintf("%d", sqlcipher_get_test_rand());
- sqlcipher_vdbe_return_string(pParse, "cipher_test_rand", rand, P4_DYNAMIC);
- }
- } else
-#endif
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_fips_status")== 0 && !zRight ){
- if(ctx) {
- char *fips_mode_status = sqlcipher_sqlite3_mprintf("%d", sqlcipher_codec_fips_status(ctx));
- sqlcipher_vdbe_return_string(pParse, "cipher_fips_status", fips_mode_status, P4_DYNAMIC);
- }
- } else
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_store_pass")==0 && zRight ) {
- if(ctx) {
- char *deprecation = "PRAGMA cipher_store_pass is deprecated, please remove from use";
- sqlcipher_codec_set_store_pass(ctx, sqlcipher_sqlite3GetBoolean(zRight, 1));
- sqlcipher_vdbe_return_string(pParse, "cipher_store_pass", deprecation, P4_TRANSIENT);
- sqlcipher_sqlite3_log(SQLITE_WARNING, deprecation);
- }
- } else
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_store_pass")==0 && !zRight ) {
- if(ctx){
- char *store_pass_value = sqlcipher_sqlite3_mprintf("%d", sqlcipher_codec_get_store_pass(ctx));
- sqlcipher_vdbe_return_string(pParse, "cipher_store_pass", store_pass_value, P4_DYNAMIC);
- }
- }
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_profile")== 0 && zRight ){
- char *profile_status = sqlcipher_sqlite3_mprintf("%d", sqlcipher_cipher_profile(db, zRight));
- sqlcipher_vdbe_return_string(pParse, "cipher_profile", profile_status, P4_DYNAMIC);
- } else
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_add_random")==0 && zRight ){
- if(ctx) {
- char *add_random_status = sqlcipher_sqlite3_mprintf("%d", sqlcipher_codec_add_random(ctx, zRight, sqlcipher_sqlite3Strlen30(zRight)));
- sqlcipher_vdbe_return_string(pParse, "cipher_add_random", add_random_status, P4_DYNAMIC);
- }
- } else
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_migrate")==0 && !zRight ){
- if(ctx){
- int status = sqlcipher_codec_ctx_migrate(ctx);
- char *migrate_status = sqlcipher_sqlite3_mprintf("%d", status);
- sqlcipher_vdbe_return_string(pParse, "cipher_migrate", migrate_status, P4_DYNAMIC);
- if(status != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_pragma: error occurred during cipher_migrate: %d", status);
- sqlcipher_codec_ctx_set_error(ctx, status);
- }
- }
- } else
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_provider")==0 && !zRight ){
- if(ctx) { sqlcipher_vdbe_return_string(pParse, "cipher_provider",
- sqlcipher_codec_get_cipher_provider(ctx), P4_TRANSIENT);
- }
- } else
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_provider_version")==0 && !zRight){
- if(ctx) { sqlcipher_vdbe_return_string(pParse, "cipher_provider_version",
- sqlcipher_codec_get_provider_version(ctx), P4_TRANSIENT);
- }
- } else
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_version")==0 && !zRight ){
- sqlcipher_vdbe_return_string(pParse, "cipher_version", sqlcipher_version(), P4_DYNAMIC);
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher")==0 ){
- if(ctx) {
- if( zRight ) {
- const char* message = "PRAGMA cipher is no longer supported.";
- sqlcipher_vdbe_return_string(pParse, "cipher", message, P4_TRANSIENT);
- sqlcipher_sqlite3_log(SQLITE_WARNING, message);
- }else {
- sqlcipher_vdbe_return_string(pParse, "cipher", sqlcipher_codec_ctx_get_cipher(ctx), P4_TRANSIENT);
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft, "rekey_cipher")==0 && zRight ){
- const char* message = "PRAGMA rekey_cipher is no longer supported.";
- sqlcipher_vdbe_return_string(pParse, "rekey_cipher", message, P4_TRANSIENT);
- sqlcipher_sqlite3_log(SQLITE_WARNING, message);
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_kdf_iter")==0 ){
- if( zRight ) {
- sqlcipher_set_default_kdf_iter(atoi(zRight)); /* change default KDF iterations */
- } else {
- char *kdf_iter = sqlcipher_sqlite3_mprintf("%d", sqlcipher_get_default_kdf_iter());
- sqlcipher_vdbe_return_string(pParse, "cipher_default_kdf_iter", kdf_iter, P4_DYNAMIC);
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft, "kdf_iter")==0 ){
- if(ctx) {
- if( zRight ) {
- sqlcipher_codec_ctx_set_kdf_iter(ctx, atoi(zRight)); /* change of RW PBKDF2 iteration */
- } else {
- char *kdf_iter = sqlcipher_sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_kdf_iter(ctx));
- sqlcipher_vdbe_return_string(pParse, "kdf_iter", kdf_iter, P4_DYNAMIC);
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft, "fast_kdf_iter")==0){
- if(ctx) {
- if( zRight ) {
- char *deprecation = "PRAGMA fast_kdf_iter is deprecated, please remove from use";
- sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, atoi(zRight)); /* change of RW PBKDF2 iteration */
- sqlcipher_vdbe_return_string(pParse, "fast_kdf_iter", deprecation, P4_TRANSIENT);
- sqlcipher_sqlite3_log(SQLITE_WARNING, deprecation);
- } else {
- char *fast_kdf_iter = sqlcipher_sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_fast_kdf_iter(ctx));
- sqlcipher_vdbe_return_string(pParse, "fast_kdf_iter", fast_kdf_iter, P4_DYNAMIC);
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft, "rekey_kdf_iter")==0 && zRight ){
- const char* message = "PRAGMA rekey_kdf_iter is no longer supported.";
- sqlcipher_vdbe_return_string(pParse, "rekey_kdf_iter", message, P4_TRANSIENT);
- sqlcipher_sqlite3_log(SQLITE_WARNING, message);
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_page_size")==0 ){
- if(ctx) {
- if( zRight ) {
- int size = atoi(zRight);
- rc = sqlcipher_codec_ctx_set_pagesize(ctx, size);
- if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
- rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
- if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
- } else {
- char * page_size = sqlcipher_sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_pagesize(ctx));
- sqlcipher_vdbe_return_string(pParse, "cipher_page_size", page_size, P4_DYNAMIC);
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_page_size")==0 ){
- if( zRight ) {
- sqlcipher_set_default_pagesize(atoi(zRight));
- } else {
- char *default_page_size = sqlcipher_sqlite3_mprintf("%d", sqlcipher_get_default_pagesize());
- sqlcipher_vdbe_return_string(pParse, "cipher_default_page_size", default_page_size, P4_DYNAMIC);
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_use_hmac")==0 ){
- if( zRight ) {
- sqlcipher_set_default_use_hmac(sqlcipher_sqlite3GetBoolean(zRight,1));
- } else {
- char *default_use_hmac = sqlcipher_sqlite3_mprintf("%d", sqlcipher_get_default_use_hmac());
- sqlcipher_vdbe_return_string(pParse, "cipher_default_use_hmac", default_use_hmac, P4_DYNAMIC);
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_use_hmac")==0 ){
- if(ctx) {
- if( zRight ) {
- rc = sqlcipher_codec_ctx_set_use_hmac(ctx, sqlcipher_sqlite3GetBoolean(zRight,1));
- if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
- /* since the use of hmac has changed, the page size may also change */
- rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
- if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
- } else {
- char *hmac_flag = sqlcipher_sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_use_hmac(ctx));
- sqlcipher_vdbe_return_string(pParse, "cipher_use_hmac", hmac_flag, P4_DYNAMIC);
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_hmac_pgno")==0 ){
- if(ctx) {
- if(zRight) {
- char *deprecation = "PRAGMA cipher_hmac_pgno is deprecated, please remove from use";
- /* clear both pgno endian flags */
- if(sqlcipher_sqlite3_stricmp(zRight, "le") == 0) {
- sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_BE_PGNO);
- sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_LE_PGNO);
- } else if(sqlcipher_sqlite3_stricmp(zRight, "be") == 0) {
- sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_LE_PGNO);
- sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_BE_PGNO);
- } else if(sqlcipher_sqlite3_stricmp(zRight, "native") == 0) {
- sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_LE_PGNO);
- sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_BE_PGNO);
- }
- sqlcipher_vdbe_return_string(pParse, "cipher_hmac_pgno", deprecation, P4_TRANSIENT);
- sqlcipher_sqlite3_log(SQLITE_WARNING, deprecation);
-
- } else {
- if(sqlcipher_codec_ctx_get_flag(ctx, CIPHER_FLAG_LE_PGNO)) {
- sqlcipher_vdbe_return_string(pParse, "cipher_hmac_pgno", "le", P4_TRANSIENT);
- } else if(sqlcipher_codec_ctx_get_flag(ctx, CIPHER_FLAG_BE_PGNO)) {
- sqlcipher_vdbe_return_string(pParse, "cipher_hmac_pgno", "be", P4_TRANSIENT);
- } else {
- sqlcipher_vdbe_return_string(pParse, "cipher_hmac_pgno", "native", P4_TRANSIENT);
- }
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_hmac_salt_mask")==0 ){
- if(ctx) {
- if(zRight) {
- char *deprecation = "PRAGMA cipher_hmac_salt_mask is deprecated, please remove from use";
- if (sqlcipher_sqlite3StrNICmp(zRight ,"x'", 2) == 0 && sqlcipher_sqlite3Strlen30(zRight) == 5) {
- unsigned char mask = 0;
- const unsigned char *hex = (const unsigned char *)zRight+2;
- cipher_hex2bin(hex,2,&mask);
- sqlcipher_set_hmac_salt_mask(mask);
- }
- sqlcipher_vdbe_return_string(pParse, "cipher_hmac_salt_mask", deprecation, P4_TRANSIENT);
- sqlcipher_sqlite3_log(SQLITE_WARNING, deprecation);
- } else {
- char *hmac_salt_mask = sqlcipher_sqlite3_mprintf("%02x", sqlcipher_get_hmac_salt_mask());
- sqlcipher_vdbe_return_string(pParse, "cipher_hmac_salt_mask", hmac_salt_mask, P4_DYNAMIC);
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_plaintext_header_size")==0 ){
- if(ctx) {
- if( zRight ) {
- int size = atoi(zRight);
- /* deliberately ignore result code, if size is invalid it will be set to -1
- and trip the error later in the codec */
- sqlcipher_codec_ctx_set_plaintext_header_size(ctx, size);
- } else {
- char *size = sqlcipher_sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_plaintext_header_size(ctx));
- sqlcipher_vdbe_return_string(pParse, "cipher_plaintext_header_size", size, P4_DYNAMIC);
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_plaintext_header_size")==0 ){
- if( zRight ) {
- sqlcipher_set_default_plaintext_header_size(atoi(zRight));
- } else {
- char *size = sqlcipher_sqlite3_mprintf("%d", sqlcipher_get_default_plaintext_header_size());
- sqlcipher_vdbe_return_string(pParse, "cipher_default_plaintext_header_size", size, P4_DYNAMIC);
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_salt")==0 ){
- if(ctx) {
- if(zRight) {
- if (sqlcipher_sqlite3StrNICmp(zRight ,"x'", 2) == 0 && sqlcipher_sqlite3Strlen30(zRight) == (FILE_HEADER_SZ*2)+3) {
- unsigned char *salt = (unsigned char*) sqlcipher_sqlite3_malloc(FILE_HEADER_SZ);
- const unsigned char *hex = (const unsigned char *)zRight+2;
- cipher_hex2bin(hex,FILE_HEADER_SZ*2,salt);
- sqlcipher_codec_ctx_set_kdf_salt(ctx, salt, FILE_HEADER_SZ);
- sqlcipher_sqlite3_free(salt);
- }
- } else {
- void *salt;
- char *hexsalt = (char*) sqlcipher_sqlite3_malloc((FILE_HEADER_SZ*2)+1);
- if((rc = sqlcipher_codec_ctx_get_kdf_salt(ctx, &salt)) == SQLITE_OK) {
- cipher_bin2hex(salt, FILE_HEADER_SZ, hexsalt);
- sqlcipher_vdbe_return_string(pParse, "cipher_salt", hexsalt, P4_DYNAMIC);
- } else {
- sqlcipher_sqlite3_free(hexsalt);
- sqlcipher_codec_ctx_set_error(ctx, rc);
- }
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_hmac_algorithm")==0 ){
- if(ctx) {
- if(zRight) {
- rc = SQLITE_ERROR;
- if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA1_LABEL) == 0) {
- rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA1);
- } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA256_LABEL) == 0) {
- rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA256);
- } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA512_LABEL) == 0) {
- rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA512);
- }
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- } else {
- int algorithm = sqlcipher_codec_ctx_get_hmac_algorithm(ctx);
- if(algorithm == SQLCIPHER_HMAC_SHA1) {
- sqlcipher_vdbe_return_string(pParse, "cipher_hmac_algorithm", SQLCIPHER_HMAC_SHA1_LABEL, P4_TRANSIENT);
- } else if(algorithm == SQLCIPHER_HMAC_SHA256) {
- sqlcipher_vdbe_return_string(pParse, "cipher_hmac_algorithm", SQLCIPHER_HMAC_SHA256_LABEL, P4_TRANSIENT);
- } else if(algorithm == SQLCIPHER_HMAC_SHA512) {
- sqlcipher_vdbe_return_string(pParse, "cipher_hmac_algorithm", SQLCIPHER_HMAC_SHA512_LABEL, P4_TRANSIENT);
- }
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_hmac_algorithm")==0 ){
- if(zRight) {
- rc = SQLITE_ERROR;
- if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA1_LABEL) == 0) {
- rc = sqlcipher_set_default_hmac_algorithm(SQLCIPHER_HMAC_SHA1);
- } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA256_LABEL) == 0) {
- rc = sqlcipher_set_default_hmac_algorithm(SQLCIPHER_HMAC_SHA256);
- } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA512_LABEL) == 0) {
- rc = sqlcipher_set_default_hmac_algorithm(SQLCIPHER_HMAC_SHA512);
- }
- } else {
- int algorithm = sqlcipher_get_default_hmac_algorithm();
- if(algorithm == SQLCIPHER_HMAC_SHA1) {
- sqlcipher_vdbe_return_string(pParse, "cipher_default_hmac_algorithm", SQLCIPHER_HMAC_SHA1_LABEL, P4_TRANSIENT);
- } else if(algorithm == SQLCIPHER_HMAC_SHA256) {
- sqlcipher_vdbe_return_string(pParse, "cipher_default_hmac_algorithm", SQLCIPHER_HMAC_SHA256_LABEL, P4_TRANSIENT);
- } else if(algorithm == SQLCIPHER_HMAC_SHA512) {
- sqlcipher_vdbe_return_string(pParse, "cipher_default_hmac_algorithm", SQLCIPHER_HMAC_SHA512_LABEL, P4_TRANSIENT);
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_kdf_algorithm")==0 ){
- if(ctx) {
- if(zRight) {
- rc = SQLITE_ERROR;
- if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL) == 0) {
- rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA1);
- } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL) == 0) {
- rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA256);
- } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL) == 0) {
- rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA512);
- }
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- } else {
- int algorithm = sqlcipher_codec_ctx_get_kdf_algorithm(ctx);
- if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
- sqlcipher_vdbe_return_string(pParse, "cipher_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL, P4_TRANSIENT);
- } else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
- sqlcipher_vdbe_return_string(pParse, "cipher_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL, P4_TRANSIENT);
- } else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
- sqlcipher_vdbe_return_string(pParse, "cipher_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL, P4_TRANSIENT);
- }
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_kdf_algorithm")==0 ){
- if(zRight) {
- rc = SQLITE_ERROR;
- if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL) == 0) {
- rc = sqlcipher_set_default_kdf_algorithm(SQLCIPHER_PBKDF2_HMAC_SHA1);
- } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL) == 0) {
- rc = sqlcipher_set_default_kdf_algorithm(SQLCIPHER_PBKDF2_HMAC_SHA256);
- } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL) == 0) {
- rc = sqlcipher_set_default_kdf_algorithm(SQLCIPHER_PBKDF2_HMAC_SHA512);
- }
- } else {
- int algorithm = sqlcipher_get_default_kdf_algorithm();
- if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
- sqlcipher_vdbe_return_string(pParse, "cipher_default_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL, P4_TRANSIENT);
- } else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
- sqlcipher_vdbe_return_string(pParse, "cipher_default_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL, P4_TRANSIENT);
- } else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
- sqlcipher_vdbe_return_string(pParse, "cipher_default_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL, P4_TRANSIENT);
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_compatibility")==0 ){
- if(ctx) {
- if(zRight) {
- int version = atoi(zRight);
-
- switch(version) {
- case 1:
- rc = sqlcipher_codec_ctx_set_pagesize(ctx, 1024);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA1);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA1);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, 4000);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_use_hmac(ctx, 0);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- break;
-
- case 2:
- rc = sqlcipher_codec_ctx_set_pagesize(ctx, 1024);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA1);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA1);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, 4000);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_use_hmac(ctx, 1);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- break;
-
- case 3:
- rc = sqlcipher_codec_ctx_set_pagesize(ctx, 1024);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA1);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA1);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, 64000);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_use_hmac(ctx, 1);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- break;
-
- default:
- rc = sqlcipher_codec_ctx_set_pagesize(ctx, 4096);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA512);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA512);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, 256000);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- rc = sqlcipher_codec_ctx_set_use_hmac(ctx, 1);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- break;
- }
-
- rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
- if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_compatibility")==0 ){
- if(zRight) {
- int version = atoi(zRight);
- switch(version) {
- case 1:
- sqlcipher_set_default_pagesize(1024);
- sqlcipher_set_default_hmac_algorithm(SQLCIPHER_HMAC_SHA1);
- sqlcipher_set_default_kdf_algorithm(SQLCIPHER_PBKDF2_HMAC_SHA1);
- sqlcipher_set_default_kdf_iter(4000);
- sqlcipher_set_default_use_hmac(0);
- break;
-
- case 2:
- sqlcipher_set_default_pagesize(1024);
- sqlcipher_set_default_hmac_algorithm(SQLCIPHER_HMAC_SHA1);
- sqlcipher_set_default_kdf_algorithm(SQLCIPHER_PBKDF2_HMAC_SHA1);
- sqlcipher_set_default_kdf_iter(4000);
- sqlcipher_set_default_use_hmac(1);
- break;
-
- case 3:
- sqlcipher_set_default_pagesize(1024);
- sqlcipher_set_default_hmac_algorithm(SQLCIPHER_HMAC_SHA1);
- sqlcipher_set_default_kdf_algorithm(SQLCIPHER_PBKDF2_HMAC_SHA1);
- sqlcipher_set_default_kdf_iter(64000);
- sqlcipher_set_default_use_hmac(1);
- break;
-
- default:
- sqlcipher_set_default_pagesize(4096);
- sqlcipher_set_default_hmac_algorithm(SQLCIPHER_HMAC_SHA512);
- sqlcipher_set_default_kdf_algorithm(SQLCIPHER_PBKDF2_HMAC_SHA512);
- sqlcipher_set_default_kdf_iter(256000);
- sqlcipher_set_default_use_hmac(1);
- break;
- }
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_memory_security")==0 ){
- if( zRight ) {
- sqlcipher_set_mem_security(sqlcipher_sqlite3GetBoolean(zRight,1));
- } else {
- char *on = sqlcipher_sqlite3_mprintf("%d", sqlcipher_get_mem_security());
- sqlcipher_vdbe_return_string(pParse, "cipher_memory_security", on, P4_DYNAMIC);
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_settings")==0 ){
- if(ctx) {
- int algorithm;
- char *pragma;
-
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA kdf_iter = %d;", sqlcipher_codec_ctx_get_kdf_iter(ctx));
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
-
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_page_size = %d;", sqlcipher_codec_ctx_get_pagesize(ctx));
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
-
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_use_hmac = %d;", sqlcipher_codec_ctx_get_use_hmac(ctx));
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
-
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_plaintext_header_size = %d;", sqlcipher_codec_ctx_get_plaintext_header_size(ctx));
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
-
- algorithm = sqlcipher_codec_ctx_get_hmac_algorithm(ctx);
- pragma = NULL;
- if(algorithm == SQLCIPHER_HMAC_SHA1) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA1_LABEL);
- } else if(algorithm == SQLCIPHER_HMAC_SHA256) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA256_LABEL);
- } else if(algorithm == SQLCIPHER_HMAC_SHA512) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA512_LABEL);
- }
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
-
- algorithm = sqlcipher_codec_ctx_get_kdf_algorithm(ctx);
- pragma = NULL;
- if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL);
- } else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL);
- } else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL);
- }
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
-
- }
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_settings")==0 ){
- int algorithm;
- char *pragma;
-
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_kdf_iter = %d;", sqlcipher_get_default_kdf_iter());
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
-
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_page_size = %d;", sqlcipher_get_default_pagesize());
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
-
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_use_hmac = %d;", sqlcipher_get_default_use_hmac());
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
-
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_plaintext_header_size = %d;", sqlcipher_get_default_plaintext_header_size());
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
-
- algorithm = sqlcipher_get_default_hmac_algorithm();
- pragma = NULL;
- if(algorithm == SQLCIPHER_HMAC_SHA1) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA1_LABEL);
- } else if(algorithm == SQLCIPHER_HMAC_SHA256) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA256_LABEL);
- } else if(algorithm == SQLCIPHER_HMAC_SHA512) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA512_LABEL);
- }
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
-
- algorithm = sqlcipher_get_default_kdf_algorithm();
- pragma = NULL;
- if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL);
- } else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL);
- } else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
- pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL);
- }
- sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
- }else
- if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_integrity_check")==0 ){
- if(ctx) {
- sqlcipher_codec_ctx_integrity_check(ctx, pParse, "cipher_integrity_check");
- }
- } else
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_log_level")==0 && zRight){
- unsigned int level = SQLCIPHER_LOG_NONE;
- if(sqlcipher_sqlite3_stricmp(zRight, "ERROR")==0) level = SQLCIPHER_LOG_ERROR;
- else if(sqlcipher_sqlite3_stricmp(zRight, "WARN" )==0) level = SQLCIPHER_LOG_WARN;
- else if(sqlcipher_sqlite3_stricmp(zRight, "INFO" )==0) level = SQLCIPHER_LOG_INFO;
- else if(sqlcipher_sqlite3_stricmp(zRight, "DEBUG")==0) level = SQLCIPHER_LOG_DEBUG;
- else if(sqlcipher_sqlite3_stricmp(zRight, "TRACE")==0) level = SQLCIPHER_LOG_TRACE;
- sqlcipher_set_log_level(level);
- sqlcipher_vdbe_return_string(pParse, "cipher_log_level", sqlcipher_sqlite3_mprintf("%u", level), P4_DYNAMIC);
- } else
- if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_log")== 0 && zRight ){
- char *status = sqlcipher_sqlite3_mprintf("%d", sqlcipher_set_log(zRight));
- sqlcipher_vdbe_return_string(pParse, "cipher_log", status, P4_DYNAMIC);
- }else {
- return 0;
- }
- return 1;
-}
-
-/* these constants are used internally within SQLite's pager.c to differentiate between
- operations on the main database or journal pages. This is important in the context
- of a rekey operations, where the journal must be written using the original key
- material (to allow a transactional rollback), while the new database pages are being
- written with the new key material*/
-#define CODEC_READ_OP 3
-#define CODEC_WRITE_OP 6
-#define CODEC_JOURNAL_OP 7
-
-/*
- * sqlcipher_sqlite3Codec can be called in multiple modes.
- * encrypt mode - expected to return a pointer to the
- * encrypted data without altering pData.
- * decrypt mode - expected to return a pointer to pData, with
- * the data decrypted in the input buffer
- */
-static void* sqlcipher_sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
- codec_ctx *ctx = (codec_ctx *) iCtx;
- int offset = 0, rc = 0;
- int page_sz = sqlcipher_codec_ctx_get_pagesize(ctx);
- unsigned char *pData = (unsigned char *) data;
- void *buffer = sqlcipher_codec_ctx_get_data(ctx);
- int plaintext_header_sz = sqlcipher_codec_ctx_get_plaintext_header_size(ctx);
- int cctx = CIPHER_READ_CTX;
-
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_sqlite3Codec: pgno=%d, mode=%d, page_sz=%d", pgno, mode, page_sz);
-
-#ifdef SQLCIPHER_EXT
- if(sqlcipher_license_check(ctx) != SQLITE_OK) return NULL;
-#endif
-
- /* call to derive keys if not present yet */
- if((rc = sqlcipher_codec_key_derive(ctx)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_sqlite3Codec: error occurred during key derivation: %d", rc);
- sqlcipher_codec_ctx_set_error(ctx, rc);
- return NULL;
- }
-
- /* if the plaintext_header_size is negative that means an invalid size was set via
- PRAGMA. We can't set the error state on the pager at that point because the pager
- may not be open yet. However, this is a fatal error state, so abort the codec */
- if(plaintext_header_sz < 0) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_sqlite3Codec: error invalid plaintext_header_sz: %d", plaintext_header_sz);
- sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
- return NULL;
- }
-
- if(pgno == 1) /* adjust starting pointers in data page for header offset on first page*/
- offset = plaintext_header_sz ? plaintext_header_sz : FILE_HEADER_SZ;
-
-
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_sqlite3Codec: switch mode=%d offset=%d", mode, offset);
- switch(mode) {
- case CODEC_READ_OP: /* decrypt */
- if(pgno == 1) /* copy initial part of file header or SQLite magic to buffer */
- memcpy(buffer, plaintext_header_sz ? pData : (void *) SQLITE_FILE_HEADER, offset);
-
- rc = sqlcipher_page_cipher(ctx, cctx, pgno, CIPHER_DECRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset);
#ifdef SQLCIPHER_TEST
- if((sqlcipher_get_test_flags() & TEST_FAIL_DECRYPT) > 0 && sqlcipher_get_test_fail()) {
- rc = SQLITE_ERROR;
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "simulating decryption failure for pgno=%d, mode=%d, page_sz=%d\n", pgno, mode, page_sz);
- }
-#endif
- if(rc != SQLITE_OK) {
- /* failure to decrypt a page is considered a permanent error and will render the pager unusable
- in order to prevent inconsistent data being loaded into page cache */
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_sqlite3Codec: error decrypting page %d data: %d", pgno, rc);
- sqlcipher_memset((unsigned char*) buffer+offset, 0, page_sz-offset);
- sqlcipher_codec_ctx_set_error(ctx, rc);
- }
- memcpy(pData, buffer, page_sz); /* copy buffer data back to pData and return */
- return pData;
- break;
-
- case CODEC_WRITE_OP: /* encrypt database page, operate on write context and fall through to case 7, so the write context is used*/
- cctx = CIPHER_WRITE_CTX;
-
- case CODEC_JOURNAL_OP: /* encrypt journal page, operate on read context use to get the original page data from the database */
- if(pgno == 1) { /* copy initial part of file header or salt to buffer */
- void *kdf_salt = NULL;
- /* retrieve the kdf salt */
- if((rc = sqlcipher_codec_ctx_get_kdf_salt(ctx, &kdf_salt)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_sqlite3Codec: error retrieving salt: %d", rc);
- sqlcipher_codec_ctx_set_error(ctx, rc);
- return NULL;
- }
- memcpy(buffer, plaintext_header_sz ? pData : kdf_salt, offset);
- }
- rc = sqlcipher_page_cipher(ctx, cctx, pgno, CIPHER_ENCRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset);
-#ifdef SQLCIPHER_TEST
- if((sqlcipher_get_test_flags() & TEST_FAIL_ENCRYPT) > 0 && sqlcipher_get_test_fail()) {
- rc = SQLITE_ERROR;
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "simulating encryption failure for pgno=%d, mode=%d, page_sz=%d\n", pgno, mode, page_sz);
- }
-#endif
- if(rc != SQLITE_OK) {
- /* failure to encrypt a page is considered a permanent error and will render the pager unusable
- in order to prevent corrupted pages from being written to the main databased when using WAL */
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_sqlite3Codec: error encrypting page %d data: %d", pgno, rc);
- sqlcipher_memset((unsigned char*)buffer+offset, 0, page_sz-offset);
- sqlcipher_codec_ctx_set_error(ctx, rc);
- return NULL;
- }
- return buffer; /* return persistent buffer data, pData remains intact */
- break;
-
- default:
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_sqlite3Codec: error unsupported codec mode %d", mode);
- sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR); /* unsupported mode, set error */
- return pData;
- break;
- }
-}
-
-static void sqlcipher_sqlite3FreeCodecArg(void *pCodecArg) {
- codec_ctx *ctx = (codec_ctx *) pCodecArg;
- if(pCodecArg == NULL) return;
- sqlcipher_codec_ctx_free(&ctx); /* wipe and free allocated memory for the context */
- sqlcipher_deactivate(); /* cleanup related structures, OpenSSL etc, when codec is detatched */
-}
-
-int sqlcipherCodecAttach(sqlcipher_sqlite3* db, int nDb, const void *zKey, int nKey) {
- struct Db *pDb = &db->aDb[nDb];
-
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipherCodecAttach: db=%p, nDb=%d", db, nDb);
-
- if(nKey && zKey && pDb->pBt) {
- int rc;
- Pager *pPager = pDb->pBt->pBt->pPager;
- sqlcipher_sqlite3_file *fd;
- codec_ctx *ctx;
-
- /* check if the sqlcipher_sqlite3_file is open, and if not force handle to NULL */
- if((fd = sqlcipher_sqlite3PagerFile(pPager))->pMethods == 0) fd = NULL;
-
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipherCodecAttach: calling sqlcipher_activate()");
- sqlcipher_activate(); /* perform internal initialization for sqlcipher */
-
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipherCodecAttach: entering database mutex %p", db->mutex);
- sqlcipher_sqlite3_mutex_enter(db->mutex);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipherCodecAttach: entered database mutex %p", db->mutex);
-
-#ifdef SQLCIPHER_EXT
- if((rc = sqlcipher_sqlite3_set_authorizer(db, sqlcipher_license_authorizer, db)) != SQLITE_OK) {
- sqlcipher_sqlite3_mutex_leave(db->mutex);
- return rc;
- }
-#endif
-
- /* point the internal codec argument against the contet to be prepared */
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipherCodecAttach: calling sqlcipher_codec_ctx_init()");
- rc = sqlcipher_codec_ctx_init(&ctx, pDb, pDb->pBt->pBt->pPager, zKey, nKey);
-
- if(rc != SQLITE_OK) {
- /* initialization failed, do not attach potentially corrupted context */
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipherCodecAttach: context initialization failed forcing error state with rc=%d", rc);
- /* force an error at the pager level, such that even the upstream caller ignores the return code
- the pager will be in an error state and will process no further operations */
- sqlcipher_sqlite3pager_error(pPager, rc);
- pDb->pBt->pBt->db->errCode = rc;
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipherCodecAttach: leaving database mutex %p (early return on rc=%d)", db->mutex, rc);
- sqlcipher_sqlite3_mutex_leave(db->mutex);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipherCodecAttach: left database mutex %p (early return on rc=%d)", db->mutex, rc);
- return rc;
- }
-
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipherCodecAttach: calling sqlcipherPagerSetCodec()");
- sqlcipherPagerSetCodec(sqlcipher_sqlite3BtreePager(pDb->pBt), sqlcipher_sqlite3Codec, NULL, sqlcipher_sqlite3FreeCodecArg, (void *) ctx);
-
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipherCodecAttach: calling codec_set_btree_to_codec_pagesize()");
- 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
- sqlcipher_sqlite3PagerDontWrite optimizations) */
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipherCodecAttach: calling sqlcipher_sqlite3BtreeSecureDelete()");
- sqlcipher_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 */
- if(fd != NULL) {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipherCodecAttach: calling sqlcipher_sqlite3BtreeSetAutoVacuum()");
- sqlcipher_sqlite3BtreeSetAutoVacuum(pDb->pBt, SQLITE_DEFAULT_AUTOVACUUM);
- }
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipherCodecAttach: leaving database mutex %p", db->mutex);
- sqlcipher_sqlite3_mutex_leave(db->mutex);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipherCodecAttach: left database mutex %p", db->mutex);
- }
- return SQLITE_OK;
-}
-
-int sqlcipher_find_db_index(sqlcipher_sqlite3 *db, const char *zDb) {
- int db_index;
- if(zDb == NULL){
- return 0;
- }
- for(db_index = 0; db_index < db->nDb; db_index++) {
- struct Db *pDb = &db->aDb[db_index];
- if(strcmp(pDb->zDbSName, zDb) == 0) {
- return db_index;
- }
- }
- return 0;
-}
-
-SQLITE_API void sqlcipher_sqlite3_activate_see(const char* in) {
- /* do nothing, security enhancements are always active */
-}
-
-SQLITE_API int sqlcipher_sqlite3_key(sqlcipher_sqlite3 *db, const void *pKey, int nKey) {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_sqlite3_key: db=%p", db);
- return sqlcipher_sqlite3_key_v2(db, "main", pKey, nKey);
-}
-
-SQLITE_API int sqlcipher_sqlite3_key_v2(sqlcipher_sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_sqlite3_key_v2: db=%p zDb=%s", db, zDb);
- /* attach key if db and pKey are not null and nKey is > 0 */
- if(db && pKey && nKey) {
- int db_index = sqlcipher_find_db_index(db, zDb);
- return sqlcipherCodecAttach(db, db_index, pKey, nKey);
- }
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_sqlite3_key_v2: no key provided");
- return SQLITE_ERROR;
-}
-
-SQLITE_API int sqlcipher_sqlite3_rekey(sqlcipher_sqlite3 *db, const void *pKey, int nKey) {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_sqlite3_rekey: db=%p", db);
- return sqlcipher_sqlite3_rekey_v2(db, "main", pKey, nKey);
-}
-
-/* sqlcipher_sqlite3_rekey_v2
-** Given a database, this will reencrypt the database using a new key.
-** There is only one possible modes of operation - to encrypt a database
-** that is already encrpyted. If the database is not already encrypted
-** this should do nothing
-** The proposed logic for this function follows:
-** 1. Determine if the database is already encryptped
-** 2. If there is NOT already a key present do nothing
-** 3. If there is a key present, re-encrypt the database with the new key
-*/
-SQLITE_API int sqlcipher_sqlite3_rekey_v2(sqlcipher_sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_sqlite3_rekey_v2: db=%p zDb=%s", db, zDb);
- if(db && pKey && nKey) {
- int db_index = sqlcipher_find_db_index(db, zDb);
- struct Db *pDb = &db->aDb[db_index];
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_sqlite3_rekey_v2: database zDb=%p db_index:%d", zDb, db_index);
- if(pDb->pBt) {
- codec_ctx *ctx;
- int rc, page_count;
- Pgno pgno;
- PgHdr *page;
- Pager *pPager = pDb->pBt->pBt->pPager;
-
- ctx = (codec_ctx*) sqlcipherPagerGetCodec(pDb->pBt->pBt->pPager);
-
- if(ctx == NULL) {
- /* there was no codec attached to this database, so this should do nothing! */
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_sqlite3_rekey_v2: no codec attached to db, exiting");
- return SQLITE_OK;
- }
-
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_sqlite3_rekey_v2: entering database mutex %p", db->mutex);
- sqlcipher_sqlite3_mutex_enter(db->mutex);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_sqlite3_rekey_v2: entered database mutex %p", db->mutex);
-
- codec_set_pass_key(db, db_index, pKey, nKey, CIPHER_WRITE_CTX);
-
- /* do stuff here to rewrite the database
- ** 1. Create a transaction on the database
- ** 2. Iterate through each page, reading it and then writing it.
- ** 3. If that goes ok then commit and put ctx->rekey into ctx->key
- ** note: don't deallocate rekey since it may be used in a subsequent iteration
- */
- rc = sqlcipher_sqlite3BtreeBeginTrans(pDb->pBt, 1, 0); /* begin write transaction */
- sqlcipher_sqlite3PagerPagecount(pPager, &page_count);
- for(pgno = 1; rc == SQLITE_OK && pgno <= (unsigned int)page_count; pgno++) { /* pgno's start at 1 see pager.c:pagerAcquire */
- if(!sqlcipher_sqlite3pager_is_sj_pgno(pPager, pgno)) { /* skip this page (see pager.c:pagerAcquire for reasoning) */
- rc = sqlcipher_sqlite3PagerGet(pPager, pgno, &page, 0);
- if(rc == SQLITE_OK) { /* write page see pager_incr_changecounter for example */
- rc = sqlcipher_sqlite3PagerWrite(page);
- if(rc == SQLITE_OK) {
- sqlcipher_sqlite3PagerUnref(page);
- } else {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_sqlite3_rekey_v2: error %d occurred writing page %d", rc, pgno);
- }
- } else {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_sqlite3_rekey_v2: error %d occurred getting page %d", rc, pgno);
- }
- }
- }
-
- /* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */
- if(rc == SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_sqlite3_rekey_v2: committing");
- rc = sqlcipher_sqlite3BtreeCommit(pDb->pBt);
- sqlcipher_codec_key_copy(ctx, CIPHER_WRITE_CTX);
- } else {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_sqlite3_rekey_v2: rollback");
- sqlcipher_sqlite3BtreeRollback(pDb->pBt, SQLITE_ABORT_ROLLBACK, 0);
- }
-
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_sqlite3_rekey_v2: leaving database mutex %p", db->mutex);
- sqlcipher_sqlite3_mutex_leave(db->mutex);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_sqlite3_rekey_v2: left database mutex %p", db->mutex);
- }
- return SQLITE_OK;
- }
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_sqlite3_rekey_v2: no key provided");
- return SQLITE_ERROR;
-}
-
-void sqlcipherCodecGetKey(sqlcipher_sqlite3* db, int nDb, void **zKey, int *nKey) {
- struct Db *pDb = &db->aDb[nDb];
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipherCodecGetKey:db=%p, nDb=%d", db, nDb);
- if( pDb->pBt ) {
- codec_ctx *ctx = (codec_ctx*) sqlcipherPagerGetCodec(pDb->pBt->pBt->pPager);
-
- if(ctx) {
- /* pass back the keyspec from the codec, unless PRAGMA cipher_store_pass
- is set or keyspec has not yet been derived, in which case pass
- back the password key material */
- sqlcipher_codec_get_keyspec(ctx, zKey, nKey);
- if(sqlcipher_codec_get_store_pass(ctx) == 1 || *zKey == NULL) {
- sqlcipher_codec_get_pass(ctx, zKey, nKey);
- }
- } else {
- *zKey = NULL;
- *nKey = 0;
- }
- }
-}
-
-/*
- * Implementation of an "export" function that allows a caller
- * to duplicate the main database to an attached database. This is intended
- * as a conveneince for users who need to:
- *
- * 1. migrate from an non-encrypted database to an encrypted database
- * 2. move from an encrypted database to a non-encrypted database
- * 3. convert beween the various flavors of encrypted databases.
- *
- * This implementation is based heavily on the procedure and code used
- * in vacuum.c, but is exposed as a function that allows export to any
- * named attached database.
- */
-
-/*
-** Finalize a prepared statement. If there was an error, store the
-** text of the error message in *pzErrMsg. Return the result code.
-**
-** Based on vacuumFinalize from vacuum.c
-*/
-static int sqlcipher_finalize(sqlcipher_sqlite3 *db, sqlcipher_sqlite3_stmt *pStmt, char **pzErrMsg){
- int rc;
- rc = sqlcipher_sqlite3VdbeFinalize((Vdbe*)pStmt);
- if( rc ){
- sqlcipher_sqlite3SetString(pzErrMsg, db, sqlcipher_sqlite3_errmsg(db));
- }
- return rc;
-}
-
-/*
-** Execute zSql on database db. Return an error code.
-**
-** Based on execSql from vacuum.c
-*/
-static int sqlcipher_execSql(sqlcipher_sqlite3 *db, char **pzErrMsg, const char *zSql){
- sqlcipher_sqlite3_stmt *pStmt;
- VVA_ONLY( int rc; )
- if( !zSql ){
- return SQLITE_NOMEM;
- }
- if( SQLITE_OK!=sqlcipher_sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
- sqlcipher_sqlite3SetString(pzErrMsg, db, sqlcipher_sqlite3_errmsg(db));
- return sqlcipher_sqlite3_errcode(db);
- }
- VVA_ONLY( rc = ) sqlcipher_sqlite3_step(pStmt);
- assert( rc!=SQLITE_ROW );
- return sqlcipher_finalize(db, pStmt, pzErrMsg);
-}
-
-/*
-** Execute zSql on database db. The statement returns exactly
-** one column. Execute this as SQL on the same database.
-**
-** Based on execExecSql from vacuum.c
-*/
-static int sqlcipher_execExecSql(sqlcipher_sqlite3 *db, char **pzErrMsg, const char *zSql){
- sqlcipher_sqlite3_stmt *pStmt;
- int rc;
-
- rc = sqlcipher_sqlite3_prepare(db, zSql, -1, &pStmt, 0);
- if( rc!=SQLITE_OK ) return rc;
-
- while( SQLITE_ROW==sqlcipher_sqlite3_step(pStmt) ){
- rc = sqlcipher_execSql(db, pzErrMsg, (char*)sqlcipher_sqlite3_column_text(pStmt, 0));
- if( rc!=SQLITE_OK ){
- sqlcipher_finalize(db, pStmt, pzErrMsg);
- return rc;
- }
- }
-
- return sqlcipher_finalize(db, pStmt, pzErrMsg);
-}
-
-/*
- * copy database and schema from the main database to an attached database
- *
- * Based on sqlcipher_sqlite3RunVacuum from vacuum.c
-*/
-void sqlcipher_exportFunc(sqlcipher_sqlite3_context *context, int argc, sqlcipher_sqlite3_value **argv) {
- sqlcipher_sqlite3 *db = sqlcipher_sqlite3_context_db_handle(context);
- const char* targetDb, *sourceDb;
- int targetDb_idx = 0;
- u64 saved_flags = db->flags; /* Saved value of the db->flags */
- u32 saved_mDbFlags = db->mDbFlags; /* Saved value of the db->mDbFlags */
- int saved_nChange = db->nChange; /* Saved value of db->nChange */
- int saved_nTotalChange = db->nTotalChange; /* Saved value of db->nTotalChange */
- u8 saved_mTrace = db->mTrace; /* Saved value of db->mTrace */
- int rc = SQLITE_OK; /* Return code from service routines */
- char *zSql = NULL; /* SQL statements */
- char *pzErrMsg = NULL;
-
- if(argc != 1 && argc != 2) {
- rc = SQLITE_ERROR;
- pzErrMsg = sqlcipher_sqlite3_mprintf("invalid number of arguments (%d) passed to sqlcipher_export", argc);
- goto end_of_export;
- }
-
- if(sqlcipher_sqlite3_value_type(argv[0]) == SQLITE_NULL) {
- rc = SQLITE_ERROR;
- pzErrMsg = sqlcipher_sqlite3_mprintf("target database can't be NULL");
- goto end_of_export;
- }
-
- targetDb = (const char*) sqlcipher_sqlite3_value_text(argv[0]);
- sourceDb = "main";
-
- if(argc == 2) {
- if(sqlcipher_sqlite3_value_type(argv[1]) == SQLITE_NULL) {
- rc = SQLITE_ERROR;
- pzErrMsg = sqlcipher_sqlite3_mprintf("target database can't be NULL");
- goto end_of_export;
- }
- sourceDb = (char *) sqlcipher_sqlite3_value_text(argv[1]);
- }
-
-
- /* if the name of the target is not main, but the index returned is zero
- there is a mismatch and we should not proceed */
- targetDb_idx = sqlcipher_find_db_index(db, targetDb);
- if(targetDb_idx == 0 && targetDb != NULL && sqlcipher_sqlite3_stricmp("main", targetDb) != 0) {
- rc = SQLITE_ERROR;
- pzErrMsg = sqlcipher_sqlite3_mprintf("unknown database %s", targetDb);
- goto end_of_export;
- }
- db->init.iDb = targetDb_idx;
-
- db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
- db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
- db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_Defensive | SQLITE_CountRows);
- db->mTrace = 0;
-
- /* Query the schema of the main database. Create a mirror schema
- ** in the temporary database.
- */
- zSql = sqlcipher_sqlite3_mprintf(
- "SELECT sql "
- " FROM %s.sqlite_schema WHERE type='table' AND name!='sqlite_sequence'"
- " AND rootpage>0"
- , sourceDb);
- rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
- if( rc!=SQLITE_OK ) goto end_of_export;
- sqlcipher_sqlite3_free(zSql);
-
- zSql = sqlcipher_sqlite3_mprintf(
- "SELECT sql "
- " FROM %s.sqlite_schema WHERE sql LIKE 'CREATE INDEX %%' "
- , sourceDb);
- rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
- if( rc!=SQLITE_OK ) goto end_of_export;
- sqlcipher_sqlite3_free(zSql);
-
- zSql = sqlcipher_sqlite3_mprintf(
- "SELECT sql "
- " FROM %s.sqlite_schema WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
- , sourceDb);
- rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
- if( rc!=SQLITE_OK ) goto end_of_export;
- sqlcipher_sqlite3_free(zSql);
-
- /* Loop through the tables in the main database. For each, do
- ** an "INSERT INTO rekey_db.xxx SELECT * FROM main.xxx;" to copy
- ** the contents to the temporary database.
- */
- zSql = sqlcipher_sqlite3_mprintf(
- "SELECT 'INSERT INTO %s.' || quote(name) "
- "|| ' SELECT * FROM %s.' || quote(name) || ';'"
- "FROM %s.sqlite_schema "
- "WHERE type = 'table' AND name!='sqlite_sequence' "
- " AND rootpage>0"
- , targetDb, sourceDb, sourceDb);
- rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
- if( rc!=SQLITE_OK ) goto end_of_export;
- sqlcipher_sqlite3_free(zSql);
-
- /* Copy over the contents of the sequence table
- */
- zSql = sqlcipher_sqlite3_mprintf(
- "SELECT 'INSERT INTO %s.' || quote(name) "
- "|| ' SELECT * FROM %s.' || quote(name) || ';' "
- "FROM %s.sqlite_schema WHERE name=='sqlite_sequence';"
- , targetDb, sourceDb, targetDb);
- rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
- if( rc!=SQLITE_OK ) goto end_of_export;
- sqlcipher_sqlite3_free(zSql);
-
- /* Copy the triggers, views, and virtual tables from the main database
- ** over to the temporary database. None of these objects has any
- ** associated storage, so all we have to do is copy their entries
- ** from the SQLITE_MASTER table.
- */
- zSql = sqlcipher_sqlite3_mprintf(
- "INSERT INTO %s.sqlite_schema "
- " SELECT type, name, tbl_name, rootpage, sql"
- " FROM %s.sqlite_schema"
- " WHERE type='view' OR type='trigger'"
- " OR (type='table' AND rootpage=0)"
- , targetDb, sourceDb);
- rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execSql(db, &pzErrMsg, zSql);
- if( rc!=SQLITE_OK ) goto end_of_export;
- sqlcipher_sqlite3_free(zSql);
-
- zSql = NULL;
-end_of_export:
- db->init.iDb = 0;
- db->flags = saved_flags;
- db->mDbFlags = saved_mDbFlags;
- db->nChange = saved_nChange;
- db->nTotalChange = saved_nTotalChange;
- db->mTrace = saved_mTrace;
-
- if(zSql) sqlcipher_sqlite3_free(zSql);
-
- if(rc) {
- if(pzErrMsg != NULL) {
- sqlcipher_sqlite3_result_error(context, pzErrMsg, -1);
- sqlcipher_sqlite3DbFree(db, pzErrMsg);
- } else {
- sqlcipher_sqlite3_result_error(context, sqlcipher_sqlite3ErrStr(rc), -1);
- }
- }
-}
-#endif
-/* END SQLCIPHER */
-
-/************** End of crypto.c **********************************************/
-/************** Begin file crypto_impl.c *************************************/
-/*
-** SQLCipher
-** http://sqlcipher.net
-**
-** Copyright (c) 2008 - 2013, ZETETIC LLC
-** All rights reserved.
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in the
-** documentation and/or other materials provided with the distribution.
-** * Neither the name of the ZETETIC LLC nor the
-** names of its contributors may be used to endorse or promote products
-** derived from this software without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
-** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
-** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-**
-*/
-/* BEGIN SQLCIPHER */
-#ifdef SQLITE_HAS_CODEC
-
-/* #include "sqlcipher.h" */
-/* #include "crypto.h" */
+/* possible flags for simulating specific test conditions */
+#define TEST_FAIL_ENCRYPT 0x01
+#define TEST_FAIL_DECRYPT 0x02
+#define TEST_FAIL_MIGRATE 0x04
-#ifdef SQLCIPHER_TEST
static volatile unsigned int cipher_test_flags = 0;
-unsigned int sqlcipher_get_test_flags() {
- return cipher_test_flags;
-}
-void sqlcipher_set_test_flags(unsigned int flags) {
- cipher_test_flags = flags;
-}
-
static volatile int cipher_test_rand = 0;
-int sqlcipher_get_test_rand() {
- return cipher_test_rand;
-}
-void sqlcipher_set_test_rand(int rand) {
- cipher_test_rand = rand;
-}
-int sqlcipher_get_test_fail() {
+
+static int sqlcipher_get_test_fail() {
int x;
/* if cipher_test_rand is not set to a non-zero value always fail (return true) */
@@ -103413,13 +107250,11 @@ int sqlcipher_get_test_fail() {
}
#endif
-/* Generate code to return a string value */
-
static volatile unsigned int default_flags = DEFAULT_CIPHER_FLAGS;
static volatile unsigned char hmac_salt_mask = HMAC_SALT_MASK;
static volatile int default_kdf_iter = PBKDF2_ITER;
static volatile int default_page_size = 4096;
-static volatile int default_plaintext_header_sz = 0;
+static volatile int default_plaintext_header_size = 0;
static volatile int default_hmac_algorithm = SQLCIPHER_HMAC_SHA512;
static volatile int default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA512;
static volatile int sqlcipher_mem_security_on = 0;
@@ -103431,14 +107266,79 @@ static sqlcipher_provider *default_provider = NULL;
static sqlcipher_sqlite3_mutex* sqlcipher_static_mutex[SQLCIPHER_MUTEX_COUNT];
static FILE* sqlcipher_log_file = NULL;
-static volatile int sqlcipher_log_logcat = 0;
+static volatile int sqlcipher_log_device = 0;
static volatile unsigned int sqlcipher_log_level = SQLCIPHER_LOG_NONE;
+static volatile unsigned int sqlcipher_log_source = SQLCIPHER_LOG_ANY;
+static volatile int sqlcipher_log_set = 0;
sqlcipher_sqlite3_mutex* sqlcipher_mutex(int mutex) {
if(mutex < 0 || mutex >= SQLCIPHER_MUTEX_COUNT) return NULL;
return sqlcipher_static_mutex[mutex];
}
+static void sqlcipher_mlock(void *ptr, sqlite_uint64 sz) {
+#ifndef OMIT_MEMLOCK
+#if defined(__unix__) || defined(__APPLE__)
+ int rc;
+ unsigned long pagesize = sysconf(_SC_PAGESIZE);
+ unsigned long offset = (unsigned long) ptr % pagesize;
+
+ if(ptr == NULL || sz == 0) return;
+
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_mlock: calling mlock(%p,%lu); _SC_PAGESIZE=%lu", ptr - offset, sz + offset, pagesize);
+ rc = mlock(ptr - offset, sz + offset);
+ if(rc!=0) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_MEMORY, "sqlcipher_mlock: mlock() returned %d errno=%d", rc, errno);
+ sqlcipher_log(SQLCIPHER_LOG_INFO, SQLCIPHER_LOG_MEMORY, "sqlcipher_mlock: mlock(%p,%lu) returned %d errno=%d", ptr - offset, sz + offset, rc, errno);
+ }
+#elif defined(_WIN32)
+#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_PC_APP))
+ int rc;
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_mlock: calling VirtualLock(%p,%d)", ptr, sz);
+ rc = VirtualLock(ptr, sz);
+ if(rc==0) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_MEMORY, "sqlcipher_mlock: VirtualLock() returned %d LastError=%d", rc, GetLastError());
+ sqlcipher_log(SQLCIPHER_LOG_INFO, SQLCIPHER_LOG_MEMORY, "sqlcipher_mlock: VirtualLock(%p,%d) returned %d LastError=%d", ptr, sz, rc, GetLastError());
+ }
+#endif
+#endif
+#endif
+}
+
+static void sqlcipher_munlock(void *ptr, sqlite_uint64 sz) {
+#ifndef OMIT_MEMLOCK
+#if defined(__unix__) || defined(__APPLE__)
+ int rc;
+ unsigned long pagesize = sysconf(_SC_PAGESIZE);
+ unsigned long offset = (unsigned long) ptr % pagesize;
+
+ if(ptr == NULL || sz == 0) return;
+
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_munlock: calling munlock(%p,%lu)", ptr - offset, sz + offset);
+ rc = munlock(ptr - offset, sz + offset);
+ if(rc!=0) {
+ sqlcipher_log(SQLCIPHER_LOG_INFO, SQLCIPHER_LOG_MEMORY, "sqlcipher_munlock: munlock(%p,%lu) returned %d errno=%d", ptr - offset, sz + offset, rc, errno);
+ }
+#elif defined(_WIN32)
+#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_PC_APP))
+ int rc;
+
+ if(ptr == NULL || sz == 0) return;
+
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_munlock: calling VirtualUnlock(%p,%d)", ptr, sz);
+ rc = VirtualUnlock(ptr, sz);
+
+ /* because memory allocations may be made from the same individual page, it is possible for VirtualUnlock to be called
+ * multiple times for the same page. Subsequent calls will return an error, but this can be safely ignored (i.e. because
+ * the previous call for that page unlocked the memory already). Log an info level event only in that case. */
+ if(!rc) {
+ sqlcipher_log(SQLCIPHER_LOG_INFO, SQLCIPHER_LOG_MEMORY, "sqlcipher_munlock: VirtualUnlock(%p,%d) returned %d LastError=%d", ptr, sz, rc, GetLastError());
+ }
+#endif
+#endif
+#endif
+}
+
static int sqlcipher_mem_init(void *pAppData) {
return default_mem_methods.xInit(pAppData);
}
@@ -103449,7 +107349,7 @@ static void *sqlcipher_mem_malloc(int n) {
void *ptr = default_mem_methods.xMalloc(n);
if(!sqlcipher_mem_executed) sqlcipher_mem_executed = 1;
if(sqlcipher_mem_security_on) {
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_mem_malloc: calling sqlcipher_mlock(%p,%d)", ptr, n);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_mem_malloc: calling sqlcipher_mlock(%p,%d)", ptr, n);
sqlcipher_mlock(ptr, n);
}
return ptr;
@@ -103462,7 +107362,7 @@ static void sqlcipher_mem_free(void *p) {
if(!sqlcipher_mem_executed) sqlcipher_mem_executed = 1;
if(sqlcipher_mem_security_on) {
sz = sqlcipher_mem_size(p);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_mem_free: calling sqlcipher_memset(%p,0,%d) and sqlcipher_munlock(%p, %d)", p, sz, p, sz);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_mem_free: calling sqlcipher_memset(%p,0,%d) and sqlcipher_munlock(%p, %d)", p, sz, p, sz);
sqlcipher_memset(p, 0, sz);
sqlcipher_munlock(p, sz);
}
@@ -103514,14 +107414,63 @@ void sqlcipher_init_memmethods() {
sqlcipher_sqlite3_config(SQLITE_CONFIG_MALLOC, &sqlcipher_mem_methods) != SQLITE_OK) {
sqlcipher_mem_security_on = sqlcipher_mem_executed = sqlcipher_mem_initialized = 0;
} else {
+#if !defined(OMIT_MEMLOCK) && defined(_WIN32) && !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_PC_APP))
+ HANDLE process = NULL;
+ SYSTEM_INFO info;
+ SIZE_T dflt_min_size, dflt_max_size, min_size, max_size;
+ DWORD pid = GetCurrentProcessId();
+
+ if(pid == 0) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_MEMORY, "sqlcipher_init_memmethods: error calling GetCurrentProcessId: %d", GetLastError());
+ goto cleanup;
+ }
+
+ if((process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SET_QUOTA, FALSE, pid)) == NULL) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_MEMORY, "sqlcipher_init_memmethods: error calling OpenProcess for pid=%d: %d", pid, GetLastError());
+ goto cleanup;
+ }
+
+ /* lookup native memory page size for caclulating default working set sizes */
+ GetNativeSystemInfo(&info);
+
+ /* https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-setprocessworkingsetsize#parameters
+ Default Min Set Size is 50 pages.
+ Default Max Set Size is 345 pages */
+ dflt_min_size = info.dwPageSize * 50;
+ dflt_max_size = info.dwPageSize * 345;
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_init_memmethods: calculated dflt_min_size=%zu dflt_max_size=%zu for memory page size %d", dflt_min_size, dflt_max_size, info.dwPageSize);
+
+ /* retrieve current min and max set sizes for comparison */
+ if(!GetProcessWorkingSetSize(process, &min_size, &max_size)) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_MEMORY, "sqlcipher_init_memmethods: error calling GetProcessWorkingSetSize %d", GetLastError());
+ goto cleanup;
+ }
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_init_memmethods: GetProcessWorkingSetSize returned min=%zu max=%zu", min_size, max_size);
+
+ if(min_size == dflt_min_size && max_size == dflt_max_size) {
+ /* application has not set any special non-default working set sizes. Caclulate the new min working set size to be
+ 5 times default to allow greater number of pages to be VirtualLocked, max size will be left unchanged */
+ min_size *= 5;
+ if(!SetProcessWorkingSetSize(process, min_size, max_size)) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_MEMORY, "sqlcipher_init_memmethods: error calling SetProcessWorkingSetSize with min=%zu max=%zu: %d", min_size, max_size, GetLastError());
+ goto cleanup;
+ }
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_MEMORY, "sqlcipher_init_memmethods: called SetProcessWorkingSetSize for min=%zu max=%zu", min_size, max_size);
+ } else {
+ sqlcipher_log(SQLCIPHER_LOG_INFO, SQLCIPHER_LOG_MEMORY, "sqlcipher_init_memmethods: application has custom working set sizes min=%zu max=%zu - skipped alteration of working set sizes", min_size, max_size);
+ }
+
+cleanup:
+ if (process) CloseHandle(process);
+#endif
sqlcipher_mem_initialized = 1;
}
}
int sqlcipher_register_provider(sqlcipher_provider *p) {
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_register_provider: entering SQLCIPHER_MUTEX_PROVIDER");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_register_provider: entering SQLCIPHER_MUTEX_PROVIDER");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_register_provider: entered SQLCIPHER_MUTEX_PROVIDER");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_register_provider: entered SQLCIPHER_MUTEX_PROVIDER");
if(default_provider != NULL && default_provider != p) {
/* only free the current registerd provider if it has been initialized
@@ -103530,9 +107479,9 @@ int sqlcipher_register_provider(sqlcipher_provider *p) {
sqlcipher_free(default_provider, sizeof(sqlcipher_provider));
}
default_provider = p;
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_register_provider: leaving SQLCIPHER_MUTEX_PROVIDER");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_register_provider: leaving SQLCIPHER_MUTEX_PROVIDER");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_register_provider: left SQLCIPHER_MUTEX_PROVIDER");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_register_provider: left SQLCIPHER_MUTEX_PROVIDER");
return SQLITE_OK;
}
@@ -103544,10 +107493,10 @@ sqlcipher_provider* sqlcipher_get_provider() {
return default_provider;
}
-void sqlcipher_activate() {
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_activate: entering static master mutex");
+static void sqlcipher_activate() {
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_activate: entering static master mutex");
sqlcipher_sqlite3_mutex_enter(sqlcipher_sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_activate: entered static master mutex");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_activate: entered static master mutex");
/* allocate new mutexes */
if(sqlcipher_activate_count == 0) {
@@ -103555,6 +107504,28 @@ void sqlcipher_activate() {
for(i = 0; i < SQLCIPHER_MUTEX_COUNT; i++) {
sqlcipher_static_mutex[i] = sqlcipher_sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
}
+#ifndef SQLCIPHER_OMIT_DEFAULT_LOGGING
+ /* when sqlcipher is first activated, set a default log target and level of WARN if the
+ logging settings have not yet been initialized. Use the "device log" for
+ android (logcat) or apple (console). Use stderr on all other platforms. */
+ if(!sqlcipher_log_set) {
+
+ /* set log level if it is different than the uninitalized default value of NONE */
+ if(sqlcipher_log_level == SQLCIPHER_LOG_NONE) {
+ sqlcipher_log_level = SQLCIPHER_LOG_WARN;
+ }
+
+ /* set the default file or device if neither is already set */
+ if(sqlcipher_log_device == 0 && sqlcipher_log_file == NULL) {
+#if defined(__ANDROID__) || defined(__APPLE__)
+ sqlcipher_log_device = 1;
+#else
+ sqlcipher_log_file = stderr;
+#endif
+ }
+ sqlcipher_log_set = 1;
+ }
+#endif
}
/* check to see if there is a provider registered at this point
@@ -103574,48 +107545,44 @@ void sqlcipher_activate() {
#elif defined (SQLCIPHER_CRYPTO_OPENSSL)
extern int sqlcipher_openssl_setup(sqlcipher_provider *p);
sqlcipher_openssl_setup(p);
+#elif defined (SQLCIPHER_CRYPTO_OSSL3)
+ extern int sqlcipher_ossl3_setup(sqlcipher_provider *p);
+ sqlcipher_ossl3_setup(p);
#else
#error "NO DEFAULT SQLCIPHER CRYPTO PROVIDER DEFINED"
#endif
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_activate: calling sqlcipher_register_provider(%p)", p);
-#ifdef SQLCIPHER_EXT
- sqlcipher_ext_provider_setup(p);
-#endif
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_activate: calling sqlcipher_register_provider(%p)", p);
sqlcipher_register_provider(p);
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_activate: called sqlcipher_register_provider(%p)",p);
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_activate: called sqlcipher_register_provider(%p)",p);
}
sqlcipher_activate_count++; /* increment activation count */
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_activate: leaving static master mutex");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_activate: leaving static master mutex");
sqlcipher_sqlite3_mutex_leave(sqlcipher_sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_activate: left static master mutex");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_activate: left static master mutex");
}
-void sqlcipher_deactivate() {
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_deactivate: entering static master mutex");
+static void sqlcipher_deactivate() {
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_deactivate: entering static master mutex");
sqlcipher_sqlite3_mutex_enter(sqlcipher_sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_deactivate: entered static master mutex");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_deactivate: entered static master mutex");
sqlcipher_activate_count--;
/* if no connections are using sqlcipher, cleanup globals */
if(sqlcipher_activate_count < 1) {
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_deactivate: entering SQLCIPHER_MUTEX_PROVIDER");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_deactivate: entering SQLCIPHER_MUTEX_PROVIDER");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_deactivate: entered SQLCIPHER_MUTEX_PROVIDER");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_deactivate: entered SQLCIPHER_MUTEX_PROVIDER");
if(default_provider != NULL) {
sqlcipher_free(default_provider, sizeof(sqlcipher_provider));
default_provider = NULL;
}
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_deactivate: leaving SQLCIPHER_MUTEX_PROVIDER");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_deactivate: leaving SQLCIPHER_MUTEX_PROVIDER");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_deactivate: left SQLCIPHER_MUTEX_PROVIDER");
-
-#ifdef SQLCIPHER_EXT
- sqlcipher_ext_provider_destroy();
-#endif
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_deactivate: left SQLCIPHER_MUTEX_PROVIDER");
/* last connection closed, free mutexes */
if(sqlcipher_activate_count == 0) {
@@ -103627,9 +107594,9 @@ void sqlcipher_deactivate() {
sqlcipher_activate_count = 0; /* reset activation count */
}
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_deactivate: leaving static master mutex");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_deactivate: leaving static master mutex");
sqlcipher_sqlite3_mutex_leave(sqlcipher_sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_deactivate: left static master mutex");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_deactivate: left static master mutex");
}
/* constant time memset using volitile to avoid having the memset
@@ -103637,12 +107604,12 @@ void sqlcipher_deactivate() {
Note: As suggested by Joachim Schipper (joachim.schipper@fox-it.com)
*/
void* sqlcipher_memset(void *v, unsigned char value, sqlite_uint64 len) {
- sqlite_uint64 i = 0;
+ volatile sqlite_uint64 i = 0;
volatile unsigned char *a = v;
if (v == NULL) return v;
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_memset: setting %p[0-%llu]=%d)", a, len, value);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_memset: setting %p[0-%llu]=%d)", a, len, value);
for(i = 0; i < len; i++) {
a[i] = value;
}
@@ -103654,8 +107621,8 @@ void* sqlcipher_memset(void *v, unsigned char value, sqlite_uint64 len) {
matches a single value (i.e. the memory is all zeros)
returns 0 if match, 1 of no match */
int sqlcipher_ismemset(const void *v, unsigned char value, sqlite_uint64 len) {
- const unsigned char *a = v;
- sqlite_uint64 i = 0, result = 0;
+ const volatile unsigned char *a = v;
+ volatile sqlite_uint64 i = 0, result = 0;
for(i = 0; i < len; i++) {
result |= a[i] ^ value;
@@ -103667,8 +107634,8 @@ int sqlcipher_ismemset(const void *v, unsigned char value, sqlite_uint64 len) {
/* constant time memory comparison routine.
returns 0 if match, 1 if no match */
int sqlcipher_memcmp(const void *v0, const void *v1, int len) {
- const unsigned char *a0 = v0, *a1 = v1;
- int i = 0, result = 0;
+ const volatile unsigned char *a0 = v0, *a1 = v1;
+ volatile int i = 0, result = 0;
for(i = 0; i < len; i++) {
result |= a0[i] ^ a1[i];
@@ -103677,60 +107644,6 @@ int sqlcipher_memcmp(const void *v0, const void *v1, int len) {
return (result != 0);
}
-void sqlcipher_mlock(void *ptr, sqlite_uint64 sz) {
-#ifndef OMIT_MEMLOCK
-#if defined(__unix__) || defined(__APPLE__)
- int rc;
- unsigned long pagesize = sysconf(_SC_PAGESIZE);
- unsigned long offset = (unsigned long) ptr % pagesize;
-
- if(ptr == NULL || sz == 0) return;
-
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_mem_lock: calling mlock(%p,%lu); _SC_PAGESIZE=%lu", ptr - offset, sz + offset, pagesize);
- rc = mlock(ptr - offset, sz + offset);
- if(rc!=0) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_mem_lock: mlock(%p,%lu) returned %d errno=%d", ptr - offset, sz + offset, rc, errno);
- }
-#elif defined(_WIN32)
-#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP))
- int rc;
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_mem_lock: calling VirtualLock(%p,%d)", ptr, sz);
- rc = VirtualLock(ptr, sz);
- if(rc==0) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_mem_lock: VirtualLock(%p,%d) returned %d LastError=%d", ptr, sz, rc, GetLastError());
- }
-#endif
-#endif
-#endif
-}
-
-void sqlcipher_munlock(void *ptr, sqlite_uint64 sz) {
-#ifndef OMIT_MEMLOCK
-#if defined(__unix__) || defined(__APPLE__)
- int rc;
- unsigned long pagesize = sysconf(_SC_PAGESIZE);
- unsigned long offset = (unsigned long) ptr % pagesize;
-
- if(ptr == NULL || sz == 0) return;
-
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_mem_unlock: calling munlock(%p,%lu)", ptr - offset, sz + offset);
- rc = munlock(ptr - offset, sz + offset);
- if(rc!=0) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_mem_unlock: munlock(%p,%lu) returned %d errno=%d", ptr - offset, sz + offset, rc, errno);
- }
-#elif defined(_WIN32)
-#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP))
- int rc;
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_mem_lock: calling VirtualUnlock(%p,%d)", ptr, sz);
- rc = VirtualUnlock(ptr, sz);
- if(!rc) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_mem_unlock: VirtualUnlock(%p,%d) returned %d LastError=%d", ptr, sz, rc, GetLastError());
- }
-#endif
-#endif
-#endif
-}
-
/**
* Free and wipe memory. Uses SQLites internal sqlcipher_sqlite3_free so that memory
* can be countend and memory leak detection works in the test suite.
@@ -103740,7 +107653,7 @@ void sqlcipher_munlock(void *ptr, sqlite_uint64 sz) {
* memory segment so it can be paged
*/
void sqlcipher_free(void *ptr, sqlite_uint64 sz) {
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_free: calling sqlcipher_memset(%p,0,%llu)", ptr, sz);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_free: calling sqlcipher_memset(%p,0,%llu)", ptr, sz);
sqlcipher_memset(ptr, 0, sz);
sqlcipher_munlock(ptr, sz);
sqlcipher_sqlite3_free(ptr);
@@ -103753,9 +107666,9 @@ void sqlcipher_free(void *ptr, sqlite_uint64 sz) {
*/
void* sqlcipher_malloc(sqlite_uint64 sz) {
void *ptr;
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_malloc: calling sqlcipher_sqlite3Malloc(%llu)", sz);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_malloc: calling sqlcipher_sqlite3Malloc(%llu)", sz);
ptr = sqlcipher_sqlite3Malloc(sz);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_malloc: calling sqlcipher_memset(%p,0,%llu)", ptr, sz);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MEMORY, "sqlcipher_malloc: calling sqlcipher_memset(%p,0,%llu)", ptr, sz);
sqlcipher_memset(ptr, 0, sz);
sqlcipher_mlock(ptr, sz);
return ptr;
@@ -103779,15 +107692,15 @@ char* sqlcipher_version() {
*/
static int sqlcipher_cipher_ctx_init(codec_ctx *ctx, cipher_ctx **iCtx) {
cipher_ctx *c_ctx;
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_cipher_ctx_init: allocating context");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_MEMORY, "sqlcipher_cipher_ctx_init: allocating context");
*iCtx = (cipher_ctx *) sqlcipher_malloc(sizeof(cipher_ctx));
c_ctx = *iCtx;
if(c_ctx == NULL) return SQLITE_NOMEM;
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_cipher_ctx_init: allocating key");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_MEMORY, "sqlcipher_cipher_ctx_init: allocating key");
c_ctx->key = (unsigned char *) sqlcipher_malloc(ctx->key_sz);
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_cipher_ctx_init: allocating hmac_key");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_MEMORY, "sqlcipher_cipher_ctx_init: allocating hmac_key");
c_ctx->hmac_key = (unsigned char *) sqlcipher_malloc(ctx->key_sz);
if(c_ctx->key == NULL) return SQLITE_NOMEM;
@@ -103801,11 +107714,11 @@ static int sqlcipher_cipher_ctx_init(codec_ctx *ctx, cipher_ctx **iCtx) {
*/
static void sqlcipher_cipher_ctx_free(codec_ctx* ctx, cipher_ctx **iCtx) {
cipher_ctx *c_ctx = *iCtx;
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "cipher_ctx_free: iCtx=%p", iCtx);
- sqlcipher_free(c_ctx->key, ctx->key_sz);
- sqlcipher_free(c_ctx->hmac_key, ctx->key_sz);
- sqlcipher_free(c_ctx->pass, c_ctx->pass_sz);
- sqlcipher_free(c_ctx->keyspec, ctx->keyspec_sz);
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_MEMORY, "cipher_ctx_free: iCtx=%p", iCtx);
+ if(c_ctx->key) sqlcipher_free(c_ctx->key, ctx->key_sz);
+ if(c_ctx->hmac_key) sqlcipher_free(c_ctx->hmac_key, ctx->key_sz);
+ if(c_ctx->pass) sqlcipher_free(c_ctx->pass, c_ctx->pass_sz);
+ if(c_ctx->keyspec) sqlcipher_free(c_ctx->keyspec, ctx->keyspec_sz);
sqlcipher_free(c_ctx, sizeof(cipher_ctx));
}
@@ -103815,14 +107728,16 @@ static int sqlcipher_codec_ctx_reserve_setup(codec_ctx *ctx) {
ctx->hmac_sz = ctx->provider->get_hmac_sz(ctx->provider_ctx, ctx->hmac_algorithm);
- if(sqlcipher_codec_ctx_get_use_hmac(ctx))
+ if(SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_HMAC))
reserve += ctx->hmac_sz; /* if reserve will include hmac, update that size */
/* calculate the amount of reserve needed in even increments of the cipher block size */
- reserve = ((reserve % ctx->block_sz) == 0) ? reserve :
+ if(ctx->block_sz > 0) {
+ reserve = ((reserve % ctx->block_sz) == 0) ? reserve :
((reserve / ctx->block_sz) + 1) * ctx->block_sz;
+ }
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_codec_ctx_reserve_setup: base_reserve=%d block_sz=%d md_size=%d reserve=%d",
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_reserve_setup: base_reserve=%d block_sz=%d md_size=%d reserve=%d",
base_reserve, ctx->block_sz, ctx->hmac_sz, reserve);
ctx->reserve_sz = reserve;
@@ -103846,7 +107761,7 @@ static int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
c1->pass_sz)
));
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_cipher_ctx_cmp: c1=%p c2=%p sqlcipher_memcmp(c1->pass, c2_pass)=%d are_equal=%d",
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_cipher_ctx_cmp: c1=%p c2=%p sqlcipher_memcmp(c1->pass, c2_pass)=%d are_equal=%d",
c1, c2,
(c1->pass == NULL || c2->pass == NULL) ?
-1 :
@@ -103873,9 +107788,9 @@ static int sqlcipher_cipher_ctx_copy(codec_ctx *ctx, cipher_ctx *target, cipher_
void *key = target->key;
void *hmac_key = target->hmac_key;
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_cipher_ctx_copy: target=%p, source=%p", target, source);
- sqlcipher_free(target->pass, target->pass_sz);
- sqlcipher_free(target->keyspec, ctx->keyspec_sz);
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_cipher_ctx_copy: target=%p, source=%p", target, source);
+ if(target->pass) sqlcipher_free(target->pass, target->pass_sz);
+ if(target->keyspec) sqlcipher_free(target->keyspec, ctx->keyspec_sz);
memcpy(target, source, sizeof(cipher_ctx));
target->key = key; /* restore pointer to previously allocated key data */
@@ -103905,7 +107820,7 @@ static int sqlcipher_cipher_ctx_copy(codec_ctx *ctx, cipher_ctx *target, cipher_
*/
static int sqlcipher_cipher_ctx_set_keyspec(codec_ctx *ctx, cipher_ctx *c_ctx, const unsigned char *key) {
/* free, zero existing pointers and size */
- sqlcipher_free(c_ctx->keyspec, ctx->keyspec_sz);
+ if(c_ctx->keyspec) sqlcipher_free(c_ctx->keyspec, ctx->keyspec_sz);
c_ctx->keyspec = NULL;
c_ctx->keyspec = sqlcipher_malloc(ctx->keyspec_sz);
@@ -103919,22 +107834,9 @@ static int sqlcipher_cipher_ctx_set_keyspec(codec_ctx *ctx, cipher_ctx *c_ctx, c
return SQLITE_OK;
}
-int sqlcipher_codec_get_store_pass(codec_ctx *ctx) {
- return ctx->store_pass;
-}
-
-void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value) {
- ctx->store_pass = value;
-}
-
-void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) {
- *zKey = ctx->read_ctx->pass;
- *nKey = ctx->read_ctx->pass_sz;
-}
-
static void sqlcipher_set_derive_key(codec_ctx *ctx, int derive) {
- if(ctx->read_ctx != NULL) ctx->read_ctx->derive_key = 1;
- if(ctx->write_ctx != NULL) ctx->write_ctx->derive_key = 1;
+ if(ctx->read_ctx != NULL) ctx->read_ctx->derive_key = derive;
+ if(ctx->write_ctx != NULL) ctx->write_ctx->derive_key = derive;
}
/**
@@ -103945,7 +107847,7 @@ static void sqlcipher_set_derive_key(codec_ctx *ctx, int derive) {
*/
static int sqlcipher_cipher_ctx_set_pass(cipher_ctx *ctx, const void *zKey, int nKey) {
/* free, zero existing pointers and size */
- sqlcipher_free(ctx->pass, ctx->pass_sz);
+ if(ctx->pass) sqlcipher_free(ctx->pass, ctx->pass_sz);
ctx->pass = NULL;
ctx->pass_sz = 0;
@@ -103958,12 +107860,12 @@ static int sqlcipher_cipher_ctx_set_pass(cipher_ctx *ctx, const void *zKey, int
return SQLITE_OK;
}
-int sqlcipher_codec_ctx_set_pass(codec_ctx *ctx, const void *zKey, int nKey, int for_ctx) {
+static int sqlcipher_codec_ctx_set_pass(codec_ctx *ctx, const void *zKey, int nKey, int for_ctx) {
cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
int rc;
if((rc = sqlcipher_cipher_ctx_set_pass(c_ctx, zKey, nKey)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_set_pass: error %d from sqlcipher_cipher_ctx_set_pass", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_set_pass: error %d from sqlcipher_cipher_ctx_set_pass", rc);
return rc;
}
@@ -103971,7 +107873,7 @@ int sqlcipher_codec_ctx_set_pass(codec_ctx *ctx, const void *zKey, int nKey, int
if(for_ctx == 2) {
if((rc = sqlcipher_cipher_ctx_copy(ctx, for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_set_pass: error %d from sqlcipher_cipher_ctx_copy", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_set_pass: error %d from sqlcipher_cipher_ctx_copy", rc);
return rc;
}
}
@@ -103979,201 +107881,101 @@ int sqlcipher_codec_ctx_set_pass(codec_ctx *ctx, const void *zKey, int nKey, int
return SQLITE_OK;
}
-const char* sqlcipher_codec_ctx_get_cipher(codec_ctx *ctx) {
- return ctx->provider->get_cipher(ctx->provider_ctx);
-}
-
-/* set the global default KDF iteration */
-void sqlcipher_set_default_kdf_iter(int iter) {
- default_kdf_iter = iter;
-}
-
-int sqlcipher_get_default_kdf_iter() {
- return default_kdf_iter;
-}
-
-int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *ctx, int kdf_iter) {
+static int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *ctx, int kdf_iter) {
ctx->kdf_iter = kdf_iter;
sqlcipher_set_derive_key(ctx, 1);
return SQLITE_OK;
}
-int sqlcipher_codec_ctx_get_kdf_iter(codec_ctx *ctx) {
- return ctx->kdf_iter;
-}
-
-int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *ctx, int fast_kdf_iter) {
+static int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *ctx, int fast_kdf_iter) {
ctx->fast_kdf_iter = fast_kdf_iter;
sqlcipher_set_derive_key(ctx, 1);
return SQLITE_OK;
}
-int sqlcipher_codec_ctx_get_fast_kdf_iter(codec_ctx *ctx) {
- return ctx->fast_kdf_iter;
-}
-
/* set the global default flag for HMAC */
-void sqlcipher_set_default_use_hmac(int use) {
- if(use) default_flags |= CIPHER_FLAG_HMAC;
- else default_flags &= ~CIPHER_FLAG_HMAC;
-}
-
-int sqlcipher_get_default_use_hmac() {
- return (default_flags & CIPHER_FLAG_HMAC) != 0;
-}
-
-void sqlcipher_set_hmac_salt_mask(unsigned char mask) {
- hmac_salt_mask = mask;
-}
-
-unsigned char sqlcipher_get_hmac_salt_mask() {
- return hmac_salt_mask;
+static void sqlcipher_set_default_use_hmac(int use) {
+ if(use) SQLCIPHER_FLAG_SET(default_flags, CIPHER_FLAG_HMAC);
+ else SQLCIPHER_FLAG_UNSET(default_flags,CIPHER_FLAG_HMAC);
}
/* 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) {
+static int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use) {
if(use) {
- sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_HMAC);
+ SQLCIPHER_FLAG_SET(ctx->flags, CIPHER_FLAG_HMAC);
} else {
- sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_HMAC);
+ SQLCIPHER_FLAG_UNSET(ctx->flags, CIPHER_FLAG_HMAC);
}
return sqlcipher_codec_ctx_reserve_setup(ctx);
}
-int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx) {
- return (ctx->flags & CIPHER_FLAG_HMAC) != 0;
-}
-
/* the length of plaintext header size must be:
* 1. greater than or equal to zero
* 2. a multiple of the cipher block size
* 3. less than the usable size of the first database page
*/
-int sqlcipher_set_default_plaintext_header_size(int size) {
- default_plaintext_header_sz = size;
- return SQLITE_OK;
-}
-
-int sqlcipher_codec_ctx_set_plaintext_header_size(codec_ctx *ctx, int size) {
- if(size >= 0 && (size % ctx->block_sz) == 0 && size < (ctx->page_sz - ctx->reserve_sz)) {
+static int sqlcipher_codec_ctx_set_plaintext_header_size(codec_ctx *ctx, int size) {
+ if(size >= 0 && ctx->block_sz > 0 && (size % ctx->block_sz) == 0 && size < (ctx->page_sz - ctx->reserve_sz)) {
ctx->plaintext_header_sz = size;
return SQLITE_OK;
}
ctx->plaintext_header_sz = -1;
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_set_plaintext_header_size: attempt to set invalid plantext_header_size %d", size);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_set_plaintext_header_size: attempt to set invalid plantext_header_size %d", size);
return SQLITE_ERROR;
}
-int sqlcipher_get_default_plaintext_header_size() {
- return default_plaintext_header_sz;
-}
-
-int sqlcipher_codec_ctx_get_plaintext_header_size(codec_ctx *ctx) {
- return ctx->plaintext_header_sz;
-}
-
-/* manipulate HMAC algorithm */
-int sqlcipher_set_default_hmac_algorithm(int algorithm) {
- default_hmac_algorithm = algorithm;
- return SQLITE_OK;
-}
-
-int sqlcipher_codec_ctx_set_hmac_algorithm(codec_ctx *ctx, int algorithm) {
+static int sqlcipher_codec_ctx_set_hmac_algorithm(codec_ctx *ctx, int algorithm) {
ctx->hmac_algorithm = algorithm;
return sqlcipher_codec_ctx_reserve_setup(ctx);
}
-int sqlcipher_get_default_hmac_algorithm() {
- return default_hmac_algorithm;
-}
-
-int sqlcipher_codec_ctx_get_hmac_algorithm(codec_ctx *ctx) {
- return ctx->hmac_algorithm;
-}
-
-/* manipulate KDF algorithm */
-int sqlcipher_set_default_kdf_algorithm(int algorithm) {
- default_kdf_algorithm = algorithm;
- return SQLITE_OK;
-}
-
-int sqlcipher_codec_ctx_set_kdf_algorithm(codec_ctx *ctx, int algorithm) {
+static int sqlcipher_codec_ctx_set_kdf_algorithm(codec_ctx *ctx, int algorithm) {
ctx->kdf_algorithm = algorithm;
return SQLITE_OK;
}
-int sqlcipher_get_default_kdf_algorithm() {
- return default_kdf_algorithm;
-}
-
-int sqlcipher_codec_ctx_get_kdf_algorithm(codec_ctx *ctx) {
- return ctx->kdf_algorithm;
-}
-
-int sqlcipher_codec_ctx_set_flag(codec_ctx *ctx, unsigned int flag) {
- ctx->flags |= flag;
- return SQLITE_OK;
-}
-
-int sqlcipher_codec_ctx_unset_flag(codec_ctx *ctx, unsigned int flag) {
- ctx->flags &= ~flag;
- return SQLITE_OK;
-}
-
-int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag) {
- return (ctx->flags & flag) != 0;
-}
-
-void sqlcipher_codec_ctx_set_error(codec_ctx *ctx, int error) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_set_error: ctx=%p, error=%d", ctx, error);
+static void sqlcipher_codec_ctx_set_error(codec_ctx *ctx, int error) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_set_error %d", error);
sqlcipher_sqlite3pager_error(ctx->pBt->pBt->pPager, error);
ctx->pBt->pBt->db->errCode = error;
}
-int sqlcipher_codec_ctx_get_reservesize(codec_ctx *ctx) {
- return ctx->reserve_sz;
-}
-
-void* sqlcipher_codec_ctx_get_data(codec_ctx *ctx) {
- return ctx->buffer;
-}
-
static int sqlcipher_codec_ctx_init_kdf_salt(codec_ctx *ctx) {
sqlcipher_sqlite3_file *fd = sqlcipher_sqlite3PagerFile(ctx->pBt->pBt->pPager);
- if(!ctx->need_kdf_salt) {
+ if(SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_HAS_KDF_SALT)) {
return SQLITE_OK; /* don't reload salt when not needed */
}
/* read salt from header, if present, otherwise generate a new random salt */
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_codec_ctx_init_kdf_salt: obtaining salt");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init_kdf_salt: obtaining salt");
if(fd == NULL || fd->pMethods == 0 || sqlcipher_sqlite3OsRead(fd, ctx->kdf_salt, ctx->kdf_salt_sz, 0) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_codec_ctx_init_kdf_salt: unable to read salt from file header, generating random");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init_kdf_salt: unable to read salt from file header, generating random");
if(ctx->provider->random(ctx->provider_ctx, ctx->kdf_salt, ctx->kdf_salt_sz) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init_kdf_salt: error retrieving random bytes from provider");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init_kdf_salt: error retrieving random bytes from provider");
return SQLITE_ERROR;
}
}
- ctx->need_kdf_salt = 0;
+ SQLCIPHER_FLAG_SET(ctx->flags, CIPHER_FLAG_HAS_KDF_SALT);
return SQLITE_OK;
}
-int sqlcipher_codec_ctx_set_kdf_salt(codec_ctx *ctx, unsigned char *salt, int size) {
+static int sqlcipher_codec_ctx_set_kdf_salt(codec_ctx *ctx, unsigned char *salt, int size) {
if(size >= ctx->kdf_salt_sz) {
memcpy(ctx->kdf_salt, salt, ctx->kdf_salt_sz);
- ctx->need_kdf_salt = 0;
+ SQLCIPHER_FLAG_SET(ctx->flags, CIPHER_FLAG_HAS_KDF_SALT);
return SQLITE_OK;
}
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_set_kdf_salt: attempt to set salt of incorrect size %d", size);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_set_kdf_salt: attempt to set salt of incorrect size %d", size);
return SQLITE_ERROR;
}
-int sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx, void** salt) {
+static int sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx, void** salt) {
int rc = SQLITE_OK;
- if(ctx->need_kdf_salt) {
+ if(!SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_HAS_KDF_SALT)) {
if((rc = sqlcipher_codec_ctx_init_kdf_salt(ctx)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_get_kdf_salt: error %d from sqlcipher_codec_ctx_init_kdf_salt", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_get_kdf_salt: error %d from sqlcipher_codec_ctx_init_kdf_salt", rc);
}
}
*salt = ctx->kdf_salt;
@@ -104181,18 +107983,13 @@ int sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx, void** salt) {
return rc;
}
-void sqlcipher_codec_get_keyspec(codec_ctx *ctx, void **zKey, int *nKey) {
- *zKey = ctx->read_ctx->keyspec;
- *nKey = ctx->keyspec_sz;
-}
-
-int sqlcipher_codec_ctx_set_pagesize(codec_ctx *ctx, int size) {
+static int sqlcipher_codec_ctx_set_pagesize(codec_ctx *ctx, int size) {
if(!((size != 0) && ((size & (size - 1)) == 0)) || size < 512 || size > 65536) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "cipher_page_size not a power of 2 and between 512 and 65536 inclusive");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "cipher_page_size not a power of 2 and between 512 and 65536 inclusive");
return SQLITE_ERROR;
}
/* attempt to free the existing page buffer */
- sqlcipher_free(ctx->buffer,ctx->page_sz);
+ if(ctx->buffer) sqlcipher_free(ctx->buffer,ctx->page_sz);
ctx->page_sz = size;
/* pre-allocate a page buffer of PageSize bytes. This will
@@ -104204,39 +108001,11 @@ int sqlcipher_codec_ctx_set_pagesize(codec_ctx *ctx, int size) {
return SQLITE_OK;
}
-int sqlcipher_codec_ctx_get_pagesize(codec_ctx *ctx) {
- return ctx->page_sz;
-}
-
-void sqlcipher_set_default_pagesize(int page_size) {
- default_page_size = page_size;
-}
-
-int sqlcipher_get_default_pagesize() {
- return default_page_size;
-}
-
-void sqlcipher_set_mem_security(int on) {
- /* memory security can only be enabled, not disabled */
- if(on) {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_set_mem_security: on");
- sqlcipher_mem_security_on = on;
- }
-}
-
-int sqlcipher_get_mem_security() {
- /* only report that memory security is enabled if pragma cipher_memory_security is ON and
- SQLCipher's allocator/deallocator was run at least one timecurrently used */
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_get_mem_security: sqlcipher_mem_security_on = %d, sqlcipher_mem_executed = %d", sqlcipher_mem_security_on, sqlcipher_mem_executed);
- return sqlcipher_mem_security_on && sqlcipher_mem_executed;
-}
-
-
-int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, const void *zKey, int nKey) {
+static int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, const void *zKey, int nKey) {
int rc;
codec_ctx *ctx;
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_codec_ctx_init: allocating context");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_MEMORY, "sqlcipher_codec_ctx_init: allocating context");
*iCtx = sqlcipher_malloc(sizeof(codec_ctx));
ctx = *iCtx;
@@ -104249,7 +108018,7 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, const voi
directly off the database file. This is the salt for the
key derivation function. If we get a short read allocate
a new random salt value */
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_codec_ctx_init: allocating kdf_salt");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_MEMORY, "sqlcipher_codec_ctx_init: allocating kdf_salt");
ctx->kdf_salt_sz = FILE_HEADER_SZ;
ctx->kdf_salt = sqlcipher_malloc(ctx->kdf_salt_sz);
if(ctx->kdf_salt == NULL) return SQLITE_NOMEM;
@@ -104257,34 +108026,31 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, const voi
/* allocate space for separate hmac salt data. We want the
HMAC derivation salt to be different than the encryption
key derivation salt */
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_codec_ctx_init: allocating hmac_kdf_salt");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_MEMORY, "sqlcipher_codec_ctx_init: allocating hmac_kdf_salt");
ctx->hmac_kdf_salt = sqlcipher_malloc(ctx->kdf_salt_sz);
if(ctx->hmac_kdf_salt == NULL) return SQLITE_NOMEM;
/* setup default flags */
ctx->flags = default_flags;
- /* defer attempt to read KDF salt until first use */
- ctx->need_kdf_salt = 1;
-
/* setup the crypto provider */
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_codec_ctx_init: allocating provider");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_MEMORY, "sqlcipher_codec_ctx_init: allocating provider");
ctx->provider = (sqlcipher_provider *) sqlcipher_malloc(sizeof(sqlcipher_provider));
if(ctx->provider == NULL) return SQLITE_NOMEM;
/* make a copy of the provider to be used for the duration of the context */
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_codec_ctx_init: entering SQLCIPHER_MUTEX_PROVIDER");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_codec_ctx_init: entering SQLCIPHER_MUTEX_PROVIDER");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_codec_ctx_init: entered SQLCIPHER_MUTEX_PROVIDER");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_codec_ctx_init: entered SQLCIPHER_MUTEX_PROVIDER");
memcpy(ctx->provider, default_provider, sizeof(sqlcipher_provider));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_codec_ctx_init: leaving SQLCIPHER_MUTEX_PROVIDER");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_codec_ctx_init: leaving SQLCIPHER_MUTEX_PROVIDER");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_codec_ctx_init: left SQLCIPHER_MUTEX_PROVIDER");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_codec_ctx_init: left SQLCIPHER_MUTEX_PROVIDER");
if((rc = ctx->provider->ctx_init(&ctx->provider_ctx)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d returned from ctx_init", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d returned from ctx_init", rc);
return rc;
}
@@ -104303,64 +108069,64 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, const voi
cases where bytes 16 & 17 of the page header are a power of 2 as reported by John Lehman
*/
if((rc = sqlcipher_codec_ctx_set_pagesize(ctx, default_page_size)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d returned from sqlcipher_codec_ctx_set_pagesize with %d", rc, default_page_size);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d returned from sqlcipher_codec_ctx_set_pagesize with %d", rc, default_page_size);
return rc;
}
/* establish settings for the KDF iterations and fast (HMAC) KDF iterations */
if((rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, default_kdf_iter)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d setting default_kdf_iter %d", rc, default_kdf_iter);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d setting default_kdf_iter %d", rc, default_kdf_iter);
return rc;
}
if((rc = sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, FAST_PBKDF2_ITER)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d setting fast_kdf_iter to %d", rc, FAST_PBKDF2_ITER);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d setting fast_kdf_iter to %d", rc, FAST_PBKDF2_ITER);
return rc;
}
/* set the default HMAC and KDF algorithms which will determine the reserve size */
if((rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, default_hmac_algorithm)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d setting sqlcipher_codec_ctx_set_hmac_algorithm with %d", rc, default_hmac_algorithm);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d setting sqlcipher_codec_ctx_set_hmac_algorithm with %d", rc, default_hmac_algorithm);
return rc;
}
/* Note that use_hmac is a special case that requires recalculation of page size
so we call set_use_hmac to perform setup */
- if((rc = sqlcipher_codec_ctx_set_use_hmac(ctx, default_flags & CIPHER_FLAG_HMAC)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d setting use_hmac %d", rc, default_flags & CIPHER_FLAG_HMAC);
+ if((rc = sqlcipher_codec_ctx_set_use_hmac(ctx, SQLCIPHER_FLAG_GET(default_flags, CIPHER_FLAG_HMAC))) != SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d setting use_hmac %d", rc, SQLCIPHER_FLAG_GET(default_flags, CIPHER_FLAG_HMAC));
return rc;
}
if((rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, default_kdf_algorithm)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d setting sqlcipher_codec_ctx_set_kdf_algorithm with %d", rc, default_kdf_algorithm);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d setting sqlcipher_codec_ctx_set_kdf_algorithm with %d", rc, default_kdf_algorithm);
return rc;
}
/* setup the default plaintext header size */
- if((rc = sqlcipher_codec_ctx_set_plaintext_header_size(ctx, default_plaintext_header_sz)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d setting sqlcipher_codec_ctx_set_plaintext_header_size with %d", rc, default_plaintext_header_sz);
+ if((rc = sqlcipher_codec_ctx_set_plaintext_header_size(ctx, default_plaintext_header_size)) != SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d setting sqlcipher_codec_ctx_set_plaintext_header_size with %d", rc, default_plaintext_header_size);
return rc;
}
/* initialize the read and write sub-contexts. this must happen after key_sz is established */
if((rc = sqlcipher_cipher_ctx_init(ctx, &ctx->read_ctx)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d initializing read_ctx", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d initializing read_ctx", rc);
return rc;
}
if((rc = sqlcipher_cipher_ctx_init(ctx, &ctx->write_ctx)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d initializing write_ctx", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d initializing write_ctx", rc);
return rc;
}
/* set the key material on one of the sub cipher contexts and sync them up */
if((rc = sqlcipher_codec_ctx_set_pass(ctx, zKey, nKey, 0)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d setting pass key", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d setting pass key", rc);
return rc;
}
if((rc = sqlcipher_cipher_ctx_copy(ctx, ctx->write_ctx, ctx->read_ctx)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_ctx_init: error %d copying write_ctx to read_ctx", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_init: error %d copying write_ctx to read_ctx", rc);
return rc;
}
@@ -104371,15 +108137,17 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, const voi
* Free and wipe memory associated with a cipher_ctx, including the allocated
* read_ctx and write_ctx.
*/
-void sqlcipher_codec_ctx_free(codec_ctx **iCtx) {
+static void sqlcipher_codec_ctx_free(codec_ctx **iCtx) {
codec_ctx *ctx = *iCtx;
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "codec_ctx_free: iCtx=%p", iCtx);
- sqlcipher_free(ctx->kdf_salt, ctx->kdf_salt_sz);
- sqlcipher_free(ctx->hmac_kdf_salt, ctx->kdf_salt_sz);
- sqlcipher_free(ctx->buffer, ctx->page_sz);
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_MEMORY, "codec_ctx_free: iCtx=%p", iCtx);
+ if(ctx->kdf_salt) sqlcipher_free(ctx->kdf_salt, ctx->kdf_salt_sz);
+ if(ctx->hmac_kdf_salt) sqlcipher_free(ctx->hmac_kdf_salt, ctx->kdf_salt_sz);
+ if(ctx->buffer) sqlcipher_free(ctx->buffer, ctx->page_sz);
- ctx->provider->ctx_free(&ctx->provider_ctx);
- sqlcipher_free(ctx->provider, sizeof(sqlcipher_provider));
+ if(ctx->provider) {
+ ctx->provider->ctx_free(&ctx->provider_ctx);
+ sqlcipher_free(ctx->provider, sizeof(sqlcipher_provider));
+ }
sqlcipher_cipher_ctx_free(ctx, &ctx->read_ctx);
sqlcipher_cipher_ctx_free(ctx, &ctx->write_ctx);
@@ -104404,9 +108172,9 @@ static int sqlcipher_page_hmac(codec_ctx *ctx, cipher_ctx *c_ctx, Pgno pgno, uns
backwards compatibility on the most popular platforms, but can optionally be configured
to use either big endian or native byte ordering via pragma. */
- if(ctx->flags & CIPHER_FLAG_LE_PGNO) { /* compute hmac using little endian pgno*/
+ if(SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_LE_PGNO)) { /* compute hmac using little endian pgno*/
sqlcipher_put4byte_le(pgno_raw, pgno);
- } else if(ctx->flags & CIPHER_FLAG_BE_PGNO) { /* compute hmac using big endian pgno */
+ } else if(SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_BE_PGNO)) { /* compute hmac using big endian pgno */
sqlcipher_sqlite3Put4byte(pgno_raw, pgno); /* sqlcipher_sqlite3Put4byte converts 32bit uint to big endian */
} else { /* use native byte ordering */
memcpy(pgno_raw, &pgno, sizeof(pgno));
@@ -104430,7 +108198,7 @@ static int sqlcipher_page_hmac(codec_ctx *ctx, cipher_ctx *c_ctx, Pgno pgno, uns
* in - pointer to input bytes
* out - pouter to output bytes
*/
-int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int page_sz, unsigned char *in, unsigned char *out) {
+static int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int page_sz, unsigned char *in, unsigned char *out) {
cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
unsigned char *iv_in, *iv_out, *hmac_in, *hmac_out, *out_start;
int size;
@@ -104446,12 +108214,12 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int
hmac_out = out + size + ctx->iv_sz;
out_start = out; /* note the original position of the output buffer pointer, as out will be rewritten during encryption */
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_page_cipher: pgno=%d, mode=%d, size=%d", pgno, mode, size);
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_page_cipher: pgno=%d, mode=%d, size=%d", pgno, mode, size);
CODEC_HEXDUMP("sqlcipher_page_cipher: input page data", in, page_sz);
/* the key size should never be zero. If it is, error out. */
if(ctx->key_sz == 0) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_page_cipher: error possible context corruption, key_sz is zero for pgno=%d", pgno);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_page_cipher: error possible context corruption, key_sz is zero for pgno=%d", pgno);
goto error;
}
@@ -104462,40 +108230,40 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int
memcpy(iv_out, iv_in, ctx->iv_sz); /* copy the iv from the input to output buffer */
}
- if((ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_DECRYPT) && !ctx->skip_read_hmac) {
+ if(SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_HMAC) && (mode == CIPHER_DECRYPT)) {
if(sqlcipher_page_hmac(ctx, c_ctx, pgno, in, size + ctx->iv_sz, hmac_out) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_page_cipher: hmac operation on decrypt failed for pgno=%d", pgno);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_page_cipher: hmac operation on decrypt failed for pgno=%d", pgno);
goto error;
}
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_page_cipher: comparing hmac on in=%p out=%p hmac_sz=%d", hmac_in, hmac_out, ctx->hmac_sz);
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_page_cipher: comparing hmac on in=%p out=%p hmac_sz=%d", hmac_in, hmac_out, ctx->hmac_sz);
if(sqlcipher_memcmp(hmac_in, hmac_out, ctx->hmac_sz) != 0) { /* the hmac check failed */
if(sqlcipher_sqlite3BtreeGetAutoVacuum(ctx->pBt) != BTREE_AUTOVACUUM_NONE && 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. */
- sqlcipher_log(SQLCIPHER_LOG_WARN, "sqlcipher_page_cipher: zeroed page (short read) for pgno %d, encryption but returning SQLITE_OK", pgno);
+ sqlcipher_log(SQLCIPHER_LOG_INFO, SQLCIPHER_LOG_CORE, "sqlcipher_page_cipher: zeroed page (short read) for pgno %d with autovacuum enabled", pgno);
sqlcipher_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 */
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_page_cipher: hmac check failed for pgno=%d returning SQLITE_ERROR", pgno);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_page_cipher: hmac check failed for pgno=%d", pgno);
goto error;
}
}
}
if(ctx->provider->cipher(ctx->provider_ctx, mode, c_ctx->key, ctx->key_sz, iv_out, in, size, out) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_page_cipher: cipher operation mode=%d failed for pgno=%d returning SQLITE_ERROR", mode, pgno);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_page_cipher: cipher operation mode=%d failed for pgno=%d", mode, pgno);
goto error;
};
- if((ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_ENCRYPT)) {
+ if(SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_HMAC) && (mode == CIPHER_ENCRYPT)) {
if(sqlcipher_page_hmac(ctx, c_ctx, pgno, out_start, size + ctx->iv_sz, hmac_out) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_page_cipher: hmac operation on encrypt failed for pgno=%d", pgno);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_page_cipher: hmac operation on encrypt failed for pgno=%d", pgno);
goto error;
};
}
@@ -104525,15 +108293,15 @@ error:
*/
static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
int rc;
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_cipher_ctx_key_derive: ctx->kdf_salt_sz=%d ctx->kdf_iter=%d ctx->fast_kdf_iter=%d ctx->key_sz=%d",
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_cipher_ctx_key_derive: ctx->kdf_salt_sz=%d ctx->kdf_iter=%d ctx->fast_kdf_iter=%d ctx->key_sz=%d",
ctx->kdf_salt_sz, ctx->kdf_iter, ctx->fast_kdf_iter, ctx->key_sz);
if(c_ctx->pass && c_ctx->pass_sz) { /* if key material is present on the context for derivation */
/* if necessary, initialize the salt from the header or random source */
- if(ctx->need_kdf_salt) {
+ if(!SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_HAS_KDF_SALT)) {
if((rc = sqlcipher_codec_ctx_init_kdf_salt(ctx)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_cipher_ctx_key_derive: error %d from sqlcipher_codec_ctx_init_kdf_salt", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_cipher_ctx_key_derive: error %d from sqlcipher_codec_ctx_init_kdf_salt", rc);
return rc;
}
}
@@ -104541,26 +108309,26 @@ static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
if (c_ctx->pass_sz == ((ctx->key_sz * 2) + 3) && sqlcipher_sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0 && cipher_isHex(c_ctx->pass + 2, ctx->key_sz * 2)) {
int n = c_ctx->pass_sz - 3; /* adjust for leading x' and tailing ' */
const unsigned char *z = c_ctx->pass + 2; /* adjust lead offset of x' */
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "cipher_ctx_key_derive: using raw key from hex");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_cipher_ctx_key_derive: using raw key from hex");
cipher_hex2bin(z, n, c_ctx->key);
} else if (c_ctx->pass_sz == (((ctx->key_sz + ctx->kdf_salt_sz) * 2) + 3) && sqlcipher_sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0 && cipher_isHex(c_ctx->pass + 2, (ctx->key_sz + ctx->kdf_salt_sz) * 2)) {
const unsigned char *z = c_ctx->pass + 2; /* adjust lead offset of x' */
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "cipher_ctx_key_derive: using raw key from hex");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_cipher_ctx_key_derive: using raw key from hex");
cipher_hex2bin(z, (ctx->key_sz * 2), c_ctx->key);
cipher_hex2bin(z + (ctx->key_sz * 2), (ctx->kdf_salt_sz * 2), ctx->kdf_salt);
} else {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "cipher_ctx_key_derive: deriving key using full PBKDF2 with %d iterations", ctx->kdf_iter);
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_cipher_ctx_key_derive: deriving key using full PBKDF2 with %d iterations", ctx->kdf_iter);
if(ctx->provider->kdf(ctx->provider_ctx, ctx->kdf_algorithm, c_ctx->pass, c_ctx->pass_sz,
ctx->kdf_salt, ctx->kdf_salt_sz, ctx->kdf_iter,
ctx->key_sz, c_ctx->key) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "cipher_ctx_key_derive: error occurred from provider kdf generating encryption key");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_cipher_ctx_key_derive: error occurred from provider kdf generating encryption key");
return SQLITE_ERROR;
}
}
/* set the context "keyspec" containing the hex-formatted key and salt to be used when attaching databases */
if((rc = sqlcipher_cipher_ctx_set_keyspec(ctx, c_ctx, c_ctx->key)) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_cipher_ctx_key_derive: error %d from sqlcipher_cipher_ctx_set_keyspec", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_cipher_ctx_key_derive: error %d from sqlcipher_cipher_ctx_set_keyspec", rc);
return rc;
}
@@ -104580,14 +108348,14 @@ static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
ctx->hmac_kdf_salt[i] ^= hmac_salt_mask;
}
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "cipher_ctx_key_derive: deriving hmac key from encryption key using PBKDF2 with %d iterations",
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "cipher_ctx_key_derive: deriving hmac key from encryption key using PBKDF2 with %d iterations",
ctx->fast_kdf_iter);
if(ctx->provider->kdf(ctx->provider_ctx, ctx->kdf_algorithm, c_ctx->key, ctx->key_sz,
ctx->hmac_kdf_salt, ctx->kdf_salt_sz, ctx->fast_kdf_iter,
ctx->key_sz, c_ctx->hmac_key) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "cipher_ctx_key_derive: error occurred from provider kdf generating HMAC key");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_cipher_ctx_key_derive: error occurred from provider kdf generating HMAC key");
return SQLITE_ERROR;
}
}
@@ -104595,15 +108363,15 @@ static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
c_ctx->derive_key = 0;
return SQLITE_OK;
}
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "cipher_ctx_key_derive: key material is not present on the context for key derivation");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_cipher_ctx_key_derive: key material is not present on the context for key derivation");
return SQLITE_ERROR;
}
-int sqlcipher_codec_key_derive(codec_ctx *ctx) {
+static int sqlcipher_codec_key_derive(codec_ctx *ctx) {
/* derive key on first use if necessary */
if(ctx->read_ctx->derive_key) {
if(sqlcipher_cipher_ctx_key_derive(ctx, ctx->read_ctx) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_key_derive: error occurred deriving read_ctx key");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_key_derive: error occurred deriving read_ctx key");
return SQLITE_ERROR;
}
}
@@ -104612,18 +108380,18 @@ int sqlcipher_codec_key_derive(codec_ctx *ctx) {
if(sqlcipher_cipher_ctx_cmp(ctx->write_ctx, ctx->read_ctx) == 0) {
/* the relevant parameters are the same, just copy read key */
if(sqlcipher_cipher_ctx_copy(ctx, ctx->write_ctx, ctx->read_ctx) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_key_derive: error occurred copying read_ctx to write_ctx");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_key_derive: error occurred copying read_ctx to write_ctx");
return SQLITE_ERROR;
}
} else {
if(sqlcipher_cipher_ctx_key_derive(ctx, ctx->write_ctx) != SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_key_derive: error occurred deriving write_ctx key");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_key_derive: error occurred deriving write_ctx key");
return SQLITE_ERROR;
}
}
}
- /* TODO: wipe and free passphrase after key derivation */
+ /* wipe and free passphrase after key derivation */
if(ctx->store_pass != 1) {
sqlcipher_cipher_ctx_set_pass(ctx->read_ctx, NULL, 0);
sqlcipher_cipher_ctx_set_pass(ctx->write_ctx, NULL, 0);
@@ -104632,7 +108400,7 @@ int sqlcipher_codec_key_derive(codec_ctx *ctx) {
return SQLITE_OK;
}
-int sqlcipher_codec_key_copy(codec_ctx *ctx, int source) {
+static int sqlcipher_codec_key_copy(codec_ctx *ctx, int source) {
if(source == CIPHER_READ_CTX) {
return sqlcipher_cipher_ctx_copy(ctx, ctx->write_ctx, ctx->read_ctx);
} else {
@@ -104640,11 +108408,6 @@ int sqlcipher_codec_key_copy(codec_ctx *ctx, int source) {
}
}
-const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx) {
- return ctx->provider->get_provider_name(ctx->provider_ctx);
-}
-
-
static int sqlcipher_check_connection(const char *filename, char *key, int key_sz, char *sql, int *user_version, char** journal_mode) {
int rc;
sqlcipher_sqlite3 *db = NULL;
@@ -104692,7 +108455,7 @@ cleanup:
return rc;
}
-int sqlcipher_codec_ctx_integrity_check(codec_ctx *ctx, Parse *pParse, char *column) {
+static int sqlcipher_codec_ctx_integrity_check(codec_ctx *ctx, Parse *pParse, char *column) {
Pgno page = 1;
int rc = 0;
char *result;
@@ -104758,7 +108521,7 @@ int sqlcipher_codec_ctx_integrity_check(codec_ctx *ctx, Parse *pParse, char *col
}
if(file_sz % ctx->page_sz != 0) {
- result = sqlcipher_sqlite3_mprintf("page %d has an invalid size of %lld bytes", page, file_sz - ((file_sz / ctx->page_sz) * ctx->page_sz));
+ result = sqlcipher_sqlite3_mprintf("page %d has an invalid size of %lld bytes (expected %d bytes)", page, file_sz - ((file_sz / ctx->page_sz) * ctx->page_sz), ctx->page_sz);
sqlcipher_sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, result, P4_DYNAMIC);
sqlcipher_sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
@@ -104768,7 +108531,7 @@ cleanup:
return SQLITE_OK;
}
-int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
+static int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
int i, pass_sz, keyspec_sz, nRes, user_version, rc, oflags;
Db *pDb = 0;
sqlcipher_sqlite3 *db = ctx->pBt->db;
@@ -104794,7 +108557,7 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
/* Version 4 - current, no upgrade required, so exit immediately */
rc = sqlcipher_check_connection(db_filename, pass, pass_sz, "", &user_version, &journal_mode);
if(rc == SQLITE_OK){
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "No upgrade required - exiting");
+ sqlcipher_log(SQLCIPHER_LOG_INFO, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: no upgrade required - exiting");
goto cleanup;
}
@@ -104802,7 +108565,7 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
pragma_compat = sqlcipher_sqlite3_mprintf("PRAGMA cipher_compatibility = %d;", i);
rc = sqlcipher_check_connection(db_filename, pass, pass_sz, pragma_compat, &user_version, &journal_mode);
if(rc == SQLITE_OK) {
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "Version %d format found", i);
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: version %d format found", i);
goto migrate;
}
if(pragma_compat) sqlcipher_free(pragma_compat, sqlcipher_sqlite3Strlen30(pragma_compat));
@@ -104810,7 +108573,7 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
}
/* if we exit the loop normally we failed to determine the version, this is an error */
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "Upgrade format not determined");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: unable to determine format version for upgrade: this may indicate custom settings were used ");
goto handle_error;
migrate:
@@ -104827,55 +108590,55 @@ migrate:
rc = sqlcipher_sqlite3_exec(db, pragma_compat, NULL, NULL, NULL);
if(rc != SQLITE_OK){
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "set compatibility mode failed, error code %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: set compatibility mode failed, error code %d", rc);
goto handle_error;
}
/* force journal mode to DELETE, we will set it back later if different */
rc = sqlcipher_sqlite3_exec(db, "PRAGMA journal_mode = delete;", NULL, NULL, NULL);
if(rc != SQLITE_OK){
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "force journal mode DELETE failed, error code %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: force journal mode DELETE failed, error code %d", rc);
goto handle_error;
}
rc = sqlcipher_sqlite3_exec(db, attach_command, NULL, NULL, NULL);
if(rc != SQLITE_OK){
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "attach failed, error code %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: attach failed, error code %d", rc);
goto handle_error;
}
rc = sqlcipher_sqlite3_key_v2(db, "migrate", pass, pass_sz);
if(rc != SQLITE_OK){
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "keying attached database failed, error code %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: keying attached database failed, error code %d", rc);
goto handle_error;
}
rc = sqlcipher_sqlite3_exec(db, "SELECT sqlcipher_export('migrate');", NULL, NULL, NULL);
if(rc != SQLITE_OK){
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_export failed, error code %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: sqlcipher_export failed, error code %d", rc);
goto handle_error;
}
#ifdef SQLCIPHER_TEST
- if((sqlcipher_get_test_flags() & TEST_FAIL_MIGRATE) > 0) {
+ if((cipher_test_flags & TEST_FAIL_MIGRATE) > 0) {
rc = SQLITE_ERROR;
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "simulated migrate failure, error code %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_WARN, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: simulated migrate failure, error code %d", rc);
goto handle_error;
}
#endif
rc = sqlcipher_sqlite3_exec(db, set_user_version, NULL, NULL, NULL);
if(rc != SQLITE_OK){
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "set user version failed, error code %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: set user version failed, error code %d", rc);
goto handle_error;
}
if( !db->autoCommit ){
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "cannot migrate from within a transaction");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: cannot migrate from within a transaction");
goto handle_error;
}
if( db->nVdbeActive>1 ){
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "cannot migrate - SQL statements in progress");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: cannot migrate - SQL statements in progress");
goto handle_error;
}
@@ -104887,10 +108650,13 @@ migrate:
/* unset the BTS_PAGESIZE_FIXED flag to avoid SQLITE_READONLY */
pDest->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
rc = sqlcipher_sqlite3BtreeSetPageSize(pDest, default_page_size, nRes, 0);
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "set btree page size to %d res %d rc %d", default_page_size, nRes, rc);
- if( rc!=SQLITE_OK ) goto handle_error;
+ if(rc != SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: failed to set btree page size to %d res %d rc %d", default_page_size, nRes, rc);
+ goto handle_error;
+ }
sqlcipherCodecGetKey(db, db->nDb - 1, (void**)&keyspec, &keyspec_sz);
+ SQLCIPHER_FLAG_UNSET(ctx->flags, CIPHER_FLAG_KEY_USED);
sqlcipherCodecAttach(db, 0, keyspec, keyspec_sz);
srcfile = sqlcipher_sqlite3PagerFile(pSrc->pBt->pPager);
@@ -104900,7 +108666,7 @@ migrate:
sqlcipher_sqlite3OsClose(destfile);
#if defined(_WIN32) || defined(SQLITE_OS_WINRT)
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "performing windows MoveFileExA");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: performing windows MoveFileExA");
w_db_filename_sz = MultiByteToWideChar(CP_UTF8, 0, (LPCCH) db_filename, -1, NULL, 0);
w_db_filename = sqlcipher_malloc(w_db_filename_sz * sizeof(wchar_t));
@@ -104912,50 +108678,59 @@ migrate:
if(!MoveFileExW(w_migrated_db_filename, w_db_filename, MOVEFILE_REPLACE_EXISTING)) {
rc = SQLITE_ERROR;
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "error occurred while renaming %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: error occurred while renaming migration files %d", rc);
goto handle_error;
}
#else
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "performing POSIX rename");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: performing POSIX rename");
if ((rc = rename(migrated_db_filename, db_filename)) != 0) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "error occurred while renaming %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: error occurred while renaming migration files %s to %s: %d", migrated_db_filename, db_filename, rc);
goto handle_error;
}
#endif
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "renamed migration database %s to main database %s: %d", migrated_db_filename, db_filename, rc);
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: renamed migration database %s to main database %s: %d", migrated_db_filename, db_filename, rc);
rc = sqlcipher_sqlite3OsOpen(db->pVfs, migrated_db_filename, srcfile, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MAIN_DB, &oflags);
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "reopened migration database: %d", rc);
- if( rc!=SQLITE_OK ) goto handle_error;
+ if(rc != SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: failed to reopen migration database %s: %d", migrated_db_filename, rc);
+ goto handle_error;
+ }
rc = sqlcipher_sqlite3OsOpen(db->pVfs, db_filename, destfile, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MAIN_DB, &oflags);
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "reopened main database: %d", rc);
- if( rc!=SQLITE_OK ) goto handle_error;
+ if(rc != SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: failed to reopen main database %s: %d", db_filename, rc);
+ goto handle_error;
+ }
sqlcipher_sqlite3pager_reset(pDest->pBt->pPager);
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "reset pager");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: reset pager");
rc = sqlcipher_sqlite3_exec(db, "DETACH DATABASE migrate;", NULL, NULL, NULL);
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "DETACH DATABASE called %d", rc);
- if(rc != SQLITE_OK) goto cleanup;
+ if(rc != SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_WARN, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: DETACH DATABASE migrate failed: %d", rc);
+ }
sqlcipher_sqlite3ResetAllSchemasOfConnection(db);
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "reset all schemas");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: reset all schemas");
set_journal_mode = sqlcipher_sqlite3_mprintf("PRAGMA journal_mode = %s;", journal_mode);
rc = sqlcipher_sqlite3_exec(db, set_journal_mode, NULL, NULL, NULL);
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "%s: %d", set_journal_mode, rc);
- if( rc!=SQLITE_OK ) goto handle_error;
+ if(rc != SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: failed to re-set journal mode via %s: %d", set_journal_mode, rc);
+ goto handle_error;
+ }
goto cleanup;
handle_error:
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "An error occurred attempting to migrate the database - last error %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: an error occurred attempting to migrate the database - last error %d", rc);
cleanup:
if(migrated_db_filename) {
int del_rc = sqlcipher_sqlite3OsDelete(db->pVfs, migrated_db_filename, 0);
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "deleted migration database: %d", del_rc);
+ if(del_rc != SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_ctx_migrate: failed to delete migration database %s: %d", migrated_db_filename, del_rc);
+ }
}
if(pass) sqlcipher_free(pass, pass_sz);
@@ -104972,7 +108747,7 @@ cleanup:
return rc;
}
-int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight, int random_sz){
+static int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight, int random_sz){
const char *suffix = &zRight[random_sz-1];
int n = random_sz - 3; /* adjust for leading x' and tailing ' */
if (n > 0 &&
@@ -104983,7 +108758,7 @@ int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight, int random_sz
int buffer_sz = n / 2;
unsigned char *random;
const unsigned char *z = (const unsigned char *)zRight + 2; /* adjust lead offset of x' */
- sqlcipher_log(SQLCIPHER_LOG_DEBUG, "sqlcipher_codec_add_random: using raw random blob from hex");
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_add_random: using raw random blob from hex");
random = sqlcipher_malloc(buffer_sz);
memset(random, 0, buffer_sz);
cipher_hex2bin(z, n, random);
@@ -104991,26 +108766,34 @@ int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight, int random_sz
sqlcipher_free(random, buffer_sz);
return rc;
}
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_codec_add_random: attemt to add random with invalid format");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_add_random: attemt to add random with invalid format");
return SQLITE_ERROR;
}
#if !defined(SQLITE_OMIT_TRACE)
+
+#define SQLCIPHER_PROFILE_FMT "Elapsed time:%.3f ms - %s\n"
+#define SQLCIPHER_PROFILE_FMT_OSLOG "Elapsed time:%{public}.3f ms - %{public}s\n"
+
static int sqlcipher_profile_callback(unsigned int trace, void *file, void *stmt, void *run_time){
FILE *f = (FILE*) file;
- char *fmt = "Elapsed time:%.3f ms - %s\n";
double elapsed = (*((sqlcipher_sqlite3_uint64*)run_time))/1000000.0;
-#ifdef __ANDROID__
if(f == NULL) {
- __android_log_print(ANDROID_LOG_DEBUG, "sqlcipher", fmt, elapsed, sqlcipher_sqlite3_sql((sqlcipher_sqlite3_stmt*)stmt));
- }
+#if !defined(SQLCIPHER_OMIT_LOG_DEVICE)
+#if defined(__ANDROID__)
+ __android_log_print(ANDROID_LOG_DEBUG, "sqlcipher", SQLCIPHER_PROFILE_FMT, elapsed, sqlcipher_sqlite3_sql((sqlcipher_sqlite3_stmt*)stmt));
+#elif defined(__APPLE__)
+ os_log(OS_LOG_DEFAULT, SQLCIPHER_PROFILE_FMT_OSLOG, elapsed, sqlcipher_sqlite3_sql((sqlcipher_sqlite3_stmt*)stmt));
#endif
- if(f) fprintf(f, fmt, elapsed, sqlcipher_sqlite3_sql((sqlcipher_sqlite3_stmt*)stmt));
+#endif
+ } else {
+ fprintf(f, SQLCIPHER_PROFILE_FMT, elapsed, sqlcipher_sqlite3_sql((sqlcipher_sqlite3_stmt*)stmt));
+ }
return SQLITE_OK;
}
#endif
-int sqlcipher_cipher_profile(sqlcipher_sqlite3 *db, const char *destination){
+static int sqlcipher_cipher_profile(sqlcipher_sqlite3 *db, const char *destination){
#if defined(SQLITE_OMIT_TRACE)
return SQLITE_ERROR;
#else
@@ -105022,8 +108805,8 @@ int sqlcipher_cipher_profile(sqlcipher_sqlite3 *db, const char *destination){
f = stdout;
}else if(sqlcipher_sqlite3_stricmp(destination, "stderr") == 0){
f = stderr;
- }else if(sqlcipher_sqlite3_stricmp(destination, "logcat") == 0){
- f = NULL; /* file pointer will be NULL indicating logcat on android */
+ }else if(sqlcipher_sqlite3_stricmp(destination, "logcat") == 0 || sqlcipher_sqlite3_stricmp(destination, "device") == 0){
+ f = NULL; /* file pointer will be NULL indicating the device target (i.e. logcat or oslog). We will accept logcat for backwards compatibility */
}else{
#if !defined(SQLCIPHER_PROFILE_USE_FOPEN) && (defined(_WIN32) && (__STDC_VERSION__ > 199901L) || defined(SQLITE_OS_WINRT))
if(fopen_s(&f, destination, "a") != 0) return SQLITE_ERROR;
@@ -105037,35 +108820,116 @@ int sqlcipher_cipher_profile(sqlcipher_sqlite3 *db, const char *destination){
#endif
}
-int sqlcipher_codec_fips_status(codec_ctx *ctx) {
- return ctx->provider->fips_status(ctx->provider_ctx);
-}
-
-const char* sqlcipher_codec_get_provider_version(codec_ctx *ctx) {
- return ctx->provider->get_provider_version(ctx->provider_ctx);
+static char *sqlcipher_get_log_level_str(unsigned int level) {
+ switch(level) {
+ case SQLCIPHER_LOG_ERROR:
+ return "ERROR";
+ case SQLCIPHER_LOG_WARN:
+ return "WARN";
+ case SQLCIPHER_LOG_INFO:
+ return "INFO";
+ case SQLCIPHER_LOG_DEBUG:
+ return "DEBUG";
+ case SQLCIPHER_LOG_TRACE:
+ return "TRACE";
+ case SQLCIPHER_LOG_ANY:
+ return "ANY";
+ }
+ return "NONE";
+}
+
+static char *sqlcipher_get_log_source_str(unsigned int source) {
+ switch(source) {
+ case SQLCIPHER_LOG_NONE:
+ return "NONE";
+ case SQLCIPHER_LOG_CORE:
+ return "CORE";
+ case SQLCIPHER_LOG_MEMORY:
+ return "MEMORY";
+ case SQLCIPHER_LOG_MUTEX:
+ return "MUTEX";
+ case SQLCIPHER_LOG_PROVIDER:
+ return "PROVIDER";
+ }
+ return "ANY";
+}
+
+static char *sqlcipher_get_log_sources_str(unsigned int source) {
+ if(source == SQLCIPHER_LOG_NONE) {
+ return sqlcipher_sqlite3_mprintf("%s", "NONE");
+ } else if (source == SQLCIPHER_LOG_ANY) {
+ return sqlcipher_sqlite3_mprintf("%s", "ANY");
+ } else {
+ char *sources = NULL;
+ unsigned int flag;
+ for(flag = SQLCIPHER_LOG_CORE; flag != 0; flag = flag << 1) {
+ if(SQLCIPHER_FLAG_GET(source, flag)) {
+ char *src = sqlcipher_get_log_source_str(flag);
+ if(sources) {
+ char *tmp = sqlcipher_sqlite3_mprintf("%s %s", sources, src);
+ sqlcipher_sqlite3_free(sources);
+ sources = tmp;
+ } else {
+ sources = sqlcipher_sqlite3_mprintf("%s", src);
+ }
+ }
+ }
+ return sources;
+ }
}
#ifndef SQLCIPHER_OMIT_LOG
/* constants from https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-crt/misc/gettimeofday.c */
#define FILETIME_1970 116444736000000000ull /* seconds between 1/1/1601 and 1/1/1970 */
#define HECTONANOSEC_PER_SEC 10000000ull
-void sqlcipher_log(unsigned int level, const char *message, ...) {
+#define MAX_LOG_LEN 8192
+void sqlcipher_log(unsigned int level, unsigned int source, const char *message, ...) {
va_list params;
va_start(params, message);
+ char formatted[MAX_LOG_LEN];
+ size_t len = 0;
#ifdef CODEC_DEBUG
-#ifdef __ANDROID__
- __android_log_vprint(ANDROID_LOG_DEBUG, "sqlcipher", message, params);
-#else
+#if defined(SQLCIPHER_OMIT_LOG_DEVICE) || (!defined(__ANDROID__) && !defined(__APPLE__))
vfprintf(stderr, message, params);
fprintf(stderr, "\n");
+ goto end;
+#else
+#if defined(__ANDROID__)
+ __android_log_vprint(ANDROID_LOG_DEBUG, "sqlcipher", message, params);
+ goto end;
+#elif defined(__APPLE__)
+ sqlcipher_sqlite3_vsnprintf(MAX_LOG_LEN, formatted, message, params);
+ os_log(OS_LOG_DEFAULT, "%{public}s", formatted);
+ goto end;
#endif
#endif
+#endif
+ if(
+ level > sqlcipher_log_level /* log level is higher, e.g. level filter is at ERROR but this message is DEBUG */
+ || !SQLCIPHER_FLAG_GET(sqlcipher_log_source, source) /* source filter doesn't match this message source */
+ || (sqlcipher_log_device == 0 && sqlcipher_log_file == NULL) /* no configured log target */
+ ) {
+ /* skip logging this message */
+ goto end;
+ }
+
+ sqlcipher_sqlite3_snprintf(MAX_LOG_LEN, formatted, "%s %s ", sqlcipher_get_log_level_str(level), sqlcipher_get_log_source_str(source));
+ len = strlen(formatted);
+ sqlcipher_sqlite3_vsnprintf(MAX_LOG_LEN - (int) len, formatted + (int) len, message, params);
- if(level > sqlcipher_log_level || (sqlcipher_log_logcat == 0 && sqlcipher_log_file == NULL)) {
- /* no log target or tag not in included filters */
+#if !defined(SQLCIPHER_OMIT_LOG_DEVICE)
+ if(sqlcipher_log_device) {
+#if defined(__ANDROID__)
+ __android_log_write(ANDROID_LOG_DEBUG, "sqlcipher", formatted);
goto end;
+#elif defined(__APPLE__)
+ os_log(OS_LOG_DEFAULT, "%{public}s", formatted);
+ goto end;
+#endif
}
+#endif
+
if(sqlcipher_log_file != NULL){
char buffer[24];
struct tm tt;
@@ -105087,26 +108951,17 @@ void sqlcipher_log(unsigned int level, const char *message, ...) {
localtime_r(&sec, &tt);
#endif
if(strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tt)) {
- fprintf((FILE*)sqlcipher_log_file, "%s.%03d: ", buffer, ms);
- vfprintf((FILE*)sqlcipher_log_file, message, params);
- fprintf((FILE*)sqlcipher_log_file, "\n");
+ fprintf((FILE*)sqlcipher_log_file, "%s.%03d: %s\n", buffer, ms, formatted);
+ goto end;
}
}
-#ifdef __ANDROID__
- if(sqlcipher_log_logcat) {
- __android_log_vprint(ANDROID_LOG_DEBUG, "sqlcipher", message, params);
- }
-#endif
+
end:
va_end(params);
}
#endif
-void sqlcipher_set_log_level(unsigned int level) {
- sqlcipher_log_level = level;
-}
-
-int sqlcipher_set_log(const char *destination){
+static int sqlcipher_set_log(const char *destination){
#ifdef SQLCIPHER_OMIT_LOG
return SQLITE_ERROR;
#else
@@ -105116,10 +108971,11 @@ int sqlcipher_set_log(const char *destination){
fclose((FILE*)sqlcipher_log_file);
}
sqlcipher_log_file = NULL;
- sqlcipher_log_logcat = 0;
+ sqlcipher_log_device = 0;
- if(sqlcipher_sqlite3_stricmp(destination, "logcat") == 0){
- sqlcipher_log_logcat = 1;
+ if(sqlcipher_sqlite3_stricmp(destination, "logcat") == 0 || sqlcipher_sqlite3_stricmp(destination, "device") == 0){
+ /* use the appropriate device log. accept logcat for backwards compatibility */
+ sqlcipher_log_device = 1;
} else if(sqlcipher_sqlite3_stricmp(destination, "stdout") == 0){
sqlcipher_log_file = stdout;
}else if(sqlcipher_sqlite3_stricmp(destination, "stderr") == 0){
@@ -105131,15 +108987,1246 @@ int sqlcipher_set_log(const char *destination){
if((sqlcipher_log_file = fopen(destination, "a")) == 0) return SQLITE_ERROR;
#endif
}
- sqlcipher_log(SQLCIPHER_LOG_INFO, "sqlcipher_set_log: set log to %s", destination);
+ sqlcipher_log(SQLCIPHER_LOG_INFO, SQLCIPHER_LOG_CORE, "sqlcipher_set_log: set log to %s", destination);
return SQLITE_OK;
#endif
}
+static void sqlcipher_vdbe_return_string(Parse *pParse, const char *zLabel, const char *value, int value_type){
+ Vdbe *v = sqlcipher_sqlite3GetVdbe(pParse);
+ sqlcipher_sqlite3VdbeSetNumCols(v, 1);
+ sqlcipher_sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC);
+ sqlcipher_sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, value, value_type);
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+}
+
+static int codec_set_btree_to_codec_pagesize(sqlcipher_sqlite3 *db, Db *pDb, codec_ctx *ctx) {
+ int rc;
+
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "codec_set_btree_to_codec_pagesize: sqlcipher_sqlite3BtreeSetPageSize() size=%d reserve=%d", ctx->page_sz, ctx->reserve_sz);
+
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "codec_set_btree_to_codec_pagesize: entering database mutex %p", db->mutex);
+ sqlcipher_sqlite3_mutex_enter(db->mutex);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "codec_set_btree_to_codec_pagesize: entered database mutex %p", db->mutex);
+ db->nextPagesize = ctx->page_sz;
+
+ /* 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;
+ rc = sqlcipher_sqlite3BtreeSetPageSize(pDb->pBt, ctx->page_sz, ctx->reserve_sz, 0);
+
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "codec_set_btree_to_codec_pagesize: sqlcipher_sqlite3BtreeSetPageSize returned %d", rc);
+
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "codec_set_btree_to_codec_pagesize: leaving database mutex %p", db->mutex);
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "codec_set_btree_to_codec_pagesize: left database mutex %p", db->mutex);
+
+ return rc;
+}
+
+static int codec_set_pass_key(sqlcipher_sqlite3* db, int nDb, const void *zKey, int nKey, int for_ctx) {
+ struct Db *pDb = &db->aDb[nDb];
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "codec_set_pass_key: db=%p nDb=%d for_ctx=%d", db, nDb, for_ctx);
+ if(pDb->pBt) {
+ codec_ctx *ctx = (codec_ctx*) sqlcipherPagerGetCodec(pDb->pBt->pBt->pPager);
+
+ if(ctx) {
+ return sqlcipher_codec_ctx_set_pass(ctx, zKey, nKey, for_ctx);
+ } else {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "codec_set_pass_key: error ocurred fetching codec from pager on db %d", nDb);
+ return SQLITE_ERROR;
+ }
+ }
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "codec_set_pass_key: no btree present on db %d", nDb);
+ return SQLITE_ERROR;
+}
+
+int sqlcipher_codec_pragma(sqlcipher_sqlite3* db, int iDb, Parse *pParse, const char *zLeft, const char *zRight) {
+ struct Db *pDb = &db->aDb[iDb];
+ codec_ctx *ctx = NULL;
+ int rc;
+
+ if(pDb->pBt) {
+ ctx = (codec_ctx*) sqlcipherPagerGetCodec(pDb->pBt->pBt->pPager);
+ }
+
+ if(sqlcipher_sqlite3_stricmp(zLeft, "key") !=0 && sqlcipher_sqlite3_stricmp(zLeft, "rekey") != 0) {
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_codec_pragma: db=%p iDb=%d pParse=%p zLeft=%s zRight=%s ctx=%p", db, iDb, pParse, zLeft, zRight, ctx);
+ }
+
+#ifdef SQLCIPHER_TEST
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_test_on")==0 ){
+ if( zRight ) {
+ if(sqlcipher_sqlite3_stricmp(zRight, "fail_encrypt")==0) {
+ SQLCIPHER_FLAG_SET(cipher_test_flags,TEST_FAIL_ENCRYPT);
+ } else
+ if(sqlcipher_sqlite3_stricmp(zRight, "fail_decrypt")==0) {
+ SQLCIPHER_FLAG_SET(cipher_test_flags,TEST_FAIL_DECRYPT);
+ } else
+ if(sqlcipher_sqlite3_stricmp(zRight, "fail_migrate")==0) {
+ SQLCIPHER_FLAG_SET(cipher_test_flags,TEST_FAIL_MIGRATE);
+ }
+ }
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_test_off")==0 ){
+ if( zRight ) {
+ if(sqlcipher_sqlite3_stricmp(zRight, "fail_encrypt")==0) {
+ SQLCIPHER_FLAG_UNSET(cipher_test_flags,TEST_FAIL_ENCRYPT);
+ } else
+ if(sqlcipher_sqlite3_stricmp(zRight, "fail_decrypt")==0) {
+ SQLCIPHER_FLAG_UNSET(cipher_test_flags,TEST_FAIL_DECRYPT);
+ } else
+ if(sqlcipher_sqlite3_stricmp(zRight, "fail_migrate")==0) {
+ SQLCIPHER_FLAG_UNSET(cipher_test_flags,TEST_FAIL_MIGRATE);
+ }
+ }
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_test")==0 ){
+ char *flags = sqlcipher_sqlite3_mprintf("%u", cipher_test_flags);
+ sqlcipher_vdbe_return_string(pParse, "cipher_test", flags, P4_DYNAMIC);
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_test_rand")==0 ){
+ if( zRight ) {
+ int rand = atoi(zRight);
+ cipher_test_rand = rand;
+ } else {
+ char *rand = sqlcipher_sqlite3_mprintf("%d", cipher_test_rand);
+ sqlcipher_vdbe_return_string(pParse, "cipher_test_rand", rand, P4_DYNAMIC);
+ }
+ } else
+#endif
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_fips_status")== 0 && !zRight ){
+ if(ctx) {
+ char *fips_mode_status = sqlcipher_sqlite3_mprintf("%d", ctx->provider->fips_status(ctx->provider_ctx));
+ sqlcipher_vdbe_return_string(pParse, "cipher_fips_status", fips_mode_status, P4_DYNAMIC);
+ }
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_store_pass")==0 && zRight ) {
+ if(ctx) {
+ char *deprecation = "PRAGMA cipher_store_pass is deprecated, please remove from use";
+ ctx->store_pass = sqlcipher_sqlite3GetBoolean(zRight, 1);
+ sqlcipher_vdbe_return_string(pParse, "cipher_store_pass", deprecation, P4_TRANSIENT);
+ sqlcipher_sqlite3_log(SQLITE_WARNING, deprecation);
+ }
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_store_pass")==0 && !zRight ) {
+ if(ctx){
+ char *store_pass_value = sqlcipher_sqlite3_mprintf("%d", ctx->store_pass);
+ sqlcipher_vdbe_return_string(pParse, "cipher_store_pass", store_pass_value, P4_DYNAMIC);
+ }
+ }
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_profile")== 0 && zRight ){
+ char *profile_status = sqlcipher_sqlite3_mprintf("%d", sqlcipher_cipher_profile(db, zRight));
+ sqlcipher_vdbe_return_string(pParse, "cipher_profile", profile_status, P4_DYNAMIC);
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_add_random")==0 && zRight ){
+ if(ctx) {
+ char *add_random_status = sqlcipher_sqlite3_mprintf("%d", sqlcipher_codec_add_random(ctx, zRight, sqlcipher_sqlite3Strlen30(zRight)));
+ sqlcipher_vdbe_return_string(pParse, "cipher_add_random", add_random_status, P4_DYNAMIC);
+ }
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_migrate")==0 && !zRight ){
+ if(ctx){
+ int status = sqlcipher_codec_ctx_migrate(ctx);
+ char *migrate_status = sqlcipher_sqlite3_mprintf("%d", status);
+ sqlcipher_vdbe_return_string(pParse, "cipher_migrate", migrate_status, P4_DYNAMIC);
+ if(status != SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_codec_pragma: error occurred during cipher_migrate: %d", status);
+ sqlcipher_codec_ctx_set_error(ctx, status);
+ }
+ }
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_provider")==0 && !zRight ){
+ if(ctx) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_provider",
+ ctx->provider->get_provider_name(ctx->provider_ctx), P4_TRANSIENT);
+ }
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_provider_version")==0 && !zRight){
+ if(ctx) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_provider_version",
+ ctx->provider->get_provider_version(ctx->provider_ctx), P4_TRANSIENT);
+ }
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_version")==0 && !zRight ){
+ sqlcipher_vdbe_return_string(pParse, "cipher_version", sqlcipher_version(), P4_DYNAMIC);
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher")==0 ){
+ if(ctx) {
+ if( zRight ) {
+ const char* message = "PRAGMA cipher is no longer supported.";
+ sqlcipher_vdbe_return_string(pParse, "cipher", message, P4_TRANSIENT);
+ sqlcipher_sqlite3_log(SQLITE_WARNING, message);
+ }else {
+ sqlcipher_vdbe_return_string(pParse, "cipher",
+ ctx->provider->get_cipher(ctx->provider_ctx), P4_TRANSIENT);
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "rekey_cipher")==0 && zRight ){
+ const char* message = "PRAGMA rekey_cipher is no longer supported.";
+ sqlcipher_vdbe_return_string(pParse, "rekey_cipher", message, P4_TRANSIENT);
+ sqlcipher_sqlite3_log(SQLITE_WARNING, message);
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_kdf_iter")==0 ){
+ if( zRight ) {
+ default_kdf_iter = atoi(zRight); /* change default KDF iterations */
+ } else {
+ char *kdf_iter = sqlcipher_sqlite3_mprintf("%d", default_kdf_iter);
+ sqlcipher_vdbe_return_string(pParse, "cipher_default_kdf_iter", kdf_iter, P4_DYNAMIC);
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "kdf_iter")==0 ){
+ if(ctx) {
+ if( zRight ) {
+ sqlcipher_codec_ctx_set_kdf_iter(ctx, atoi(zRight)); /* change of RW PBKDF2 iteration */
+ } else {
+ char *kdf_iter = sqlcipher_sqlite3_mprintf("%d", ctx->kdf_iter);
+ sqlcipher_vdbe_return_string(pParse, "kdf_iter", kdf_iter, P4_DYNAMIC);
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "fast_kdf_iter")==0){
+ if(ctx) {
+ if( zRight ) {
+ char *deprecation = "PRAGMA fast_kdf_iter is deprecated, please remove from use";
+ sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, atoi(zRight)); /* change of RW PBKDF2 iteration */
+ sqlcipher_vdbe_return_string(pParse, "fast_kdf_iter", deprecation, P4_TRANSIENT);
+ sqlcipher_sqlite3_log(SQLITE_WARNING, deprecation);
+ } else {
+ char *fast_kdf_iter = sqlcipher_sqlite3_mprintf("%d", ctx->fast_kdf_iter);
+ sqlcipher_vdbe_return_string(pParse, "fast_kdf_iter", fast_kdf_iter, P4_DYNAMIC);
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "rekey_kdf_iter")==0 && zRight ){
+ const char* message = "PRAGMA rekey_kdf_iter is no longer supported.";
+ sqlcipher_vdbe_return_string(pParse, "rekey_kdf_iter", message, P4_TRANSIENT);
+ sqlcipher_sqlite3_log(SQLITE_WARNING, message);
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"page_size")==0 || sqlcipher_sqlite3_stricmp(zLeft,"cipher_page_size")==0 ){
+ /* PRAGMA cipher_page_size will alter the size of the database pages while ensuring that the
+ required reserve space is allocated at the end of each page. This will also override the
+ standard SQLite PRAGMA page_size behavior if a codec context is attached to the database handle.
+ If PRAGMA page_size is invoked but a codec context is not attached (i.e. dealing with a standard
+ unencrypted database) then return early and allow the standard PRAGMA page_size logic to apply. */
+ if(ctx) {
+ if( zRight ) {
+ int size = atoi(zRight);
+ rc = sqlcipher_codec_ctx_set_pagesize(ctx, size);
+ if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
+ rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
+ if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
+ } else {
+ char * page_size = sqlcipher_sqlite3_mprintf("%d", ctx->page_sz);
+ sqlcipher_vdbe_return_string(pParse, "cipher_page_size", page_size, P4_DYNAMIC);
+ }
+ } else {
+ return 0; /* return early so that the PragTyp_PAGE_SIZE case logic in pragma.c will take effect */
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_page_size")==0 ){
+ if( zRight ) {
+ default_page_size = atoi(zRight);
+ } else {
+ char *page_size = sqlcipher_sqlite3_mprintf("%d", default_page_size);
+ sqlcipher_vdbe_return_string(pParse, "cipher_default_page_size", page_size, P4_DYNAMIC);
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_use_hmac")==0 ){
+ if( zRight ) {
+ sqlcipher_set_default_use_hmac(sqlcipher_sqlite3GetBoolean(zRight,1));
+ } else {
+ char *default_use_hmac = sqlcipher_sqlite3_mprintf("%d", SQLCIPHER_FLAG_GET(default_flags, CIPHER_FLAG_HMAC));
+ sqlcipher_vdbe_return_string(pParse, "cipher_default_use_hmac", default_use_hmac, P4_DYNAMIC);
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_use_hmac")==0 ){
+ if(ctx) {
+ if( zRight ) {
+ rc = sqlcipher_codec_ctx_set_use_hmac(ctx, sqlcipher_sqlite3GetBoolean(zRight,1));
+ if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
+ /* since the use of hmac has changed, the page size may also change */
+ rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
+ if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
+ } else {
+ char *hmac_flag = sqlcipher_sqlite3_mprintf("%d", SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_HMAC));
+ sqlcipher_vdbe_return_string(pParse, "cipher_use_hmac", hmac_flag, P4_DYNAMIC);
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_hmac_pgno")==0 ){
+ if(ctx) {
+ if(zRight) {
+ char *deprecation = "PRAGMA cipher_hmac_pgno is deprecated, please remove from use";
+ /* clear both pgno endian flags */
+ if(sqlcipher_sqlite3_stricmp(zRight, "le") == 0) {
+ SQLCIPHER_FLAG_UNSET(ctx->flags, CIPHER_FLAG_BE_PGNO);
+ SQLCIPHER_FLAG_SET(ctx->flags, CIPHER_FLAG_LE_PGNO);
+ } else if(sqlcipher_sqlite3_stricmp(zRight, "be") == 0) {
+ SQLCIPHER_FLAG_UNSET(ctx->flags, CIPHER_FLAG_LE_PGNO);
+ SQLCIPHER_FLAG_SET(ctx->flags, CIPHER_FLAG_BE_PGNO);
+ } else if(sqlcipher_sqlite3_stricmp(zRight, "native") == 0) {
+ SQLCIPHER_FLAG_UNSET(ctx->flags, CIPHER_FLAG_LE_PGNO);
+ SQLCIPHER_FLAG_UNSET(ctx->flags, CIPHER_FLAG_BE_PGNO);
+ }
+ sqlcipher_vdbe_return_string(pParse, "cipher_hmac_pgno", deprecation, P4_TRANSIENT);
+ sqlcipher_sqlite3_log(SQLITE_WARNING, deprecation);
+
+ } else {
+ if(SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_LE_PGNO)) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_hmac_pgno", "le", P4_TRANSIENT);
+ } else if(SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_BE_PGNO)) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_hmac_pgno", "be", P4_TRANSIENT);
+ } else {
+ sqlcipher_vdbe_return_string(pParse, "cipher_hmac_pgno", "native", P4_TRANSIENT);
+ }
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_hmac_salt_mask")==0 ){
+ if(ctx) {
+ if(zRight) {
+ char *deprecation = "PRAGMA cipher_hmac_salt_mask is deprecated, please remove from use";
+ if (sqlcipher_sqlite3StrNICmp(zRight ,"x'", 2) == 0 && sqlcipher_sqlite3Strlen30(zRight) == 5) {
+ unsigned char mask = 0;
+ const unsigned char *hex = (const unsigned char *)zRight+2;
+ cipher_hex2bin(hex,2,&mask);
+ hmac_salt_mask = mask;
+ }
+ sqlcipher_vdbe_return_string(pParse, "cipher_hmac_salt_mask", deprecation, P4_TRANSIENT);
+ sqlcipher_sqlite3_log(SQLITE_WARNING, deprecation);
+ } else {
+ char *mask = sqlcipher_sqlite3_mprintf("%02x", hmac_salt_mask);
+ sqlcipher_vdbe_return_string(pParse, "cipher_hmac_salt_mask", mask, P4_DYNAMIC);
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_plaintext_header_size")==0 ){
+ if(ctx) {
+ if( zRight ) {
+ int size = atoi(zRight);
+ /* deliberately ignore result code, if size is invalid it will be set to -1
+ and trip the error later in the codec */
+ sqlcipher_codec_ctx_set_plaintext_header_size(ctx, size);
+ } else {
+ char *size = sqlcipher_sqlite3_mprintf("%d", ctx->plaintext_header_sz);
+ sqlcipher_vdbe_return_string(pParse, "cipher_plaintext_header_size", size, P4_DYNAMIC);
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_plaintext_header_size")==0 ){
+ if( zRight ) {
+ default_plaintext_header_size = atoi(zRight);
+ } else {
+ char *size = sqlcipher_sqlite3_mprintf("%d", default_plaintext_header_size);
+ sqlcipher_vdbe_return_string(pParse, "cipher_default_plaintext_header_size", size, P4_DYNAMIC);
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_salt")==0 ){
+ if(ctx) {
+ if(zRight) {
+ if (sqlcipher_sqlite3StrNICmp(zRight ,"x'", 2) == 0 && sqlcipher_sqlite3Strlen30(zRight) == (FILE_HEADER_SZ*2)+3) {
+ unsigned char *salt = (unsigned char*) sqlcipher_sqlite3_malloc(FILE_HEADER_SZ);
+ const unsigned char *hex = (const unsigned char *)zRight+2;
+ cipher_hex2bin(hex,FILE_HEADER_SZ*2,salt);
+ sqlcipher_codec_ctx_set_kdf_salt(ctx, salt, FILE_HEADER_SZ);
+ sqlcipher_sqlite3_free(salt);
+ }
+ } else {
+ void *salt;
+ char *hexsalt = (char*) sqlcipher_sqlite3_malloc((FILE_HEADER_SZ*2)+1);
+ if((rc = sqlcipher_codec_ctx_get_kdf_salt(ctx, &salt)) == SQLITE_OK) {
+ cipher_bin2hex(salt, FILE_HEADER_SZ, hexsalt);
+ sqlcipher_vdbe_return_string(pParse, "cipher_salt", hexsalt, P4_DYNAMIC);
+ } else {
+ sqlcipher_sqlite3_free(hexsalt);
+ sqlcipher_codec_ctx_set_error(ctx, rc);
+ }
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_hmac_algorithm")==0 ){
+ if(ctx) {
+ if(zRight) {
+ rc = SQLITE_ERROR;
+ if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA1_LABEL) == 0) {
+ rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA1);
+ } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA256_LABEL) == 0) {
+ rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA256);
+ } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA512_LABEL) == 0) {
+ rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA512);
+ }
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ } else {
+ int algorithm = ctx->hmac_algorithm;
+ if(ctx->hmac_algorithm == SQLCIPHER_HMAC_SHA1) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_hmac_algorithm", SQLCIPHER_HMAC_SHA1_LABEL, P4_TRANSIENT);
+ } else if(algorithm == SQLCIPHER_HMAC_SHA256) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_hmac_algorithm", SQLCIPHER_HMAC_SHA256_LABEL, P4_TRANSIENT);
+ } else if(algorithm == SQLCIPHER_HMAC_SHA512) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_hmac_algorithm", SQLCIPHER_HMAC_SHA512_LABEL, P4_TRANSIENT);
+ }
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_hmac_algorithm")==0 ){
+ if(zRight) {
+ rc = SQLITE_OK;
+ if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA1_LABEL) == 0) {
+ default_hmac_algorithm = SQLCIPHER_HMAC_SHA1;
+ } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA256_LABEL) == 0) {
+ default_hmac_algorithm = SQLCIPHER_HMAC_SHA256;
+ } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_HMAC_SHA512_LABEL) == 0) {
+ default_hmac_algorithm = SQLCIPHER_HMAC_SHA512;
+ }
+ } else {
+ if(default_hmac_algorithm == SQLCIPHER_HMAC_SHA1) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_default_hmac_algorithm", SQLCIPHER_HMAC_SHA1_LABEL, P4_TRANSIENT);
+ } else if(default_hmac_algorithm == SQLCIPHER_HMAC_SHA256) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_default_hmac_algorithm", SQLCIPHER_HMAC_SHA256_LABEL, P4_TRANSIENT);
+ } else if(default_hmac_algorithm == SQLCIPHER_HMAC_SHA512) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_default_hmac_algorithm", SQLCIPHER_HMAC_SHA512_LABEL, P4_TRANSIENT);
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_kdf_algorithm")==0 ){
+ if(ctx) {
+ if(zRight) {
+ rc = SQLITE_ERROR;
+ if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL) == 0) {
+ rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA1);
+ } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL) == 0) {
+ rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA256);
+ } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL) == 0) {
+ rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA512);
+ }
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ } else {
+ if(ctx->kdf_algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL, P4_TRANSIENT);
+ } else if(ctx->kdf_algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL, P4_TRANSIENT);
+ } else if(ctx->kdf_algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL, P4_TRANSIENT);
+ }
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_kdf_algorithm")==0 ){
+ if(zRight) {
+ rc = SQLITE_OK;
+ if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL) == 0) {
+ default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA1;
+ } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL) == 0) {
+ default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA256;
+ } else if(sqlcipher_sqlite3_stricmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL) == 0) {
+ default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA512;
+ }
+ } else {
+ if(default_kdf_algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_default_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL, P4_TRANSIENT);
+ } else if(default_kdf_algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_default_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL, P4_TRANSIENT);
+ } else if(default_kdf_algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
+ sqlcipher_vdbe_return_string(pParse, "cipher_default_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL, P4_TRANSIENT);
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_compatibility")==0 ){
+ if(ctx) {
+ if(zRight) {
+ int version = atoi(zRight);
+
+ switch(version) {
+ case 1:
+ rc = sqlcipher_codec_ctx_set_pagesize(ctx, 1024);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA1);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA1);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, 4000);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_use_hmac(ctx, 0);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ break;
+
+ case 2:
+ rc = sqlcipher_codec_ctx_set_pagesize(ctx, 1024);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA1);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA1);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, 4000);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_use_hmac(ctx, 1);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ break;
+
+ case 3:
+ rc = sqlcipher_codec_ctx_set_pagesize(ctx, 1024);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA1);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA1);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, 64000);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_use_hmac(ctx, 1);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ break;
+
+ default:
+ rc = sqlcipher_codec_ctx_set_pagesize(ctx, 4096);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA512);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA512);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, 256000);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ rc = sqlcipher_codec_ctx_set_use_hmac(ctx, 1);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ break;
+ }
+
+ rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
+ if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_compatibility")==0 ){
+ if(zRight) {
+ int version = atoi(zRight);
+ switch(version) {
+ case 1:
+ default_page_size = 1024;
+ default_hmac_algorithm = SQLCIPHER_HMAC_SHA1;
+ default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA1;
+ default_kdf_iter = 4000;
+ sqlcipher_set_default_use_hmac(0);
+ break;
+
+ case 2:
+ default_page_size = 1024;
+ default_hmac_algorithm = SQLCIPHER_HMAC_SHA1;
+ default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA1;
+ default_kdf_iter = 4000;
+ sqlcipher_set_default_use_hmac(1);
+ break;
+
+ case 3:
+ default_page_size = 1024;
+ default_hmac_algorithm = SQLCIPHER_HMAC_SHA1;
+ default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA1;
+ default_kdf_iter = 64000;
+ sqlcipher_set_default_use_hmac(1);
+ break;
+
+ default:
+ default_page_size = 4096;
+ default_hmac_algorithm = SQLCIPHER_HMAC_SHA512;
+ default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA512;
+ default_kdf_iter = 256000;
+ sqlcipher_set_default_use_hmac(1);
+ break;
+ }
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_memory_security")==0 ){
+ if( zRight ) {
+ if(sqlcipher_sqlite3GetBoolean(zRight,1)) {
+ /* memory security can only be enabled, not disabled */
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_set_mem_security: on");
+ sqlcipher_mem_security_on = 1;
+ }
+ } else {
+ /* only report that memory security is enabled if pragma cipher_memory_security is ON and
+ SQLCipher's allocator/deallocator was run at least one time */
+ int state = sqlcipher_mem_security_on && sqlcipher_mem_executed;
+ char *on = sqlcipher_sqlite3_mprintf("%d", state);
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE,
+ "sqlcipher_get_mem_security: sqlcipher_mem_security_on = %d, sqlcipher_mem_executed = %d",
+ sqlcipher_mem_security_on, sqlcipher_mem_executed);
+ sqlcipher_vdbe_return_string(pParse, "cipher_memory_security", on, P4_DYNAMIC);
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_settings")==0 ){
+ if(ctx) {
+ int algorithm;
+ char *pragma;
+
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA kdf_iter = %d;", ctx->kdf_iter);
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_page_size = %d;", ctx->page_sz);
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_use_hmac = %d;", SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_HMAC));
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_plaintext_header_size = %d;", ctx->plaintext_header_sz);
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+
+ algorithm = ctx->hmac_algorithm;
+ pragma = NULL;
+ if(algorithm == SQLCIPHER_HMAC_SHA1) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA1_LABEL);
+ } else if(algorithm == SQLCIPHER_HMAC_SHA256) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA256_LABEL);
+ } else if(algorithm == SQLCIPHER_HMAC_SHA512) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA512_LABEL);
+ }
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+
+ algorithm = ctx->kdf_algorithm;
+ pragma = NULL;
+ if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL);
+ } else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL);
+ } else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL);
+ }
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+
+ }
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_default_settings")==0 ){
+ char *pragma;
+
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_kdf_iter = %d;", default_kdf_iter);
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_page_size = %d;", default_page_size);
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_use_hmac = %d;", SQLCIPHER_FLAG_GET(default_flags, CIPHER_FLAG_HMAC));
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_plaintext_header_size = %d;", default_plaintext_header_size);
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+
+ pragma = NULL;
+ if(default_hmac_algorithm == SQLCIPHER_HMAC_SHA1) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA1_LABEL);
+ } else if(default_hmac_algorithm == SQLCIPHER_HMAC_SHA256) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA256_LABEL);
+ } else if(default_hmac_algorithm == SQLCIPHER_HMAC_SHA512) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA512_LABEL);
+ }
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+
+ pragma = NULL;
+ if(default_kdf_algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL);
+ } else if(default_kdf_algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL);
+ } else if(default_kdf_algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
+ pragma = sqlcipher_sqlite3_mprintf("PRAGMA cipher_default_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL);
+ }
+ sqlcipher_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
+ }else
+ if( sqlcipher_sqlite3_stricmp(zLeft,"cipher_integrity_check")==0 ){
+ if(ctx) {
+ sqlcipher_codec_ctx_integrity_check(ctx, pParse, "cipher_integrity_check");
+ }
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_log_level")==0 ){
+ if(zRight) {
+ sqlcipher_log_level = SQLCIPHER_LOG_NONE;
+ if(sqlcipher_sqlite3_stricmp(zRight, "ERROR")==0) sqlcipher_log_level = SQLCIPHER_LOG_ERROR;
+ else if(sqlcipher_sqlite3_stricmp(zRight, "WARN" )==0) sqlcipher_log_level = SQLCIPHER_LOG_WARN;
+ else if(sqlcipher_sqlite3_stricmp(zRight, "INFO" )==0) sqlcipher_log_level = SQLCIPHER_LOG_INFO;
+ else if(sqlcipher_sqlite3_stricmp(zRight, "DEBUG")==0) sqlcipher_log_level = SQLCIPHER_LOG_DEBUG;
+ else if(sqlcipher_sqlite3_stricmp(zRight, "TRACE")==0) sqlcipher_log_level = SQLCIPHER_LOG_TRACE;
+ }
+ sqlcipher_vdbe_return_string(pParse, "cipher_log_level", sqlcipher_get_log_level_str(sqlcipher_log_level), P4_TRANSIENT);
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_log_source")==0 ){
+ if(zRight) {
+ if(sqlcipher_sqlite3_stricmp(zRight, "NONE" )==0) sqlcipher_log_source = SQLCIPHER_LOG_NONE;
+ else if(sqlcipher_sqlite3_stricmp(zRight, "ANY" )==0) sqlcipher_log_source = SQLCIPHER_LOG_ANY;
+ else {
+ if(sqlcipher_sqlite3_stricmp(zRight, "CORE" )==0) SQLCIPHER_FLAG_SET(sqlcipher_log_source, SQLCIPHER_LOG_CORE);
+ else if(sqlcipher_sqlite3_stricmp(zRight, "MEMORY" )==0) SQLCIPHER_FLAG_SET(sqlcipher_log_source, SQLCIPHER_LOG_MEMORY);
+ else if(sqlcipher_sqlite3_stricmp(zRight, "MUTEX" )==0) SQLCIPHER_FLAG_SET(sqlcipher_log_source, SQLCIPHER_LOG_MUTEX);
+ else if(sqlcipher_sqlite3_stricmp(zRight, "PROVIDER")==0) SQLCIPHER_FLAG_SET(sqlcipher_log_source, SQLCIPHER_LOG_PROVIDER);
+ }
+ }
+ sqlcipher_vdbe_return_string(pParse, "cipher_log_source", sqlcipher_get_log_sources_str(sqlcipher_log_source), P4_DYNAMIC);
+ } else
+ if( sqlcipher_sqlite3_stricmp(zLeft, "cipher_log")== 0 && zRight ){
+ char *status = sqlcipher_sqlite3_mprintf("%d", sqlcipher_set_log(zRight));
+ sqlcipher_vdbe_return_string(pParse, "cipher_log", status, P4_DYNAMIC);
+ }else {
+ return 0;
+ }
+ return 1;
+}
+
+/* these constants are used internally within SQLite's pager.c to differentiate between
+ operations on the main database or journal pages. This is important in the context
+ of a rekey operations, where the journal must be written using the original key
+ material (to allow a transactional rollback), while the new database pages are being
+ written with the new key material*/
+#define CODEC_READ_OP 3
+#define CODEC_WRITE_OP 6
+#define CODEC_JOURNAL_OP 7
+
+/*
+ * sqlcipher_sqlite3Codec can be called in multiple modes.
+ * encrypt mode - expected to return a pointer to the
+ * encrypted data without altering pData.
+ * decrypt mode - expected to return a pointer to pData, with
+ * the data decrypted in the input buffer
+ */
+static void* sqlcipher_sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
+ codec_ctx *ctx = (codec_ctx *) iCtx;
+ int offset = 0, rc = 0;
+ unsigned char *pData = (unsigned char *) data;
+ int cctx = CIPHER_READ_CTX;
+
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3Codec: pgno=%d, mode=%d, ctx->page_sz=%d", pgno, mode, ctx->page_sz);
+
+ /* call to derive keys if not present yet */
+ if((rc = sqlcipher_codec_key_derive(ctx)) != SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3Codec: error occurred during key derivation: %d", rc);
+ sqlcipher_codec_ctx_set_error(ctx, rc);
+ return NULL;
+ }
+
+ /* if the plaintext_header_size is negative that means an invalid size was set via
+ PRAGMA. We can't set the error state on the pager at that point because the pager
+ may not be open yet. However, this is a fatal error state, so abort the codec */
+ if(ctx->plaintext_header_sz < 0) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3Codec: error invalid ctx->plaintext_header_sz: %d", ctx->plaintext_header_sz);
+ sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
+ return NULL;
+ }
+
+ if(pgno == 1) /* adjust starting pointers in data page for header offset on first page*/
+ offset = ctx->plaintext_header_sz ? ctx->plaintext_header_sz : FILE_HEADER_SZ;
+
+
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3Codec: switch mode=%d offset=%d", mode, offset);
+ switch(mode) {
+ case CODEC_READ_OP: /* decrypt */
+ if(pgno == 1) /* copy initial part of file header or SQLite magic to buffer */
+ memcpy(ctx->buffer, ctx->plaintext_header_sz ? pData : (void *) SQLITE_FILE_HEADER, offset);
+
+ rc = sqlcipher_page_cipher(ctx, cctx, pgno, CIPHER_DECRYPT, ctx->page_sz - offset, pData + offset, (unsigned char*)ctx->buffer + offset);
+#ifdef SQLCIPHER_TEST
+ if((cipher_test_flags & TEST_FAIL_DECRYPT) > 0 && sqlcipher_get_test_fail()) {
+ rc = SQLITE_ERROR;
+ sqlcipher_log(SQLCIPHER_LOG_WARN, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3Codec: simulating decryption failure for pgno=%d, mode=%d, ctx->page_sz=%d\n", pgno, mode, ctx->page_sz);
+ }
+#endif
+ if(rc != SQLITE_OK) {
+ /* failure to decrypt a page is considered a permanent error and will render the pager unusable
+ in order to prevent inconsistent data being loaded into page cache */
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3Codec: error decrypting page %d data: %d", pgno, rc);
+ sqlcipher_memset((unsigned char*) ctx->buffer+offset, 0, ctx->page_sz-offset);
+ sqlcipher_codec_ctx_set_error(ctx, rc);
+ } else {
+ SQLCIPHER_FLAG_SET(ctx->flags, CIPHER_FLAG_KEY_USED);
+ }
+ memcpy(pData, ctx->buffer, ctx->page_sz); /* copy buffer data back to pData and return */
+ return pData;
+ break;
+
+ case CODEC_WRITE_OP: /* encrypt database page, operate on write context and fall through to case 7, so the write context is used*/
+ cctx = CIPHER_WRITE_CTX;
+
+ case CODEC_JOURNAL_OP: /* encrypt journal page, operate on read context use to get the original page data from the database */
+ if(pgno == 1) { /* copy initial part of file header or salt to buffer */
+ void *kdf_salt = NULL;
+ /* retrieve the kdf salt */
+ if((rc = sqlcipher_codec_ctx_get_kdf_salt(ctx, &kdf_salt)) != SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3Codec: error retrieving salt: %d", rc);
+ sqlcipher_codec_ctx_set_error(ctx, rc);
+ return NULL;
+ }
+ memcpy(ctx->buffer, ctx->plaintext_header_sz ? pData : kdf_salt, offset);
+ }
+ rc = sqlcipher_page_cipher(ctx, cctx, pgno, CIPHER_ENCRYPT, ctx->page_sz - offset, pData + offset, (unsigned char*)ctx->buffer + offset);
+#ifdef SQLCIPHER_TEST
+ if((cipher_test_flags & TEST_FAIL_ENCRYPT) > 0 && sqlcipher_get_test_fail()) {
+ rc = SQLITE_ERROR;
+ sqlcipher_log(SQLCIPHER_LOG_WARN, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3Codec: simulating encryption failure for pgno=%d, mode=%d, ctx->page_sz=%d\n", pgno, mode, ctx->page_sz);
+ }
+#endif
+ if(rc != SQLITE_OK) {
+ /* failure to encrypt a page is considered a permanent error and will render the pager unusable
+ in order to prevent corrupted pages from being written to the main databased when using WAL */
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3Codec: error encrypting page %d data: %d", pgno, rc);
+ sqlcipher_memset((unsigned char*)ctx->buffer+offset, 0, ctx->page_sz-offset);
+ sqlcipher_codec_ctx_set_error(ctx, rc);
+ return NULL;
+ }
+ SQLCIPHER_FLAG_SET(ctx->flags, CIPHER_FLAG_KEY_USED);
+ return ctx->buffer; /* return persistent buffer data, pData remains intact */
+ break;
+
+ default:
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3Codec: error unsupported codec mode %d", mode);
+ sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR); /* unsupported mode, set error */
+ return pData;
+ break;
+ }
+}
+
+static void sqlcipher_sqlite3FreeCodecArg(void *pCodecArg) {
+ codec_ctx *ctx = (codec_ctx *) pCodecArg;
+ if(pCodecArg == NULL) return;
+ sqlcipher_codec_ctx_free(&ctx); /* wipe and free allocated memory for the context */
+ sqlcipher_deactivate(); /* cleanup related structures, OpenSSL etc, when codec is detatched */
+}
+
+int sqlcipherCodecAttach(sqlcipher_sqlite3* db, int nDb, const void *zKey, int nKey) {
+ struct Db *pDb = &db->aDb[nDb];
+
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipherCodecAttach: db=%p, nDb=%d", db, nDb);
+
+ if(nKey && zKey && pDb->pBt) {
+ int rc;
+ Pager *pPager = pDb->pBt->pBt->pPager;
+ sqlcipher_sqlite3_file *fd;
+ codec_ctx *ctx;
+
+ ctx = (codec_ctx*) sqlcipherPagerGetCodec(pDb->pBt->pBt->pPager);
+
+ if(ctx != NULL && SQLCIPHER_FLAG_GET(ctx->flags, CIPHER_FLAG_KEY_USED)) {
+ /* there is already a codec attached to this database, so we should not proceed */
+ sqlcipher_log(SQLCIPHER_LOG_WARN, SQLCIPHER_LOG_CORE, "sqlcipherCodecAttach: no codec attached to db");
+ return SQLITE_OK;
+ }
+
+ /* check if the sqlcipher_sqlite3_file is open, and if not force handle to NULL */
+ if((fd = sqlcipher_sqlite3PagerFile(pPager))->pMethods == 0) fd = NULL;
+
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipherCodecAttach: calling sqlcipher_activate()");
+ sqlcipher_activate(); /* perform internal initialization for sqlcipher */
+
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipherCodecAttach: entering database mutex %p", db->mutex);
+ sqlcipher_sqlite3_mutex_enter(db->mutex);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipherCodecAttach: entered database mutex %p", db->mutex);
+
+ /* point the internal codec argument against the contet to be prepared */
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipherCodecAttach: calling sqlcipher_codec_ctx_init()");
+ rc = sqlcipher_codec_ctx_init(&ctx, pDb, pDb->pBt->pBt->pPager, zKey, nKey);
+
+ if(rc != SQLITE_OK) {
+ /* initialization failed, do not attach potentially corrupted context */
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipherCodecAttach: context initialization failed, forcing error state with rc=%d", rc);
+ /* force an error at the pager level, such that even the upstream caller ignores the return code
+ the pager will be in an error state and will process no further operations */
+ sqlcipher_sqlite3pager_error(pPager, rc);
+ pDb->pBt->pBt->db->errCode = rc;
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipherCodecAttach: leaving database mutex %p (early return on rc=%d)", db->mutex, rc);
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipherCodecAttach: left database mutex %p (early return on rc=%d)", db->mutex, rc);
+ return rc;
+ }
+
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipherCodecAttach: calling sqlcipherPagerSetCodec()");
+ sqlcipherPagerSetCodec(sqlcipher_sqlite3BtreePager(pDb->pBt), sqlcipher_sqlite3Codec, NULL, sqlcipher_sqlite3FreeCodecArg, (void *) ctx);
+
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipherCodecAttach: calling codec_set_btree_to_codec_pagesize()");
+ 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
+ sqlcipher_sqlite3PagerDontWrite optimizations) */
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipherCodecAttach: calling sqlcipher_sqlite3BtreeSecureDelete()");
+ sqlcipher_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 */
+ if(fd != NULL) {
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipherCodecAttach: calling sqlcipher_sqlite3BtreeSetAutoVacuum()");
+ sqlcipher_sqlite3BtreeSetAutoVacuum(pDb->pBt, SQLITE_DEFAULT_AUTOVACUUM);
+ }
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipherCodecAttach: leaving database mutex %p", db->mutex);
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipherCodecAttach: left database mutex %p", db->mutex);
+ }
+ return SQLITE_OK;
+}
+
+int sqlcipher_find_db_index(sqlcipher_sqlite3 *db, const char *zDb) {
+ int db_index;
+ if(zDb == NULL){
+ return 0;
+ }
+ for(db_index = 0; db_index < db->nDb; db_index++) {
+ struct Db *pDb = &db->aDb[db_index];
+ if(strcmp(pDb->zDbSName, zDb) == 0) {
+ return db_index;
+ }
+ }
+ return 0;
+}
+
+SQLITE_API void sqlcipher_sqlite3_activate_see(const char* in) {
+ /* do nothing, security enhancements are always active */
+}
+
+SQLITE_API int sqlcipher_sqlite3_key(sqlcipher_sqlite3 *db, const void *pKey, int nKey) {
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_key: db=%p", db);
+ return sqlcipher_sqlite3_key_v2(db, "main", pKey, nKey);
+}
+
+SQLITE_API int sqlcipher_sqlite3_key_v2(sqlcipher_sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_key_v2: db=%p zDb=%s", db, zDb);
+ /* attach key if db and pKey are not null and nKey is > 0 */
+ if(db && pKey && nKey) {
+ int db_index = sqlcipher_find_db_index(db, zDb);
+ return sqlcipherCodecAttach(db, db_index, pKey, nKey);
+ }
+ sqlcipher_log(SQLCIPHER_LOG_WARN, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_key_v2: no key provided");
+ return SQLITE_ERROR;
+}
+
+SQLITE_API int sqlcipher_sqlite3_rekey(sqlcipher_sqlite3 *db, const void *pKey, int nKey) {
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_rekey: db=%p", db);
+ return sqlcipher_sqlite3_rekey_v2(db, "main", pKey, nKey);
+}
+
+/* sqlcipher_sqlite3_rekey_v2
+** Given a database, this will reencrypt the database using a new key.
+** There is only one possible modes of operation - to encrypt a database
+** that is already encrpyted. If the database is not already encrypted
+** this should do nothing
+** The proposed logic for this function follows:
+** 1. Determine if the database is already encryptped
+** 2. If there is NOT already a key present do nothing
+** 3. If there is a key present, re-encrypt the database with the new key
+*/
+SQLITE_API int sqlcipher_sqlite3_rekey_v2(sqlcipher_sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_rekey_v2: db=%p zDb=%s", db, zDb);
+ if(db && pKey && nKey) {
+ int db_index = sqlcipher_find_db_index(db, zDb);
+ struct Db *pDb = &db->aDb[db_index];
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_rekey_v2: database zDb=%p db_index:%d", zDb, db_index);
+ if(pDb->pBt) {
+ codec_ctx *ctx;
+ int rc, page_count;
+ Pgno pgno;
+ PgHdr *page;
+ Pager *pPager = pDb->pBt->pBt->pPager;
+
+ ctx = (codec_ctx*) sqlcipherPagerGetCodec(pDb->pBt->pBt->pPager);
+
+ if(ctx == NULL) {
+ /* there was no codec attached to this database, so this should do nothing! */
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_rekey_v2: no codec attached to db %s: rekey can't be used on an unencrypted database", zDb);
+ return SQLITE_MISUSE;
+ }
+
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_sqlite3_rekey_v2: entering database mutex %p", db->mutex);
+ sqlcipher_sqlite3_mutex_enter(db->mutex);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_sqlite3_rekey_v2: entered database mutex %p", db->mutex);
+
+ codec_set_pass_key(db, db_index, pKey, nKey, CIPHER_WRITE_CTX);
+
+ /* do stuff here to rewrite the database
+ ** 1. Create a transaction on the database
+ ** 2. Iterate through each page, reading it and then writing it.
+ ** 3. If that goes ok then commit and put ctx->rekey into ctx->key
+ ** note: don't deallocate rekey since it may be used in a subsequent iteration
+ */
+ rc = sqlcipher_sqlite3BtreeBeginTrans(pDb->pBt, 1, 0); /* begin write transaction */
+ sqlcipher_sqlite3PagerPagecount(pPager, &page_count);
+ for(pgno = 1; rc == SQLITE_OK && pgno <= (unsigned int)page_count; pgno++) { /* pgno's start at 1 see pager.c:pagerAcquire */
+ if(!sqlcipher_sqlite3pager_is_sj_pgno(pPager, pgno)) { /* skip this page (see pager.c:pagerAcquire for reasoning) */
+ rc = sqlcipher_sqlite3PagerGet(pPager, pgno, &page, 0);
+ if(rc == SQLITE_OK) { /* write page see pager_incr_changecounter for example */
+ rc = sqlcipher_sqlite3PagerWrite(page);
+ if(rc == SQLITE_OK) {
+ sqlcipher_sqlite3PagerUnref(page);
+ } else {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_rekey_v2: error %d occurred writing page %d", rc, pgno);
+ }
+ } else {
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_rekey_v2: error %d occurred reading page %d", rc, pgno);
+ }
+ }
+ }
+
+ /* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */
+ if(rc == SQLITE_OK) {
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_rekey_v2: committing");
+ rc = sqlcipher_sqlite3BtreeCommit(pDb->pBt);
+ sqlcipher_codec_key_copy(ctx, CIPHER_WRITE_CTX);
+ } else {
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_rekey_v2: rollback");
+ sqlcipher_sqlite3BtreeRollback(pDb->pBt, SQLITE_ABORT_ROLLBACK, 0);
+ }
+
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_sqlite3_rekey_v2: leaving database mutex %p", db->mutex);
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_sqlite3_rekey_v2: left database mutex %p", db->mutex);
+ }
+ return SQLITE_OK;
+ }
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_CORE, "sqlcipher_sqlite3_rekey_v2: no key provided for db %s: rekey can't be used to decrypt an encrypted database", zDb);
+ return SQLITE_ERROR;
+}
+
+void sqlcipherCodecGetKey(sqlcipher_sqlite3* db, int nDb, void **zKey, int *nKey) {
+ struct Db *pDb = &db->aDb[nDb];
+ sqlcipher_log(SQLCIPHER_LOG_DEBUG, SQLCIPHER_LOG_CORE, "sqlcipherCodecGetKey:db=%p, nDb=%d", db, nDb);
+ if( pDb->pBt ) {
+ codec_ctx *ctx = (codec_ctx*) sqlcipherPagerGetCodec(pDb->pBt->pBt->pPager);
+
+ if(ctx) {
+ /* pass back the keyspec from the codec, unless PRAGMA cipher_store_pass
+ is set or keyspec has not yet been derived, in which case pass
+ back the password key material */
+ *zKey = ctx->read_ctx->keyspec;
+ *nKey = ctx->keyspec_sz;
+ if(ctx->store_pass == 1 || *zKey == NULL) {
+ *zKey = ctx->read_ctx->pass;
+ *nKey = ctx->read_ctx->pass_sz;
+ }
+ } else {
+ *zKey = NULL;
+ *nKey = 0;
+ }
+ }
+}
+
+/*
+ * Implementation of an "export" function that allows a caller
+ * to duplicate the main database to an attached database. This is intended
+ * as a conveneince for users who need to:
+ *
+ * 1. migrate from an non-encrypted database to an encrypted database
+ * 2. move from an encrypted database to a non-encrypted database
+ * 3. convert beween the various flavors of encrypted databases.
+ *
+ * This implementation is based heavily on the procedure and code used
+ * in vacuum.c, but is exposed as a function that allows export to any
+ * named attached database.
+ */
+
+/*
+** Finalize a prepared statement. If there was an error, store the
+** text of the error message in *pzErrMsg. Return the result code.
+**
+** Based on vacuumFinalize from vacuum.c
+*/
+static int sqlcipher_finalize(sqlcipher_sqlite3 *db, sqlcipher_sqlite3_stmt *pStmt, char **pzErrMsg){
+ int rc;
+ rc = sqlcipher_sqlite3VdbeFinalize((Vdbe*)pStmt);
+ if( rc ){
+ sqlcipher_sqlite3SetString(pzErrMsg, db, sqlcipher_sqlite3_errmsg(db));
+ }
+ return rc;
+}
+
+/*
+** Execute zSql on database db. Return an error code.
+**
+** Based on execSql from vacuum.c
+*/
+static int sqlcipher_execSql(sqlcipher_sqlite3 *db, char **pzErrMsg, const char *zSql){
+ sqlcipher_sqlite3_stmt *pStmt;
+ VVA_ONLY( int rc; )
+ if( !zSql ){
+ return SQLITE_NOMEM;
+ }
+ if( SQLITE_OK!=sqlcipher_sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
+ sqlcipher_sqlite3SetString(pzErrMsg, db, sqlcipher_sqlite3_errmsg(db));
+ return sqlcipher_sqlite3_errcode(db);
+ }
+ VVA_ONLY( rc = ) sqlcipher_sqlite3_step(pStmt);
+ assert( rc!=SQLITE_ROW );
+ return sqlcipher_finalize(db, pStmt, pzErrMsg);
+}
+
+/*
+** Execute zSql on database db. The statement returns exactly
+** one column. Execute this as SQL on the same database.
+**
+** Based on execExecSql from vacuum.c
+*/
+static int sqlcipher_execExecSql(sqlcipher_sqlite3 *db, char **pzErrMsg, const char *zSql){
+ sqlcipher_sqlite3_stmt *pStmt;
+ int rc;
+
+ rc = sqlcipher_sqlite3_prepare(db, zSql, -1, &pStmt, 0);
+ if( rc!=SQLITE_OK ) return rc;
+
+ while( SQLITE_ROW==sqlcipher_sqlite3_step(pStmt) ){
+ rc = sqlcipher_execSql(db, pzErrMsg, (char*)sqlcipher_sqlite3_column_text(pStmt, 0));
+ if( rc!=SQLITE_OK ){
+ sqlcipher_finalize(db, pStmt, pzErrMsg);
+ return rc;
+ }
+ }
+
+ return sqlcipher_finalize(db, pStmt, pzErrMsg);
+}
+
+/*
+ * copy database and schema from the main database to an attached database
+ *
+ * Based on sqlcipher_sqlite3RunVacuum from vacuum.c
+*/
+void sqlcipher_exportFunc(sqlcipher_sqlite3_context *context, int argc, sqlcipher_sqlite3_value **argv) {
+ sqlcipher_sqlite3 *db = sqlcipher_sqlite3_context_db_handle(context);
+ const char* targetDb, *sourceDb;
+ int targetDb_idx = 0;
+ u64 saved_flags = db->flags; /* Saved value of the db->flags */
+ u32 saved_mDbFlags = db->mDbFlags; /* Saved value of the db->mDbFlags */
+ int saved_nChange = db->nChange; /* Saved value of db->nChange */
+ int saved_nTotalChange = db->nTotalChange; /* Saved value of db->nTotalChange */
+ u8 saved_mTrace = db->mTrace; /* Saved value of db->mTrace */
+ int rc = SQLITE_OK; /* Return code from service routines */
+ char *zSql = NULL; /* SQL statements */
+ char *pzErrMsg = NULL;
+
+ if(argc != 1 && argc != 2) {
+ rc = SQLITE_ERROR;
+ pzErrMsg = sqlcipher_sqlite3_mprintf("invalid number of arguments (%d) passed to sqlcipher_export", argc);
+ goto end_of_export;
+ }
+
+ if(sqlcipher_sqlite3_value_type(argv[0]) == SQLITE_NULL) {
+ rc = SQLITE_ERROR;
+ pzErrMsg = sqlcipher_sqlite3_mprintf("target database can't be NULL");
+ goto end_of_export;
+ }
+
+ targetDb = (const char*) sqlcipher_sqlite3_value_text(argv[0]);
+ sourceDb = "main";
+
+ if(argc == 2) {
+ if(sqlcipher_sqlite3_value_type(argv[1]) == SQLITE_NULL) {
+ rc = SQLITE_ERROR;
+ pzErrMsg = sqlcipher_sqlite3_mprintf("target database can't be NULL");
+ goto end_of_export;
+ }
+ sourceDb = (char *) sqlcipher_sqlite3_value_text(argv[1]);
+ }
+
+
+ /* if the name of the target is not main, but the index returned is zero
+ there is a mismatch and we should not proceed */
+ targetDb_idx = sqlcipher_find_db_index(db, targetDb);
+ if(targetDb_idx == 0 && targetDb != NULL && sqlcipher_sqlite3_stricmp("main", targetDb) != 0) {
+ rc = SQLITE_ERROR;
+ pzErrMsg = sqlcipher_sqlite3_mprintf("unknown database %s", targetDb);
+ goto end_of_export;
+ }
+ db->init.iDb = targetDb_idx;
+
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
+ db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
+ db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_Defensive | SQLITE_CountRows);
+ db->mTrace = 0;
+
+ /* Query the schema of the main database. Create a mirror schema
+ ** in the temporary database.
+ */
+ zSql = sqlcipher_sqlite3_mprintf(
+ "SELECT sql "
+ " FROM %s.sqlite_schema WHERE type='table' AND name!='sqlite_sequence'"
+ " AND rootpage>0"
+ , sourceDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlcipher_sqlite3_free(zSql);
+
+ zSql = sqlcipher_sqlite3_mprintf(
+ "SELECT sql "
+ " FROM %s.sqlite_schema WHERE sql LIKE 'CREATE INDEX %%' "
+ , sourceDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlcipher_sqlite3_free(zSql);
+
+ zSql = sqlcipher_sqlite3_mprintf(
+ "SELECT sql "
+ " FROM %s.sqlite_schema WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
+ , sourceDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlcipher_sqlite3_free(zSql);
+
+ /* Loop through the tables in the main database. For each, do
+ ** an "INSERT INTO rekey_db.xxx SELECT * FROM main.xxx;" to copy
+ ** the contents to the temporary database.
+ */
+ zSql = sqlcipher_sqlite3_mprintf(
+ "SELECT 'INSERT INTO %s.' || quote(name) "
+ "|| ' SELECT * FROM %s.' || quote(name) || ';'"
+ "FROM %s.sqlite_schema "
+ "WHERE type = 'table' AND name!='sqlite_sequence' "
+ " AND rootpage>0"
+ , targetDb, sourceDb, sourceDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlcipher_sqlite3_free(zSql);
+
+ /* Copy over the contents of the sequence table
+ */
+ zSql = sqlcipher_sqlite3_mprintf(
+ "SELECT 'INSERT INTO %s.' || quote(name) "
+ "|| ' SELECT * FROM %s.' || quote(name) || ';' "
+ "FROM %s.sqlite_schema WHERE name=='sqlite_sequence';"
+ , targetDb, sourceDb, targetDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlcipher_sqlite3_free(zSql);
+
+ /* Copy the triggers, views, and virtual tables from the main database
+ ** over to the temporary database. None of these objects has any
+ ** associated storage, so all we have to do is copy their entries
+ ** from the SQLITE_MASTER table.
+ */
+ zSql = sqlcipher_sqlite3_mprintf(
+ "INSERT INTO %s.sqlite_schema "
+ " SELECT type, name, tbl_name, rootpage, sql"
+ " FROM %s.sqlite_schema"
+ " WHERE type='view' OR type='trigger'"
+ " OR (type='table' AND rootpage=0)"
+ , targetDb, sourceDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlcipher_sqlite3_free(zSql);
+
+ zSql = NULL;
+end_of_export:
+ db->init.iDb = 0;
+ db->flags = saved_flags;
+ db->mDbFlags = saved_mDbFlags;
+ db->nChange = saved_nChange;
+ db->nTotalChange = saved_nTotalChange;
+ db->mTrace = saved_mTrace;
+
+ if(zSql) sqlcipher_sqlite3_free(zSql);
+
+ if(rc) {
+ if(pzErrMsg != NULL) {
+ sqlcipher_sqlite3_result_error(context, pzErrMsg, -1);
+ sqlcipher_sqlite3DbFree(db, pzErrMsg);
+ } else {
+ sqlcipher_sqlite3_result_error(context, sqlcipher_sqlite3ErrStr(rc), -1);
+ }
+ }
+}
#endif
/* END SQLCIPHER */
-/************** End of crypto_impl.c *****************************************/
+/************** End of sqlcipher.c *******************************************/
/************** Begin file crypto_libtomcrypt.c ******************************/
/*
** SQLCipher
@@ -105191,9 +110278,9 @@ static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) {
int block_sz = data_to_read < FORTUNA_MAX_SZ ? data_to_read : FORTUNA_MAX_SZ;
const unsigned char * data = (const unsigned char *)buffer;
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_add_random: entering SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_add_random: entering SQLCIPHER_MUTEX_PROVIDER_RAND");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_RAND));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_add_random: entered SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_add_random: entered SQLCIPHER_MUTEX_PROVIDER_RAND");
while(data_to_read > 0){
rc = fortuna_add_entropy(data, block_sz, &prng);
@@ -105207,9 +110294,9 @@ static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) {
}
fortuna_ready(&prng);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_add_random: leaving SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_add_random: leaving SQLCIPHER_MUTEX_PROVIDER_RAND");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_RAND));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_add_random: left SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_add_random: left SQLCIPHER_MUTEX_PROVIDER_RAND");
return rc;
}
@@ -105217,9 +110304,9 @@ static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) {
static int sqlcipher_ltc_activate(void *ctx) {
unsigned char random_buffer[FORTUNA_MAX_SZ];
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_activate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_activate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_activate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_activate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_memset(random_buffer, 0, FORTUNA_MAX_SZ);
if(ltc_init == 0) {
@@ -105245,17 +110332,17 @@ static int sqlcipher_ltc_activate(void *ctx) {
}
sqlcipher_memset(random_buffer, 0, FORTUNA_MAX_SZ);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_activate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_activate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_activate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_activate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
return SQLITE_OK;
}
static int sqlcipher_ltc_deactivate(void *ctx) {
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_deactivate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_deactivate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_deactivate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_deactivate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
ltc_ref_count--;
if(ltc_ref_count == 0){
@@ -105263,9 +110350,9 @@ static int sqlcipher_ltc_deactivate(void *ctx) {
sqlcipher_memset((void *)&prng, 0, sizeof(prng));
}
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_deactivate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_deactivate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_deactivate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_deactivate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
return SQLITE_OK;
}
@@ -105279,15 +110366,15 @@ static const char* sqlcipher_ltc_get_provider_version(void *ctx) {
}
static int sqlcipher_ltc_random(void *ctx, void *buffer, int length) {
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_random: entering SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_random: entering SQLCIPHER_MUTEX_PROVIDER_RAND");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_RAND));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_random: entered SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_random: entered SQLCIPHER_MUTEX_PROVIDER_RAND");
fortuna_read(buffer, length, &prng);
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_random: leaving SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_random: leaving SQLCIPHER_MUTEX_PROVIDER_RAND");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_RAND));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_ltc_random: left SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_ltc_random: left SQLCIPHER_MUTEX_PROVIDER_RAND");
return SQLITE_OK;
}
@@ -105473,7 +110560,6 @@ int sqlcipher_ltc_setup(sqlcipher_provider *p) {
/* BEGIN SQLCIPHER */
#ifdef SQLITE_HAS_CODEC
#ifdef SQLCIPHER_CRYPTO_NSS
-/* #include "crypto.h" */
/* #include "sqlcipher.h" */
#include <nss/blapit.h>
#include <nss/nss.h>
@@ -105486,25 +110572,25 @@ int sqlcipher_nss_setup(sqlcipher_provider *p);
static int sqlcipher_nss_activate(void *ctx) {
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_nss_activate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_nss_activate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_nss_activate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_nss_activate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
if (nss_init_context == NULL) {
nss_init_context = NSS_InitContext("", "", "", "", NULL,
NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB |
NSS_INIT_FORCEOPEN | NSS_INIT_OPTIMIZESPACE | NSS_INIT_NOROOTINIT);
}
nss_init_count++;
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_nss_activate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_nss_activate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_nss_activate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_nss_activate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
return SQLITE_OK;
}
static int sqlcipher_nss_deactivate(void *ctx) {
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_nss_activate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_nss_activate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_nss_activate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_nss_activate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
nss_init_count--;
if (nss_init_count == 0 && nss_init_context != NULL) {
@@ -105512,9 +110598,9 @@ static int sqlcipher_nss_deactivate(void *ctx) {
nss_init_context = NULL;
}
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_nss_activate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_nss_activate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_nss_activate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_nss_activate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
return SQLITE_OK;
}
@@ -105783,21 +110869,20 @@ int sqlcipher_nss_setup(sqlcipher_provider *p) {
#ifdef SQLITE_HAS_CODEC
#ifdef SQLCIPHER_CRYPTO_OPENSSL
/* #include "sqliteInt.h" */
-/* #include "crypto.h" */
/* #include "sqlcipher.h" */
-#include <openssl/crypto.h>
-#include <openssl/rand.h>
-#include <openssl/evp.h>
-#include <openssl/objects.h>
-#include <openssl/hmac.h>
-#include <openssl/err.h>
+#include <openssl/crypto.h> /* amalgamator: dontcache */
+#include <openssl/rand.h> /* amalgamator: dontcache */
+#include <openssl/evp.h> /* amalgamator: dontcache */
+#include <openssl/objects.h> /* amalgamator: dontcache */
+#include <openssl/hmac.h> /* amalgamator: dontcache */
+#include <openssl/err.h> /* amalgamator: dontcache */
static unsigned int openssl_init_count = 0;
static void sqlcipher_openssl_log_errors() {
unsigned long err = 0;
while((err = ERR_get_error()) != 0) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_log_errors: ERR_get_error() returned %lx: %s", err, ERR_error_string(err, NULL));
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_log_errors: ERR_get_error() returned %lx: %s", err, ERR_error_string(err, NULL));
}
}
@@ -105826,15 +110911,15 @@ static void HMAC_CTX_free(HMAC_CTX *ctx)
static int sqlcipher_openssl_add_random(void *ctx, void *buffer, int length) {
#ifndef SQLCIPHER_OPENSSL_NO_MUTEX_RAND
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_add_random: entering SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_add_random: entering SQLCIPHER_MUTEX_PROVIDER_RAND");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_RAND));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_add_random: entered SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_add_random: entered SQLCIPHER_MUTEX_PROVIDER_RAND");
#endif
RAND_add(buffer, length, 0);
#ifndef SQLCIPHER_OPENSSL_NO_MUTEX_RAND
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_add_random: leaving SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_add_random: leaving SQLCIPHER_MUTEX_PROVIDER_RAND");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_RAND));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_add_random: left SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_add_random: left SQLCIPHER_MUTEX_PROVIDER_RAND");
#endif
return SQLITE_OK;
}
@@ -105853,9 +110938,9 @@ static int sqlcipher_openssl_activate(void *ctx) {
e.g. on startup */
int rc = 0;
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_activate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_activate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_activate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_activate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
#if (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L)
ERR_load_crypto_strings();
@@ -105864,16 +110949,16 @@ static int sqlcipher_openssl_activate(void *ctx) {
#ifdef SQLCIPHER_FIPS
if(!FIPS_mode()){
if(!(rc = FIPS_mode_set(1))){
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_activate: FIPS_mode_set() returned %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_activate: FIPS_mode_set() returned %d", rc);
sqlcipher_openssl_log_errors();
}
}
#endif
openssl_init_count++;
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_activate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_activate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_activate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_activate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
return SQLITE_OK;
}
@@ -105881,15 +110966,15 @@ static int sqlcipher_openssl_activate(void *ctx) {
freeing the EVP structures on the final deactivation to ensure that
OpenSSL memory is cleaned up */
static int sqlcipher_openssl_deactivate(void *ctx) {
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_deactivate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_deactivate: entering SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_deactivate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_deactivate: entered SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
openssl_init_count--;
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_deactivate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_deactivate: leaving SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_ACTIVATE));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_deactivate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_deactivate: left SQLCIPHER_MUTEX_PROVIDER_ACTIVATE");
return SQLITE_OK;
}
@@ -105898,7 +110983,11 @@ static const char* sqlcipher_openssl_get_provider_name(void *ctx) {
}
static const char* sqlcipher_openssl_get_provider_version(void *ctx) {
+#if (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L)
return OPENSSL_VERSION_TEXT;
+#else
+ return OpenSSL_version(OPENSSL_VERSION);
+#endif
}
/* generate a defined number of random bytes */
@@ -105911,18 +111000,18 @@ static int sqlcipher_openssl_random (void *ctx, void *buffer, int length) {
but a more proper solution is that applications setup platform-appropriate
thread saftey in openssl externally */
#ifndef SQLCIPHER_OPENSSL_NO_MUTEX_RAND
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_random: entering SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_random: entering SQLCIPHER_MUTEX_PROVIDER_RAND");
sqlcipher_sqlite3_mutex_enter(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_RAND));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_random: entered SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_random: entered SQLCIPHER_MUTEX_PROVIDER_RAND");
#endif
rc = RAND_bytes((unsigned char *)buffer, length);
#ifndef SQLCIPHER_OPENSSL_NO_MUTEX_RAND
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_random: leaving SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_random: leaving SQLCIPHER_MUTEX_PROVIDER_RAND");
sqlcipher_sqlite3_mutex_leave(sqlcipher_mutex(SQLCIPHER_MUTEX_PROVIDER_RAND));
- sqlcipher_log(SQLCIPHER_LOG_TRACE, "sqlcipher_openssl_random: left SQLCIPHER_MUTEX_PROVIDER_RAND");
+ sqlcipher_log(SQLCIPHER_LOG_TRACE, SQLCIPHER_LOG_MUTEX, "sqlcipher_openssl_random: left SQLCIPHER_MUTEX_PROVIDER_RAND");
#endif
if(!rc) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_random: RAND_bytes() returned %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_random: RAND_bytes() returned %d", rc);
sqlcipher_openssl_log_errors();
return SQLITE_ERROR;
}
@@ -105940,7 +111029,7 @@ static int sqlcipher_openssl_hmac(void *ctx, int algorithm, unsigned char *hmac_
hctx = HMAC_CTX_new();
if(hctx == NULL) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: HMAC_CTX_new() failed");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: HMAC_CTX_new() failed");
sqlcipher_openssl_log_errors();
goto error;
}
@@ -105948,46 +111037,46 @@ static int sqlcipher_openssl_hmac(void *ctx, int algorithm, unsigned char *hmac_
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
if(!(rc = HMAC_Init_ex(hctx, hmac_key, key_sz, EVP_sha1(), NULL))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: HMAC_Init_ex() with key size %d and EVP_sha1() returned %d", key_sz, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: HMAC_Init_ex() with key size %d and EVP_sha1() returned %d", key_sz, rc);
sqlcipher_openssl_log_errors();
goto error;
}
break;
case SQLCIPHER_HMAC_SHA256:
if(!(rc = HMAC_Init_ex(hctx, hmac_key, key_sz, EVP_sha256(), NULL))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: HMAC_Init_ex() with key size %d and EVP_sha256() returned %d", key_sz, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: HMAC_Init_ex() with key size %d and EVP_sha256() returned %d", key_sz, rc);
sqlcipher_openssl_log_errors();
goto error;
}
break;
case SQLCIPHER_HMAC_SHA512:
if(!(rc = HMAC_Init_ex(hctx, hmac_key, key_sz, EVP_sha512(), NULL))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: HMAC_Init_ex() with key size %d and EVP_sha512() returned %d", key_sz, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: HMAC_Init_ex() with key size %d and EVP_sha512() returned %d", key_sz, rc);
sqlcipher_openssl_log_errors();
goto error;
}
break;
default:
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: invalid algorithm %d", algorithm);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: invalid algorithm %d", algorithm);
goto error;
}
if(!(rc = HMAC_Update(hctx, in, in_sz))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: HMAC_Update() on 1st input buffer of %d bytes using algorithm %d returned %d", in_sz, algorithm, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: HMAC_Update() on 1st input buffer of %d bytes using algorithm %d returned %d", in_sz, algorithm, rc);
sqlcipher_openssl_log_errors();
goto error;
}
if(in2 != NULL) {
if(!(rc = HMAC_Update(hctx, in2, in2_sz))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: HMAC_Update() on 2nd input buffer of %d bytes using algorithm %d returned %d", in2_sz, algorithm, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: HMAC_Update() on 2nd input buffer of %d bytes using algorithm %d returned %d", in2_sz, algorithm, rc);
sqlcipher_openssl_log_errors();
goto error;
}
}
if(!(rc = HMAC_Final(hctx, out, &outlen))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: HMAC_Final() using algorithm %d returned %d", algorithm, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: HMAC_Final() using algorithm %d returned %d", algorithm, rc);
sqlcipher_openssl_log_errors();
goto error;
}
@@ -106013,14 +111102,14 @@ cleanup:
mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
if(mac == NULL) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: EVP_MAC_fetch for HMAC failed");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: EVP_MAC_fetch for HMAC failed");
sqlcipher_openssl_log_errors();
goto error;
}
hctx = EVP_MAC_CTX_new(mac);
if(hctx == NULL) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: EVP_MAC_CTX_new() failed");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: EVP_MAC_CTX_new() failed");
sqlcipher_openssl_log_errors();
goto error;
}
@@ -106028,52 +111117,52 @@ cleanup:
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
if(!(rc = EVP_MAC_init(hctx, hmac_key, key_sz, sha1))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: EVP_MAC_init() with key size %d and sha1 returned %d", key_sz, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: EVP_MAC_init() with key size %d and sha1 returned %d", key_sz, rc);
sqlcipher_openssl_log_errors();
goto error;
}
break;
case SQLCIPHER_HMAC_SHA256:
if(!(rc = EVP_MAC_init(hctx, hmac_key, key_sz, sha256))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: EVP_MAC_init() with key size %d and sha256 returned %d", key_sz, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: EVP_MAC_init() with key size %d and sha256 returned %d", key_sz, rc);
sqlcipher_openssl_log_errors();
goto error;
}
break;
case SQLCIPHER_HMAC_SHA512:
if(!(rc = EVP_MAC_init(hctx, hmac_key, key_sz, sha512))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: EVP_MAC_init() with key size %d and sha512 returned %d", key_sz, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: EVP_MAC_init() with key size %d and sha512 returned %d", key_sz, rc);
sqlcipher_openssl_log_errors();
goto error;
}
break;
default:
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: invalid algorithm %d", algorithm);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: invalid algorithm %d", algorithm);
goto error;
}
if(!(rc = EVP_MAC_update(hctx, in, in_sz))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: EVP_MAC_update() on 1st input buffer of %d bytes using algorithm %d returned %d", in_sz, algorithm, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: EVP_MAC_update() on 1st input buffer of %d bytes using algorithm %d returned %d", in_sz, algorithm, rc);
sqlcipher_openssl_log_errors();
goto error;
}
if(in2 != NULL) {
if(!(rc = EVP_MAC_update(hctx, in2, in2_sz))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: EVP_MAC_update() on 2nd input buffer of %d bytes using algorithm %d returned %d", in_sz, algorithm, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: EVP_MAC_update() on 2nd input buffer of %d bytes using algorithm %d returned %d", in_sz, algorithm, rc);
sqlcipher_openssl_log_errors();
goto error;
}
}
if(!(rc = EVP_MAC_final(hctx, NULL, &outlen, 0))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: 1st EVP_MAC_final() for output length calculation using algorithm %d returned %d", algorithm, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: 1st EVP_MAC_final() for output length calculation using algorithm %d returned %d", algorithm, rc);
sqlcipher_openssl_log_errors();
goto error;
}
if(!(rc = EVP_MAC_final(hctx, out, &outlen, outlen))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_hmac: 2nd EVP_MAC_final() using algorithm %d returned %d", algorithm, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_hmac: 2nd EVP_MAC_final() using algorithm %d returned %d", algorithm, rc);
sqlcipher_openssl_log_errors();
goto error;
}
@@ -106099,21 +111188,21 @@ static int sqlcipher_openssl_kdf(void *ctx, int algorithm, const unsigned char *
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
if(!(rc = PKCS5_PBKDF2_HMAC((const char *)pass, pass_sz, salt, salt_sz, workfactor, EVP_sha1(), key_sz, key))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_kdf: PKCS5_PBKDF2_HMAC() for EVP_sha1() workfactor %d and key size %d returned %d", workfactor, key_sz, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_kdf: PKCS5_PBKDF2_HMAC() for EVP_sha1() workfactor %d and key size %d returned %d", workfactor, key_sz, rc);
sqlcipher_openssl_log_errors();
goto error;
}
break;
case SQLCIPHER_HMAC_SHA256:
if(!(rc = PKCS5_PBKDF2_HMAC((const char *)pass, pass_sz, salt, salt_sz, workfactor, EVP_sha256(), key_sz, key))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_kdf: PKCS5_PBKDF2_HMAC() for EVP_sha256() workfactor %d and key size %d returned %d", workfactor, key_sz, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_kdf: PKCS5_PBKDF2_HMAC() for EVP_sha256() workfactor %d and key size %d returned %d", workfactor, key_sz, rc);
sqlcipher_openssl_log_errors();
goto error;
}
break;
case SQLCIPHER_HMAC_SHA512:
if(!(rc = PKCS5_PBKDF2_HMAC((const char *)pass, pass_sz, salt, salt_sz, workfactor, EVP_sha512(), key_sz, key))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_kdf: PKCS5_PBKDF2_HMAC() for EVP_sha512() workfactor %d and key size %d returned %d", workfactor, key_sz, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_kdf: PKCS5_PBKDF2_HMAC() for EVP_sha512() workfactor %d and key size %d returned %d", workfactor, key_sz, rc);
sqlcipher_openssl_log_errors();
goto error;
}
@@ -106134,31 +111223,31 @@ static int sqlcipher_openssl_cipher(void *ctx, int mode, unsigned char *key, int
int tmp_csz, csz, rc = 0;
EVP_CIPHER_CTX* ectx = EVP_CIPHER_CTX_new();
if(ectx == NULL) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_cipher: EVP_CIPHER_CTX_new failed");
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_cipher: EVP_CIPHER_CTX_new failed");
sqlcipher_openssl_log_errors();
goto error;
}
if(!(rc = EVP_CipherInit_ex(ectx, OPENSSL_CIPHER, NULL, NULL, NULL, mode))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_cipher: EVP_CipherInit_ex for mode %d returned %d", mode, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_cipher: EVP_CipherInit_ex for mode %d returned %d", mode, rc);
sqlcipher_openssl_log_errors();
goto error;
}
if(!(rc = EVP_CIPHER_CTX_set_padding(ectx, 0))) { /* no padding */
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_cipher: EVP_CIPHER_CTX_set_padding 0 returned %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_cipher: EVP_CIPHER_CTX_set_padding 0 returned %d", rc);
sqlcipher_openssl_log_errors();
goto error;
}
if(!(rc = EVP_CipherInit_ex(ectx, NULL, NULL, key, iv, mode))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_cipher: EVP_CipherInit_ex for mode %d returned %d", mode, rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_cipher: EVP_CipherInit_ex for mode %d returned %d", mode, rc);
sqlcipher_openssl_log_errors();
goto error;
}
if(!(rc = EVP_CipherUpdate(ectx, out, &tmp_csz, in, in_sz))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_cipher: EVP_CipherUpdate returned %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_cipher: EVP_CipherUpdate returned %d", rc);
sqlcipher_openssl_log_errors();
goto error;
}
@@ -106166,7 +111255,7 @@ static int sqlcipher_openssl_cipher(void *ctx, int mode, unsigned char *key, int
csz = tmp_csz;
out += tmp_csz;
if(!(rc = EVP_CipherFinal_ex(ectx, out, &tmp_csz))) {
- sqlcipher_log(SQLCIPHER_LOG_ERROR, "sqlcipher_openssl_cipher: EVP_CipherFinal_ex returned %d", rc);
+ sqlcipher_log(SQLCIPHER_LOG_ERROR, SQLCIPHER_LOG_PROVIDER, "sqlcipher_openssl_cipher: EVP_CipherFinal_ex returned %d", rc);
sqlcipher_openssl_log_errors();
goto error;
}
@@ -106291,7 +111380,6 @@ int sqlcipher_openssl_setup(sqlcipher_provider *p) {
/* BEGIN SQLCIPHER */
#ifdef SQLITE_HAS_CODEC
#ifdef SQLCIPHER_CRYPTO_CC
-/* #include "crypto.h" */
/* #include "sqlcipher.h" */
#include <CommonCrypto/CommonCrypto.h>
#include <Security/SecRandom.h>
@@ -106514,7 +111602,7 @@ static int walkWindowList(Walker *pWalker, Window *pList, int bOneOnly){
** The return value from this routine is WRC_Abort to abandon the tree walk
** and WRC_Continue to continue.
*/
-static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
+SQLITE_PRIVATE SQLITE_NOINLINE int sqlcipher_sqlite3WalkExprNN(Walker *pWalker, Expr *pExpr){
int rc;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
@@ -106523,7 +111611,9 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
if( rc ) return rc & WRC_Abort;
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
assert( pExpr->x.pList==0 || pExpr->pRight==0 );
- if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
+ if( pExpr->pLeft && sqlcipher_sqlite3WalkExprNN(pWalker, pExpr->pLeft) ){
+ return WRC_Abort;
+ }
if( pExpr->pRight ){
assert( !ExprHasProperty(pExpr, EP_WinFunc) );
pExpr = pExpr->pRight;
@@ -106547,7 +111637,7 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
SQLITE_PRIVATE int sqlcipher_sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
- return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;
+ return pExpr ? sqlcipher_sqlite3WalkExprNN(pWalker,pExpr) : WRC_Continue;
}
/*
@@ -106673,7 +111763,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WalkSelect(Walker *pWalker, Select *p){
}
/* Increase the walkerDepth when entering a subquery, and
-** descrease when leaving the subquery.
+** decrease when leaving the subquery.
*/
SQLITE_PRIVATE int sqlcipher_sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){
UNUSED_PARAMETER(pSelect);
@@ -106792,6 +111882,8 @@ static void resolveAlias(
assert( iCol>=0 && iCol<pEList->nExpr );
pOrig = pEList->a[iCol].pExpr;
assert( pOrig!=0 );
+ assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) );
+ if( pExpr->pAggInfo ) return;
db = pParse->db;
pDup = sqlcipher_sqlite3ExprDup(db, pOrig, 0);
if( db->mallocFailed ){
@@ -106812,28 +111904,41 @@ static void resolveAlias(
pExpr->y.pWin->pOwner = pExpr;
}
}
- sqlcipher_sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlcipher_sqlite3*,void*))sqlcipher_sqlite3ExprDelete,
- pDup);
+ sqlcipher_sqlite3ExprDeferredDelete(pParse, pDup);
}
}
/*
-** Subqueries stores the original database, table and column names for their
-** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
-** Check to see if the zSpan given to this routine matches the zDb, zTab,
-** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
-** match anything.
+** Subqueries store the original database, table and column names for their
+** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN",
+** and mark the expression-list item by setting ExprList.a[].fg.eEName
+** to ENAME_TAB.
+**
+** Check to see if the zSpan/eEName of the expression-list item passed to this
+** routine matches the zDb, zTab, and zCol. If any of zDb, zTab, and zCol are
+** NULL then those fields will match anything. Return true if there is a match,
+** or false otherwise.
+**
+** SF_NestedFrom subqueries also store an entry for the implicit rowid (or
+** _rowid_, or oid) column by setting ExprList.a[].fg.eEName to ENAME_ROWID,
+** and setting zSpan to "DATABASE.TABLE.<rowid-alias>". This type of pItem
+** argument matches if zCol is a rowid alias. If it is not NULL, (*pbRowid)
+** is set to 1 if there is this kind of match.
*/
SQLITE_PRIVATE int sqlcipher_sqlite3MatchEName(
const struct ExprList_item *pItem,
const char *zCol,
const char *zTab,
- const char *zDb
+ const char *zDb,
+ int *pbRowid
){
int n;
const char *zSpan;
- if( pItem->fg.eEName!=ENAME_TAB ) return 0;
+ int eEName = pItem->fg.eEName;
+ if( eEName!=ENAME_TAB && (eEName!=ENAME_ROWID || NEVER(pbRowid==0)) ){
+ return 0;
+ }
+ assert( pbRowid==0 || *pbRowid==0 );
zSpan = pItem->zEName;
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
if( zDb && (sqlcipher_sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
@@ -106845,9 +111950,11 @@ SQLITE_PRIVATE int sqlcipher_sqlite3MatchEName(
return 0;
}
zSpan += n+1;
- if( zCol && sqlcipher_sqlite3StrICmp(zSpan, zCol)!=0 ){
- return 0;
+ if( zCol ){
+ if( eEName==ENAME_TAB && sqlcipher_sqlite3StrICmp(zSpan, zCol)!=0 ) return 0;
+ if( eEName==ENAME_ROWID && sqlcipher_sqlite3IsRowid(zCol)==0 ) return 0;
}
+ if( eEName==ENAME_ROWID ) *pbRowid = 1;
return 1;
}
@@ -106880,6 +111987,7 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3ExprColUsed(Expr *pExpr){
assert( ExprUseYTab(pExpr) );
pExTab = pExpr->y.pTab;
assert( pExTab!=0 );
+ assert( n < pExTab->nCol );
if( (pExTab->tabFlags & TF_HasGenerated)!=0
&& (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0
){
@@ -106918,6 +112026,32 @@ static void extendFJMatch(
}
/*
+** Return TRUE (non-zero) if zTab is a valid name for the schema table pTab.
+*/
+static SQLITE_NOINLINE int isValidSchemaTableName(
+ const char *zTab, /* Name as it appears in the SQL */
+ Table *pTab, /* The schema table we are trying to match */
+ const char *zDb /* non-NULL if a database qualifier is present */
+){
+ const char *zLegacy;
+ assert( pTab!=0 );
+ assert( pTab->tnum==1 );
+ if( sqlcipher_sqlite3StrNICmp(zTab, "sqlite_", 7)!=0 ) return 0;
+ zLegacy = pTab->zName;
+ if( strcmp(zLegacy+7, &LEGACY_TEMP_SCHEMA_TABLE[7])==0 ){
+ if( sqlcipher_sqlite3StrICmp(zTab+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){
+ return 1;
+ }
+ if( zDb==0 ) return 0;
+ if( sqlcipher_sqlite3StrICmp(zTab+7, &LEGACY_SCHEMA_TABLE[7])==0 ) return 1;
+ if( sqlcipher_sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1;
+ }else{
+ if( sqlcipher_sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1;
+ }
+ return 0;
+}
+
+/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
** that name in the set of source tables in pSrcList and make the pExpr
** expression node refer back to that source column. The following changes
@@ -106948,13 +112082,13 @@ static int lookupName(
Parse *pParse, /* The parsing context */
const char *zDb, /* Name of the database containing table, or NULL */
const char *zTab, /* Name of table containing column, or NULL */
- const char *zCol, /* Name of the column. */
+ const Expr *pRight, /* Name of the column. */
NameContext *pNC, /* The name context used to resolve the name */
Expr *pExpr /* Make this EXPR node point to the selected column */
){
int i, j; /* Loop counters */
int cnt = 0; /* Number of matching column names */
- int cntTab = 0; /* Number of matching table names */
+ int cntTab = 0; /* Number of potential "rowid" matches */
int nSubquery = 0; /* How many levels of subquery */
sqlcipher_sqlite3 *db = pParse->db; /* The database connection */
SrcItem *pItem; /* Use for looping over pSrcList items */
@@ -106965,6 +112099,7 @@ static int lookupName(
Table *pTab = 0; /* Table holding the row */
Column *pCol; /* A column of pTab */
ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */
+ const char *zCol = pRight->u.zToken;
assert( pNC ); /* the name context cannot be NULL. */
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
@@ -107031,54 +112166,66 @@ static int lookupName(
assert( pEList!=0 );
assert( pEList->nExpr==pTab->nCol );
for(j=0; j<pEList->nExpr; j++){
- if( !sqlcipher_sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
+ int bRowid = 0; /* True if possible rowid match */
+ if( !sqlcipher_sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){
continue;
}
- if( cnt>0 ){
- if( pItem->fg.isUsing==0
- || sqlcipher_sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
- ){
- /* Two or more tables have the same column name which is
- ** not joined by USING. This is an error. Signal as much
- ** by clearing pFJMatch and letting cnt go above 1. */
- sqlcipher_sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else
- if( (pItem->fg.jointype & JT_RIGHT)==0 ){
- /* An INNER or LEFT JOIN. Use the left-most table */
- continue;
- }else
- if( (pItem->fg.jointype & JT_LEFT)==0 ){
- /* A RIGHT JOIN. Use the right-most table */
- cnt = 0;
- sqlcipher_sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else{
- /* For a FULL JOIN, we must construct a coalesce() func */
- extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
+ if( bRowid==0 ){
+ if( cnt>0 ){
+ if( pItem->fg.isUsing==0
+ || sqlcipher_sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
+ ){
+ /* Two or more tables have the same column name which is
+ ** not joined by USING. This is an error. Signal as much
+ ** by clearing pFJMatch and letting cnt go above 1. */
+ sqlcipher_sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else
+ if( (pItem->fg.jointype & JT_RIGHT)==0 ){
+ /* An INNER or LEFT JOIN. Use the left-most table */
+ continue;
+ }else
+ if( (pItem->fg.jointype & JT_LEFT)==0 ){
+ /* A RIGHT JOIN. Use the right-most table */
+ cnt = 0;
+ sqlcipher_sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else{
+ /* For a FULL JOIN, we must construct a coalesce() func */
+ extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
+ }
}
+ cnt++;
+ hit = 1;
+ }else if( cnt>0 ){
+ /* This is a potential rowid match, but there has already been
+ ** a real match found. So this can be ignored. */
+ continue;
}
- cnt++;
- cntTab = 2;
+ cntTab++;
pMatch = pItem;
pExpr->iColumn = j;
pEList->a[j].fg.bUsed = 1;
- hit = 1;
+
+ /* rowid cannot be part of a USING clause - assert() this. */
+ assert( bRowid==0 || pEList->a[j].fg.bUsingTerm==0 );
if( pEList->a[j].fg.bUsingTerm ) break;
}
if( hit || zTab==0 ) continue;
}
assert( zDb==0 || zTab!=0 );
if( zTab ){
- const char *zTabName;
if( zDb ){
if( pTab->pSchema!=pSchema ) continue;
if( pSchema==0 && strcmp(zDb,"*")!=0 ) continue;
}
- zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
- assert( zTabName!=0 );
- if( sqlcipher_sqlite3StrICmp(zTabName, zTab)!=0 ){
- continue;
+ if( pItem->zAlias!=0 ){
+ if( sqlcipher_sqlite3StrICmp(zTab, pItem->zAlias)!=0 ){
+ continue;
+ }
+ }else if( sqlcipher_sqlite3StrICmp(zTab, pTab->zName)!=0 ){
+ if( pTab->tnum!=1 ) continue;
+ if( !isValidSchemaTableName(zTab, pTab, zDb) ) continue;
}
assert( ExprUseYTab(pExpr) );
if( IN_RENAME_OBJECT && pItem->zAlias ){
@@ -107125,8 +112272,37 @@ static int lookupName(
}
}
if( 0==cnt && VisibleRowid(pTab) ){
+ /* pTab is a potential ROWID match. Keep track of it and match
+ ** the ROWID later if that seems appropriate. (Search for "cntTab"
+ ** to find related code.) Only allow a ROWID match if there is
+ ** a single ROWID match candidate.
+ */
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ /* In SQLITE_ALLOW_ROWID_IN_VIEW mode, allow a ROWID match
+ ** if there is a single VIEW candidate or if there is a single
+ ** non-VIEW candidate plus multiple VIEW candidates. In other
+ ** words non-VIEW candidate terms take precedence over VIEWs.
+ */
+ if( cntTab==0
+ || (cntTab==1
+ && ALWAYS(pMatch!=0)
+ && ALWAYS(pMatch->pTab!=0)
+ && (pMatch->pTab->tabFlags & TF_Ephemeral)!=0
+ && (pTab->tabFlags & TF_Ephemeral)==0)
+ ){
+ cntTab = 1;
+ pMatch = pItem;
+ }else{
+ cntTab++;
+ }
+#else
+ /* The (much more common) non-SQLITE_ALLOW_ROWID_IN_VIEW case is
+ ** simpler since we require exactly one candidate, which will
+ ** always be a non-VIEW
+ */
cntTab++;
pMatch = pItem;
+#endif
}
}
if( pMatch ){
@@ -107154,7 +112330,9 @@ static int lookupName(
assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
if( pParse->bReturning ){
if( (pNC->ncFlags & NC_UBaseReg)!=0
- && (zTab==0 || sqlcipher_sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0)
+ && ALWAYS(zTab==0
+ || sqlcipher_sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0
+ || isValidSchemaTableName(zTab, pParse->pTriggerTab, 0))
){
pExpr->iTable = op!=TK_DELETE;
pTab = pParse->pTriggerTab;
@@ -107221,6 +112399,7 @@ static int lookupName(
if( pParse->bReturning ){
eNewExprOp = TK_REGISTER;
pExpr->op2 = TK_COLUMN;
+ pExpr->iColumn = iCol;
pExpr->iTable = pNC->uNC.iBaseReg + (pTab->nCol+1)*pExpr->iTable +
sqlcipher_sqlite3TableColumnToStorage(pTab, iCol) + 1;
}else{
@@ -107250,14 +112429,19 @@ static int lookupName(
** Perhaps the name is a reference to the ROWID
*/
if( cnt==0
- && cntTab==1
+ && cntTab>=1
&& pMatch
&& (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
&& sqlcipher_sqlite3IsRowid(zCol)
- && ALWAYS(VisibleRowid(pMatch->pTab))
+ && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom)
){
- cnt = 1;
- pExpr->iColumn = -1;
+ cnt = cntTab;
+#if SQLITE_ALLOW_ROWID_IN_VIEW+0==2
+ if( pMatch->pTab!=0 && IsView(pMatch->pTab) ){
+ eNewExprOp = TK_NULL;
+ }
+#endif
+ if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1;
pExpr->affExpr = SQLITE_AFF_INTEGER;
}
@@ -107410,12 +112594,17 @@ static int lookupName(
sqlcipher_sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol);
}else if( zTab ){
sqlcipher_sqlite3ErrorMsg(pParse, "%s: %s.%s", zErr, zTab, zCol);
+ }else if( cnt==0 && ExprHasProperty(pRight,EP_DblQuoted) ){
+ sqlcipher_sqlite3ErrorMsg(pParse, "%s: \"%s\" - should this be a"
+ " string literal in single-quotes?",
+ zErr, zCol);
}else{
sqlcipher_sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol);
}
sqlcipher_sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr);
pParse->checkSchema = 1;
pTopNC->nNcErr++;
+ eNewExprOp = TK_NULL;
}
assert( pFJMatch==0 );
@@ -107442,8 +112631,12 @@ static int lookupName(
** If a generated column is referenced, set bits for every column
** of the table.
*/
- if( pExpr->iColumn>=0 && pMatch!=0 ){
- pMatch->colUsed |= sqlcipher_sqlite3ExprColUsed(pExpr);
+ if( pMatch ){
+ if( pExpr->iColumn>=0 ){
+ pMatch->colUsed |= sqlcipher_sqlite3ExprColUsed(pExpr);
+ }else{
+ pMatch->fg.rowidUsed = 1;
+ }
}
pExpr->op = eNewExprOp;
@@ -107620,6 +112813,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
** resolved. This prevents "column" from being counted as having been
** referenced, which might prevent a SELECT from being erroneously
** marked as correlated.
+ **
+ ** 2024-03-28: Beware of aggregates. A bare column of aggregated table
+ ** can still evaluate to NULL even though it is marked as NOT NULL.
+ ** Example:
+ **
+ ** CREATE TABLE t1(a INT NOT NULL);
+ ** SELECT a, a IS NULL, a IS NOT NULL, count(*) FROM t1;
+ **
+ ** The "a IS NULL" and "a IS NOT NULL" expressions cannot be optimized
+ ** here because at the time this case is hit, we do not yet know whether
+ ** or not t1 is being aggregated. We have to assume the worst and omit
+ ** the optimization. The only time it is safe to apply this optimization
+ ** is within the WHERE clause.
*/
case TK_NOTNULL:
case TK_ISNULL: {
@@ -107630,23 +112836,36 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
anRef[i] = p->nRef;
}
sqlcipher_sqlite3WalkExpr(pWalker, pExpr->pLeft);
- if( 0==sqlcipher_sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){
- testcase( ExprHasProperty(pExpr, EP_OuterON) );
- assert( !ExprHasProperty(pExpr, EP_IntValue) );
- if( pExpr->op==TK_NOTNULL ){
- pExpr->u.zToken = "true";
- ExprSetProperty(pExpr, EP_IsTrue);
- }else{
- pExpr->u.zToken = "false";
- ExprSetProperty(pExpr, EP_IsFalse);
- }
- pExpr->op = TK_TRUEFALSE;
- for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
- p->nRef = anRef[i];
+ if( IN_RENAME_OBJECT ) return WRC_Prune;
+ if( sqlcipher_sqlite3ExprCanBeNull(pExpr->pLeft) ){
+ /* The expression can be NULL. So the optimization does not apply */
+ return WRC_Prune;
+ }
+
+ for(i=0, p=pNC; p; p=p->pNext, i++){
+ if( (p->ncFlags & NC_Where)==0 ){
+ return WRC_Prune; /* Not in a WHERE clause. Unsafe to optimize. */
}
- sqlcipher_sqlite3ExprDelete(pParse->db, pExpr->pLeft);
- pExpr->pLeft = 0;
}
+ testcase( ExprHasProperty(pExpr, EP_OuterON) );
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+#if TREETRACE_ENABLED
+ if( sqlcipher_sqlite3TreeTrace & 0x80000 ){
+ sqlcipher_sqlite3DebugPrintf(
+ "NOT NULL strength reduction converts the following to %d:\n",
+ pExpr->op==TK_NOTNULL
+ );
+ sqlcipher_sqlite3ShowExpr(pExpr);
+ }
+#endif /* TREETRACE_ENABLED */
+ pExpr->u.iValue = (pExpr->op==TK_NOTNULL);
+ pExpr->flags |= EP_IntValue;
+ pExpr->op = TK_INTEGER;
+ for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
+ p->nRef = anRef[i];
+ }
+ sqlcipher_sqlite3ExprDelete(pParse->db, pExpr->pLeft);
+ pExpr->pLeft = 0;
return WRC_Prune;
}
@@ -107660,7 +112879,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
*/
case TK_ID:
case TK_DOT: {
- const char *zColumn;
const char *zTable;
const char *zDb;
Expr *pRight;
@@ -107669,7 +112887,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
zDb = 0;
zTable = 0;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- zColumn = pExpr->u.zToken;
+ pRight = pExpr;
}else{
Expr *pLeft = pExpr->pLeft;
testcase( pNC->ncFlags & NC_IdxExpr );
@@ -107688,14 +112906,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
assert( ExprUseUToken(pLeft) && ExprUseUToken(pRight) );
zTable = pLeft->u.zToken;
- zColumn = pRight->u.zToken;
assert( ExprUseYTab(pExpr) );
if( IN_RENAME_OBJECT ){
sqlcipher_sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight);
sqlcipher_sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft);
}
}
- return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
+ return lookupName(pParse, zDb, zTable, pRight, pNC, pExpr);
}
/* Resolve function names
@@ -107714,6 +112931,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0);
#endif
assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
+ assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER );
zId = pExpr->u.zToken;
pDef = sqlcipher_sqlite3FindFunction(pParse->db, zId, n, enc, 0);
if( pDef==0 ){
@@ -107855,6 +113073,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pNC->nNcErr++;
}
#endif
+ else if( is_agg==0 && pExpr->pLeft ){
+ sqlcipher_sqlite3ExprOrderByAggregateError(pParse, pExpr);
+ pNC->nNcErr++;
+ }
if( is_agg ){
/* Window functions may not be arguments of aggregate functions.
** Or arguments of other window functions. But aggregate functions
@@ -107866,13 +113088,16 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
#endif
}
}
-#ifndef SQLITE_OMIT_WINDOWFUNC
- else if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ else if( ExprHasProperty(pExpr, EP_WinFunc) || pExpr->pLeft ){
is_agg = 1;
}
-#endif
sqlcipher_sqlite3WalkExprList(pWalker, pList);
if( is_agg ){
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ sqlcipher_sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList);
+ }
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pWin ){
Select *pSel = pNC->pWinSelect;
@@ -107901,11 +113126,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
while( pNC2
&& sqlcipher_sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0
){
- pExpr->op2++;
+ pExpr->op2 += (1 + pNC2->nNestedSelect);
pNC2 = pNC2->pNext;
}
assert( pDef!=0 || IN_RENAME_OBJECT );
if( pNC2 && pDef ){
+ pExpr->op2 += pNC2->nNestedSelect;
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg );
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
@@ -107934,6 +113160,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
testcase( pNC->ncFlags & NC_PartIdx );
testcase( pNC->ncFlags & NC_IdxExpr );
testcase( pNC->ncFlags & NC_GenCol );
+ assert( pExpr->x.pSelect );
if( pNC->ncFlags & NC_SelfRef ){
notValidImpl(pParse, pNC, "subqueries", pExpr, pExpr);
}else{
@@ -107942,8 +113169,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
- pNC->ncFlags |= NC_VarSelect;
+ pExpr->x.pSelect->selFlags |= SF_Correlated;
}
+ pNC->ncFlags |= NC_Subquery;
}
break;
}
@@ -108383,7 +113611,7 @@ static int resolveOrderGroupBy(
}
for(j=0; j<pSelect->pEList->nExpr; j++){
if( sqlcipher_sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
- /* Since this expresion is being changed into a reference
+ /* Since this expression is being changed into a reference
** to an identical expression in the result set, remove all Window
** objects belonging to the expression from the Select.pWin list. */
windowRemoveExprFromSelect(pSelect, pE);
@@ -108436,10 +113664,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
while( p ){
assert( (p->selFlags & SF_Expanded)!=0 );
assert( (p->selFlags & SF_Resolved)==0 );
- assert( db->suppressErr==0 ); /* SF_Resolved not set if errors suppressed */
p->selFlags |= SF_Resolved;
-
/* Resolve the expressions in the LIMIT and OFFSET clauses. These
** are not allowed to refer to any names, so pass an empty NameContext.
*/
@@ -108466,8 +113692,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
/* Recursively resolve names in all subqueries in the FROM clause
*/
+ if( pOuterNC ) pOuterNC->nNestedSelect++;
for(i=0; i<p->pSrc->nSrc; i++){
SrcItem *pItem = &p->pSrc->a[i];
+ assert( pItem->zName!=0 || pItem->pSelect!=0 );/* Test of tag-20240424-1*/
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
int nRef = pOuterNC ? pOuterNC->nRef : 0;
const char *zSavedContext = pParse->zAuthContext;
@@ -108490,6 +113718,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
}
}
+ if( pOuterNC && ALWAYS(pOuterNC->nNestedSelect>0) ){
+ pOuterNC->nNestedSelect--;
+ }
/* Set up the local name-context to pass to sqlcipher_sqlite3ResolveExprNames() to
** resolve the result-set expression list.
@@ -108533,7 +113764,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
if( sqlcipher_sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
}
+ sNC.ncFlags |= NC_Where;
if( sqlcipher_sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
+ sNC.ncFlags &= ~NC_Where;
/* Resolve names in table-valued-function arguments */
for(i=0; i<p->pSrc->nSrc; i++){
@@ -108706,7 +113939,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ResolveExprNames(
return SQLITE_ERROR;
}
#endif
- sqlcipher_sqlite3WalkExpr(&w, pExpr);
+ assert( pExpr!=0 );
+ sqlcipher_sqlite3WalkExprNN(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
w.pParse->nHeight -= pExpr->nHeight;
#endif
@@ -108723,6 +113957,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ResolveExprNames(
** Resolve all names for all expression in an expression list. This is
** just like sqlcipher_sqlite3ResolveExprNames() except that it works for an expression
** list rather than a single expression.
+**
+** The return value is SQLITE_OK (0) for success or SQLITE_ERROR (1) for a
+** failure.
*/
SQLITE_PRIVATE int sqlcipher_sqlite3ResolveExprListNames(
NameContext *pNC, /* Namespace to resolve expressions in. */
@@ -108731,7 +113968,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ResolveExprListNames(
int i;
int savedHasAgg = 0;
Walker w;
- if( pList==0 ) return WRC_Continue;
+ if( pList==0 ) return SQLITE_OK;
w.pParse = pNC->pParse;
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
@@ -108745,10 +113982,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ResolveExprListNames(
#if SQLITE_MAX_EXPR_DEPTH>0
w.pParse->nHeight += pExpr->nHeight;
if( sqlcipher_sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
- return WRC_Abort;
+ return SQLITE_ERROR;
}
#endif
- sqlcipher_sqlite3WalkExpr(&w, pExpr);
+ sqlcipher_sqlite3WalkExprNN(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
w.pParse->nHeight -= pExpr->nHeight;
#endif
@@ -108762,15 +113999,15 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ResolveExprListNames(
(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
}
- if( w.pParse->nErr>0 ) return WRC_Abort;
+ if( w.pParse->nErr>0 ) return SQLITE_ERROR;
}
pNC->ncFlags |= savedHasAgg;
- return WRC_Continue;
+ return SQLITE_OK;
}
/*
** Resolve all names in all expressions of a SELECT and in all
-** decendents of the SELECT, including compounds off of p->pPrior,
+** descendants of the SELECT, including compounds off of p->pPrior,
** subqueries in expressions, and subqueries used as FROM clause
** terms.
**
@@ -108897,50 +114134,123 @@ SQLITE_PRIVATE char sqlcipher_sqlite3TableColumnAffinity(const Table *pTab, int
*/
SQLITE_PRIVATE char sqlcipher_sqlite3ExprAffinity(const Expr *pExpr){
int op;
- while( ExprHasProperty(pExpr, EP_Skip|EP_IfNullRow) ){
- assert( pExpr->op==TK_COLLATE
- || pExpr->op==TK_IF_NULL_ROW
- || (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) );
- pExpr = pExpr->pLeft;
- assert( pExpr!=0 );
- }
op = pExpr->op;
- if( op==TK_REGISTER ) op = pExpr->op2;
- if( op==TK_COLUMN || op==TK_AGG_COLUMN ){
- assert( ExprUseYTab(pExpr) );
- if( pExpr->y.pTab ){
+ while( 1 /* exit-by-break */ ){
+ if( op==TK_COLUMN || (op==TK_AGG_COLUMN && pExpr->y.pTab!=0) ){
+ assert( ExprUseYTab(pExpr) );
+ assert( pExpr->y.pTab!=0 );
return sqlcipher_sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
}
- }
- if( op==TK_SELECT ){
- assert( ExprUseXSelect(pExpr) );
- assert( pExpr->x.pSelect!=0 );
- assert( pExpr->x.pSelect->pEList!=0 );
- assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 );
- return sqlcipher_sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
- }
+ if( op==TK_SELECT ){
+ assert( ExprUseXSelect(pExpr) );
+ assert( pExpr->x.pSelect!=0 );
+ assert( pExpr->x.pSelect->pEList!=0 );
+ assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 );
+ return sqlcipher_sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
+ }
#ifndef SQLITE_OMIT_CAST
- if( op==TK_CAST ){
- assert( !ExprHasProperty(pExpr, EP_IntValue) );
- return sqlcipher_sqlite3AffinityType(pExpr->u.zToken, 0);
- }
+ if( op==TK_CAST ){
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ return sqlcipher_sqlite3AffinityType(pExpr->u.zToken, 0);
+ }
#endif
- if( op==TK_SELECT_COLUMN ){
- assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) );
- assert( pExpr->iColumn < pExpr->iTable );
- assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr );
- return sqlcipher_sqlite3ExprAffinity(
- pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
- );
- }
- if( op==TK_VECTOR ){
- assert( ExprUseXList(pExpr) );
- return sqlcipher_sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr);
+ if( op==TK_SELECT_COLUMN ){
+ assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) );
+ assert( pExpr->iColumn < pExpr->iTable );
+ assert( pExpr->iColumn >= 0 );
+ assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr );
+ return sqlcipher_sqlite3ExprAffinity(
+ pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
+ );
+ }
+ if( op==TK_VECTOR ){
+ assert( ExprUseXList(pExpr) );
+ return sqlcipher_sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr);
+ }
+ if( ExprHasProperty(pExpr, EP_Skip|EP_IfNullRow) ){
+ assert( pExpr->op==TK_COLLATE
+ || pExpr->op==TK_IF_NULL_ROW
+ || (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) );
+ pExpr = pExpr->pLeft;
+ op = pExpr->op;
+ continue;
+ }
+ if( op!=TK_REGISTER || (op = pExpr->op2)==TK_REGISTER ) break;
}
return pExpr->affExpr;
}
/*
+** Make a guess at all the possible datatypes of the result that could
+** be returned by an expression. Return a bitmask indicating the answer:
+**
+** 0x01 Numeric
+** 0x02 Text
+** 0x04 Blob
+**
+** If the expression must return NULL, then 0x00 is returned.
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3ExprDataType(const Expr *pExpr){
+ while( pExpr ){
+ switch( pExpr->op ){
+ case TK_COLLATE:
+ case TK_IF_NULL_ROW:
+ case TK_UPLUS: {
+ pExpr = pExpr->pLeft;
+ break;
+ }
+ case TK_NULL: {
+ pExpr = 0;
+ break;
+ }
+ case TK_STRING: {
+ return 0x02;
+ }
+ case TK_BLOB: {
+ return 0x04;
+ }
+ case TK_CONCAT: {
+ return 0x06;
+ }
+ case TK_VARIABLE:
+ case TK_AGG_FUNCTION:
+ case TK_FUNCTION: {
+ return 0x07;
+ }
+ case TK_COLUMN:
+ case TK_AGG_COLUMN:
+ case TK_SELECT:
+ case TK_CAST:
+ case TK_SELECT_COLUMN:
+ case TK_VECTOR: {
+ int aff = sqlcipher_sqlite3ExprAffinity(pExpr);
+ if( aff>=SQLITE_AFF_NUMERIC ) return 0x05;
+ if( aff==SQLITE_AFF_TEXT ) return 0x06;
+ return 0x07;
+ }
+ case TK_CASE: {
+ int res = 0;
+ int ii;
+ ExprList *pList = pExpr->x.pList;
+ assert( ExprUseXList(pExpr) && pList!=0 );
+ assert( pList->nExpr > 0);
+ for(ii=1; ii<pList->nExpr; ii+=2){
+ res |= sqlcipher_sqlite3ExprDataType(pList->a[ii].pExpr);
+ }
+ if( pList->nExpr % 2 ){
+ res |= sqlcipher_sqlite3ExprDataType(pList->a[pList->nExpr-1].pExpr);
+ }
+ return res;
+ }
+ default: {
+ return 0x01;
+ }
+ } /* End of switch(op) */
+ } /* End of while(pExpr) */
+ return 0x00;
+}
+
+/*
** Set the collating sequence for expression pExpr to be the collating
** sequence named by pToken. Return a pointer to a new Expr node that
** implements the COLLATE operator.
@@ -108998,9 +114308,10 @@ SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
assert( pExpr->x.pList->nExpr>0 );
assert( pExpr->op==TK_FUNCTION );
pExpr = pExpr->x.pList->a[0].pExpr;
- }else{
- assert( pExpr->op==TK_COLLATE );
+ }else if( pExpr->op==TK_COLLATE ){
pExpr = pExpr->pLeft;
+ }else{
+ break;
}
}
return pExpr;
@@ -109027,18 +114338,17 @@ SQLITE_PRIVATE CollSeq *sqlcipher_sqlite3ExprCollSeq(Parse *pParse, const Expr *
while( p ){
int op = p->op;
if( op==TK_REGISTER ) op = p->op2;
- if( op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER ){
+ if( (op==TK_AGG_COLUMN && p->y.pTab!=0)
+ || op==TK_COLUMN || op==TK_TRIGGER
+ ){
+ int j;
assert( ExprUseYTab(p) );
- if( p->y.pTab!=0 ){
- /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally
- ** a TK_COLUMN but was previously evaluated and cached in a register */
- int j = p->iColumn;
- if( j>=0 ){
- const char *zColl = sqlcipher_sqlite3ColumnColl(&p->y.pTab->aCol[j]);
- pColl = sqlcipher_sqlite3FindCollSeq(db, ENC(db), zColl, 0);
- }
- break;
+ assert( p->y.pTab!=0 );
+ if( (j = p->iColumn)>=0 ){
+ const char *zColl = sqlcipher_sqlite3ColumnColl(&p->y.pTab->aCol[j]);
+ pColl = sqlcipher_sqlite3FindCollSeq(db, ENC(db), zColl, 0);
}
+ break;
}
if( op==TK_CAST || op==TK_UPLUS ){
p = p->pLeft;
@@ -109060,11 +114370,10 @@ SQLITE_PRIVATE CollSeq *sqlcipher_sqlite3ExprCollSeq(Parse *pParse, const Expr *
}else{
Expr *pNext = p->pRight;
/* The Expr.x union is never used at the same time as Expr.pRight */
- assert( ExprUseXList(p) );
- assert( p->x.pList==0 || p->pRight==0 );
- if( p->x.pList!=0 && !db->mallocFailed ){
+ assert( !ExprUseXList(p) || p->x.pList==0 || p->pRight==0 );
+ if( ExprUseXList(p) && p->x.pList!=0 && !db->mallocFailed ){
int i;
- for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
+ for(i=0; i<p->x.pList->nExpr; i++){
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
pNext = p->x.pList->a[i].pExpr;
break;
@@ -109086,7 +114395,7 @@ SQLITE_PRIVATE CollSeq *sqlcipher_sqlite3ExprCollSeq(Parse *pParse, const Expr *
/*
** Return the collation sequence for the expression pExpr. If
** there is no defined collating sequence, return a pointer to the
-** defautl collation sequence.
+** default collation sequence.
**
** See also: sqlcipher_sqlite3ExprCollSeq()
**
@@ -109216,7 +114525,7 @@ SQLITE_PRIVATE CollSeq *sqlcipher_sqlite3BinaryCompareCollSeq(
return pColl;
}
-/* Expresssion p is a comparison operator. Return a collation sequence
+/* Expression p is a comparison operator. Return a collation sequence
** appropriate for the comparison operator.
**
** This is normally just a wrapper around sqlcipher_sqlite3BinaryCompareCollSeq().
@@ -109373,6 +114682,7 @@ SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprForVectorField(
*/
pRet = sqlcipher_sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0);
if( pRet ){
+ ExprSetProperty(pRet, EP_FullSize);
pRet->iTable = nField;
pRet->iColumn = iField;
pRet->pLeft = pVector;
@@ -109623,7 +114933,9 @@ static void heightOfSelect(const Select *pSelect, int *pnHeight){
*/
static void exprSetHeight(Expr *p){
int nHeight = p->pLeft ? p->pLeft->nHeight : 0;
- if( p->pRight && p->pRight->nHeight>nHeight ) nHeight = p->pRight->nHeight;
+ if( NEVER(p->pRight) && p->pRight->nHeight>nHeight ){
+ nHeight = p->pRight->nHeight;
+ }
if( ExprUseXSelect(p) ){
heightOfSelect(p->x.pSelect, &nHeight);
}else if( p->x.pList ){
@@ -109671,6 +114983,15 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *
#endif /* SQLITE_MAX_EXPR_DEPTH>0 */
/*
+** Set the error offset for an Expr node, if possible.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3ExprSetErrorOffset(Expr *pExpr, int iOfst){
+ if( pExpr==0 ) return;
+ if( NEVER(ExprUseWJoin(pExpr)) ) return;
+ pExpr->w.iOfst = iOfst;
+}
+
+/*
** This routine is the core allocator for Expr nodes.
**
** Construct a new expression node and return a pointer to it. Memory
@@ -109684,11 +115005,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *
** appear to be quoted. If the quotes were of the form "..." (double-quotes)
** then the EP_DblQuoted flag is set on the expression node.
**
-** Special case: If op==TK_INTEGER and pToken points to a string that
-** can be translated into a 32-bit integer, then the token is not
-** stored in u.zToken. Instead, the integer values is written
-** into u.iValue and the EP_IntValue flag is set. No extra storage
+** Special case (tag-20240227-a): If op==TK_INTEGER and pToken points to
+** a string that can be translated into a 32-bit integer, then the token is
+** not stored in u.zToken. Instead, the integer values is written
+** into u.iValue and the EP_IntValue flag is set. No extra storage
** is allocated to hold the integer text and the dequote flag is ignored.
+** See also tag-20240227-b.
*/
SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprAlloc(
sqlcipher_sqlite3 *db, /* Handle for sqlcipher_sqlite3DbMallocRawNN() */
@@ -109704,7 +115026,7 @@ SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprAlloc(
if( pToken ){
if( op!=TK_INTEGER || pToken->z==0
|| sqlcipher_sqlite3GetInt32(pToken->z, &iValue)==0 ){
- nExtra = pToken->n+1;
+ nExtra = pToken->n+1; /* tag-20240227-a */
assert( iValue>=0 );
}
}
@@ -109766,15 +115088,26 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprAttachSubtrees(
sqlcipher_sqlite3ExprDelete(db, pLeft);
sqlcipher_sqlite3ExprDelete(db, pRight);
}else{
+ assert( ExprUseXList(pRoot) );
+ assert( pRoot->x.pSelect==0 );
if( pRight ){
pRoot->pRight = pRight;
pRoot->flags |= EP_Propagate & pRight->flags;
+#if SQLITE_MAX_EXPR_DEPTH>0
+ pRoot->nHeight = pRight->nHeight+1;
+ }else{
+ pRoot->nHeight = 1;
+#endif
}
if( pLeft ){
pRoot->pLeft = pLeft;
pRoot->flags |= EP_Propagate & pLeft->flags;
+#if SQLITE_MAX_EXPR_DEPTH>0
+ if( pLeft->nHeight>=pRoot->nHeight ){
+ pRoot->nHeight = pLeft->nHeight+1;
+ }
+#endif
}
- exprSetHeight(pRoot);
}
}
@@ -109883,9 +115216,9 @@ SQLITE_PRIVATE Select *sqlcipher_sqlite3ExprListToValues(Parse *pParse, int nEle
** 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.
+** If one side or the other of the AND is known to be false, and neither side
+** is part of an ON clause, then instead of returning an AND expression,
+** just return a constant expression with a value of false.
*/
SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
sqlcipher_sqlite3 *db = pParse->db;
@@ -109893,14 +115226,17 @@ SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *
return pRight;
}else if( pRight==0 ){
return pLeft;
- }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight))
- && !IN_RENAME_OBJECT
- ){
- sqlcipher_sqlite3ExprDeferredDelete(pParse, pLeft);
- sqlcipher_sqlite3ExprDeferredDelete(pParse, pRight);
- return sqlcipher_sqlite3Expr(db, TK_INTEGER, "0");
}else{
- return sqlcipher_sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
+ u32 f = pLeft->flags | pRight->flags;
+ if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse))==EP_IsFalse
+ && !IN_RENAME_OBJECT
+ ){
+ sqlcipher_sqlite3ExprDeferredDelete(pParse, pLeft);
+ sqlcipher_sqlite3ExprDeferredDelete(pParse, pRight);
+ return sqlcipher_sqlite3Expr(db, TK_INTEGER, "0");
+ }else{
+ return sqlcipher_sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
+ }
}
}
@@ -109939,6 +115275,67 @@ SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprFunction(
}
/*
+** Report an error when attempting to use an ORDER BY clause within
+** the arguments of a non-aggregate function.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3ExprOrderByAggregateError(Parse *pParse, Expr *p){
+ sqlcipher_sqlite3ErrorMsg(pParse,
+ "ORDER BY may not be used with non-aggregate %#T()", p
+ );
+}
+
+/*
+** Attach an ORDER BY clause to a function call.
+**
+** functionname( arguments ORDER BY sortlist )
+** \_____________________/ \______/
+** pExpr pOrderBy
+**
+** The ORDER BY clause is inserted into a new Expr node of type TK_ORDER
+** and added to the Expr.pLeft field of the parent TK_FUNCTION node.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3ExprAddFunctionOrderBy(
+ Parse *pParse, /* Parsing context */
+ Expr *pExpr, /* The function call to which ORDER BY is to be added */
+ ExprList *pOrderBy /* The ORDER BY clause to add */
+){
+ Expr *pOB;
+ sqlcipher_sqlite3 *db = pParse->db;
+ if( NEVER(pOrderBy==0) ){
+ assert( db->mallocFailed );
+ return;
+ }
+ if( pExpr==0 ){
+ assert( db->mallocFailed );
+ sqlcipher_sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+ assert( pExpr->op==TK_FUNCTION );
+ assert( pExpr->pLeft==0 );
+ assert( ExprUseXList(pExpr) );
+ if( pExpr->x.pList==0 || NEVER(pExpr->x.pList->nExpr==0) ){
+ /* Ignore ORDER BY on zero-argument aggregates */
+ sqlcipher_sqlite3ParserAddCleanup(pParse, sqlcipher_sqlite3ExprListDeleteGeneric, pOrderBy);
+ return;
+ }
+ if( IsWindowFunc(pExpr) ){
+ sqlcipher_sqlite3ExprOrderByAggregateError(pParse, pExpr);
+ sqlcipher_sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+
+ pOB = sqlcipher_sqlite3ExprAlloc(db, TK_ORDER, 0, 0);
+ if( pOB==0 ){
+ sqlcipher_sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+ pOB->x.pList = pOrderBy;
+ assert( ExprUseXList(pOB) );
+ pExpr->pLeft = pOB;
+ ExprSetProperty(pOB, EP_FullSize);
+}
+
+/*
** Check to see if a function is usable according to current access
** rules:
**
@@ -110060,6 +115457,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pE
*/
static SQLITE_NOINLINE void sqlcipher_sqlite3ExprDeleteNN(sqlcipher_sqlite3 *db, Expr *p){
assert( p!=0 );
+ assert( db!=0 );
+exprDeleteRestart:
assert( !ExprUseUValue(p) || p->u.iValue>=0 );
assert( !ExprUseYWin(p) || !ExprUseYSub(p) );
assert( !ExprUseYWin(p) || p->y.pWin!=0 || db->mallocFailed );
@@ -110075,7 +115474,6 @@ static SQLITE_NOINLINE void sqlcipher_sqlite3ExprDeleteNN(sqlcipher_sqlite3 *db,
if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){
/* The Expr.x union is never used at the same time as Expr.pRight */
assert( (ExprUseXList(p) && p->x.pList==0) || p->pRight==0 );
- if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlcipher_sqlite3ExprDeleteNN(db, p->pLeft);
if( p->pRight ){
assert( !ExprHasProperty(p, EP_WinFunc) );
sqlcipher_sqlite3ExprDeleteNN(db, p->pRight);
@@ -110090,18 +115488,30 @@ static SQLITE_NOINLINE void sqlcipher_sqlite3ExprDeleteNN(sqlcipher_sqlite3 *db,
}
#endif
}
- }
- if( ExprHasProperty(p, EP_MemToken) ){
- assert( !ExprHasProperty(p, EP_IntValue) );
- sqlcipher_sqlite3DbFree(db, p->u.zToken);
+ if( p->pLeft && p->op!=TK_SELECT_COLUMN ){
+ Expr *pLeft = p->pLeft;
+ if( !ExprHasProperty(p, EP_Static)
+ && !ExprHasProperty(pLeft, EP_Static)
+ ){
+ /* Avoid unnecessary recursion on unary operators */
+ sqlcipher_sqlite3DbNNFreeNN(db, p);
+ p = pLeft;
+ goto exprDeleteRestart;
+ }else{
+ sqlcipher_sqlite3ExprDeleteNN(db, pLeft);
+ }
+ }
}
if( !ExprHasProperty(p, EP_Static) ){
- sqlcipher_sqlite3DbFreeNN(db, p);
+ sqlcipher_sqlite3DbNNFreeNN(db, p);
}
}
SQLITE_PRIVATE void sqlcipher_sqlite3ExprDelete(sqlcipher_sqlite3 *db, Expr *p){
if( p ) sqlcipher_sqlite3ExprDeleteNN(db, p);
}
+SQLITE_PRIVATE void sqlcipher_sqlite3ExprDeleteGeneric(sqlcipher_sqlite3 *db, void *p){
+ if( ALWAYS(p) ) sqlcipher_sqlite3ExprDeleteNN(db, (Expr*)p);
+}
/*
** Clear both elements of an OnOrUsing object
@@ -110119,16 +115529,15 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ClearOnOrUsing(sqlcipher_sqlite3 *db, OnOrU
/*
** Arrange to cause pExpr to be deleted when the pParse is deleted.
** This is similar to sqlcipher_sqlite3ExprDelete() except that the delete is
-** deferred untilthe pParse is deleted.
+** deferred until the pParse is deleted.
**
** The pExpr might be deleted immediately on an OOM error.
**
-** The deferred delete is (currently) implemented by adding the
-** pExpr to the pParse->pConstExpr list with a register number of 0.
+** Return 0 if the delete was successfully deferred. Return non-zero
+** if the delete happened immediately because of an OOM.
*/
-SQLITE_PRIVATE void sqlcipher_sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
- pParse->pConstExpr =
- sqlcipher_sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
+SQLITE_PRIVATE int sqlcipher_sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
+ return 0==sqlcipher_sqlite3ParserAddCleanup(pParse, sqlcipher_sqlite3ExprDeleteGeneric, pExpr);
}
/* Invoke sqlcipher_sqlite3RenameExprUnmap() and sqlcipher_sqlite3ExprDelete() on the
@@ -110193,16 +115602,11 @@ static int dupedExprStructSize(const Expr *p, int flags){
assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
assert( EXPR_FULLSIZE<=0xfff );
assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
- if( 0==flags || p->op==TK_SELECT_COLUMN
-#ifndef SQLITE_OMIT_WINDOWFUNC
- || ExprHasProperty(p, EP_WinFunc)
-#endif
- ){
+ if( 0==flags || ExprHasProperty(p, EP_FullSize) ){
nSize = EXPR_FULLSIZE;
}else{
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(p, EP_OuterON) );
- assert( !ExprHasProperty(p, EP_MemToken) );
assert( !ExprHasVVAProperty(p, EP_NoReduce) );
if( p->pLeft || p->x.pList ){
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
@@ -110229,56 +115633,93 @@ static int dupedExprNodeSize(const Expr *p, int flags){
/*
** Return the number of bytes required to create a duplicate of the
-** expression passed as the first argument. The second argument is a
-** mask containing EXPRDUP_XXX flags.
+** expression passed as the first argument.
**
** The value returned includes space to create a copy of the Expr struct
** itself and the buffer referred to by Expr.u.zToken, if any.
**
-** If the EXPRDUP_REDUCE flag is set, then the return value includes
-** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
-** and Expr.pRight variables (but not for any structures pointed to or
-** descended from the Expr.x.pList or Expr.x.pSelect variables).
+** The return value includes space to duplicate all Expr nodes in the
+** tree formed by Expr.pLeft and Expr.pRight, but not any other
+** substructure such as Expr.x.pList, Expr.x.pSelect, and Expr.y.pWin.
*/
-static int dupedExprSize(const Expr *p, int flags){
- int nByte = 0;
- if( p ){
- nByte = dupedExprNodeSize(p, flags);
- if( flags&EXPRDUP_REDUCE ){
- nByte += dupedExprSize(p->pLeft, flags) + dupedExprSize(p->pRight, flags);
- }
- }
+static int dupedExprSize(const Expr *p){
+ int nByte;
+ assert( p!=0 );
+ nByte = dupedExprNodeSize(p, EXPRDUP_REDUCE);
+ if( p->pLeft ) nByte += dupedExprSize(p->pLeft);
+ if( p->pRight ) nByte += dupedExprSize(p->pRight);
+ assert( nByte==ROUND8(nByte) );
return nByte;
}
/*
-** This function is similar to sqlcipher_sqlite3ExprDup(), except that if pzBuffer
-** is not NULL then *pzBuffer is assumed to point to a buffer large enough
-** to store the copy of expression p, the copies of p->u.zToken
-** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
-** if any. Before returning, *pzBuffer is set to the first byte past the
-** portion of the buffer copied into by this function.
+** An EdupBuf is a memory allocation used to stored multiple Expr objects
+** together with their Expr.zToken content. This is used to help implement
+** compression while doing sqlcipher_sqlite3ExprDup(). The top-level Expr does the
+** allocation for itself and many of its decendents, then passes an instance
+** of the structure down into exprDup() so that they decendents can have
+** access to that memory.
*/
-static Expr *exprDup(sqlcipher_sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
+typedef struct EdupBuf EdupBuf;
+struct EdupBuf {
+ u8 *zAlloc; /* Memory space available for storage */
+#ifdef SQLITE_DEBUG
+ u8 *zEnd; /* First byte past the end of memory */
+#endif
+};
+
+/*
+** This function is similar to sqlcipher_sqlite3ExprDup(), except that if pEdupBuf
+** is not NULL then it points to memory that can be used to store a copy
+** of the input Expr p together with its p->u.zToken (if any). pEdupBuf
+** is updated with the new buffer tail prior to returning.
+*/
+static Expr *exprDup(
+ sqlcipher_sqlite3 *db, /* Database connection (for memory allocation) */
+ const Expr *p, /* Expr tree to be duplicated */
+ int dupFlags, /* EXPRDUP_REDUCE for compression. 0 if not */
+ EdupBuf *pEdupBuf /* Preallocated storage space, or NULL */
+){
Expr *pNew; /* Value to return */
- u8 *zAlloc; /* Memory space from which to build Expr object */
+ EdupBuf sEdupBuf; /* Memory space from which to build Expr object */
u32 staticFlag; /* EP_Static if space not obtained from malloc */
+ int nToken = -1; /* Space needed for p->u.zToken. -1 means unknown */
assert( db!=0 );
assert( p );
assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE );
- assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE );
+ assert( pEdupBuf==0 || dupFlags==EXPRDUP_REDUCE );
/* Figure out where to write the new Expr structure. */
- if( pzBuffer ){
- zAlloc = *pzBuffer;
+ if( pEdupBuf ){
+ sEdupBuf.zAlloc = pEdupBuf->zAlloc;
+#ifdef SQLITE_DEBUG
+ sEdupBuf.zEnd = pEdupBuf->zEnd;
+#endif
staticFlag = EP_Static;
- assert( zAlloc!=0 );
+ assert( sEdupBuf.zAlloc!=0 );
+ assert( dupFlags==EXPRDUP_REDUCE );
}else{
- zAlloc = sqlcipher_sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags));
+ int nAlloc;
+ if( dupFlags ){
+ nAlloc = dupedExprSize(p);
+ }else if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nToken = sqlcipher_sqlite3Strlen30NN(p->u.zToken)+1;
+ nAlloc = ROUND8(EXPR_FULLSIZE + nToken);
+ }else{
+ nToken = 0;
+ nAlloc = ROUND8(EXPR_FULLSIZE);
+ }
+ assert( nAlloc==ROUND8(nAlloc) );
+ sEdupBuf.zAlloc = sqlcipher_sqlite3DbMallocRawNN(db, nAlloc);
+#ifdef SQLITE_DEBUG
+ sEdupBuf.zEnd = sEdupBuf.zAlloc ? sEdupBuf.zAlloc+nAlloc : 0;
+#endif
+
staticFlag = 0;
}
- pNew = (Expr *)zAlloc;
+ pNew = (Expr *)sEdupBuf.zAlloc;
+ assert( EIGHT_BYTE_ALIGNMENT(pNew) );
if( pNew ){
/* Set nNewSize to the size allocated for the structure pointed to
@@ -110287,26 +115728,31 @@ static Expr *exprDup(sqlcipher_sqlite3 *db, const Expr *p, int dupFlags, u8 **pz
** by the copy of the p->u.zToken string (if any).
*/
const unsigned nStructSize = dupedExprStructSize(p, dupFlags);
- const int nNewSize = nStructSize & 0xfff;
- int nToken;
- if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
- nToken = sqlcipher_sqlite3Strlen30(p->u.zToken) + 1;
- }else{
- nToken = 0;
+ int nNewSize = nStructSize & 0xfff;
+ if( nToken<0 ){
+ if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nToken = sqlcipher_sqlite3Strlen30(p->u.zToken) + 1;
+ }else{
+ nToken = 0;
+ }
}
if( dupFlags ){
+ assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >= nNewSize+nToken );
assert( ExprHasProperty(p, EP_Reduced)==0 );
- memcpy(zAlloc, p, nNewSize);
+ memcpy(sEdupBuf.zAlloc, p, nNewSize);
}else{
u32 nSize = (u32)exprStructSize(p);
- memcpy(zAlloc, p, nSize);
+ assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >=
+ (int)EXPR_FULLSIZE+nToken );
+ memcpy(sEdupBuf.zAlloc, p, nSize);
if( nSize<EXPR_FULLSIZE ){
- memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
+ memset(&sEdupBuf.zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
}
+ nNewSize = EXPR_FULLSIZE;
}
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
- pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
+ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static);
pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
pNew->flags |= staticFlag;
ExprClearVVAProperties(pNew);
@@ -110315,44 +115761,50 @@ static Expr *exprDup(sqlcipher_sqlite3 *db, const Expr *p, int dupFlags, u8 **pz
}
/* Copy the p->u.zToken string, if any. */
- if( nToken ){
- char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
+ assert( nToken>=0 );
+ if( nToken>0 ){
+ char *zToken = pNew->u.zToken = (char*)&sEdupBuf.zAlloc[nNewSize];
memcpy(zToken, p->u.zToken, nToken);
+ nNewSize += nToken;
}
+ sEdupBuf.zAlloc += ROUND8(nNewSize);
+
+ if( ((p->flags|pNew->flags)&(EP_TokenOnly|EP_Leaf))==0 ){
- if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
if( ExprUseXSelect(p) ){
pNew->x.pSelect = sqlcipher_sqlite3SelectDup(db, p->x.pSelect, dupFlags);
}else{
- pNew->x.pList = sqlcipher_sqlite3ExprListDup(db, p->x.pList, dupFlags);
+ pNew->x.pList = sqlcipher_sqlite3ExprListDup(db, p->x.pList,
+ p->op!=TK_ORDER ? dupFlags : 0);
}
- }
- /* Fill in pNew->pLeft and pNew->pRight. */
- if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){
- zAlloc += dupedExprNodeSize(p, dupFlags);
- if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){
- pNew->pLeft = p->pLeft ?
- exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0;
- pNew->pRight = p->pRight ?
- exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0;
- }
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(p, EP_WinFunc) ){
pNew->y.pWin = sqlcipher_sqlite3WindowDup(db, pNew, p->y.pWin);
assert( ExprHasProperty(pNew, EP_WinFunc) );
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
- if( pzBuffer ){
- *pzBuffer = zAlloc;
- }
- }else{
- if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
- if( pNew->op==TK_SELECT_COLUMN ){
+
+ /* Fill in pNew->pLeft and pNew->pRight. */
+ if( dupFlags ){
+ if( p->op==TK_SELECT_COLUMN ){
+ pNew->pLeft = p->pLeft;
+ assert( p->pRight==0
+ || p->pRight==p->pLeft
+ || ExprHasProperty(p->pLeft, EP_Subquery) );
+ }else{
+ pNew->pLeft = p->pLeft ?
+ exprDup(db, p->pLeft, EXPRDUP_REDUCE, &sEdupBuf) : 0;
+ }
+ pNew->pRight = p->pRight ?
+ exprDup(db, p->pRight, EXPRDUP_REDUCE, &sEdupBuf) : 0;
+ }else{
+ if( p->op==TK_SELECT_COLUMN ){
pNew->pLeft = p->pLeft;
- assert( p->pRight==0 || p->pRight==p->pLeft
- || ExprHasProperty(p->pLeft, EP_Subquery) );
+ assert( p->pRight==0
+ || p->pRight==p->pLeft
+ || ExprHasProperty(p->pLeft, EP_Subquery) );
}else{
pNew->pLeft = sqlcipher_sqlite3ExprDup(db, p->pLeft, 0);
}
@@ -110360,6 +115812,8 @@ static Expr *exprDup(sqlcipher_sqlite3 *db, const Expr *p, int dupFlags, u8 **pz
}
}
}
+ if( pEdupBuf ) memcpy(pEdupBuf, &sEdupBuf, sizeof(sEdupBuf));
+ assert( sEdupBuf.zAlloc <= sEdupBuf.zEnd );
return pNew;
}
@@ -110519,17 +115973,19 @@ SQLITE_PRIVATE SrcList *sqlcipher_sqlite3SrcListDup(sqlcipher_sqlite3 *db, const
pNewItem->iCursor = pOldItem->iCursor;
pNewItem->addrFillSub = pOldItem->addrFillSub;
pNewItem->regReturn = pOldItem->regReturn;
+ pNewItem->regResult = pOldItem->regResult;
if( pNewItem->fg.isIndexedBy ){
pNewItem->u1.zIndexedBy = sqlcipher_sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
+ }else if( pNewItem->fg.isTabFunc ){
+ pNewItem->u1.pFuncArg =
+ sqlcipher_sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
+ }else{
+ pNewItem->u1.nRow = pOldItem->u1.nRow;
}
pNewItem->u2 = pOldItem->u2;
if( pNewItem->fg.isCte ){
pNewItem->u2.pCteUse->nUse++;
}
- if( pNewItem->fg.isTabFunc ){
- pNewItem->u1.pFuncArg =
- sqlcipher_sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
- }
pTab = pNewItem->pTab = pOldItem->pTab;
if( pTab ){
pTab->nTabRef++;
@@ -110624,11 +116080,7 @@ SQLITE_PRIVATE Select *sqlcipher_sqlite3SelectDup(sqlcipher_sqlite3 *db, const S
** initially NULL, then create a new expression list.
**
** The pList argument must be either NULL or a pointer to an ExprList
-** obtained from a prior call to sqlcipher_sqlite3ExprListAppend(). This routine
-** may not be used with an ExprList obtained from sqlcipher_sqlite3ExprListDup().
-** Reason: This routine assumes that the number of slots in pList->a[]
-** is a power of two. That is true for sqlcipher_sqlite3ExprListAppend() returns
-** but is not necessarily true from the return value of sqlcipher_sqlite3ExprListDup().
+** obtained from a prior call to sqlcipher_sqlite3ExprListAppend().
**
** If a memory allocation error occurs, the entire list is freed and
** NULL is returned. If non-NULL is returned, then it is guaranteed
@@ -110882,16 +116334,20 @@ static SQLITE_NOINLINE void exprListDeleteNN(sqlcipher_sqlite3 *db, ExprList *pL
int i = pList->nExpr;
struct ExprList_item *pItem = pList->a;
assert( pList->nExpr>0 );
+ assert( db!=0 );
do{
sqlcipher_sqlite3ExprDelete(db, pItem->pExpr);
- sqlcipher_sqlite3DbFree(db, pItem->zEName);
+ if( pItem->zEName ) sqlcipher_sqlite3DbNNFreeNN(db, pItem->zEName);
pItem++;
}while( --i>0 );
- sqlcipher_sqlite3DbFreeNN(db, pList);
+ sqlcipher_sqlite3DbNNFreeNN(db, pList);
}
SQLITE_PRIVATE void sqlcipher_sqlite3ExprListDelete(sqlcipher_sqlite3 *db, ExprList *pList){
if( pList ) exprListDeleteNN(db, pList);
}
+SQLITE_PRIVATE void sqlcipher_sqlite3ExprListDeleteGeneric(sqlcipher_sqlite3 *db, void *pList){
+ if( ALWAYS(pList) ) exprListDeleteNN(db, (ExprList*)pList);
+}
/*
** Return the bitwise-OR of all Expr.flags fields in the given
@@ -110960,7 +116416,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprIdToTrueFalse(Expr *pExpr){
** and 0 if it is FALSE.
*/
SQLITE_PRIVATE int sqlcipher_sqlite3ExprTruthValue(const Expr *pExpr){
- pExpr = sqlcipher_sqlite3ExprSkipCollate((Expr*)pExpr);
+ pExpr = sqlcipher_sqlite3ExprSkipCollateAndLikely((Expr*)pExpr);
assert( pExpr->op==TK_TRUEFALSE );
assert( !ExprHasProperty(pExpr, EP_IntValue) );
assert( sqlcipher_sqlite3StrICmp(pExpr->u.zToken,"true")==0
@@ -110995,6 +116451,54 @@ SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprSimplifiedAndOr(Expr *pExpr){
return pExpr;
}
+/*
+** pExpr is a TK_FUNCTION node. Try to determine whether or not the
+** function is a constant function. A function is constant if all of
+** the following are true:
+**
+** (1) It is a scalar function (not an aggregate or window function)
+** (2) It has either the SQLITE_FUNC_CONSTANT or SQLITE_FUNC_SLOCHNG
+** property.
+** (3) All of its arguments are constants
+**
+** This routine sets pWalker->eCode to 0 if pExpr is not a constant.
+** It makes no changes to pWalker->eCode if pExpr is constant. In
+** every case, it returns WRC_Abort.
+**
+** Called as a service subroutine from exprNodeIsConstant().
+*/
+static SQLITE_NOINLINE int exprNodeIsConstantFunction(
+ Walker *pWalker,
+ Expr *pExpr
+){
+ int n; /* Number of arguments */
+ ExprList *pList; /* List of arguments */
+ FuncDef *pDef; /* The function */
+ sqlcipher_sqlite3 *db; /* The database */
+
+ assert( pExpr->op==TK_FUNCTION );
+ if( ExprHasProperty(pExpr, EP_TokenOnly)
+ || (pList = pExpr->x.pList)==0
+ ){;
+ n = 0;
+ }else{
+ n = pList->nExpr;
+ sqlcipher_sqlite3WalkExprList(pWalker, pList);
+ if( pWalker->eCode==0 ) return WRC_Abort;
+ }
+ db = pWalker->pParse->db;
+ pDef = sqlcipher_sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
+ if( pDef==0
+ || pDef->xFinalize!=0
+ || (pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
+ || ExprHasProperty(pExpr, EP_WinFunc)
+ ){
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+ return WRC_Prune;
+}
+
/*
** These routines are Walker callbacks used to check expressions to
@@ -111023,6 +116527,7 @@ SQLITE_PRIVATE Expr *sqlcipher_sqlite3ExprSimplifiedAndOr(Expr *pExpr){
** malformed schema error.
*/
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
+ assert( pWalker->eCode>0 );
/* If pWalker->eCode is 2 then any term of the expression that comes from
** the ON or USING clauses of an outer join disqualifies the expression
@@ -111042,6 +116547,8 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
){
if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL);
return WRC_Continue;
+ }else if( pWalker->pParse ){
+ return exprNodeIsConstantFunction(pWalker, pExpr);
}else{
pWalker->eCode = 0;
return WRC_Abort;
@@ -111070,9 +116577,11 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
case TK_IF_NULL_ROW:
case TK_REGISTER:
case TK_DOT:
+ case TK_RAISE:
testcase( pExpr->op==TK_REGISTER );
testcase( pExpr->op==TK_IF_NULL_ROW );
testcase( pExpr->op==TK_DOT );
+ testcase( pExpr->op==TK_RAISE );
pWalker->eCode = 0;
return WRC_Abort;
case TK_VARIABLE:
@@ -111094,15 +116603,15 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
}
-static int exprIsConst(Expr *p, int initFlag, int iCur){
+static int exprIsConst(Parse *pParse, Expr *p, int initFlag){
Walker w;
w.eCode = initFlag;
+ w.pParse = pParse;
w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = sqlcipher_sqlite3SelectWalkFail;
#ifdef SQLITE_DEBUG
w.xSelectCallback2 = sqlcipher_sqlite3SelectWalkAssert2;
#endif
- w.u.iCur = iCur;
sqlcipher_sqlite3WalkExpr(&w, p);
return w.eCode;
}
@@ -111114,9 +116623,15 @@ static int exprIsConst(Expr *p, int initFlag, int iCur){
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
** a constant.
+**
+** The pParse parameter may be NULL. But if it is NULL, there is no way
+** to determine if function calls are constant or not, and hence all
+** function calls will be considered to be non-constant. If pParse is
+** not NULL, then a function call might be constant, depending on the
+** function and on its parameters.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstant(Expr *p){
- return exprIsConst(p, 1, 0);
+SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstant(Parse *pParse, Expr *p){
+ return exprIsConst(pParse, p, 1);
}
/*
@@ -111132,8 +116647,24 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstant(Expr *p){
** can be added to the pParse->pConstExpr list and evaluated once when
** the prepared statement starts up. See sqlcipher_sqlite3ExprCodeRunJustOnce().
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstantNotJoin(Expr *p){
- return exprIsConst(p, 2, 0);
+static int sqlcipher_sqlite3ExprIsConstantNotJoin(Parse *pParse, Expr *p){
+ return exprIsConst(pParse, p, 2);
+}
+
+/*
+** This routine examines sub-SELECT statements as an expression is being
+** walked as part of sqlcipher_sqlite3ExprIsTableConstant(). Sub-SELECTs are considered
+** constant as long as they are uncorrelated - meaning that they do not
+** contain any terms from outer contexts.
+*/
+static int exprSelectWalkTableConstant(Walker *pWalker, Select *pSelect){
+ assert( pSelect!=0 );
+ assert( pWalker->eCode==3 || pWalker->eCode==0 );
+ if( (pSelect->selFlags & SF_Correlated)!=0 ){
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+ return WRC_Prune;
}
/*
@@ -111141,35 +116672,79 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstantNotJoin(Expr *p){
** for any single row of the table with cursor iCur. In other words, the
** expression must not refer to any non-deterministic function nor any
** table other than iCur.
+**
+** Consider uncorrelated subqueries to be constants if the bAllowSubq
+** parameter is true.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsTableConstant(Expr *p, int iCur){
- return exprIsConst(p, 3, iCur);
+static int sqlcipher_sqlite3ExprIsTableConstant(Expr *p, int iCur, int bAllowSubq){
+ Walker w;
+ w.eCode = 3;
+ w.pParse = 0;
+ w.xExprCallback = exprNodeIsConstant;
+ if( bAllowSubq ){
+ w.xSelectCallback = exprSelectWalkTableConstant;
+ }else{
+ w.xSelectCallback = sqlcipher_sqlite3SelectWalkFail;
+#ifdef SQLITE_DEBUG
+ w.xSelectCallback2 = sqlcipher_sqlite3SelectWalkAssert2;
+#endif
+ }
+ w.u.iCur = iCur;
+ sqlcipher_sqlite3WalkExpr(&w, p);
+ return w.eCode;
}
/*
-** Check pExpr to see if it is an invariant constraint on data source pSrc.
+** Check pExpr to see if it is an constraint on the single data source
+** pSrc = &pSrcList->a[iSrc]. In other words, check to see if pExpr
+** constrains pSrc but does not depend on any other tables or data
+** sources anywhere else in the query. Return true (non-zero) if pExpr
+** is a constraint on pSrc only.
+**
** This is an optimization. False negatives will perhaps cause slower
** queries, but false positives will yield incorrect answers. So when in
** doubt, return 0.
**
-** To be an invariant constraint, the following must be true:
+** To be an single-source constraint, the following must be true:
**
** (1) pExpr cannot refer to any table other than pSrc->iCursor.
**
-** (2) pExpr cannot use subqueries or non-deterministic functions.
+** (2a) pExpr cannot use subqueries unless the bAllowSubq parameter is
+** true and the subquery is non-correlated
+**
+** (2b) pExpr cannot use non-deterministic functions.
**
** (3) pSrc cannot be part of the left operand for a RIGHT JOIN.
** (Is there some way to relax this constraint?)
**
** (4) If pSrc is the right operand of a LEFT JOIN, then...
** (4a) pExpr must come from an ON clause..
- (4b) and specifically the ON clause associated with the LEFT JOIN.
+** (4b) and specifically the ON clause associated with the LEFT JOIN.
**
** (5) If pSrc is not the right operand of a LEFT JOIN or the left
** operand of a RIGHT JOIN, then pExpr must be from the WHERE
** clause, not an ON clause.
+**
+** (6) Either:
+**
+** (6a) pExpr does not originate in an ON or USING clause, or
+**
+** (6b) The ON or USING clause from which pExpr is derived is
+** not to the left of a RIGHT JOIN (or FULL JOIN).
+**
+** Without this restriction, accepting pExpr as a single-table
+** constraint might move the the ON/USING filter expression
+** from the left side of a RIGHT JOIN over to the right side,
+** which leads to incorrect answers. See also restriction (9)
+** on push-down.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
+SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsSingleTableConstraint(
+ Expr *pExpr, /* The constraint */
+ const SrcList *pSrcList, /* Complete FROM clause */
+ int iSrc, /* Which element of pSrcList to use */
+ int bAllowSubq /* Allow non-correlated subqueries */
+){
+ const SrcItem *pSrc = &pSrcList->a[iSrc];
if( pSrc->fg.jointype & JT_LTORJ ){
return 0; /* rule (3) */
}
@@ -111179,7 +116754,21 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsTableConstraint(Expr *pExpr, const Src
}else{
if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (5) */
}
- return sqlcipher_sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
+ if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) /* (6a) */
+ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (6b) */
+ ){
+ int jj;
+ for(jj=0; jj<iSrc; jj++){
+ if( pExpr->w.iJoin==pSrcList->a[jj].iCursor ){
+ if( (pSrcList->a[jj].fg.jointype & JT_LTORJ)!=0 ){
+ return 0; /* restriction (6) */
+ }
+ break;
+ }
+ }
+ }
+ /* Rules (1), (2a), and (2b) handled by the following: */
+ return sqlcipher_sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor, bAllowSubq);
}
@@ -111264,7 +116853,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr
*/
SQLITE_PRIVATE int sqlcipher_sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
assert( isInit==0 || isInit==1 );
- return exprIsConst(p, 4+isInit, 0);
+ return exprIsConst(0, p, 4+isInit);
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
@@ -111354,10 +116943,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprCanBeNull(const Expr *p){
return 0;
case TK_COLUMN:
assert( ExprUseYTab(p) );
- return ExprHasProperty(p, EP_CanBeNull) ||
- p->y.pTab==0 || /* Reference to column of index on expression */
- (p->iColumn>=0
+ return ExprHasProperty(p, EP_CanBeNull)
+ || NEVER(p->y.pTab==0) /* Reference to column of index on expr */
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ || (p->iColumn==XN_ROWID && IsView(p->y.pTab))
+#endif
+ || (p->iColumn>=0
&& p->y.pTab->aCol!=0 /* Possible due to prior error */
+ && ALWAYS(p->iColumn<p->y.pTab->nCol)
&& p->y.pTab->aCol[p->iColumn].notNull==0);
default:
return 1;
@@ -111418,10 +117011,31 @@ SQLITE_PRIVATE int sqlcipher_sqlite3IsRowid(const char *z){
}
/*
+** Return a pointer to a buffer containing a usable rowid alias for table
+** pTab. An alias is usable if there is not an explicit user-defined column
+** of the same name.
+*/
+SQLITE_PRIVATE const char *sqlcipher_sqlite3RowidAlias(Table *pTab){
+ const char *azOpt[] = {"_ROWID_", "ROWID", "OID"};
+ int ii;
+ assert( VisibleRowid(pTab) );
+ for(ii=0; ii<ArraySize(azOpt); ii++){
+ int iCol;
+ for(iCol=0; iCol<pTab->nCol; iCol++){
+ if( sqlcipher_sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break;
+ }
+ if( iCol==pTab->nCol ){
+ return azOpt[ii];
+ }
+ }
+ return 0;
+}
+
+/*
** pX is the RHS of an IN operator. If pX is a SELECT statement
** that can be simplified to a direct table access, then return
** a pointer to the SELECT statement. If pX is not a SELECT statement,
-** or if the SELECT statement needs to be manifested into a transient
+** or if the SELECT statement needs to be materialized into a transient
** table, then return NULL.
*/
#ifndef SQLITE_OMIT_SUBQUERY
@@ -111487,13 +117101,13 @@ static void sqlcipher_sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
** The argument is an IN operator with a list (not a subquery) on the
** right-hand side. Return TRUE if that list is constant.
*/
-static int sqlcipher_sqlite3InRhsIsConstant(Expr *pIn){
+static int sqlcipher_sqlite3InRhsIsConstant(Parse *pParse, Expr *pIn){
Expr *pLHS;
int res;
assert( !ExprHasProperty(pIn, EP_xIsSelect) );
pLHS = pIn->pLeft;
pIn->pLeft = 0;
- res = sqlcipher_sqlite3ExprIsConstant(pIn);
+ res = sqlcipher_sqlite3ExprIsConstant(pParse, pIn);
pIn->pLeft = pLHS;
return res;
}
@@ -111517,7 +117131,7 @@ static int sqlcipher_sqlite3InRhsIsConstant(Expr *pIn){
** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index.
** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
** IN_INDEX_EPH - The cursor was opened on a specially created and
-** populated epheremal table.
+** populated ephemeral table.
** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be
** implemented as a sequence of comparisons.
**
@@ -111530,7 +117144,7 @@ static int sqlcipher_sqlite3InRhsIsConstant(Expr *pIn){
** an ephemeral table might need to be generated from the RHS and then
** pX->iTable made to point to the ephemeral table instead of an
** existing table. In this case, the creation and initialization of the
-** ephmeral table might be put inside of a subroutine, the EP_Subrtn flag
+** ephemeral table might be put inside of a subroutine, the EP_Subrtn flag
** will be set on pX and the pX->y.sub fields will be set to show where
** the subroutine is coded.
**
@@ -111542,12 +117156,12 @@ static int sqlcipher_sqlite3InRhsIsConstant(Expr *pIn){
**
** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate
** through the set members) then the b-tree must not contain duplicates.
-** An epheremal table will be created unless the selected columns are guaranteed
+** An ephemeral table will be created unless the selected columns are guaranteed
** to be unique - either because it is an INTEGER PRIMARY KEY or due to
** a UNIQUE constraint or index.
**
** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used
-** for fast set membership tests) then an epheremal table must
+** for fast set membership tests) then an ephemeral table must
** be used unless <columns> is a single INTEGER PRIMARY KEY column or an
** index can be found with the specified <columns> as its left-most.
**
@@ -111707,7 +117321,6 @@ SQLITE_PRIVATE int sqlcipher_sqlite3FindInIndex(
CollSeq *pReq = sqlcipher_sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
int j;
- assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
for(j=0; j<nExpr; j++){
if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
assert( pIdx->azColl[j] );
@@ -111763,7 +117376,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3FindInIndex(
if( eType==0
&& (inFlags & IN_INDEX_NOOP_OK)
&& ExprUseXList(pX)
- && (!sqlcipher_sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2)
+ && (!sqlcipher_sqlite3InRhsIsConstant(pParse,pX) || pX->x.pList->nExpr<=2)
){
pParse->nTab--; /* Back out the allocation of the unused cursor */
iTab = -1; /* Cursor is not allocated */
@@ -111881,7 +117494,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
** x IN (SELECT a FROM b) -- IN operator with subquery on the right
**
** The pExpr parameter is the IN operator. The cursor number for the
-** constructed ephermeral table is returned. The first time the ephemeral
+** constructed ephemeral table is returned. The first time the ephemeral
** table is computed, the cursor number is also stored in pExpr->iTable,
** however the cursor number returned might not be the same, as it might
** have been duplicated using OP_OpenDup.
@@ -112046,7 +117659,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3CodeRhsOfIN(
** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time.
*/
- if( addrOnce && !sqlcipher_sqlite3ExprIsConstant(pE2) ){
+ if( addrOnce && !sqlcipher_sqlite3ExprIsConstant(pParse, pE2) ){
sqlcipher_sqlite3VdbeChangeToNoop(v, addrOnce-1);
sqlcipher_sqlite3VdbeChangeToNoop(v, addrOnce);
ExprClearProperty(pExpr, EP_Subrtn);
@@ -112065,6 +117678,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3CodeRhsOfIN(
sqlcipher_sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
}
if( addrOnce ){
+ sqlcipher_sqlite3VdbeAddOp1(v, OP_NullRow, iTab);
sqlcipher_sqlite3VdbeJumpHere(v, addrOnce);
/* Subroutine return */
assert( ExprUseYSub(pExpr) );
@@ -112100,6 +117714,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
SelectDest dest; /* How to deal with SELECT result */
int nReg; /* Registers to allocate */
Expr *pLimit; /* New limit expression */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExplain; /* Address of OP_Explain instruction */
+#endif
Vdbe *v = pParse->pVdbe;
assert( v!=0 );
@@ -112152,8 +117769,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** In both cases, the query is augmented with "LIMIT 1". Any
** preexisting limit is discarded in place of the new LIMIT 1.
*/
- ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY %d",
+ ExplainQueryPlan2(addrExplain, (pParse, 1, "%sSCALAR SUBQUERY %d",
addrOnce?"":"CORRELATED ", pSel->selId));
+ sqlcipher_sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, -1);
nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
sqlcipher_sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
pParse->nMem += nReg;
@@ -112178,7 +117796,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
pLimit = sqlcipher_sqlite3PExpr(pParse, TK_NE,
sqlcipher_sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit);
}
- sqlcipher_sqlite3ExprDelete(db, pSel->pLimit->pLeft);
+ sqlcipher_sqlite3ExprDeferredDelete(pParse, pSel->pLimit->pLeft);
pSel->pLimit->pLeft = pLimit;
}else{
/* If there is no pre-existing limit add a limit of 1 */
@@ -112196,6 +117814,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
if( addrOnce ){
sqlcipher_sqlite3VdbeJumpHere(v, addrOnce);
}
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
/* Subroutine return */
assert( ExprUseYSub(pExpr) );
@@ -112604,6 +118223,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprCodeGeneratedColumn(
){
int iAddr;
Vdbe *v = pParse->pVdbe;
+ int nErr = pParse->nErr;
assert( v!=0 );
assert( pParse->iSelfTab!=0 );
if( pParse->iSelfTab>0 ){
@@ -112616,6 +118236,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprCodeGeneratedColumn(
sqlcipher_sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1);
}
if( iAddr ) sqlcipher_sqlite3VdbeJumpHere(v, iAddr);
+ if( pParse->nErr>nErr ) pParse->db->errByteOffset = -1;
}
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
@@ -112631,10 +118252,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprCodeGetColumnOfTable(
){
Column *pCol;
assert( v!=0 );
- if( pTab==0 ){
- sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
- return;
- }
+ assert( pTab!=0 );
+ assert( iCol!=XN_EXPR );
if( iCol<0 || iCol==pTab->iPKey ){
sqlcipher_sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
VdbeComment((v, "%s.rowid", pTab->zName));
@@ -112690,10 +118309,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprCodeGetColumn(
u8 p5 /* P5 value for OP_Column + FLAGS */
){
assert( pParse->pVdbe!=0 );
+ assert( (p5 & (OPFLAG_NOCHNG|OPFLAG_TYPEOFARG|OPFLAG_LENGTHARG))==p5 );
+ assert( IsVirtual(pTab) || (p5 & OPFLAG_NOCHNG)==0 );
sqlcipher_sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
if( p5 ){
- VdbeOp *pOp = sqlcipher_sqlite3VdbeGetOp(pParse->pVdbe,-1);
+ VdbeOp *pOp = sqlcipher_sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Column ) pOp->p5 = p5;
+ if( pOp->opcode==OP_VColumn ) pOp->p5 = (p5 & OPFLAG_NOCHNG);
}
return iReg;
}
@@ -112722,7 +118344,7 @@ static void exprToRegister(Expr *pExpr, int iReg){
/*
** Evaluate an expression (either a vector or a scalar expression) and store
-** the result in continguous temporary registers. Return the index of
+** the result in contiguous temporary registers. Return the index of
** the first register used to store the result.
**
** If the returned result register is a temporary scalar, then also write
@@ -112761,8 +118383,8 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
** so that a subsequent copy will not be merged into this one.
*/
static void setDoNotMergeFlagOnCopy(Vdbe *v){
- if( sqlcipher_sqlite3VdbeGetOp(v, -1)->opcode==OP_Copy ){
- sqlcipher_sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */
+ if( sqlcipher_sqlite3VdbeGetLastOp(v)->opcode==OP_Copy ){
+ sqlcipher_sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergeable */
}
}
@@ -112852,13 +118474,13 @@ static int exprCodeInlineFunction(
}
case INLINEFUNC_implies_nonnull_row: {
- /* REsult of sqlcipher_sqlite3ExprImpliesNonNullRow() */
+ /* Result of sqlcipher_sqlite3ExprImpliesNonNullRow() */
Expr *pA1;
assert( nFarg==2 );
pA1 = pFarg->a[1].pExpr;
if( pA1->op==TK_COLUMN ){
sqlcipher_sqlite3VdbeAddOp2(v, OP_Integer,
- sqlcipher_sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable),
+ sqlcipher_sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable,1),
target);
}else{
sqlcipher_sqlite3VdbeAddOp2(v, OP_Null, 0, target);
@@ -112871,10 +118493,13 @@ static int exprCodeInlineFunction(
** the type affinity of the argument. This is used for testing of
** the SQLite type logic.
*/
- const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
+ const char *azAff[] = { "blob", "text", "numeric", "integer",
+ "real", "flexnum" };
char aff;
assert( nFarg==1 );
aff = sqlcipher_sqlite3ExprAffinity(pFarg->a[0].pExpr);
+ assert( aff<=SQLITE_AFF_NONE
+ || (aff>=SQLITE_AFF_BLOB && aff<=SQLITE_AFF_FLEXNUM) );
sqlcipher_sqlite3VdbeLoadString(v, target,
(aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
break;
@@ -112884,6 +118509,99 @@ static int exprCodeInlineFunction(
return target;
}
+/*
+** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr.
+** If it is, then resolve the expression by reading from the index and
+** return the register into which the value has been read. If pExpr is
+** not an indexed expression, then return negative.
+*/
+static SQLITE_NOINLINE int sqlcipher_sqlite3IndexedExprLookup(
+ Parse *pParse, /* The parsing context */
+ Expr *pExpr, /* The expression to potentially bypass */
+ int target /* Where to store the result of the expression */
+){
+ IndexedExpr *p;
+ Vdbe *v;
+ for(p=pParse->pIdxEpr; p; p=p->pIENext){
+ u8 exprAff;
+ int iDataCur = p->iDataCur;
+ if( iDataCur<0 ) continue;
+ if( pParse->iSelfTab ){
+ if( p->iDataCur!=pParse->iSelfTab-1 ) continue;
+ iDataCur = -1;
+ }
+ if( sqlcipher_sqlite3ExprCompare(0, pExpr, p->pExpr, iDataCur)!=0 ) continue;
+ assert( p->aff>=SQLITE_AFF_BLOB && p->aff<=SQLITE_AFF_NUMERIC );
+ exprAff = sqlcipher_sqlite3ExprAffinity(pExpr);
+ if( (exprAff<=SQLITE_AFF_BLOB && p->aff!=SQLITE_AFF_BLOB)
+ || (exprAff==SQLITE_AFF_TEXT && p->aff!=SQLITE_AFF_TEXT)
+ || (exprAff>=SQLITE_AFF_NUMERIC && p->aff!=SQLITE_AFF_NUMERIC)
+ ){
+ /* Affinity mismatch on a generated column */
+ continue;
+ }
+
+ v = pParse->pVdbe;
+ assert( v!=0 );
+ if( p->bMaybeNullRow ){
+ /* If the index is on a NULL row due to an outer join, then we
+ ** cannot extract the value from the index. The value must be
+ ** computed using the original expression. */
+ int addr = sqlcipher_sqlite3VdbeCurrentAddr(v);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_IfNullRow, p->iIdxCur, addr+3, target);
+ VdbeCoverage(v);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target);
+ VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol));
+ sqlcipher_sqlite3VdbeGoto(v, 0);
+ p = pParse->pIdxEpr;
+ pParse->pIdxEpr = 0;
+ sqlcipher_sqlite3ExprCode(pParse, pExpr, target);
+ pParse->pIdxEpr = p;
+ sqlcipher_sqlite3VdbeJumpHere(v, addr+2);
+ }else{
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target);
+ VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol));
+ }
+ return target;
+ }
+ return -1; /* Not found */
+}
+
+
+/*
+** Expresion pExpr is guaranteed to be a TK_COLUMN or equivalent. This
+** function checks the Parse.pIdxPartExpr list to see if this column
+** can be replaced with a constant value. If so, it generates code to
+** put the constant value in a register (ideally, but not necessarily,
+** register iTarget) and returns the register number.
+**
+** Or, if the TK_COLUMN cannot be replaced by a constant, zero is
+** returned.
+*/
+static int exprPartidxExprLookup(Parse *pParse, Expr *pExpr, int iTarget){
+ IndexedExpr *p;
+ for(p=pParse->pIdxPartExpr; p; p=p->pIENext){
+ if( pExpr->iColumn==p->iIdxCol && pExpr->iTable==p->iDataCur ){
+ Vdbe *v = pParse->pVdbe;
+ int addr = 0;
+ int ret;
+
+ if( p->bMaybeNullRow ){
+ addr = sqlcipher_sqlite3VdbeAddOp1(v, OP_IfNullRow, p->iIdxCur);
+ }
+ ret = sqlcipher_sqlite3ExprCodeTarget(pParse, p->pExpr, iTarget);
+ sqlcipher_sqlite3VdbeAddOp4(pParse->pVdbe, OP_Affinity, ret, 1, 0,
+ (const char*)&p->aff, 1);
+ if( addr ){
+ sqlcipher_sqlite3VdbeJumpHere(v, addr);
+ sqlcipher_sqlite3VdbeChangeP3(v, addr, ret);
+ }
+ return ret;
+ }
+ }
+ return 0;
+}
+
/*
** Generate code into the current Vdbe to evaluate the given
@@ -112912,25 +118630,44 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, i
expr_code_doover:
if( pExpr==0 ){
op = TK_NULL;
+ }else if( pParse->pIdxEpr!=0
+ && !ExprHasProperty(pExpr, EP_Leaf)
+ && (r1 = sqlcipher_sqlite3IndexedExprLookup(pParse, pExpr, target))>=0
+ ){
+ return r1;
}else{
assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
op = pExpr->op;
}
+ assert( op!=TK_ORDER );
switch( op ){
case TK_AGG_COLUMN: {
AggInfo *pAggInfo = pExpr->pAggInfo;
struct AggInfo_col *pCol;
assert( pAggInfo!=0 );
- assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ assert( pExpr->iAgg>=0 );
+ if( pExpr->iAgg>=pAggInfo->nColumn ){
+ /* Happens when the left table of a RIGHT JOIN is null and
+ ** is using an expression index */
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+#ifdef SQLITE_VDBE_COVERAGE
+ /* Verify that the OP_Null above is exercised by tests
+ ** tag-20230325-2 */
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_NotNull, target, 1, 20230325);
+ VdbeCoverageNeverTaken(v);
+#endif
+ break;
+ }
pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
- assert( pCol->iMem>0 );
- return pCol->iMem;
+ return AggInfoColumnReg(pAggInfo, pExpr->iAgg);
}else if( pAggInfo->useSortingIdx ){
Table *pTab = pCol->pTab;
sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
pCol->iSorterColumn, target);
- if( pCol->iColumn<0 ){
+ if( pTab==0 ){
+ /* No comment added */
+ }else if( pCol->iColumn<0 ){
VdbeComment((v,"%s.rowid",pTab->zName));
}else{
VdbeComment((v,"%s.%s",
@@ -112940,6 +118677,11 @@ expr_code_doover:
}
}
return target;
+ }else if( pExpr->y.pTab==0 ){
+ /* This case happens when the argument to an aggregate function
+ ** is rewritten by aggregateConvertIndexedExprRefToColumn() */
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, pExpr->iColumn, target);
+ return target;
}
/* Otherwise, fall thru into the TK_COLUMN case */
/* no break */ deliberate_fall_through
@@ -112950,20 +118692,17 @@ expr_code_doover:
if( ExprHasProperty(pExpr, EP_FixedCol) ){
/* This COLUMN expression is really a constant due to WHERE clause
** constraints, and that constant is coded by the pExpr->pLeft
- ** expresssion. However, make sure the constant has the correct
+ ** expression. However, make sure the constant has the correct
** datatype by applying the Affinity of the table column to the
** constant.
*/
int aff;
iReg = sqlcipher_sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
assert( ExprUseYTab(pExpr) );
- if( pExpr->y.pTab ){
- aff = sqlcipher_sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
- }else{
- aff = pExpr->affExpr;
- }
+ assert( pExpr->y.pTab!=0 );
+ aff = sqlcipher_sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
if( aff>SQLITE_AFF_BLOB ){
- static const char zAff[] = "B\000C\000D\000E";
+ static const char zAff[] = "B\000C\000D\000E\000F";
assert( SQLITE_AFF_BLOB=='A' );
assert( SQLITE_AFF_TEXT=='B' );
sqlcipher_sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0,
@@ -113022,13 +118761,16 @@ expr_code_doover:
iTab = pParse->iSelfTab - 1;
}
}
+ else if( pParse->pIdxPartExpr
+ && 0!=(r1 = exprPartidxExprLookup(pParse, pExpr, target))
+ ){
+ return r1;
+ }
assert( ExprUseYTab(pExpr) );
+ assert( pExpr->y.pTab!=0 );
iReg = sqlcipher_sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
pExpr->iColumn, iTab, target,
pExpr->op2);
- if( pExpr->y.pTab==0 && pExpr->affExpr==SQLITE_AFF_REAL ){
- sqlcipher_sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
- }
return iReg;
}
case TK_INTEGER: {
@@ -113081,12 +118823,6 @@ expr_code_doover:
assert( pExpr->u.zToken!=0 );
assert( pExpr->u.zToken[0]!=0 );
sqlcipher_sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
- if( pExpr->u.zToken[1]!=0 ){
- const char *z = sqlcipher_sqlite3VListNumToName(pParse->pVList, pExpr->iColumn);
- assert( pExpr->u.zToken[0]=='?' || (z && !strcmp(pExpr->u.zToken, z)) );
- pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */
- sqlcipher_sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC);
- }
return target;
}
case TK_REGISTER: {
@@ -113095,11 +118831,8 @@ expr_code_doover:
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
- inReg = sqlcipher_sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- if( inReg!=target ){
- sqlcipher_sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
+ sqlcipher_sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ assert( inReg==target );
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlcipher_sqlite3VdbeAddOp2(v, OP_Cast, target,
sqlcipher_sqlite3AffinityType(pExpr->u.zToken, 0));
@@ -113242,7 +118975,7 @@ expr_code_doover:
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlcipher_sqlite3ErrorMsg(pParse, "misuse of aggregate: %#T()", pExpr);
}else{
- return pInfo->aFunc[pExpr->iAgg].iMem;
+ return AggInfoFuncReg(pInfo, pExpr->iAgg);
}
break;
}
@@ -113263,7 +118996,9 @@ expr_code_doover:
}
#endif
- if( ConstFactorOk(pParse) && sqlcipher_sqlite3ExprIsConstantNotJoin(pExpr) ){
+ if( ConstFactorOk(pParse)
+ && sqlcipher_sqlite3ExprIsConstantNotJoin(pParse,pExpr)
+ ){
/* SQL functions can be expensive. So try to avoid running them
** multiple times if we know they always give the same result */
return sqlcipher_sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
@@ -113284,7 +119019,7 @@ expr_code_doover:
sqlcipher_sqlite3ErrorMsg(pParse, "unknown function: %#T()", pExpr);
break;
}
- if( pDef->funcFlags & SQLITE_FUNC_INLINE ){
+ if( (pDef->funcFlags & SQLITE_FUNC_INLINE)!=0 && ALWAYS(pFarg!=0) ){
assert( (pDef->funcFlags & SQLITE_FUNC_UNSAFE)==0 );
assert( (pDef->funcFlags & SQLITE_FUNC_DIRECT)==0 );
return exprCodeInlineFunction(pParse, pFarg,
@@ -113294,7 +119029,7 @@ expr_code_doover:
}
for(i=0; i<nFarg; i++){
- if( i<32 && sqlcipher_sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
+ if( i<32 && sqlcipher_sqlite3ExprIsConstant(pParse, pFarg->a[i].pExpr) ){
testcase( i==31 );
constMask |= MASKBIT32(i);
}
@@ -113310,10 +119045,10 @@ expr_code_doover:
r1 = sqlcipher_sqlite3GetTempRange(pParse, nFarg);
}
- /* For length() and typeof() functions with a column argument,
+ /* For length() and typeof() and octet_length() functions,
** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG
- ** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
- ** loading.
+ ** or OPFLAG_TYPEOFARG or OPFLAG_BYTELENARG respectively, to avoid
+ ** unnecessary data loading.
*/
if( (pDef->funcFlags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
u8 exprOp;
@@ -113323,14 +119058,16 @@ expr_code_doover:
if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
- testcase( pDef->funcFlags & OPFLAG_LENGTHARG );
- pFarg->a[0].pExpr->op2 =
- pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
+ assert( SQLITE_FUNC_BYTELEN==OPFLAG_BYTELENARG );
+ assert( (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG)==OPFLAG_BYTELENARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_LENGTHARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_TYPEOFARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_BYTELENARG);
+ pFarg->a[0].pExpr->op2 = pDef->funcFlags & OPFLAG_BYTELENARG;
}
}
- sqlcipher_sqlite3ExprCodeExprList(pParse, pFarg, r1, 0,
- SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
+ sqlcipher_sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_FACTOR);
}else{
r1 = 0;
}
@@ -113431,17 +119168,17 @@ expr_code_doover:
return target;
}
case TK_COLLATE: {
- if( !ExprHasProperty(pExpr, EP_Collate)
- && ALWAYS(pExpr->pLeft)
- && pExpr->pLeft->op==TK_FUNCTION
- ){
- inReg = sqlcipher_sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- if( inReg!=target ){
- sqlcipher_sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
- sqlcipher_sqlite3VdbeAddOp1(v, OP_ClrSubtype, inReg);
- return inReg;
+ if( !ExprHasProperty(pExpr, EP_Collate) ){
+ /* A TK_COLLATE Expr node without the EP_Collate tag is a so-called
+ ** "SOFT-COLLATE" that is added to constraints that are pushed down
+ ** from outer queries into sub-queries by the WHERE-clause push-down
+ ** optimization. Clear subtypes as subtypes may not cross a subquery
+ ** boundary.
+ */
+ assert( pExpr->pLeft );
+ sqlcipher_sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ sqlcipher_sqlite3VdbeAddOp1(v, OP_ClrSubtype, target);
+ return target;
}else{
pExpr = pExpr->pLeft;
goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. */
@@ -113527,16 +119264,34 @@ expr_code_doover:
case TK_IF_NULL_ROW: {
int addrINR;
u8 okConstFactor = pParse->okConstFactor;
- addrINR = sqlcipher_sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
- /* Temporarily disable factoring of constant expressions, since
- ** even though expressions may appear to be constant, they are not
- ** really constant because they originate from the right-hand side
- ** of a LEFT JOIN. */
- pParse->okConstFactor = 0;
- inReg = sqlcipher_sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
+ AggInfo *pAggInfo = pExpr->pAggInfo;
+ if( pAggInfo ){
+ assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ if( !pAggInfo->directMode ){
+ inReg = AggInfoColumnReg(pAggInfo, pExpr->iAgg);
+ break;
+ }
+ if( pExpr->pAggInfo->useSortingIdx ){
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
+ pAggInfo->aCol[pExpr->iAgg].iSorterColumn,
+ target);
+ inReg = target;
+ break;
+ }
+ }
+ addrINR = sqlcipher_sqlite3VdbeAddOp3(v, OP_IfNullRow, pExpr->iTable, 0, target);
+ /* The OP_IfNullRow opcode above can overwrite the result register with
+ ** NULL. So we have to ensure that the result register is not a value
+ ** that is suppose to be a constant. Two defenses are needed:
+ ** (1) Temporarily disable factoring of constant expressions
+ ** (2) Make sure the computed value really is stored in register
+ ** "target" and not someplace else.
+ */
+ pParse->okConstFactor = 0; /* note (1) above */
+ sqlcipher_sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ assert( target==inReg );
pParse->okConstFactor = okConstFactor;
sqlcipher_sqlite3VdbeJumpHere(v, addrINR);
- sqlcipher_sqlite3VdbeChangeP3(v, addrINR, inReg);
break;
}
@@ -113668,9 +119423,9 @@ expr_code_doover:
** once. If no functions are involved, then factor the code out and put it at
** the end of the prepared statement in the initialization section.
**
-** If regDest>=0 then the result is always stored in that register and the
+** If regDest>0 then the result is always stored in that register and the
** result is not reusable. If regDest<0 then this routine is free to
-** store the value whereever it wants. The register where the expression
+** store the value wherever it wants. The register where the expression
** is stored is returned. When regDest<0, two identical expressions might
** code to the same register, if they do not contain function calls and hence
** are factored out into the initialization section at the end of the
@@ -113683,6 +119438,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprCodeRunJustOnce(
){
ExprList *p;
assert( ConstFactorOk(pParse) );
+ assert( regDest!=0 );
p = pParse->pConstExpr;
if( regDest<0 && p ){
struct ExprList_item *pItem;
@@ -113741,7 +119497,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int
if( ConstFactorOk(pParse)
&& ALWAYS(pExpr!=0)
&& pExpr->op!=TK_REGISTER
- && sqlcipher_sqlite3ExprIsConstantNotJoin(pExpr)
+ && sqlcipher_sqlite3ExprIsConstantNotJoin(pParse, pExpr)
){
*pReg = 0;
r2 = sqlcipher_sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
@@ -113773,7 +119529,11 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprCode(Parse *pParse, Expr *pExpr, int ta
inReg = sqlcipher_sqlite3ExprCodeTarget(pParse, pExpr, target);
if( inReg!=target ){
u8 op;
- if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){
+ Expr *pX = sqlcipher_sqlite3ExprSkipCollateAndLikely(pExpr);
+ testcase( pX!=pExpr );
+ if( ALWAYS(pX)
+ && (ExprHasProperty(pX,EP_Subquery) || pX->op==TK_REGISTER)
+ ){
op = OP_Copy;
}else{
op = OP_SCopy;
@@ -113801,7 +119561,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, in
** might choose to code the expression at initialization time.
*/
SQLITE_PRIVATE void sqlcipher_sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
- if( pParse->okConstFactor && sqlcipher_sqlite3ExprIsConstantNotJoin(pExpr) ){
+ if( pParse->okConstFactor && sqlcipher_sqlite3ExprIsConstantNotJoin(pParse,pExpr) ){
sqlcipher_sqlite3ExprCodeRunJustOnce(pParse, pExpr, target);
}else{
sqlcipher_sqlite3ExprCodeCopy(pParse, pExpr, target);
@@ -113860,7 +119620,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprCodeExprList(
sqlcipher_sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
}
}else if( (flags & SQLITE_ECEL_FACTOR)!=0
- && sqlcipher_sqlite3ExprIsConstantNotJoin(pExpr)
+ && sqlcipher_sqlite3ExprIsConstantNotJoin(pParse,pExpr)
){
sqlcipher_sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i);
}else{
@@ -113868,7 +119628,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprCodeExprList(
if( inReg!=target+i ){
VdbeOp *pOp;
if( copyOp==OP_Copy
- && (pOp=sqlcipher_sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
+ && (pOp=sqlcipher_sqlite3VdbeGetLastOp(v))->opcode==OP_Copy
&& pOp->p1+pOp->p3+1==inReg
&& pOp->p2+pOp->p3+1==target+i
&& pOp->p5==0 /* The do-not-merge flag must be clear */
@@ -114067,6 +119827,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
r1 = sqlcipher_sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ sqlcipher_sqlite3VdbeTypeofColumn(v, r1);
sqlcipher_sqlite3VdbeAddOp2(v, op, r1, dest);
VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL);
@@ -114241,6 +120002,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int
case TK_ISNULL:
case TK_NOTNULL: {
r1 = sqlcipher_sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ sqlcipher_sqlite3VdbeTypeofColumn(v, r1);
sqlcipher_sqlite3VdbeAddOp2(v, op, r1, dest);
testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL);
testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL);
@@ -114394,7 +120156,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprCompare(
if( pB->op==TK_COLLATE && sqlcipher_sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){
return 1;
}
- return 2;
+ if( pA->op==TK_AGG_COLUMN && pB->op==TK_COLUMN
+ && pB->iTable<0 && pA->iTable==iTab
+ ){
+ /* fall through */
+ }else{
+ return 2;
+ }
}
assert( !ExprHasProperty(pA, EP_IntValue) );
assert( !ExprHasProperty(pB, EP_IntValue) );
@@ -114484,8 +120252,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprListCompare(const ExprList *pA, const Ex
*/
SQLITE_PRIVATE int sqlcipher_sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){
return sqlcipher_sqlite3ExprCompare(0,
- sqlcipher_sqlite3ExprSkipCollateAndLikely(pA),
- sqlcipher_sqlite3ExprSkipCollateAndLikely(pB),
+ sqlcipher_sqlite3ExprSkipCollate(pA),
+ sqlcipher_sqlite3ExprSkipCollate(pB),
iTab);
}
@@ -114578,7 +120346,7 @@ static int exprImpliesNotNull(
** pE1: x!=123 pE2: x IS NOT NULL Result: true
** pE1: x!=?1 pE2: x IS NOT NULL Result: true
** pE1: x IS NULL pE2: x IS NOT NULL Result: false
-** pE1: x IS ?2 pE2: x IS NOT NULL Reuslt: false
+** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
**
** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
** Expr.iTable<0 then assume a table number given by iTab.
@@ -114615,11 +120383,29 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprImpliesExpr(
return 0;
}
+/* This is a helper function to impliesNotNullRow(). In this routine,
+** set pWalker->eCode to one only if *both* of the input expressions
+** separately have the implies-not-null-row property.
+*/
+static void bothImplyNotNullRow(Walker *pWalker, Expr *pE1, Expr *pE2){
+ if( pWalker->eCode==0 ){
+ sqlcipher_sqlite3WalkExpr(pWalker, pE1);
+ if( pWalker->eCode ){
+ pWalker->eCode = 0;
+ sqlcipher_sqlite3WalkExpr(pWalker, pE2);
+ }
+ }
+}
+
/*
** This is the Expr node callback for sqlcipher_sqlite3ExprImpliesNonNullRow().
** If the expression node requires that the table at pWalker->iCur
** have one or more non-NULL column, then set pWalker->eCode to 1 and abort.
**
+** pWalker->mWFlags is non-zero if this inquiry is being undertaking on
+** behalf of a RIGHT JOIN (or FULL JOIN). That makes a difference when
+** evaluating terms in the ON clause of an inner join.
+**
** This routine controls an optimization. False positives (setting
** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives
** (never setting pWalker->eCode) is a harmless missed optimization.
@@ -114628,28 +120414,33 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_AGG_COLUMN );
testcase( pExpr->op==TK_AGG_FUNCTION );
if( ExprHasProperty(pExpr, EP_OuterON) ) return WRC_Prune;
+ if( ExprHasProperty(pExpr, EP_InnerON) && pWalker->mWFlags ){
+ /* If iCur is used in an inner-join ON clause to the left of a
+ ** RIGHT JOIN, that does *not* mean that the table must be non-null.
+ ** But it is difficult to check for that condition precisely.
+ ** To keep things simple, any use of iCur from any inner-join is
+ ** ignored while attempting to simplify a RIGHT JOIN. */
+ return WRC_Prune;
+ }
switch( pExpr->op ){
case TK_ISNOT:
case TK_ISNULL:
case TK_NOTNULL:
case TK_IS:
- case TK_OR:
case TK_VECTOR:
- case TK_CASE:
- case TK_IN:
case TK_FUNCTION:
case TK_TRUTH:
+ case TK_CASE:
testcase( pExpr->op==TK_ISNOT );
testcase( pExpr->op==TK_ISNULL );
testcase( pExpr->op==TK_NOTNULL );
testcase( pExpr->op==TK_IS );
- testcase( pExpr->op==TK_OR );
testcase( pExpr->op==TK_VECTOR );
- testcase( pExpr->op==TK_CASE );
- testcase( pExpr->op==TK_IN );
testcase( pExpr->op==TK_FUNCTION );
testcase( pExpr->op==TK_TRUTH );
+ testcase( pExpr->op==TK_CASE );
return WRC_Prune;
+
case TK_COLUMN:
if( pWalker->u.iCur==pExpr->iTable ){
pWalker->eCode = 1;
@@ -114657,21 +120448,38 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
}
return WRC_Prune;
+ case TK_OR:
case TK_AND:
- if( pWalker->eCode==0 ){
+ /* Both sides of an AND or OR must separately imply non-null-row.
+ ** Consider these cases:
+ ** 1. NOT (x AND y)
+ ** 2. x OR y
+ ** If only one of x or y is non-null-row, then the overall expression
+ ** can be true if the other arm is false (case 1) or true (case 2).
+ */
+ testcase( pExpr->op==TK_OR );
+ testcase( pExpr->op==TK_AND );
+ bothImplyNotNullRow(pWalker, pExpr->pLeft, pExpr->pRight);
+ return WRC_Prune;
+
+ case TK_IN:
+ /* Beware of "x NOT IN ()" and "x NOT IN (SELECT 1 WHERE false)",
+ ** both of which can be true. But apart from these cases, if
+ ** the left-hand side of the IN is NULL then the IN itself will be
+ ** NULL. */
+ if( ExprUseXList(pExpr) && ALWAYS(pExpr->x.pList->nExpr>0) ){
sqlcipher_sqlite3WalkExpr(pWalker, pExpr->pLeft);
- if( pWalker->eCode ){
- pWalker->eCode = 0;
- sqlcipher_sqlite3WalkExpr(pWalker, pExpr->pRight);
- }
}
return WRC_Prune;
case TK_BETWEEN:
- if( sqlcipher_sqlite3WalkExpr(pWalker, pExpr->pLeft)==WRC_Abort ){
- assert( pWalker->eCode );
- return WRC_Abort;
- }
+ /* In "x NOT BETWEEN y AND z" either x must be non-null-row or else
+ ** both y and z must be non-null row */
+ assert( ExprUseXList(pExpr) );
+ assert( pExpr->x.pList->nExpr==2 );
+ sqlcipher_sqlite3WalkExpr(pWalker, pExpr->pLeft);
+ bothImplyNotNullRow(pWalker, pExpr->x.pList->a[0].pExpr,
+ pExpr->x.pList->a[1].pExpr);
return WRC_Prune;
/* Virtual tables are allowed to use constraints like x=NULL. So
@@ -114696,10 +120504,10 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) );
assert( pRight->op!=TK_COLUMN || ExprUseYTab(pRight) );
if( (pLeft->op==TK_COLUMN
- && pLeft->y.pTab!=0
+ && ALWAYS(pLeft->y.pTab!=0)
&& IsVirtual(pLeft->y.pTab))
|| (pRight->op==TK_COLUMN
- && pRight->y.pTab!=0
+ && ALWAYS(pRight->y.pTab!=0)
&& IsVirtual(pRight->y.pTab))
){
return WRC_Prune;
@@ -114733,7 +120541,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
** be non-NULL, then the LEFT JOIN can be safely converted into an
** ordinary join.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
+SQLITE_PRIVATE int sqlcipher_sqlite3ExprImpliesNonNullRow(Expr *p, int iTab, int isRJ){
Walker w;
p = sqlcipher_sqlite3ExprSkipCollateAndLikely(p);
if( p==0 ) return 0;
@@ -114741,7 +120549,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
p = p->pLeft;
}else{
while( p->op==TK_AND ){
- if( sqlcipher_sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1;
+ if( sqlcipher_sqlite3ExprImpliesNonNullRow(p->pLeft, iTab, isRJ) ) return 1;
p = p->pRight;
}
}
@@ -114749,6 +120557,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
w.xSelectCallback = 0;
w.xSelectCallback2 = 0;
w.eCode = 0;
+ w.mWFlags = isRJ!=0;
w.u.iCur = iTab;
sqlcipher_sqlite3WalkExpr(&w, p);
return w.eCode;
@@ -114809,7 +120618,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExprCoveredByIndex(
}
-/* Structure used to pass information throught the Walker in order to
+/* Structure used to pass information throughout the Walker in order to
** implement sqlcipher_sqlite3ReferencesSrcList().
*/
struct RefSrcList {
@@ -114904,6 +120713,7 @@ static int exprRefToSrcList(Walker *pWalker, Expr *pExpr){
SQLITE_PRIVATE int sqlcipher_sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList *pSrcList){
Walker w;
struct RefSrcList x;
+ assert( pParse->db!=0 );
memset(&w, 0, sizeof(w));
memset(&x, 0, sizeof(x));
w.xExprCallback = exprRefToSrcList;
@@ -114915,12 +120725,18 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr
assert( pExpr->op==TK_AGG_FUNCTION );
assert( ExprUseXList(pExpr) );
sqlcipher_sqlite3WalkExprList(&w, pExpr->x.pList);
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ assert( pExpr->pLeft->x.pList!=0 );
+ sqlcipher_sqlite3WalkExprList(&w, pExpr->pLeft->x.pList);
+ }
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(pExpr, EP_WinFunc) ){
sqlcipher_sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
}
#endif
- sqlcipher_sqlite3DbFree(pParse->db, x.aiExclude);
+ if( x.aiExclude ) sqlcipher_sqlite3DbNNFreeNN(pParse->db, x.aiExclude);
if( w.eCode & 0x01 ){
return 1;
}else if( w.eCode ){
@@ -114938,10 +120754,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr
** it does, make a copy. This is done because the pExpr argument is
** subject to change.
**
-** The copy is stored on pParse->pConstExpr with a register number of 0.
-** This will cause the expression to be deleted automatically when the
-** Parse object is destroyed, but the zero register number means that it
-** will not generate any code in the preamble.
+** The copy is scheduled for deletion using the sqlcipher_sqlite3ExprDeferredDelete()
+** which builds on the sqlcipher_sqlite3ParserAddCleanup() mechanism.
*/
static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced))
@@ -114951,23 +120765,24 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
int iAgg = pExpr->iAgg;
Parse *pParse = pWalker->pParse;
sqlcipher_sqlite3 *db = pParse->db;
- assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION );
- if( pExpr->op==TK_AGG_COLUMN ){
- assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
- if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
+ assert( iAgg>=0 );
+ if( pExpr->op!=TK_AGG_FUNCTION ){
+ if( iAgg<pAggInfo->nColumn
+ && pAggInfo->aCol[iAgg].pCExpr==pExpr
+ ){
pExpr = sqlcipher_sqlite3ExprDup(db, pExpr, 0);
- if( pExpr ){
+ if( pExpr && !sqlcipher_sqlite3ExprDeferredDelete(pParse, pExpr) ){
pAggInfo->aCol[iAgg].pCExpr = pExpr;
- sqlcipher_sqlite3ExprDeferredDelete(pParse, pExpr);
}
}
}else{
- assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
- if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
+ assert( pExpr->op==TK_AGG_FUNCTION );
+ if( ALWAYS(iAgg<pAggInfo->nFunc)
+ && pAggInfo->aFunc[iAgg].pFExpr==pExpr
+ ){
pExpr = sqlcipher_sqlite3ExprDup(db, pExpr, 0);
- if( pExpr ){
+ if( pExpr && !sqlcipher_sqlite3ExprDeferredDelete(pParse, pExpr) ){
pAggInfo->aFunc[iAgg].pFExpr = pExpr;
- sqlcipher_sqlite3ExprDeferredDelete(pParse, pExpr);
}
}
}
@@ -115019,6 +120834,74 @@ static int addAggInfoFunc(sqlcipher_sqlite3 *db, AggInfo *pInfo){
}
/*
+** Search the AggInfo object for an aCol[] entry that has iTable and iColumn.
+** Return the index in aCol[] of the entry that describes that column.
+**
+** If no prior entry is found, create a new one and return -1. The
+** new column will have an index of pAggInfo->nColumn-1.
+*/
+static void findOrCreateAggInfoColumn(
+ Parse *pParse, /* Parsing context */
+ AggInfo *pAggInfo, /* The AggInfo object to search and/or modify */
+ Expr *pExpr /* Expr describing the column to find or insert */
+){
+ struct AggInfo_col *pCol;
+ int k;
+
+ assert( pAggInfo->iFirstReg==0 );
+ pCol = pAggInfo->aCol;
+ for(k=0; k<pAggInfo->nColumn; k++, pCol++){
+ if( pCol->pCExpr==pExpr ) return;
+ if( pCol->iTable==pExpr->iTable
+ && pCol->iColumn==pExpr->iColumn
+ && pExpr->op!=TK_IF_NULL_ROW
+ ){
+ goto fix_up_expr;
+ }
+ }
+ k = addAggInfoColumn(pParse->db, pAggInfo);
+ if( k<0 ){
+ /* OOM on resize */
+ assert( pParse->db->mallocFailed );
+ return;
+ }
+ pCol = &pAggInfo->aCol[k];
+ assert( ExprUseYTab(pExpr) );
+ pCol->pTab = pExpr->y.pTab;
+ pCol->iTable = pExpr->iTable;
+ pCol->iColumn = pExpr->iColumn;
+ pCol->iSorterColumn = -1;
+ pCol->pCExpr = pExpr;
+ if( pAggInfo->pGroupBy && pExpr->op!=TK_IF_NULL_ROW ){
+ int j, n;
+ ExprList *pGB = pAggInfo->pGroupBy;
+ struct ExprList_item *pTerm = pGB->a;
+ n = pGB->nExpr;
+ for(j=0; j<n; j++, pTerm++){
+ Expr *pE = pTerm->pExpr;
+ if( pE->op==TK_COLUMN
+ && pE->iTable==pExpr->iTable
+ && pE->iColumn==pExpr->iColumn
+ ){
+ pCol->iSorterColumn = j;
+ break;
+ }
+ }
+ }
+ if( pCol->iSorterColumn<0 ){
+ pCol->iSorterColumn = pAggInfo->nSortingColumn++;
+ }
+fix_up_expr:
+ ExprSetVVAProperty(pExpr, EP_NoReduce);
+ assert( pExpr->pAggInfo==0 || pExpr->pAggInfo==pAggInfo );
+ pExpr->pAggInfo = pAggInfo;
+ if( pExpr->op==TK_COLUMN ){
+ pExpr->op = TK_AGG_COLUMN;
+ }
+ pExpr->iAgg = (i16)k;
+}
+
+/*
** This is the xExprCallback for a tree walker. It is used to
** implement sqlcipher_sqlite3ExprAnalyzeAggregates(). See sqlcipher_sqlite3ExprAnalyzeAggregates
** for additional information.
@@ -115031,87 +120914,76 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
AggInfo *pAggInfo = pNC->uNC.pAggInfo;
assert( pNC->ncFlags & NC_UAggInfo );
+ assert( pAggInfo->iFirstReg==0 );
switch( pExpr->op ){
+ default: {
+ IndexedExpr *pIEpr;
+ Expr tmp;
+ assert( pParse->iSelfTab==0 );
+ if( (pNC->ncFlags & NC_InAggFunc)==0 ) break;
+ if( pParse->pIdxEpr==0 ) break;
+ for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){
+ int iDataCur = pIEpr->iDataCur;
+ if( iDataCur<0 ) continue;
+ if( sqlcipher_sqlite3ExprCompare(0, pExpr, pIEpr->pExpr, iDataCur)==0 ) break;
+ }
+ if( pIEpr==0 ) break;
+ if( NEVER(!ExprUseYTab(pExpr)) ) break;
+ for(i=0; i<pSrcList->nSrc; i++){
+ if( pSrcList->a[0].iCursor==pIEpr->iDataCur ) break;
+ }
+ if( i>=pSrcList->nSrc ) break;
+ if( NEVER(pExpr->pAggInfo!=0) ) break; /* Resolved by outer context */
+ if( pParse->nErr ){ return WRC_Abort; }
+
+ /* If we reach this point, it means that expression pExpr can be
+ ** translated into a reference to an index column as described by
+ ** pIEpr.
+ */
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.op = TK_AGG_COLUMN;
+ tmp.iTable = pIEpr->iIdxCur;
+ tmp.iColumn = pIEpr->iIdxCol;
+ findOrCreateAggInfoColumn(pParse, pAggInfo, &tmp);
+ if( pParse->nErr ){ return WRC_Abort; }
+ assert( pAggInfo->aCol!=0 );
+ assert( tmp.iAgg<pAggInfo->nColumn );
+ pAggInfo->aCol[tmp.iAgg].pCExpr = pExpr;
+ pExpr->pAggInfo = pAggInfo;
+ pExpr->iAgg = tmp.iAgg;
+ return WRC_Prune;
+ }
+ case TK_IF_NULL_ROW:
case TK_AGG_COLUMN:
case TK_COLUMN: {
testcase( pExpr->op==TK_AGG_COLUMN );
testcase( pExpr->op==TK_COLUMN );
+ testcase( pExpr->op==TK_IF_NULL_ROW );
/* Check to see if the column is in one of the tables in the FROM
** clause of the aggregate query */
if( ALWAYS(pSrcList!=0) ){
SrcItem *pItem = pSrcList->a;
for(i=0; i<pSrcList->nSrc; i++, pItem++){
- struct AggInfo_col *pCol;
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
if( pExpr->iTable==pItem->iCursor ){
- /* If we reach this point, it means that pExpr refers to a table
- ** that is in the FROM clause of the aggregate query.
- **
- ** Make an entry for the column in pAggInfo->aCol[] if there
- ** is not an entry there already.
- */
- int k;
- pCol = pAggInfo->aCol;
- for(k=0; k<pAggInfo->nColumn; k++, pCol++){
- if( pCol->iTable==pExpr->iTable &&
- pCol->iColumn==pExpr->iColumn ){
- break;
- }
- }
- if( (k>=pAggInfo->nColumn)
- && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0
- ){
- pCol = &pAggInfo->aCol[k];
- assert( ExprUseYTab(pExpr) );
- pCol->pTab = pExpr->y.pTab;
- pCol->iTable = pExpr->iTable;
- pCol->iColumn = pExpr->iColumn;
- pCol->iMem = ++pParse->nMem;
- pCol->iSorterColumn = -1;
- pCol->pCExpr = pExpr;
- if( pAggInfo->pGroupBy ){
- int j, n;
- ExprList *pGB = pAggInfo->pGroupBy;
- struct ExprList_item *pTerm = pGB->a;
- n = pGB->nExpr;
- for(j=0; j<n; j++, pTerm++){
- Expr *pE = pTerm->pExpr;
- if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable &&
- pE->iColumn==pExpr->iColumn ){
- pCol->iSorterColumn = j;
- break;
- }
- }
- }
- if( pCol->iSorterColumn<0 ){
- pCol->iSorterColumn = pAggInfo->nSortingColumn++;
- }
- }
- /* There is now an entry for pExpr in pAggInfo->aCol[] (either
- ** because it was there before or because we just created it).
- ** Convert the pExpr to be a TK_AGG_COLUMN referring to that
- ** pAggInfo->aCol[] entry.
- */
- ExprSetVVAProperty(pExpr, EP_NoReduce);
- pExpr->pAggInfo = pAggInfo;
- pExpr->op = TK_AGG_COLUMN;
- pExpr->iAgg = (i16)k;
+ findOrCreateAggInfoColumn(pParse, pAggInfo, pExpr);
break;
} /* endif pExpr->iTable==pItem->iCursor */
} /* end loop over pSrcList */
}
- return WRC_Prune;
+ return WRC_Continue;
}
case TK_AGG_FUNCTION: {
if( (pNC->ncFlags & NC_InAggFunc)==0
&& pWalker->walkerDepth==pExpr->op2
+ && pExpr->pAggInfo==0
){
/* Check to see if pExpr is a duplicate of another aggregate
** function that is already in the pAggInfo structure
*/
struct AggInfo_func *pItem = pAggInfo->aFunc;
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
- if( pItem->pFExpr==pExpr ) break;
+ if( NEVER(pItem->pFExpr==pExpr) ) break;
if( sqlcipher_sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
break;
}
@@ -115122,15 +120994,44 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
u8 enc = ENC(pParse->db);
i = addAggInfoFunc(pParse->db, pAggInfo);
if( i>=0 ){
+ int nArg;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pItem = &pAggInfo->aFunc[i];
pItem->pFExpr = pExpr;
- pItem->iMem = ++pParse->nMem;
assert( ExprUseUToken(pExpr) );
+ nArg = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
pItem->pFunc = sqlcipher_sqlite3FindFunction(pParse->db,
- pExpr->u.zToken,
- pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
- if( pExpr->flags & EP_Distinct ){
+ pExpr->u.zToken, nArg, enc, 0);
+ assert( pItem->bOBUnique==0 );
+ if( pExpr->pLeft
+ && (pItem->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)==0
+ ){
+ /* The NEEDCOLL test above causes any ORDER BY clause on
+ ** aggregate min() or max() to be ignored. */
+ ExprList *pOBList;
+ assert( nArg>0 );
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ pItem->iOBTab = pParse->nTab++;
+ pOBList = pExpr->pLeft->x.pList;
+ assert( pOBList->nExpr>0 );
+ assert( pItem->bOBUnique==0 );
+ if( pOBList->nExpr==1
+ && nArg==1
+ && sqlcipher_sqlite3ExprCompare(0,pOBList->a[0].pExpr,
+ pExpr->x.pList->a[0].pExpr,0)==0
+ ){
+ pItem->bOBPayload = 0;
+ pItem->bOBUnique = ExprHasProperty(pExpr, EP_Distinct);
+ }else{
+ pItem->bOBPayload = 1;
+ }
+ pItem->bUseSubtype =
+ (pItem->pFunc->funcFlags & SQLITE_SUBTYPE)!=0;
+ }else{
+ pItem->iOBTab = -1;
+ }
+ if( ExprHasProperty(pExpr, EP_Distinct) && !pItem->bOBUnique ){
pItem->iDistinct = pParse->nTab++;
}else{
pItem->iDistinct = -1;
@@ -115255,6 +121156,37 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ClearTempRegCache(Parse *pParse){
}
/*
+** Make sure sufficient registers have been allocated so that
+** iReg is a valid register number.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3TouchRegister(Parse *pParse, int iReg){
+ if( pParse->nMem<iReg ) pParse->nMem = iReg;
+}
+
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
+/*
+** Return the latest reusable register in the set of all registers.
+** The value returned is no less than iMin. If any register iMin or
+** greater is in permanent use, then return one more than that last
+** permanent register.
+*/
+SQLITE_PRIVATE int sqlcipher_sqlite3FirstAvailableRegister(Parse *pParse, int iMin){
+ const ExprList *pList = pParse->pConstExpr;
+ if( pList ){
+ int i;
+ for(i=0; i<pList->nExpr; i++){
+ if( pList->a[i].u.iConstExprReg>=iMin ){
+ iMin = pList->a[i].u.iConstExprReg + 1;
+ }
+ }
+ }
+ pParse->nTempReg = 0;
+ pParse->nRangeReg = 0;
+ return iMin;
+}
+#endif /* SQLITE_ENABLE_STAT4 || SQLITE_DEBUG */
+
+/*
** Validate that no temporary register falls within the range of
** iFirst..iLast, inclusive. This routine is only call from within assert()
** statements.
@@ -115273,6 +121205,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3NoTempsInRange(Parse *pParse, int iFirst, in
return 0;
}
}
+ if( pParse->pConstExpr ){
+ ExprList *pList = pParse->pConstExpr;
+ for(i=0; i<pList->nExpr; i++){
+ int iReg = pList->a[i].u.iConstExprReg;
+ if( iReg==0 ) continue;
+ if( iReg>=iFirst && iReg<=iLast ) return 0;
+ }
+ }
return 1;
}
#endif /* SQLITE_DEBUG */
@@ -115727,14 +121667,19 @@ SQLITE_PRIVATE void sqlcipher_sqlite3AlterFinishAddColumn(Parse *pParse, Token *
/* Verify that constraints are still satisfied */
if( pNew->pCheck!=0
|| (pCol->notNull && (pCol->colFlags & COLFLAG_GENERATED)!=0)
+ || (pTab->tabFlags & TF_Strict)!=0
){
sqlcipher_sqlite3NestedParse(pParse,
"SELECT CASE WHEN quick_check GLOB 'CHECK*'"
" THEN raise(ABORT,'CHECK constraint failed')"
+ " WHEN quick_check GLOB 'non-* value in*'"
+ " THEN raise(ABORT,'type mismatch on DEFAULT')"
" ELSE raise(ABORT,'NOT NULL constraint failed')"
" END"
" FROM pragma_quick_check(%Q,%Q)"
- " WHERE quick_check GLOB 'CHECK*' OR quick_check GLOB 'NULL*'",
+ " WHERE quick_check GLOB 'CHECK*'"
+ " OR quick_check GLOB 'NULL*'"
+ " OR quick_check GLOB 'non-* value in*'",
zTab, zDb
);
}
@@ -115823,7 +121768,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3AlterBeginAddColumn(Parse *pParse, SrcList
pNew->u.tab.pDfltList = sqlcipher_sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0);
pNew->pSchema = db->aDb[iDb].pSchema;
pNew->u.tab.addColOffset = pTab->u.tab.addColOffset;
- pNew->nTabRef = 1;
+ assert( pNew->nTabRef==1 );
exit_begin_add_column:
sqlcipher_sqlite3SrcListDelete(db, pSrc);
@@ -116022,13 +121967,14 @@ static void renameTokenCheckAll(Parse *pParse, const void *pPtr){
assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 );
if( pParse->nErr==0 ){
const RenameToken *p;
- u8 i = 0;
+ u32 i = 1;
for(p=pParse->pRename; p; p=p->pNext){
if( p->p ){
assert( p->p!=pPtr );
- i += *(u8*)(p->p);
+ i += *(u8*)(p->p) | 1;
}
}
+ assert( i>0 );
}
}
#else
@@ -116327,7 +122273,7 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
}
/*
-** An error occured while parsing or otherwise processing a database
+** An error occurred while parsing or otherwise processing a database
** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an
** ALTER TABLE RENAME COLUMN program. The error message emitted by the
** sub-routine is currently stored in pParse->zErrMsg. This function
@@ -116560,6 +122506,19 @@ static int renameEditSql(
}
/*
+** Set all pEList->a[].fg.eEName fields in the expression-list to val.
+*/
+static void renameSetENames(ExprList *pEList, int val){
+ if( pEList ){
+ int i;
+ for(i=0; i<pEList->nExpr; i++){
+ assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME );
+ pEList->a[i].fg.eEName = val;
+ }
+ }
+}
+
+/*
** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming
** it was read from the schema of database zDb. Return SQLITE_OK if
** successful. Otherwise, return an SQLite error code and leave an error
@@ -116582,7 +122541,7 @@ static int renameResolveTrigger(Parse *pParse){
/* ALWAYS() because if the table of the trigger does not exist, the
** error would have been hit before this point */
if( ALWAYS(pParse->pTriggerTab) ){
- rc = sqlcipher_sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab);
+ rc = sqlcipher_sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab)!=0;
}
/* Resolve symbols in WHEN clause */
@@ -116606,7 +122565,17 @@ static int renameResolveTrigger(Parse *pParse){
pSrc = 0;
rc = SQLITE_NOMEM;
}else{
+ /* pStep->pExprList contains an expression-list used for an UPDATE
+ ** statement. So the a[].zEName values are the RHS of the
+ ** "<col> = <expr>" clauses of the UPDATE statement. So, before
+ ** running SelectPrep(), change all the eEName values in
+ ** pStep->pExprList to ENAME_SPAN (from their current value of
+ ** ENAME_NAME). This is to prevent any ids in ON() clauses that are
+ ** part of pSrc from being incorrectly resolved against the
+ ** a[].zEName values as if they were column aliases. */
+ renameSetENames(pStep->pExprList, ENAME_SPAN);
sqlcipher_sqlite3SelectPrep(pParse, pSel, 0);
+ renameSetENames(pStep->pExprList, ENAME_NAME);
rc = pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
assert( pStep->pExprList==0 || pStep->pExprList==pSel->pEList );
assert( pSrc==pSel->pSrc );
@@ -117514,7 +123483,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3AlterDropColumn(Parse *pParse, SrcList *pSr
if( i==pTab->iPKey ){
sqlcipher_sqlite3VdbeAddOp2(v, OP_Null, 0, regOut);
}else{
+ char aff = pTab->aCol[i].affinity;
+ if( aff==SQLITE_AFF_REAL ){
+ pTab->aCol[i].affinity = SQLITE_AFF_NUMERIC;
+ }
sqlcipher_sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
+ pTab->aCol[i].affinity = aff;
}
nField++;
}
@@ -117825,9 +123799,9 @@ static void openStatTable(
typedef struct StatAccum StatAccum;
typedef struct StatSample StatSample;
struct StatSample {
- tRowcnt *anEq; /* sqlite_stat4.nEq */
tRowcnt *anDLt; /* sqlite_stat4.nDLt */
#ifdef SQLITE_ENABLE_STAT4
+ tRowcnt *anEq; /* sqlite_stat4.nEq */
tRowcnt *anLt; /* sqlite_stat4.nLt */
union {
i64 iRowid; /* Rowid in main table of the key */
@@ -117985,9 +123959,9 @@ static void statInit(
/* Allocate the space required for the StatAccum object */
n = sizeof(*p)
- + sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
- + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
+ + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
#ifdef SQLITE_ENABLE_STAT4
+ n += sizeof(tRowcnt)*nColUp; /* StatAccum.anEq */
if( mxSample ){
n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
+ sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
@@ -118008,9 +123982,9 @@ static void statInit(
p->nKeyCol = nKeyCol;
p->nSkipAhead = 0;
p->current.anDLt = (tRowcnt*)&p[1];
- p->current.anEq = &p->current.anDLt[nColUp];
#ifdef SQLITE_ENABLE_STAT4
+ p->current.anEq = &p->current.anDLt[nColUp];
p->mxSample = p->nLimit==0 ? mxSample : 0;
if( mxSample ){
u8 *pSpace; /* Allocated space not yet assigned */
@@ -118277,7 +124251,9 @@ static void statPush(
if( p->nRow==0 ){
/* This is the first call to this function. Do initialization. */
+#ifdef SQLITE_ENABLE_STAT4
for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
+#endif
}else{
/* Second and subsequent calls get processed here */
#ifdef SQLITE_ENABLE_STAT4
@@ -118286,15 +124262,17 @@ static void statPush(
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
** to the current row of the index. */
+#ifdef SQLITE_ENABLE_STAT4
for(i=0; i<iChng; i++){
p->current.anEq[i]++;
}
+#endif
for(i=iChng; i<p->nCol; i++){
p->current.anDLt[i]++;
#ifdef SQLITE_ENABLE_STAT4
if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i];
-#endif
p->current.anEq[i] = 1;
+#endif
}
}
@@ -118428,7 +124406,9 @@ static void statGet(
u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1;
sqlcipher_sqlite3_str_appendf(&sStat, " %llu", iVal);
- assert( p->current.anEq[i] );
+#ifdef SQLITE_ENABLE_STAT4
+ assert( p->current.anEq[i] || p->nRow==0 );
+#endif
}
sqlcipher_sqlite3ResultStrAccum(context, &sStat);
}
@@ -118514,6 +124494,7 @@ static void analyzeVdbeCommentIndexWithColumnName(
if( NEVER(i==XN_ROWID) ){
VdbeComment((v,"%s.rowid",pIdx->zName));
}else if( i==XN_EXPR ){
+ assert( pIdx->bHasExpr );
VdbeComment((v,"%s.expr(%d)",pIdx->zName, k));
}else{
VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zCnName));
@@ -118554,11 +124535,15 @@ static void analyzeOneTable(
int regIdxname = iMem++; /* Register containing index name */
int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */
int regPrev = iMem; /* MUST BE LAST (see below) */
+#ifdef SQLITE_ENABLE_STAT4
+ int doOnce = 1; /* Flag for a one-time computation */
+#endif
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
Table *pStat1 = 0;
#endif
- pParse->nMem = MAX(pParse->nMem, iMem);
+ sqlcipher_sqlite3TouchRegister(pParse, iMem);
+ assert( sqlcipher_sqlite3NoTempsInRange(pParse, regNewRowid, iMem) );
v = sqlcipher_sqlite3GetVdbe(pParse);
if( v==0 || NEVER(pTab==0) ){
return;
@@ -118607,7 +124592,7 @@ static void analyzeOneTable(
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int nCol; /* Number of columns in pIdx. "N" */
- int addrRewind; /* Address of "OP_Rewind iIdxCur" */
+ int addrGotoEnd; /* Address of "OP_Rewind iIdxCur" */
int addrNextRow; /* Address of "next_row:" */
const char *zIdxName; /* Name of the index */
int nColTest; /* Number of columns to test for changes */
@@ -118631,9 +124616,14 @@ static void analyzeOneTable(
/*
** Pseudo-code for loop that calls stat_push():
**
- ** Rewind csr
- ** if eof(csr) goto end_of_scan;
** regChng = 0
+ ** Rewind csr
+ ** if eof(csr){
+ ** stat_init() with count = 0;
+ ** goto end_of_scan;
+ ** }
+ ** count()
+ ** stat_init()
** goto chng_addr_0;
**
** next_row:
@@ -118664,7 +124654,7 @@ static void analyzeOneTable(
** the regPrev array and a trailing rowid (the rowid slot is required
** when building a record to insert into the sample column of
** the sqlite_stat4 table. */
- pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
+ sqlcipher_sqlite3TouchRegister(pParse, regPrev+nColTest);
/* Open a read-only cursor on the index being analyzed. */
assert( iDb==sqlcipher_sqlite3SchemaToIndex(db, pIdx->pSchema) );
@@ -118672,41 +124662,36 @@ static void analyzeOneTable(
sqlcipher_sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
- /* Invoke the stat_init() function. The arguments are:
+ /* Implementation of the following:
**
+ ** regChng = 0
+ ** Rewind csr
+ ** if eof(csr){
+ ** stat_init() with count = 0;
+ ** goto end_of_scan;
+ ** }
+ ** count()
+ ** stat_init()
+ ** goto chng_addr_0;
+ */
+ assert( regTemp2==regStat+4 );
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
+
+ /* Arguments to stat_init():
** (1) the number of columns in the index including the rowid
** (or for a WITHOUT ROWID table, the number of PK columns),
** (2) the number of columns in the key without the rowid/pk
- ** (3) estimated number of rows in the index,
- */
+ ** (3) estimated number of rows in the index. */
sqlcipher_sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1);
assert( regRowid==regStat+2 );
sqlcipher_sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid);
-#ifdef SQLITE_ENABLE_STAT4
- if( OptimizationEnabled(db, SQLITE_Stat4) ){
- sqlcipher_sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp);
- addrRewind = sqlcipher_sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
- VdbeCoverage(v);
- }else
-#endif
- {
- addrRewind = sqlcipher_sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
- VdbeCoverage(v);
- sqlcipher_sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1);
- }
- assert( regTemp2==regStat+4 );
- sqlcipher_sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp,
+ OptimizationDisabled(db, SQLITE_Stat4));
sqlcipher_sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4,
&statInitFuncdef, 0);
+ addrGotoEnd = sqlcipher_sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
+ VdbeCoverage(v);
- /* Implementation of the following:
- **
- ** Rewind csr
- ** if eof(csr) goto end_of_scan;
- ** regChng = 0
- ** goto next_push_0;
- **
- */
sqlcipher_sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
addrNextRow = sqlcipher_sqlite3VdbeCurrentAddr(v);
@@ -118813,6 +124798,12 @@ static void analyzeOneTable(
}
/* Add the entry to the stat1 table. */
+ if( pIdx->pPartIdxWhere ){
+ /* Partial indexes might get a zero-entry in sqlite_stat1. But
+ ** an empty table is omitted from sqlite_stat1. */
+ sqlcipher_sqlite3VdbeJumpHere(v, addrGotoEnd);
+ addrGotoEnd = 0;
+ }
callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1);
assert( "BBB"[0]==SQLITE_AFF_TEXT );
sqlcipher_sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
@@ -118836,7 +124827,42 @@ static void analyzeOneTable(
int addrIsNull;
u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
- pParse->nMem = MAX(pParse->nMem, regCol+nCol);
+ /* No STAT4 data is generated if the number of rows is zero */
+ if( addrGotoEnd==0 ){
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_Cast, regStat1, SQLITE_AFF_INTEGER);
+ addrGotoEnd = sqlcipher_sqlite3VdbeAddOp1(v, OP_IfNot, regStat1);
+ VdbeCoverage(v);
+ }
+
+ if( doOnce ){
+ int mxCol = nCol;
+ Index *pX;
+
+ /* Compute the maximum number of columns in any index */
+ for(pX=pTab->pIndex; pX; pX=pX->pNext){
+ int nColX; /* Number of columns in pX */
+ if( !HasRowid(pTab) && IsPrimaryKeyIndex(pX) ){
+ nColX = pX->nKeyCol;
+ }else{
+ nColX = pX->nColumn;
+ }
+ if( nColX>mxCol ) mxCol = nColX;
+ }
+
+ /* Allocate space to compute results for the largest index */
+ sqlcipher_sqlite3TouchRegister(pParse, regCol+mxCol);
+ doOnce = 0;
+#ifdef SQLITE_DEBUG
+ /* Verify that the call to sqlcipher_sqlite3ClearTempRegCache() below
+ ** really is needed.
+ ** https://sqlite.org/forum/forumpost/83cb4a95a0 (2023-03-25)
+ */
+ testcase( !sqlcipher_sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
+#endif
+ sqlcipher_sqlite3ClearTempRegCache(pParse); /* tag-20230325-1 */
+ assert( sqlcipher_sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
+ }
+ assert( sqlcipher_sqlite3NoTempsInRange(pParse, regEq, regCol+nCol) );
addrNext = sqlcipher_sqlite3VdbeCurrentAddr(v);
callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
@@ -118860,7 +124886,7 @@ static void analyzeOneTable(
#endif /* SQLITE_ENABLE_STAT4 */
/* End of analysis */
- sqlcipher_sqlite3VdbeJumpHere(v, addrRewind);
+ if( addrGotoEnd ) sqlcipher_sqlite3VdbeJumpHere(v, addrGotoEnd);
}
@@ -118917,6 +124943,11 @@ static void analyzeDatabase(Parse *pParse, int iDb){
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab);
+#ifdef SQLITE_ENABLE_STAT4
+ iMem = sqlcipher_sqlite3FirstAvailableRegister(pParse, iMem);
+#else
+ assert( iMem==sqlcipher_sqlite3FirstAvailableRegister(pParse,iMem) );
+#endif
}
loadAnalysis(pParse, iDb);
}
@@ -119079,6 +125110,16 @@ static void decodeIntArray(
while( z[0]!=0 && z[0]!=' ' ) z++;
while( z[0]==' ' ) z++;
}
+
+ /* Set the bLowQual flag if the peak number of rows obtained
+ ** from a full equality match is so large that a full table scan
+ ** seems likely to be faster than using the index.
+ */
+ if( aLog[0] > 66 /* Index has more than 100 rows */
+ && aLog[0] <= aLog[nOut-1] /* And only a single value seen */
+ ){
+ pIndex->bLowQual = 1;
+ }
}
}
@@ -119157,6 +125198,8 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
** and its contents.
*/
SQLITE_PRIVATE void sqlcipher_sqlite3DeleteIndexSamples(sqlcipher_sqlite3 *db, Index *pIdx){
+ assert( db!=0 );
+ assert( pIdx!=0 );
#ifdef SQLITE_ENABLE_STAT4
if( pIdx->aSample ){
int j;
@@ -119166,7 +125209,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3DeleteIndexSamples(sqlcipher_sqlite3 *db, I
}
sqlcipher_sqlite3DbFree(db, pIdx->aSample);
}
- if( db && db->pnBytesFreed==0 ){
+ if( db->pnBytesFreed==0 ){
pIdx->nSample = 0;
pIdx->aSample = 0;
}
@@ -119302,6 +125345,10 @@ static int loadStatTbl(
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
assert( pIdx==0 || pIdx->nSample==0 );
if( pIdx==0 ) continue;
+ if( pIdx->aSample!=0 ){
+ /* The same index appears in sqlite_stat4 under multiple names */
+ continue;
+ }
assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
nIdxCol = pIdx->nKeyCol;
@@ -119309,6 +125356,7 @@ static int loadStatTbl(
nIdxCol = pIdx->nColumn;
}
pIdx->nSampleCol = nIdxCol;
+ pIdx->mxSample = nSample;
nByte = sizeof(IndexSample) * nSample;
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
@@ -119348,6 +125396,11 @@ static int loadStatTbl(
if( zIndex==0 ) continue;
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
if( pIdx==0 ) continue;
+ if( pIdx->nSample>=pIdx->mxSample ){
+ /* Too many slots used because the same index appears in
+ ** sqlite_stat4 using multiple names */
+ continue;
+ }
/* This next condition is true if data has already been loaded from
** the sqlite_stat4 table. */
nCol = pIdx->nSampleCol;
@@ -119360,14 +125413,15 @@ static int loadStatTbl(
decodeIntArray((char*)sqlcipher_sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0);
decodeIntArray((char*)sqlcipher_sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0);
- /* Take a copy of the sample. Add two 0x00 bytes the end of the buffer.
+ /* Take a copy of the sample. Add 8 extra 0x00 bytes the end of the buffer.
** This is in case the sample record is corrupted. In that case, the
** sqlcipher_sqlite3VdbeRecordCompare() may read up to two varints past the
** end of the allocated buffer before it realizes it is dealing with
- ** a corrupt record. Adding the two 0x00 bytes prevents this from causing
+ ** a corrupt record. Or it might try to read a large integer from the
+ ** buffer. In any case, eight 0x00 bytes prevents this from causing
** a buffer overread. */
pSample->n = sqlcipher_sqlite3_column_bytes(pStmt, 4);
- pSample->p = sqlcipher_sqlite3DbMallocZero(db, pSample->n + 2);
+ pSample->p = sqlcipher_sqlite3DbMallocZero(db, pSample->n + 8);
if( pSample->p==0 ){
sqlcipher_sqlite3_finalize(pStmt);
return SQLITE_NOMEM_BKPT;
@@ -119391,11 +125445,12 @@ static int loadStat4(sqlcipher_sqlite3 *db, const char *zDb){
const Table *pStat4;
assert( db->lookaside.bDisable );
- if( (pStat4 = sqlcipher_sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
+ if( OptimizationEnabled(db, SQLITE_Stat4)
+ && (pStat4 = sqlcipher_sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
&& IsOrdinaryTable(pStat4)
){
rc = loadStatTbl(db,
- "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
+ "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx COLLATE nocase",
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
zDb
);
@@ -119585,7 +125640,7 @@ static void attachFunc(
char *zErr = 0;
unsigned int flags;
Db *aNew; /* New array of Db pointers */
- Db *pNew; /* Db object for the newly attached database */
+ Db *pNew = 0; /* Db object for the newly attached database */
char *zErrDyn = 0;
sqlcipher_sqlite3_vfs *pVfs;
@@ -119605,13 +125660,26 @@ static void attachFunc(
/* This is not a real ATTACH. Instead, this routine is being called
** from sqlcipher_sqlite3_deserialize() to close database db->init.iDb and
** reopen it as a MemDB */
+ Btree *pNewBt = 0;
pVfs = sqlcipher_sqlite3_vfs_find("memdb");
if( pVfs==0 ) return;
- pNew = &db->aDb[db->init.iDb];
- if( pNew->pBt ) sqlcipher_sqlite3BtreeClose(pNew->pBt);
- pNew->pBt = 0;
- pNew->pSchema = 0;
- rc = sqlcipher_sqlite3BtreeOpen(pVfs, "x\0", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB);
+ rc = sqlcipher_sqlite3BtreeOpen(pVfs, "x\0", db, &pNewBt, 0, SQLITE_OPEN_MAIN_DB);
+ if( rc==SQLITE_OK ){
+ Schema *pNewSchema = sqlcipher_sqlite3SchemaGet(db, pNewBt);
+ if( pNewSchema ){
+ /* Both the Btree and the new Schema were allocated successfully.
+ ** Close the old db and update the aDb[] slot with the new memdb
+ ** values. */
+ pNew = &db->aDb[db->init.iDb];
+ if( ALWAYS(pNew->pBt) ) sqlcipher_sqlite3BtreeClose(pNew->pBt);
+ pNew->pBt = pNewBt;
+ pNew->pSchema = pNewSchema;
+ }else{
+ sqlcipher_sqlite3BtreeClose(pNewBt);
+ rc = SQLITE_NOMEM;
+ }
+ }
+ if( rc ) goto attach_error;
}else{
/* This is a real ATTACH
**
@@ -119761,7 +125829,7 @@ static void attachFunc(
}
#endif
if( rc ){
- if( !REOPEN_AS_MEMDB(db) ){
+ if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){
int iDb = db->nDb - 1;
assert( iDb>=2 );
if( db->aDb[iDb].pBt ){
@@ -119878,6 +125946,8 @@ static void codeAttach(
sqlcipher_sqlite3* db = pParse->db;
int regArgs;
+ if( SQLITE_OK!=sqlcipher_sqlite3ReadSchema(pParse) ) goto attach_end;
+
if( pParse->nErr ) goto attach_end;
memset(&sName, 0, sizeof(NameContext));
sName.pParse = pParse;
@@ -120346,7 +126416,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3AuthCheck(
sqlcipher_sqlite3 *db = pParse->db;
int rc;
- /* Don't do any authorization checks if the database is initialising
+ /* Don't do any authorization checks if the database is initializing
** or if the parser is being invoked from within sqlcipher_sqlite3_declare_vtab.
*/
assert( !IN_RENAME_OBJECT || db->xAuth==0 );
@@ -120553,6 +126623,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3DbMaskAllZero(yDbMask m){
SQLITE_PRIVATE void sqlcipher_sqlite3FinishCoding(Parse *pParse){
sqlcipher_sqlite3 *db;
Vdbe *v;
+ int iDb, i;
assert( pParse->pToplevel==0 );
db = pParse->db;
@@ -120582,7 +126653,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3FinishCoding(Parse *pParse){
if( pParse->bReturning ){
Returning *pReturning = pParse->u1.pReturning;
int addrRewind;
- int i;
int reg;
if( pReturning->nRetCol ){
@@ -120602,7 +126672,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3FinishCoding(Parse *pParse){
}
sqlcipher_sqlite3VdbeAddOp0(v, OP_Halt);
-#if SQLITE_USER_AUTHENTICATION
+#if SQLITE_USER_AUTHENTICATION && !defined(SQLITE_OMIT_SHARED_CACHE)
if( pParse->nTableLock>0 && db->init.busy==0 ){
sqlcipher_sqlite3UserAuthInit(db);
if( db->auth.authLevel<UAUTH_User ){
@@ -120619,76 +126689,66 @@ SQLITE_PRIVATE void sqlcipher_sqlite3FinishCoding(Parse *pParse){
** transaction on each used database and to verify the schema cookie
** on each used database.
*/
- if( db->mallocFailed==0
- && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr)
- ){
- int iDb, i;
- assert( sqlcipher_sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
- sqlcipher_sqlite3VdbeJumpHere(v, 0);
- assert( db->nDb>0 );
- iDb = 0;
- do{
- Schema *pSchema;
- if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
- sqlcipher_sqlite3VdbeUsesBtree(v, iDb);
- pSchema = db->aDb[iDb].pSchema;
- sqlcipher_sqlite3VdbeAddOp4Int(v,
- OP_Transaction, /* Opcode */
- iDb, /* P1 */
- DbMaskTest(pParse->writeMask,iDb), /* P2 */
- pSchema->schema_cookie, /* P3 */
- pSchema->iGeneration /* P4 */
- );
- if( db->init.busy==0 ) sqlcipher_sqlite3VdbeChangeP5(v, 1);
- VdbeComment((v,
- "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
- }while( ++iDb<db->nDb );
+ assert( pParse->nErr>0 || sqlcipher_sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
+ sqlcipher_sqlite3VdbeJumpHere(v, 0);
+ assert( db->nDb>0 );
+ iDb = 0;
+ do{
+ Schema *pSchema;
+ if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
+ sqlcipher_sqlite3VdbeUsesBtree(v, iDb);
+ pSchema = db->aDb[iDb].pSchema;
+ sqlcipher_sqlite3VdbeAddOp4Int(v,
+ OP_Transaction, /* Opcode */
+ iDb, /* P1 */
+ DbMaskTest(pParse->writeMask,iDb), /* P2 */
+ pSchema->schema_cookie, /* P3 */
+ pSchema->iGeneration /* P4 */
+ );
+ if( db->init.busy==0 ) sqlcipher_sqlite3VdbeChangeP5(v, 1);
+ VdbeComment((v,
+ "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
+ }while( ++iDb<db->nDb );
#ifndef SQLITE_OMIT_VIRTUALTABLE
- for(i=0; i<pParse->nVtabLock; i++){
- char *vtab = (char *)sqlcipher_sqlite3GetVTable(db, pParse->apVtabLock[i]);
- sqlcipher_sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
- }
- pParse->nVtabLock = 0;
+ for(i=0; i<pParse->nVtabLock; i++){
+ char *vtab = (char *)sqlcipher_sqlite3GetVTable(db, pParse->apVtabLock[i]);
+ sqlcipher_sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
+ }
+ pParse->nVtabLock = 0;
#endif
- /* Once all the cookies have been verified and transactions opened,
- ** obtain the required table-locks. This is a no-op unless the
- ** shared-cache feature is enabled.
- */
- codeTableLocks(pParse);
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ /* Once all the cookies have been verified and transactions opened,
+ ** obtain the required table-locks. This is a no-op unless the
+ ** shared-cache feature is enabled.
+ */
+ if( pParse->nTableLock ) codeTableLocks(pParse);
+#endif
- /* Initialize any AUTOINCREMENT data structures required.
- */
- sqlcipher_sqlite3AutoincrementBegin(pParse);
+ /* Initialize any AUTOINCREMENT data structures required.
+ */
+ if( pParse->pAinc ) sqlcipher_sqlite3AutoincrementBegin(pParse);
- /* Code constant expressions that where factored out of inner loops.
- **
- ** The pConstExpr list might also contain expressions that we simply
- ** want to keep around until the Parse object is deleted. Such
- ** expressions have iConstExprReg==0. Do not generate code for
- ** those expressions, of course.
- */
- if( pParse->pConstExpr ){
- ExprList *pEL = pParse->pConstExpr;
- pParse->okConstFactor = 0;
- for(i=0; i<pEL->nExpr; i++){
- int iReg = pEL->a[i].u.iConstExprReg;
- if( iReg>0 ){
- sqlcipher_sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
- }
- }
+ /* Code constant expressions that were factored out of inner loops.
+ */
+ if( pParse->pConstExpr ){
+ ExprList *pEL = pParse->pConstExpr;
+ pParse->okConstFactor = 0;
+ for(i=0; i<pEL->nExpr; i++){
+ assert( pEL->a[i].u.iConstExprReg>0 );
+ sqlcipher_sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
}
+ }
- if( pParse->bReturning ){
- Returning *pRet = pParse->u1.pReturning;
- if( pRet->nRetCol ){
- sqlcipher_sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
- }
+ if( pParse->bReturning ){
+ Returning *pRet = pParse->u1.pReturning;
+ if( pRet->nRetCol ){
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
}
-
- /* Finally, jump back to the beginning of the executable code. */
- sqlcipher_sqlite3VdbeGoto(v, 1);
}
+
+ /* Finally, jump back to the beginning of the executable code. */
+ sqlcipher_sqlite3VdbeGoto(v, 1);
}
/* Get the VDBE program ready for execution
@@ -120727,6 +126787,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3NestedParse(Parse *pParse, const char *zFor
char saveBuf[PARSE_TAIL_SZ];
if( pParse->nErr ) return;
+ if( pParse->eParseMode ) return;
assert( pParse->nested<10 ); /* Nesting should only be of limited depth */
va_start(ap, zFormat);
zSql = sqlcipher_sqlite3VMPrintf(db, zFormat, ap);
@@ -120873,7 +126934,7 @@ SQLITE_PRIVATE Table *sqlcipher_sqlite3LocateTable(
/* If zName is the not the name of a table in the schema created using
** CREATE, then check to see if it is the name of an virtual table that
** can be an eponymous virtual table. */
- if( pParse->disableVtab==0 && db->init.busy==0 ){
+ if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){
Module *pMod = (Module*)sqlcipher_sqlite3HashFind(&db->aModule, zName);
if( pMod==0 && sqlcipher_sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
pMod = sqlcipher_sqlite3PragmaVtabRegister(db, zName);
@@ -120886,7 +126947,7 @@ SQLITE_PRIVATE Table *sqlcipher_sqlite3LocateTable(
#endif
if( flags & LOCATE_NOERR ) return 0;
pParse->checkSchema = 1;
- }else if( IsVirtual(p) && pParse->disableVtab ){
+ }else if( IsVirtual(p) && (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)!=0 ){
p = 0;
}
@@ -121142,7 +127203,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ColumnSetExpr(
*/
SQLITE_PRIVATE Expr *sqlcipher_sqlite3ColumnExpr(Table *pTab, Column *pCol){
if( pCol->iDflt==0 ) return 0;
- if( NEVER(!IsOrdinaryTable(pTab)) ) return 0;
+ if( !IsOrdinaryTable(pTab) ) return 0;
if( NEVER(pTab->u.tab.pDfltList==0) ) return 0;
if( NEVER(pTab->u.tab.pDfltList->nExpr<pCol->iDflt) ) return 0;
return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
@@ -121174,7 +127235,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ColumnSetColl(
}
/*
-** Return the collating squence name for a column
+** Return the collating sequence name for a column
*/
SQLITE_PRIVATE const char *sqlcipher_sqlite3ColumnColl(Column *pCol){
const char *z;
@@ -121195,16 +127256,17 @@ SQLITE_PRIVATE void sqlcipher_sqlite3DeleteColumnNames(sqlcipher_sqlite3 *db, Ta
int i;
Column *pCol;
assert( pTable!=0 );
+ assert( db!=0 );
if( (pCol = pTable->aCol)!=0 ){
for(i=0; i<pTable->nCol; i++, pCol++){
assert( pCol->zCnName==0 || pCol->hName==sqlcipher_sqlite3StrIHash(pCol->zCnName) );
sqlcipher_sqlite3DbFree(db, pCol->zCnName);
}
- sqlcipher_sqlite3DbFree(db, pTable->aCol);
+ sqlcipher_sqlite3DbNNFreeNN(db, pTable->aCol);
if( IsOrdinaryTable(pTable) ){
sqlcipher_sqlite3ExprListDelete(db, pTable->u.tab.pDfltList);
}
- if( db==0 || db->pnBytesFreed==0 ){
+ if( db->pnBytesFreed==0 ){
pTable->aCol = 0;
pTable->nCol = 0;
if( IsOrdinaryTable(pTable) ){
@@ -121241,7 +127303,8 @@ static void SQLITE_NOINLINE deleteTable(sqlcipher_sqlite3 *db, Table *pTable){
** a Table object that was going to be marked ephemeral. So do not check
** that no lookaside memory is used in this case either. */
int nLookaside = 0;
- if( db && !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){
+ assert( db!=0 );
+ if( !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){
nLookaside = sqlcipher_sqlite3LookasideUsed(db, 0);
}
#endif
@@ -121251,7 +127314,7 @@ static void SQLITE_NOINLINE deleteTable(sqlcipher_sqlite3 *db, Table *pTable){
pNext = pIndex->pNext;
assert( pIndex->pSchema==pTable->pSchema
|| (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) );
- if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){
+ if( db->pnBytesFreed==0 && !IsVirtual(pTable) ){
char *zName = pIndex->zName;
TESTONLY ( Index *pOld = ) sqlcipher_sqlite3HashInsert(
&pIndex->pSchema->idxHash, zName, 0
@@ -121265,7 +127328,7 @@ static void SQLITE_NOINLINE deleteTable(sqlcipher_sqlite3 *db, Table *pTable){
if( IsOrdinaryTable(pTable) ){
sqlcipher_sqlite3FkDelete(db, pTable);
}
-#ifndef SQLITE_OMIT_VIRTUAL_TABLE
+#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( IsVirtual(pTable) ){
sqlcipher_sqlite3VtabClear(db, pTable);
}
@@ -121288,10 +127351,14 @@ static void SQLITE_NOINLINE deleteTable(sqlcipher_sqlite3 *db, Table *pTable){
}
SQLITE_PRIVATE void sqlcipher_sqlite3DeleteTable(sqlcipher_sqlite3 *db, Table *pTable){
/* Do not delete the table until the reference count reaches zero. */
+ assert( db!=0 );
if( !pTable ) return;
- if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return;
+ if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return;
deleteTable(db, pTable);
}
+SQLITE_PRIVATE void sqlcipher_sqlite3DeleteTableGeneric(sqlcipher_sqlite3 *db, void *pTable){
+ sqlcipher_sqlite3DeleteTable(db, (Table*)pTable);
+}
/*
@@ -121827,19 +127894,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ColumnPropertiesFromName(Table *pTab, Colum
#endif
/*
-** Name of the special TEMP trigger used to implement RETURNING. The
-** name begins with "sqlite_" so that it is guaranteed not to collide
-** with any application-generated triggers.
-*/
-#define RETURNING_TRIGGER_NAME "sqlite_returning"
-
-/*
** Clean up the data structures associated with the RETURNING clause.
*/
-static void sqlcipher_sqlite3DeleteReturning(sqlcipher_sqlite3 *db, Returning *pRet){
+static void sqlcipher_sqlite3DeleteReturning(sqlcipher_sqlite3 *db, void *pArg){
+ Returning *pRet = (Returning*)pArg;
Hash *pHash;
pHash = &(db->aDb[1].pSchema->trigHash);
- sqlcipher_sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, 0);
+ sqlcipher_sqlite3HashInsert(pHash, pRet->zName, 0);
sqlcipher_sqlite3ExprListDelete(db, pRet->pReturnEL);
sqlcipher_sqlite3DbFree(db, pRet);
}
@@ -121867,7 +127928,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3AddReturning(Parse *pParse, ExprList *pList
if( pParse->pNewTrigger ){
sqlcipher_sqlite3ErrorMsg(pParse, "cannot use RETURNING in a trigger");
}else{
- assert( pParse->bReturning==0 );
+ assert( pParse->bReturning==0 || pParse->ifNotExists );
}
pParse->bReturning = 1;
pRet = sqlcipher_sqlite3DbMallocZero(db, sizeof(*pRet));
@@ -121878,11 +127939,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3AddReturning(Parse *pParse, ExprList *pList
pParse->u1.pReturning = pRet;
pRet->pParse = pParse;
pRet->pReturnEL = pList;
- sqlcipher_sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlcipher_sqlite3*,void*))sqlcipher_sqlite3DeleteReturning, pRet);
+ sqlcipher_sqlite3ParserAddCleanup(pParse, sqlcipher_sqlite3DeleteReturning, pRet);
testcase( pParse->earlyCleanup );
if( db->mallocFailed ) return;
- pRet->retTrig.zName = RETURNING_TRIGGER_NAME;
+ sqlcipher_sqlite3_snprintf(sizeof(pRet->zName), pRet->zName,
+ "sqlite_returning_%p", pParse);
+ pRet->retTrig.zName = pRet->zName;
pRet->retTrig.op = TK_RETURNING;
pRet->retTrig.tr_tm = TRIGGER_AFTER;
pRet->retTrig.bReturning = 1;
@@ -121893,8 +127955,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3AddReturning(Parse *pParse, ExprList *pList
pRet->retTStep.pTrig = &pRet->retTrig;
pRet->retTStep.pExprList = pList;
pHash = &(db->aDb[1].pSchema->trigHash);
- assert( sqlcipher_sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0 || pParse->nErr );
- if( sqlcipher_sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig)
+ assert( sqlcipher_sqlite3HashFind(pHash, pRet->zName)==0
+ || pParse->nErr || pParse->ifNotExists );
+ if( sqlcipher_sqlite3HashInsert(pHash, pRet->zName, &pRet->retTrig)
==&pRet->retTrig ){
sqlcipher_sqlite3OomFault(db);
}
@@ -121928,7 +127991,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3AddColumn(Parse *pParse, Token sName, Token
}
if( !IN_RENAME_OBJECT ) sqlcipher_sqlite3DequoteToken(&sName);
- /* Because keywords GENERATE ALWAYS can be converted into indentifiers
+ /* Because keywords GENERATE ALWAYS can be converted into identifiers
** by the parser, we can sometimes end up with a typename that ends
** with "generated always". Check for this case and omit the surplus
** text. */
@@ -122075,7 +128138,8 @@ SQLITE_PRIVATE char sqlcipher_sqlite3AffinityType(const char *zIn, Column *pCol)
assert( zIn!=0 );
while( zIn[0] ){
- h = (h<<8) + sqlcipher_sqlite3UpperToLower[(*zIn)&0xff];
+ u8 x = *(u8*)zIn;
+ h = (h<<8) + sqlcipher_sqlite3UpperToLower[x];
zIn++;
if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */
aff = SQLITE_AFF_TEXT;
@@ -122149,7 +128213,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3AddDefaultValue(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* The parsed expression of the default value */
const char *zStart, /* Start of the default value text */
- const char *zEnd /* First character past end of defaut value text */
+ const char *zEnd /* First character past end of default value text */
){
Table *p;
Column *pCol;
@@ -122421,6 +128485,14 @@ SQLITE_PRIVATE void sqlcipher_sqlite3AddGenerated(Parse *pParse, Expr *pExpr, To
if( pCol->colFlags & COLFLAG_PRIMKEY ){
makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */
}
+ if( ALWAYS(pExpr) && pExpr->op==TK_ID ){
+ /* The value of a generated column needs to be a real expression, not
+ ** just a reference to another column, in order for covering index
+ ** optimizations to work correctly. So if the value is not an expression,
+ ** turn it into one by adding a unary "+" operator. */
+ pExpr = sqlcipher_sqlite3PExpr(pParse, TK_UPLUS, pExpr, 0);
+ }
+ if( pExpr && pExpr->op!=TK_RAISE ) pExpr->affExpr = pCol->affinity;
sqlcipher_sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr);
pExpr = 0;
goto generated_done;
@@ -122489,7 +128561,7 @@ static int identLength(const char *z){
** to the specified offset in the buffer and updates *pIdx to refer
** to the first byte after the last byte written before returning.
**
-** If the string zSignedIdent consists entirely of alpha-numeric
+** If the string zSignedIdent consists entirely of alphanumeric
** characters, does not begin with a digit and is not an SQL keyword,
** then it is copied to the output buffer exactly as it is. Otherwise,
** it is quoted using double-quotes.
@@ -122557,7 +128629,8 @@ static char *createTableStmt(sqlcipher_sqlite3 *db, Table *p){
/* SQLITE_AFF_TEXT */ " TEXT",
/* SQLITE_AFF_NUMERIC */ " NUM",
/* SQLITE_AFF_INTEGER */ " INT",
- /* SQLITE_AFF_REAL */ " REAL"
+ /* SQLITE_AFF_REAL */ " REAL",
+ /* SQLITE_AFF_FLEXNUM */ " NUM",
};
int len;
const char *zType;
@@ -122573,10 +128646,12 @@ static char *createTableStmt(sqlcipher_sqlite3 *db, Table *p){
testcase( pCol->affinity==SQLITE_AFF_NUMERIC );
testcase( pCol->affinity==SQLITE_AFF_INTEGER );
testcase( pCol->affinity==SQLITE_AFF_REAL );
+ testcase( pCol->affinity==SQLITE_AFF_FLEXNUM );
zType = azType[pCol->affinity - SQLITE_AFF_BLOB];
len = sqlcipher_sqlite3Strlen30(zType);
assert( pCol->affinity==SQLITE_AFF_BLOB
+ || pCol->affinity==SQLITE_AFF_FLEXNUM
|| pCol->affinity==sqlcipher_sqlite3AffinityType(zType, 0) );
memcpy(&zStmt[k], zType, len);
k += len;
@@ -122638,7 +128713,7 @@ static void estimateIndexWidth(Index *pIdx){
for(i=0; i<pIdx->nColumn; i++){
i16 x = pIdx->aiColumn[i];
assert( x<pIdx->pTable->nCol );
- wIndex += x<0 ? 1 : aCol[pIdx->aiColumn[i]].szEst;
+ wIndex += x<0 ? 1 : aCol[x].szEst;
}
pIdx->szIdxRow = sqlcipher_sqlite3LogEst(wIndex*4);
}
@@ -122693,7 +128768,8 @@ static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){
/* Recompute the colNotIdxed field of the Index.
**
** colNotIdxed is a bitmask that has a 0 bit representing each indexed
-** columns that are within the first 63 columns of the table. The
+** columns that are within the first 63 columns of the table and a 1 for
+** all other bits (all columns that are not in the index). The
** high-order bit of colNotIdxed is always 1. All unindexed columns
** of the table have a 1.
**
@@ -122721,7 +128797,7 @@ static void recomputeColumnsNotIndexed(Index *pIdx){
}
}
pIdx->colNotIdxed = ~m;
- assert( (pIdx->colNotIdxed>>63)==1 );
+ assert( (pIdx->colNotIdxed>>63)==1 ); /* See note-20221022-a */
}
/*
@@ -122990,6 +129066,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ShadowTableName(sqlcipher_sqlite3 *db, const
** not pass them into code generator routines by mistake.
*/
static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){
+ (void)pWalker;
ExprSetVVAProperty(pExpr, EP_Immutable);
return WRC_Continue;
}
@@ -123234,20 +129311,20 @@ SQLITE_PRIVATE void sqlcipher_sqlite3EndTable(
int regRowid; /* Rowid of the next row to insert */
int addrInsLoop; /* Top of the loop for inserting rows */
Table *pSelTab; /* A table that describes the SELECT results */
+ int iCsr; /* Write cursor on the new table */
if( IN_SPECIAL_PARSE ){
pParse->rc = SQLITE_ERROR;
pParse->nErr++;
return;
}
+ iCsr = pParse->nTab++;
regYield = ++pParse->nMem;
regRec = ++pParse->nMem;
regRowid = ++pParse->nMem;
- assert(pParse->nTab==1);
sqlcipher_sqlite3MayAbort(pParse);
- sqlcipher_sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->regRoot, iDb);
sqlcipher_sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
- pParse->nTab = 2;
addrTop = sqlcipher_sqlite3VdbeCurrentAddr(v) + 1;
sqlcipher_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
if( pParse->nErr ) return;
@@ -123268,11 +129345,11 @@ SQLITE_PRIVATE void sqlcipher_sqlite3EndTable(
VdbeCoverage(v);
sqlcipher_sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec);
sqlcipher_sqlite3TableAffinity(v, p, 0);
- sqlcipher_sqlite3VdbeAddOp2(v, OP_NewRowid, 1, regRowid);
- sqlcipher_sqlite3VdbeAddOp3(v, OP_Insert, 1, regRec, regRowid);
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_NewRowid, iCsr, regRowid);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Insert, iCsr, regRec, regRowid);
sqlcipher_sqlite3VdbeGoto(v, addrInsLoop);
sqlcipher_sqlite3VdbeJumpHere(v, addrInsLoop);
- sqlcipher_sqlite3VdbeAddOp1(v, OP_Close, 1);
+ sqlcipher_sqlite3VdbeAddOp1(v, OP_Close, iCsr);
}
/* Compute the complete text of the CREATE statement */
@@ -123325,6 +129402,14 @@ SQLITE_PRIVATE void sqlcipher_sqlite3EndTable(
/* Reparse everything to update our internal data structures */
sqlcipher_sqlite3VdbeAddParseSchemaOp(v, iDb,
sqlcipher_sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);
+
+ /* Test for cycles in generated columns and illegal expressions
+ ** in CHECK constraints and in DEFAULT clauses. */
+ if( p->tabFlags & TF_HasGenerated ){
+ sqlcipher_sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0,
+ sqlcipher_sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"",
+ db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
+ }
}
/* Add the table to the in-memory representation of the database.
@@ -123401,9 +129486,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3CreateView(
** on a view, even though views do not have rowids. The following flag
** setting fixes this problem. But the fix can be disabled by compiling
** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that
- ** depend upon the old buggy behavior. */
-#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
- p->tabFlags |= TF_NoVisibleRowid;
+ ** depend upon the old buggy behavior. The ability can also be toggled
+ ** using sqlcipher_sqlite3_config(SQLITE_CONFIG_ROWID_IN_VIEW,...) */
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ p->tabFlags |= sqlcipher_sqlite3Config.mNoVisibleRowid; /* Optional. Allow by default */
+#else
+ p->tabFlags |= TF_NoVisibleRowid; /* Never allow rowid in view */
#endif
sqlcipher_sqlite3TwoPartName(pParse, pName1, pName2, &pName);
@@ -123459,10 +129547,11 @@ create_view_fail:
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** The Table structure pTable is really a VIEW. Fill in the names of
-** the columns of the view in the pTable structure. Return the number
-** of errors. If an error is seen leave an error message in pParse->zErrMsg.
+** the columns of the view in the pTable structure. Return non-zero if
+** there are errors. If an error is seen an error message is left
+** in pParse->zErrMsg.
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
+static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){
Table *pSelTab; /* A fake table from which we get the result set */
Select *pSel; /* Copy of the SELECT that implements the view */
int nErr = 0; /* Number of errors encountered */
@@ -123487,9 +129576,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ViewGetColumnNames(Parse *pParse, Table *pTa
#ifndef SQLITE_OMIT_VIEW
/* A positive nCol means the columns names for this view are
- ** already known.
+ ** already known. This routine is not called unless either the
+ ** table is virtual or nCol is zero.
*/
- if( pTable->nCol>0 ) return 0;
+ assert( pTable->nCol<=0 );
/* A negative nCol is a special marker meaning that we are currently
** trying to compute the column names. If we enter this routine with
@@ -123555,8 +129645,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ViewGetColumnNames(Parse *pParse, Table *pTa
&& pTable->nCol==pSel->pEList->nExpr
){
assert( db->mallocFailed==0 );
- sqlcipher_sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel,
- SQLITE_AFF_NONE);
+ sqlcipher_sqlite3SubqueryColumnTypes(pParse, pTable, pSel, SQLITE_AFF_NONE);
}
}else{
/* CREATE VIEW name AS... without an argument list. Construct
@@ -123583,7 +129672,12 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ViewGetColumnNames(Parse *pParse, Table *pTa
sqlcipher_sqlite3DeleteColumnNames(db, pTable);
}
#endif /* SQLITE_OMIT_VIEW */
- return nErr;
+ return nErr + pParse->nErr;
+}
+SQLITE_PRIVATE int sqlcipher_sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
+ assert( pTable!=0 );
+ if( !IsVirtual(pTable) && pTable->nCol>0 ) return 0;
+ return viewGetColumnNames(pParse, pTable);
}
#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
@@ -124369,7 +130463,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3CreateIndex(
#ifndef SQLITE_OMIT_TEMPDB
/* If the index name was unqualified, check if the table
** is a temp table. If so, set the database to 1. Do not do this
- ** if initialising a database schema.
+ ** if initializing a database schema.
*/
if( !db->init.busy ){
pTab = sqlcipher_sqlite3SrcListLookup(pParse, pTblName);
@@ -124450,7 +130544,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3CreateIndex(
}
if( !IN_RENAME_OBJECT ){
if( !db->init.busy ){
- if( sqlcipher_sqlite3FindTable(db, zName, 0)!=0 ){
+ if( sqlcipher_sqlite3FindTable(db, zName, pDb->zDbSName)!=0 ){
sqlcipher_sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
goto exit_create_index;
}
@@ -124603,6 +130697,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3CreateIndex(
j = XN_EXPR;
pIndex->aiColumn[i] = XN_EXPR;
pIndex->uniqNotNull = 0;
+ pIndex->bHasExpr = 1;
}else{
j = pCExpr->iColumn;
assert( j<=0x7fff );
@@ -124614,6 +130709,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3CreateIndex(
}
if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){
pIndex->bHasVCol = 1;
+ pIndex->bHasExpr = 1;
}
}
pIndex->aiColumn[i] = (i16)j;
@@ -125103,12 +131199,13 @@ SQLITE_PRIVATE IdList *sqlcipher_sqlite3IdListAppend(Parse *pParse, IdList *pLis
*/
SQLITE_PRIVATE void sqlcipher_sqlite3IdListDelete(sqlcipher_sqlite3 *db, IdList *pList){
int i;
+ assert( db!=0 );
if( pList==0 ) return;
assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */
for(i=0; i<pList->nId; i++){
sqlcipher_sqlite3DbFree(db, pList->a[i].zName);
}
- sqlcipher_sqlite3DbFreeNN(db, pList);
+ sqlcipher_sqlite3DbNNFreeNN(db, pList);
}
/*
@@ -125311,11 +131408,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3SrcListAssignCursors(Parse *pParse, SrcList
SQLITE_PRIVATE void sqlcipher_sqlite3SrcListDelete(sqlcipher_sqlite3 *db, SrcList *pList){
int i;
SrcItem *pItem;
+ assert( db!=0 );
if( pList==0 ) return;
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
- if( pItem->zDatabase ) sqlcipher_sqlite3DbFreeNN(db, pItem->zDatabase);
- sqlcipher_sqlite3DbFree(db, pItem->zName);
- if( pItem->zAlias ) sqlcipher_sqlite3DbFreeNN(db, pItem->zAlias);
+ if( pItem->zDatabase ) sqlcipher_sqlite3DbNNFreeNN(db, pItem->zDatabase);
+ if( pItem->zName ) sqlcipher_sqlite3DbNNFreeNN(db, pItem->zName);
+ if( pItem->zAlias ) sqlcipher_sqlite3DbNNFreeNN(db, pItem->zAlias);
if( pItem->fg.isIndexedBy ) sqlcipher_sqlite3DbFree(db, pItem->u1.zIndexedBy);
if( pItem->fg.isTabFunc ) sqlcipher_sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
sqlcipher_sqlite3DeleteTable(db, pItem->pTab);
@@ -125326,7 +131424,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3SrcListDelete(sqlcipher_sqlite3 *db, SrcLis
sqlcipher_sqlite3ExprDelete(db, pItem->u3.pOn);
}
}
- sqlcipher_sqlite3DbFreeNN(db, pList);
+ sqlcipher_sqlite3DbNNFreeNN(db, pList);
}
/*
@@ -125907,7 +132005,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Reindex(Parse *pParse, Token *pName1, Token
if( iDb<0 ) return;
z = sqlcipher_sqlite3NameFromToken(db, pObjName);
if( z==0 ) return;
- zDb = db->aDb[iDb].zDbSName;
+ zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
pTab = sqlcipher_sqlite3FindTable(db, z, zDb);
if( pTab ){
reindexTable(pParse, pTab, 0);
@@ -125917,6 +132015,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Reindex(Parse *pParse, Token *pName1, Token
pIndex = sqlcipher_sqlite3FindIndex(db, z, zDb);
sqlcipher_sqlite3DbFree(db, z);
if( pIndex ){
+ iDb = sqlcipher_sqlite3SchemaToIndex(db, pIndex->pTable->pSchema);
sqlcipher_sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlcipher_sqlite3RefillIndex(pParse, pIndex, -1);
return;
@@ -126022,7 +132121,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3CteDelete(sqlcipher_sqlite3 *db, Cte *pCte)
/*
** This routine is invoked once per CTE by the parser while parsing a
-** WITH clause. The CTE described by teh third argument is added to
+** WITH clause. The CTE described by the third argument is added to
** the WITH clause of the second argument. If the second argument is
** NULL, then a new WITH argument is created.
*/
@@ -126082,6 +132181,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WithDelete(sqlcipher_sqlite3 *db, With *pWi
sqlcipher_sqlite3DbFree(db, pWith);
}
}
+SQLITE_PRIVATE void sqlcipher_sqlite3WithDeleteGeneric(sqlcipher_sqlite3 *db, void *pWith){
+ sqlcipher_sqlite3WithDelete(db, (With*)pWith);
+}
#endif /* !defined(SQLITE_OMIT_CTE) */
/************** End of build.c ***********************************************/
@@ -126273,6 +132375,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3SetTextEncoding(sqlcipher_sqlite3 *db, u8 e
** strings is BINARY.
*/
db->pDfltColl = sqlcipher_sqlite3FindCollSeq(db, enc, sqlcipher_sqlite3StrBINARY, 0);
+ sqlcipher_sqlite3ExpirePreparedStatements(db, 1);
}
/*
@@ -126578,19 +132681,21 @@ SQLITE_PRIVATE void sqlcipher_sqlite3SchemaClear(void *p){
Hash temp2;
HashElem *pElem;
Schema *pSchema = (Schema *)p;
+ sqlcipher_sqlite3 xdb;
+ memset(&xdb, 0, sizeof(xdb));
temp1 = pSchema->tblHash;
temp2 = pSchema->trigHash;
sqlcipher_sqlite3HashInit(&pSchema->trigHash);
sqlcipher_sqlite3HashClear(&pSchema->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
- sqlcipher_sqlite3DeleteTrigger(0, (Trigger*)sqliteHashData(pElem));
+ sqlcipher_sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem));
}
sqlcipher_sqlite3HashClear(&temp2);
sqlcipher_sqlite3HashInit(&pSchema->tblHash);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
- sqlcipher_sqlite3DeleteTable(0, pTab);
+ sqlcipher_sqlite3DeleteTable(&xdb, pTab);
}
sqlcipher_sqlite3HashClear(&temp1);
sqlcipher_sqlite3HashClear(&pSchema->fkeyHash);
@@ -126661,8 +132766,9 @@ SQLITE_PRIVATE Table *sqlcipher_sqlite3SrcListLookup(Parse *pParse, SrcList *pSr
Table *pTab;
assert( pItem && pSrc->nSrc>=1 );
pTab = sqlcipher_sqlite3LocateTableItem(pParse, 0, pItem);
- sqlcipher_sqlite3DeleteTable(pParse->db, pItem->pTab);
+ if( pItem->pTab ) sqlcipher_sqlite3DeleteTable(pParse->db, pItem->pTab);
pItem->pTab = pTab;
+ pItem->fg.notCte = 1;
if( pTab ){
pTab->nTabRef++;
if( pItem->fg.isIndexedBy && sqlcipher_sqlite3IndexedByLookup(pParse, pItem) ){
@@ -126689,18 +132795,42 @@ SQLITE_PRIVATE void sqlcipher_sqlite3CodeChangeCount(Vdbe *v, int regCounter, co
** 1) It is a virtual table and no implementation of the xUpdate method
** has been provided
**
-** 2) It is a system table (i.e. sqlite_schema), this call is not
+** 2) A trigger is currently being coded and the table is a virtual table
+** that is SQLITE_VTAB_DIRECTONLY or if PRAGMA trusted_schema=OFF and
+** the table is not SQLITE_VTAB_INNOCUOUS.
+**
+** 3) It is a system table (i.e. sqlite_schema), this call is not
** part of a nested parse and writable_schema pragma has not
** been specified
**
-** 3) The table is a shadow table, the database connection is in
+** 4) The table is a shadow table, the database connection is in
** defensive mode, and the current sqlcipher_sqlite3_prepare()
** is for a top-level SQL statement.
*/
+static int vtabIsReadOnly(Parse *pParse, Table *pTab){
+ if( sqlcipher_sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){
+ return 1;
+ }
+
+ /* Within triggers:
+ ** * Do not allow DELETE, INSERT, or UPDATE of SQLITE_VTAB_DIRECTONLY
+ ** virtual tables
+ ** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS
+ ** virtual tables if PRAGMA trusted_schema=ON.
+ */
+ if( pParse->pToplevel!=0
+ && pTab->u.vtab.p->eVtabRisk >
+ ((pParse->db->flags & SQLITE_TrustedSchema)!=0)
+ ){
+ sqlcipher_sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
+ pTab->zName);
+ }
+ return 0;
+}
static int tabIsReadOnly(Parse *pParse, Table *pTab){
sqlcipher_sqlite3 *db;
if( IsVirtual(pTab) ){
- return sqlcipher_sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0;
+ return vtabIsReadOnly(pParse, pTab);
}
if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0;
db = pParse->db;
@@ -126712,17 +132842,21 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
}
/*
-** Check to make sure the given table is writable. If it is not
-** writable, generate an error message and return 1. If it is
-** writable return 0;
+** Check to make sure the given table is writable.
+**
+** If pTab is not writable -> generate an error message and return 1.
+** If pTab is writable but other errors have occurred -> return 1.
+** If pTab is writable and no prior errors -> return 0;
*/
-SQLITE_PRIVATE int sqlcipher_sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
+SQLITE_PRIVATE int sqlcipher_sqlite3IsReadOnly(Parse *pParse, Table *pTab, Trigger *pTrigger){
if( tabIsReadOnly(pParse, pTab) ){
sqlcipher_sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
#ifndef SQLITE_OMIT_VIEW
- if( !viewOk && IsView(pTab) ){
+ if( IsView(pTab)
+ && (pTrigger==0 || (pTrigger->bReturning && pTrigger->pNext==0))
+ ){
sqlcipher_sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
return 1;
}
@@ -126787,7 +132921,7 @@ SQLITE_PRIVATE Expr *sqlcipher_sqlite3LimitWhere(
sqlcipher_sqlite3 *db = pParse->db;
Expr *pLhs = NULL; /* LHS of IN(SELECT...) operator */
Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */
- ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */
+ ExprList *pEList = NULL; /* Expression list containing only pSelectRowid*/
SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */
Select *pSelect = NULL; /* Complete SELECT tree */
Table *pTab;
@@ -126825,14 +132959,20 @@ SQLITE_PRIVATE Expr *sqlcipher_sqlite3LimitWhere(
);
}else{
Index *pPk = sqlcipher_sqlite3PrimaryKeyIndex(pTab);
+ assert( pPk!=0 );
+ assert( pPk->nKeyCol>=1 );
if( pPk->nKeyCol==1 ){
- const char *zName = pTab->aCol[pPk->aiColumn[0]].zCnName;
+ const char *zName;
+ assert( pPk->aiColumn[0]>=0 && pPk->aiColumn[0]<pTab->nCol );
+ zName = pTab->aCol[pPk->aiColumn[0]].zCnName;
pLhs = sqlcipher_sqlite3Expr(db, TK_ID, zName);
pEList = sqlcipher_sqlite3ExprListAppend(pParse, 0, sqlcipher_sqlite3Expr(db, TK_ID, zName));
}else{
int i;
for(i=0; i<pPk->nKeyCol; i++){
- Expr *p = sqlcipher_sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName);
+ Expr *p;
+ assert( pPk->aiColumn[i]>=0 && pPk->aiColumn[i]<pTab->nCol );
+ p = sqlcipher_sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName);
pEList = sqlcipher_sqlite3ExprListAppend(pParse, pEList, p);
}
pLhs = sqlcipher_sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
@@ -126861,7 +133001,7 @@ SQLITE_PRIVATE Expr *sqlcipher_sqlite3LimitWhere(
pOrderBy,0,pLimit
);
- /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
+ /* now generate the new WHERE rowid IN clause for the DELETE/UPDATE */
pInClause = sqlcipher_sqlite3PExpr(pParse, TK_IN, pLhs, 0);
sqlcipher_sqlite3PExprAddSelect(pParse, pInClause, pSelect);
return pInClause;
@@ -126976,7 +133116,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3DeleteFrom(
goto delete_from_cleanup;
}
- if( sqlcipher_sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
+ if( sqlcipher_sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto delete_from_cleanup;
}
iDb = sqlcipher_sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -127075,21 +133215,22 @@ SQLITE_PRIVATE void sqlcipher_sqlite3DeleteFrom(
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->pSchema==pTab->pSchema );
- sqlcipher_sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
- sqlcipher_sqlite3VdbeChangeP3(v, -1, memCnt ? memCnt : -1);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Clear, pIdx->tnum, iDb, memCnt ? memCnt : -1);
+ }else{
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
}
}
}else
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
{
u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
- if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
+ if( sNC.ncFlags & NC_Subquery ) bComplex = 1;
wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
if( HasRowid(pTab) ){
/* For a rowid table, initialize the RowSet to an empty set */
pPk = 0;
- nPk = 1;
+ assert( nPk==1 );
iRowSet = ++pParse->nMem;
sqlcipher_sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
}else{
@@ -127117,7 +133258,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3DeleteFrom(
if( pWInfo==0 ) goto delete_from_cleanup;
eOnePass = sqlcipher_sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
- assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF );
+ assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF
+ || OptimizationDisabled(db, SQLITE_OnePass) );
if( eOnePass!=ONEPASS_SINGLE ) sqlcipher_sqlite3MultiWrite(pParse);
if( sqlcipher_sqlite3WhereUsesDeferredSeek(pWInfo) ){
sqlcipher_sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur);
@@ -127277,7 +133419,7 @@ delete_from_cleanup:
sqlcipher_sqlite3ExprListDelete(db, pOrderBy);
sqlcipher_sqlite3ExprDelete(db, pLimit);
#endif
- sqlcipher_sqlite3DbFree(db, aToOpen);
+ if( aToOpen ) sqlcipher_sqlite3DbNNFreeNN(db, aToOpen);
return;
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
@@ -127454,9 +133596,11 @@ SQLITE_PRIVATE void sqlcipher_sqlite3GenerateRowDelete(
sqlcipher_sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0);
/* Invoke AFTER DELETE trigger programs. */
- sqlcipher_sqlite3CodeRowTrigger(pParse, pTrigger,
- TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
- );
+ if( pTrigger ){
+ sqlcipher_sqlite3CodeRowTrigger(pParse, pTrigger,
+ TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
+ );
+ }
/* Jump here if the row had already been deleted before any BEFORE
** trigger programs were invoked. Or if a trigger program throws a
@@ -127770,6 +133914,42 @@ static void lengthFunc(
}
/*
+** Implementation of the octet_length() function
+*/
+static void bytelengthFunc(
+ sqlcipher_sqlite3_context *context,
+ int argc,
+ sqlcipher_sqlite3_value **argv
+){
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ switch( sqlcipher_sqlite3_value_type(argv[0]) ){
+ case SQLITE_BLOB: {
+ sqlcipher_sqlite3_result_int(context, sqlcipher_sqlite3_value_bytes(argv[0]));
+ break;
+ }
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT: {
+ i64 m = sqlcipher_sqlite3_context_db_handle(context)->enc<=SQLITE_UTF8 ? 1 : 2;
+ sqlcipher_sqlite3_result_int64(context, sqlcipher_sqlite3_value_bytes(argv[0])*m);
+ break;
+ }
+ case SQLITE_TEXT: {
+ if( sqlcipher_sqlite3_value_encoding(argv[0])<=SQLITE_UTF8 ){
+ sqlcipher_sqlite3_result_int(context, sqlcipher_sqlite3_value_bytes(argv[0]));
+ }else{
+ sqlcipher_sqlite3_result_int(context, sqlcipher_sqlite3_value_bytes16(argv[0]));
+ }
+ break;
+ }
+ default: {
+ sqlcipher_sqlite3_result_null(context);
+ break;
+ }
+ }
+}
+
+/*
** Implementation of the abs() function.
**
** IMP: R-23979-26855 The abs(X) function returns the absolute value of
@@ -128045,7 +134225,7 @@ static void roundFunc(sqlcipher_sqlite3_context *context, int argc, sqlcipher_sq
}else if( n==0 ){
r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5)));
}else{
- zBuf = sqlcipher_sqlite3_mprintf("%.*f",n,r);
+ zBuf = sqlcipher_sqlite3_mprintf("%!.*f",n,r);
if( zBuf==0 ){
sqlcipher_sqlite3_result_error_nomem(context);
return;
@@ -128245,7 +134425,7 @@ struct compareInfo {
/*
** For LIKE and GLOB matching on EBCDIC machines, assume that every
-** character is exactly one byte in size. Also, provde the Utf8Read()
+** character is exactly one byte in size. Also, provide the Utf8Read()
** macro for fast reading of the next character in the common case where
** the next character is ASCII.
*/
@@ -128360,7 +134540,7 @@ static int patternCompare(
** c but in the other case and search the input string for either
** c or cx.
*/
- if( c<=0x80 ){
+ if( c<0x80 ){
char zStop[3];
int bMatch;
if( noCase ){
@@ -128443,7 +134623,13 @@ static int patternCompare(
** non-zero if there is no match.
*/
SQLITE_API int sqlcipher_sqlite3_strglob(const char *zGlobPattern, const char *zString){
- return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
+ if( zString==0 ){
+ return zGlobPattern!=0;
+ }else if( zGlobPattern==0 ){
+ return 1;
+ }else {
+ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
+ }
}
/*
@@ -128451,7 +134637,13 @@ SQLITE_API int sqlcipher_sqlite3_strglob(const char *zGlobPattern, const char *z
** a miss - like strcmp().
*/
SQLITE_API int sqlcipher_sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
- return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
+ if( zStr==0 ){
+ return zPattern!=0;
+ }else if( zPattern==0 ){
+ return 1;
+ }else{
+ return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
+ }
}
/*
@@ -128466,7 +134658,7 @@ SQLITE_API int sqlcipher_sqlite3_like_count = 0;
/*
** Implementation of the like() SQL function. This function implements
-** the build-in LIKE operator. The first argument to the function is the
+** the built-in LIKE operator. The first argument to the function is the
** pattern and the second argument is the string. So, the SQL statements:
**
** A LIKE B
@@ -128673,13 +134865,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3QuoteValue(StrAccum *pStr, sqlcipher_sqlite
double r1, r2;
const char *zVal;
r1 = sqlcipher_sqlite3_value_double(pValue);
- sqlcipher_sqlite3_str_appendf(pStr, "%!.15g", r1);
+ sqlcipher_sqlite3_str_appendf(pStr, "%!0.15g", r1);
zVal = sqlcipher_sqlite3_str_value(pStr);
if( zVal ){
sqlcipher_sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
if( r1!=r2 ){
sqlcipher_sqlite3_str_reset(pStr);
- sqlcipher_sqlite3_str_appendf(pStr, "%!.20e", r1);
+ sqlcipher_sqlite3_str_appendf(pStr, "%!0.20e", r1);
}
}
break;
@@ -128690,7 +134882,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3QuoteValue(StrAccum *pStr, sqlcipher_sqlite
}
case SQLITE_BLOB: {
char const *zBlob = sqlcipher_sqlite3_value_blob(pValue);
- int nBlob = sqlcipher_sqlite3_value_bytes(pValue);
+ i64 nBlob = sqlcipher_sqlite3_value_bytes(pValue);
assert( zBlob==sqlcipher_sqlite3_value_blob(pValue) ); /* No encoding change */
sqlcipher_sqlite3StrAccumEnlarge(pStr, nBlob*2 + 4);
if( pStr->accError==0 ){
@@ -128799,6 +134991,7 @@ static void charFunc(
*zOut++ = 0x80 + (u8)(c & 0x3F);
} \
}
+ *zOut = 0;
sqlcipher_sqlite3_result_text64(context, (char*)z, zOut-z, sqlcipher_sqlite3_free, SQLITE_UTF8);
}
@@ -128827,11 +135020,102 @@ static void hexFunc(
*(z++) = hexdigits[c&0xf];
}
*z = 0;
- sqlcipher_sqlite3_result_text(context, zHex, n*2, sqlcipher_sqlite3_free);
+ sqlcipher_sqlite3_result_text64(context, zHex, (u64)(z-zHex),
+ sqlcipher_sqlite3_free, SQLITE_UTF8);
}
}
/*
+** Buffer zStr contains nStr bytes of utf-8 encoded text. Return 1 if zStr
+** contains character ch, or 0 if it does not.
+*/
+static int strContainsChar(const u8 *zStr, int nStr, u32 ch){
+ const u8 *zEnd = &zStr[nStr];
+ const u8 *z = zStr;
+ while( z<zEnd ){
+ u32 tst = Utf8Read(z);
+ if( tst==ch ) return 1;
+ }
+ return 0;
+}
+
+/*
+** The unhex() function. This function may be invoked with either one or
+** two arguments. In both cases the first argument is interpreted as text
+** a text value containing a set of pairs of hexadecimal digits which are
+** decoded and returned as a blob.
+**
+** If there is only a single argument, then it must consist only of an
+** even number of hexadecimal digits. Otherwise, return NULL.
+**
+** Or, if there is a second argument, then any character that appears in
+** the second argument is also allowed to appear between pairs of hexadecimal
+** digits in the first argument. If any other character appears in the
+** first argument, or if one of the allowed characters appears between
+** two hexadecimal digits that make up a single byte, NULL is returned.
+**
+** The following expressions are all true:
+**
+** unhex('ABCD') IS x'ABCD'
+** unhex('AB CD') IS NULL
+** unhex('AB CD', ' ') IS x'ABCD'
+** unhex('A BCD', ' ') IS NULL
+*/
+static void unhexFunc(
+ sqlcipher_sqlite3_context *pCtx,
+ int argc,
+ sqlcipher_sqlite3_value **argv
+){
+ const u8 *zPass = (const u8*)"";
+ int nPass = 0;
+ const u8 *zHex = sqlcipher_sqlite3_value_text(argv[0]);
+ int nHex = sqlcipher_sqlite3_value_bytes(argv[0]);
+#ifdef SQLITE_DEBUG
+ const u8 *zEnd = zHex ? &zHex[nHex] : 0;
+#endif
+ u8 *pBlob = 0;
+ u8 *p = 0;
+
+ assert( argc==1 || argc==2 );
+ if( argc==2 ){
+ zPass = sqlcipher_sqlite3_value_text(argv[1]);
+ nPass = sqlcipher_sqlite3_value_bytes(argv[1]);
+ }
+ if( !zHex || !zPass ) return;
+
+ p = pBlob = contextMalloc(pCtx, (nHex/2)+1);
+ if( pBlob ){
+ u8 c; /* Most significant digit of next byte */
+ u8 d; /* Least significant digit of next byte */
+
+ while( (c = *zHex)!=0x00 ){
+ while( !sqlcipher_sqlite3Isxdigit(c) ){
+ u32 ch = Utf8Read(zHex);
+ assert( zHex<=zEnd );
+ if( !strContainsChar(zPass, nPass, ch) ) goto unhex_null;
+ c = *zHex;
+ if( c==0x00 ) goto unhex_done;
+ }
+ zHex++;
+ assert( *zEnd==0x00 );
+ assert( zHex<=zEnd );
+ d = *(zHex++);
+ if( !sqlcipher_sqlite3Isxdigit(d) ) goto unhex_null;
+ *(p++) = (sqlcipher_sqlite3HexToInt(c)<<4) | sqlcipher_sqlite3HexToInt(d);
+ }
+ }
+
+ unhex_done:
+ sqlcipher_sqlite3_result_blob(pCtx, pBlob, (p - pBlob), sqlcipher_sqlite3_free);
+ return;
+
+ unhex_null:
+ sqlcipher_sqlite3_free(pBlob);
+ return;
+}
+
+
+/*
** The zeroblob(N) function returns a zero-filled blob of size N bytes.
*/
static void zeroblobFunc(
@@ -128889,7 +135173,7 @@ static void replaceFunc(
}
if( zPattern[0]==0 ){
assert( sqlcipher_sqlite3_value_type(argv[1])!=SQLITE_NULL );
- sqlcipher_sqlite3_result_value(context, argv[0]);
+ sqlcipher_sqlite3_result_text(context, (const char*)zStr, nStr, SQLITE_TRANSIENT);
return;
}
nPattern = sqlcipher_sqlite3_value_bytes(argv[1]);
@@ -129031,12 +135315,87 @@ static void trimFunc(
sqlcipher_sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
}
+/* The core implementation of the CONCAT(...) and CONCAT_WS(SEP,...)
+** functions.
+**
+** Return a string value that is the concatenation of all non-null
+** entries in argv[]. Use zSep as the separator.
+*/
+static void concatFuncCore(
+ sqlcipher_sqlite3_context *context,
+ int argc,
+ sqlcipher_sqlite3_value **argv,
+ int nSep,
+ const char *zSep
+){
+ i64 j, k, n = 0;
+ int i;
+ char *z;
+ for(i=0; i<argc; i++){
+ n += sqlcipher_sqlite3_value_bytes(argv[i]);
+ }
+ n += (argc-1)*nSep;
+ z = sqlcipher_sqlite3_malloc64(n+1);
+ if( z==0 ){
+ sqlcipher_sqlite3_result_error_nomem(context);
+ return;
+ }
+ j = 0;
+ for(i=0; i<argc; i++){
+ k = sqlcipher_sqlite3_value_bytes(argv[i]);
+ if( k>0 ){
+ const char *v = (const char*)sqlcipher_sqlite3_value_text(argv[i]);
+ if( v!=0 ){
+ if( j>0 && nSep>0 ){
+ memcpy(&z[j], zSep, nSep);
+ j += nSep;
+ }
+ memcpy(&z[j], v, k);
+ j += k;
+ }
+ }
+ }
+ z[j] = 0;
+ assert( j<=n );
+ sqlcipher_sqlite3_result_text64(context, z, j, sqlcipher_sqlite3_free, SQLITE_UTF8);
+}
+
+/*
+** The CONCAT(...) function. Generate a string result that is the
+** concatentation of all non-null arguments.
+*/
+static void concatFunc(
+ sqlcipher_sqlite3_context *context,
+ int argc,
+ sqlcipher_sqlite3_value **argv
+){
+ concatFuncCore(context, argc, argv, 0, "");
+}
+
+/*
+** The CONCAT_WS(separator, ...) function.
+**
+** Generate a string that is the concatenation of 2nd through the Nth
+** argument. Use the first argument (which must be non-NULL) as the
+** separator.
+*/
+static void concatwsFunc(
+ sqlcipher_sqlite3_context *context,
+ int argc,
+ sqlcipher_sqlite3_value **argv
+){
+ int nSep = sqlcipher_sqlite3_value_bytes(argv[0]);
+ const char *zSep = (const char*)sqlcipher_sqlite3_value_text(argv[0]);
+ if( zSep==0 ) return;
+ concatFuncCore(context, argc-1, argv+1, nSep, zSep);
+}
+
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
/*
** The "unknown" function is automatically substituted in place of
** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN
-** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used.
+** when the SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION compile-time option is used.
** When the "sqlcipher_sqlite3" command-line shell is built using this functionality,
** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries
** involving application-defined functions to be examined in a generic
@@ -129048,6 +135407,9 @@ static void unknownFunc(
sqlcipher_sqlite3_value **argv
){
/* no-op */
+ (void)context;
+ (void)argc;
+ (void)argv;
}
#endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/
@@ -129149,14 +135511,69 @@ static void loadExt(sqlcipher_sqlite3_context *context, int argc, sqlcipher_sqli
*/
typedef struct SumCtx SumCtx;
struct SumCtx {
- double rSum; /* Floating point sum */
- i64 iSum; /* Integer sum */
+ double rSum; /* Running sum as as a double */
+ double rErr; /* Error term for Kahan-Babushka-Neumaier summation */
+ i64 iSum; /* Running sum as a signed integer */
i64 cnt; /* Number of elements summed */
- u8 overflow; /* True if integer overflow seen */
- u8 approx; /* True if non-integer value was input to the sum */
+ u8 approx; /* True if any non-integer value was input to the sum */
+ u8 ovrfl; /* Integer overflow seen */
};
/*
+** Do one step of the Kahan-Babushka-Neumaier summation.
+**
+** https://en.wikipedia.org/wiki/Kahan_summation_algorithm
+**
+** Variables are marked "volatile" to defeat c89 x86 floating point
+** optimizations can mess up this algorithm.
+*/
+static void kahanBabuskaNeumaierStep(
+ volatile SumCtx *pSum,
+ volatile double r
+){
+ volatile double s = pSum->rSum;
+ volatile double t = s + r;
+ if( fabs(s) > fabs(r) ){
+ pSum->rErr += (s - t) + r;
+ }else{
+ pSum->rErr += (r - t) + s;
+ }
+ pSum->rSum = t;
+}
+
+/*
+** Add a (possibly large) integer to the running sum.
+*/
+static void kahanBabuskaNeumaierStepInt64(volatile SumCtx *pSum, i64 iVal){
+ if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){
+ i64 iBig, iSm;
+ iSm = iVal % 16384;
+ iBig = iVal - iSm;
+ kahanBabuskaNeumaierStep(pSum, iBig);
+ kahanBabuskaNeumaierStep(pSum, iSm);
+ }else{
+ kahanBabuskaNeumaierStep(pSum, (double)iVal);
+ }
+}
+
+/*
+** Initialize the Kahan-Babaska-Neumaier sum from a 64-bit integer
+*/
+static void kahanBabuskaNeumaierInit(
+ volatile SumCtx *p,
+ i64 iVal
+){
+ if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){
+ i64 iSm = iVal % 16384;
+ p->rSum = (double)(iVal - iSm);
+ p->rErr = (double)iSm;
+ }else{
+ p->rSum = (double)iVal;
+ p->rErr = 0.0;
+ }
+}
+
+/*
** Routines used to compute the sum, average, and total.
**
** The SUM() function follows the (broken) SQL standard which means
@@ -129175,15 +135592,29 @@ static void sumStep(sqlcipher_sqlite3_context *context, int argc, sqlcipher_sqli
type = sqlcipher_sqlite3_value_numeric_type(argv[0]);
if( p && type!=SQLITE_NULL ){
p->cnt++;
- if( type==SQLITE_INTEGER ){
- i64 v = sqlcipher_sqlite3_value_int64(argv[0]);
- p->rSum += v;
- if( (p->approx|p->overflow)==0 && sqlcipher_sqlite3AddInt64(&p->iSum, v) ){
- p->approx = p->overflow = 1;
+ if( p->approx==0 ){
+ if( type!=SQLITE_INTEGER ){
+ kahanBabuskaNeumaierInit(p, p->iSum);
+ p->approx = 1;
+ kahanBabuskaNeumaierStep(p, sqlcipher_sqlite3_value_double(argv[0]));
+ }else{
+ i64 x = p->iSum;
+ if( sqlcipher_sqlite3AddInt64(&x, sqlcipher_sqlite3_value_int64(argv[0]))==0 ){
+ p->iSum = x;
+ }else{
+ p->ovrfl = 1;
+ kahanBabuskaNeumaierInit(p, p->iSum);
+ p->approx = 1;
+ kahanBabuskaNeumaierStepInt64(p, sqlcipher_sqlite3_value_int64(argv[0]));
+ }
}
}else{
- p->rSum += sqlcipher_sqlite3_value_double(argv[0]);
- p->approx = 1;
+ if( type==SQLITE_INTEGER ){
+ kahanBabuskaNeumaierStepInt64(p, sqlcipher_sqlite3_value_int64(argv[0]));
+ }else{
+ p->ovrfl = 0;
+ kahanBabuskaNeumaierStep(p, sqlcipher_sqlite3_value_double(argv[0]));
+ }
}
}
}
@@ -129200,13 +135631,18 @@ static void sumInverse(sqlcipher_sqlite3_context *context, int argc, sqlcipher_s
if( ALWAYS(p) && type!=SQLITE_NULL ){
assert( p->cnt>0 );
p->cnt--;
- assert( type==SQLITE_INTEGER || p->approx );
- if( type==SQLITE_INTEGER && p->approx==0 ){
- i64 v = sqlcipher_sqlite3_value_int64(argv[0]);
- p->rSum -= v;
- p->iSum -= v;
+ if( !p->approx ){
+ p->iSum -= sqlcipher_sqlite3_value_int64(argv[0]);
+ }else if( type==SQLITE_INTEGER ){
+ i64 iVal = sqlcipher_sqlite3_value_int64(argv[0]);
+ if( iVal!=SMALLEST_INT64 ){
+ kahanBabuskaNeumaierStepInt64(p, -iVal);
+ }else{
+ kahanBabuskaNeumaierStepInt64(p, LARGEST_INT64);
+ kahanBabuskaNeumaierStepInt64(p, 1);
+ }
}else{
- p->rSum -= sqlcipher_sqlite3_value_double(argv[0]);
+ kahanBabuskaNeumaierStep(p, -sqlcipher_sqlite3_value_double(argv[0]));
}
}
}
@@ -129217,10 +135653,14 @@ static void sumFinalize(sqlcipher_sqlite3_context *context){
SumCtx *p;
p = sqlcipher_sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
- if( p->overflow ){
- sqlcipher_sqlite3_result_error(context,"integer overflow",-1);
- }else if( p->approx ){
- sqlcipher_sqlite3_result_double(context, p->rSum);
+ if( p->approx ){
+ if( p->ovrfl ){
+ sqlcipher_sqlite3_result_error(context,"integer overflow",-1);
+ }else if( !sqlcipher_sqlite3IsOverflow(p->rErr) ){
+ sqlcipher_sqlite3_result_double(context, p->rSum+p->rErr);
+ }else{
+ sqlcipher_sqlite3_result_double(context, p->rSum);
+ }
}else{
sqlcipher_sqlite3_result_int64(context, p->iSum);
}
@@ -129230,14 +135670,29 @@ static void avgFinalize(sqlcipher_sqlite3_context *context){
SumCtx *p;
p = sqlcipher_sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
- sqlcipher_sqlite3_result_double(context, p->rSum/(double)p->cnt);
+ double r;
+ if( p->approx ){
+ r = p->rSum;
+ if( !sqlcipher_sqlite3IsOverflow(p->rErr) ) r += p->rErr;
+ }else{
+ r = (double)(p->iSum);
+ }
+ sqlcipher_sqlite3_result_double(context, r/(double)p->cnt);
}
}
static void totalFinalize(sqlcipher_sqlite3_context *context){
SumCtx *p;
+ double r = 0.0;
p = sqlcipher_sqlite3_aggregate_context(context, 0);
- /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
- sqlcipher_sqlite3_result_double(context, p ? p->rSum : (double)0);
+ if( p ){
+ if( p->approx ){
+ r = p->rSum;
+ if( !sqlcipher_sqlite3IsOverflow(p->rErr) ) r += p->rErr;
+ }else{
+ r = (double)(p->iSum);
+ }
+ }
+ sqlcipher_sqlite3_result_double(context, r);
}
/*
@@ -129356,6 +135811,7 @@ static void minMaxFinalize(sqlcipher_sqlite3_context *context){
/*
** group_concat(EXPR, ?SEPARATOR?)
+** string_agg(EXPR, SEPARATOR)
**
** The SEPARATOR goes before the EXPR string. This is tragic. The
** groupConcatInverse() implementation would have been easier if the
@@ -129459,7 +135915,7 @@ static void groupConcatInverse(
if( sqlcipher_sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pGCC = (GroupConcatCtx*)sqlcipher_sqlite3_aggregate_context(context, sizeof(*pGCC));
/* pGCC is always non-NULL since groupConcatStep() will have always
- ** run frist to initialize it */
+ ** run first to initialize it */
if( ALWAYS(pGCC) ){
int nVS;
/* Must call sqlcipher_sqlite3_value_text() to convert the argument into text prior
@@ -129514,6 +135970,8 @@ static void groupConcatValue(sqlcipher_sqlite3_context *context){
sqlcipher_sqlite3_result_error_toobig(context);
}else if( pAccum->accError==SQLITE_NOMEM ){
sqlcipher_sqlite3_result_error_nomem(context);
+ }else if( pGCC->nAccum>0 && pAccum->nChar==0 ){
+ sqlcipher_sqlite3_result_text(context, "", 1, SQLITE_STATIC);
}else{
const char *zText = sqlcipher_sqlite3_str_value(pAccum);
sqlcipher_sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT);
@@ -129541,9 +135999,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3RegisterPerConnectionBuiltinFunctions(sqlci
extern void sqlcipher_exportFunc(sqlcipher_sqlite3_context *, int, sqlcipher_sqlite3_value **);
sqlcipher_sqlite3CreateFunc(db, "sqlcipher_export", -1, SQLITE_TEXT, 0, sqlcipher_exportFunc, 0, 0, 0, 0, 0);
}
-#ifdef SQLCIPHER_EXT
-#include "sqlcipher_funcs_init.h"
-#endif
#endif
/* END SQLCIPHER */
}
@@ -129554,8 +136009,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3RegisterPerConnectionBuiltinFunctions(sqlci
** sensitive.
*/
SQLITE_PRIVATE void sqlcipher_sqlite3RegisterLikeFunctions(sqlcipher_sqlite3 *db, int caseSensitive){
+ FuncDef *pDef;
struct compareInfo *pInfo;
int flags;
+ int nArg;
if( caseSensitive ){
pInfo = (struct compareInfo*)&likeInfoAlt;
flags = SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE;
@@ -129563,10 +136020,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3RegisterLikeFunctions(sqlcipher_sqlite3 *db
pInfo = (struct compareInfo*)&likeInfoNorm;
flags = SQLITE_FUNC_LIKE;
}
- sqlcipher_sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
- sqlcipher_sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
- sqlcipher_sqlite3FindFunction(db, "like", 2, SQLITE_UTF8, 0)->funcFlags |= flags;
- sqlcipher_sqlite3FindFunction(db, "like", 3, SQLITE_UTF8, 0)->funcFlags |= flags;
+ for(nArg=2; nArg<=3; nArg++){
+ sqlcipher_sqlite3CreateFunc(db, "like", nArg, SQLITE_UTF8, pInfo, likeFunc,
+ 0, 0, 0, 0, 0);
+ pDef = sqlcipher_sqlite3FindFunction(db, "like", nArg, SQLITE_UTF8, 0);
+ pDef->funcFlags |= flags;
+ pDef->funcFlags &= ~SQLITE_FUNC_UNSAFE;
+ }
}
/*
@@ -129688,6 +136148,18 @@ static double xCeil(double x){ return ceil(x); }
static double xFloor(double x){ return floor(x); }
/*
+** Some systems do not have log2() and log10() in their standard math
+** libraries.
+*/
+#if defined(HAVE_LOG10) && HAVE_LOG10==0
+# define log10(X) (0.4342944819032517867*log(X))
+#endif
+#if defined(HAVE_LOG2) && HAVE_LOG2==0
+# define log2(X) (1.442695040888963456*log(X))
+#endif
+
+
+/*
** Implementation of SQL functions:
**
** ln(X) - natural logarithm
@@ -129725,17 +136197,15 @@ static void logFunc(
}
ans = log(x)/b;
}else{
- ans = log(x);
switch( SQLITE_PTR_TO_INT(sqlcipher_sqlite3_user_data(context)) ){
case 1:
- /* Convert from natural logarithm to log base 10 */
- ans /= M_LN10;
+ ans = log10(x);
break;
case 2:
- /* Convert from natural logarithm to log base 2 */
- ans /= M_LN2;
+ ans = log2(x);
break;
default:
+ ans = log(x);
break;
}
}
@@ -129804,6 +136274,7 @@ static void piFunc(
sqlcipher_sqlite3_value **argv
){
assert( argc==0 );
+ (void)argv;
sqlcipher_sqlite3_result_double(context, M_PI);
}
@@ -129827,6 +136298,37 @@ static void signFunc(
sqlcipher_sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0);
}
+#ifdef SQLITE_DEBUG
+/*
+** Implementation of fpdecode(x,y,z) function.
+**
+** x is a real number that is to be decoded. y is the precision.
+** z is the maximum real precision.
+*/
+static void fpdecodeFunc(
+ sqlcipher_sqlite3_context *context,
+ int argc,
+ sqlcipher_sqlite3_value **argv
+){
+ FpDecode s;
+ double x;
+ int y, z;
+ char zBuf[100];
+ UNUSED_PARAMETER(argc);
+ assert( argc==3 );
+ x = sqlcipher_sqlite3_value_double(argv[0]);
+ y = sqlcipher_sqlite3_value_int(argv[1]);
+ z = sqlcipher_sqlite3_value_int(argv[2]);
+ sqlcipher_sqlite3FpDecode(&s, x, y, z);
+ if( s.isSpecial==2 ){
+ sqlcipher_sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN");
+ }else{
+ sqlcipher_sqlite3_snprintf(sizeof(zBuf), zBuf, "%c%.*s/%d", s.sign, s.n, s.z, s.iDP);
+ }
+ sqlcipher_sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+}
+#endif /* SQLITE_DEBUG */
+
/*
** All of the FuncDef structures in the aBuiltinFunc[] array above
** to the global function hash table. This occurs at start-time (as
@@ -129891,12 +136393,16 @@ SQLITE_PRIVATE void sqlcipher_sqlite3RegisterBuiltinFunctions(void){
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
+ FUNCTION2(octet_length, 1, 0, 0, bytelengthFunc,SQLITE_FUNC_BYTELEN),
FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(printf, -1, 0, 0, printfFunc ),
FUNCTION(format, -1, 0, 0, printfFunc ),
FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
FUNCTION(char, -1, 0, 0, charFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ),
+#ifdef SQLITE_DEBUG
+ FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ),
+#endif
#ifndef SQLITE_OMIT_FLOATING_POINT
FUNCTION(round, 1, 0, 0, roundFunc ),
FUNCTION(round, 2, 0, 0, roundFunc ),
@@ -129904,6 +136410,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3RegisterBuiltinFunctions(void){
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
FUNCTION(hex, 1, 0, 0, hexFunc ),
+ FUNCTION(unhex, 1, 0, 0, unhexFunc ),
+ FUNCTION(unhex, 2, 0, 0, unhexFunc ),
+ FUNCTION(concat, -1, 0, 0, concatFunc ),
+ FUNCTION(concat, 0, 0, 0, 0 ),
+ FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ),
+ FUNCTION(concat_ws, 0, 0, 0, 0 ),
+ FUNCTION(concat_ws, 1, 0, 0, 0 ),
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
@@ -129933,6 +136446,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3RegisterBuiltinFunctions(void){
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
+ WAGGREGATE(string_agg, 2, 0, 0, groupConcatStep,
+ groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
#ifdef SQLITE_CASE_SENSITIVE_LIKE
@@ -130875,6 +137390,7 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){
if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull)
|| (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull)
){
+ assert( (pTop->db->flags & SQLITE_FkNoAction)==0 );
return 1;
}
}
@@ -131069,6 +137585,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3FkCheck(
}
if( regOld!=0 ){
int eAction = pFKey->aAction[aChange!=0];
+ if( (db->flags & SQLITE_FkNoAction) ) eAction = OE_None;
+
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1);
/* If this is a deferred FK constraint, or a CASCADE or SET NULL
** action applies, then any foreign key violations caused by
@@ -131184,7 +137702,11 @@ SQLITE_PRIVATE int sqlcipher_sqlite3FkRequired(
/* Check if any parent key columns are being modified. */
for(p=sqlcipher_sqlite3FkReferences(pTab); p; p=p->pNextTo){
if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
- if( p->aAction[1]!=OE_None ) return 2;
+ if( (pParse->db->flags & SQLITE_FkNoAction)==0
+ && p->aAction[1]!=OE_None
+ ){
+ return 2;
+ }
bHaveFK = 1;
}
}
@@ -131234,6 +137756,7 @@ static Trigger *fkActionTrigger(
int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */
action = pFKey->aAction[iAction];
+ if( (db->flags & SQLITE_FkNoAction) ) action = OE_None;
if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){
return 0;
}
@@ -131334,22 +137857,22 @@ static Trigger *fkActionTrigger(
if( action==OE_Restrict ){
int iDb = sqlcipher_sqlite3SchemaToIndex(db, pTab->pSchema);
- Token tFrom;
- Token tDb;
+ SrcList *pSrc;
Expr *pRaise;
- tFrom.z = zFrom;
- tFrom.n = nFrom;
- tDb.z = db->aDb[iDb].zDbSName;
- tDb.n = sqlcipher_sqlite3Strlen30(tDb.z);
-
pRaise = sqlcipher_sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
if( pRaise ){
pRaise->affExpr = OE_Abort;
}
+ pSrc = sqlcipher_sqlite3SrcListAppend(pParse, 0, 0, 0);
+ if( pSrc ){
+ assert( pSrc->nSrc==1 );
+ pSrc->a[0].zName = sqlcipher_sqlite3DbStrDup(db, zFrom);
+ pSrc->a[0].zDatabase = sqlcipher_sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
+ }
pSelect = sqlcipher_sqlite3SelectNew(pParse,
sqlcipher_sqlite3ExprListAppend(pParse, 0, pRaise),
- sqlcipher_sqlite3SrcListAppend(pParse, 0, &tDb, &tFrom),
+ pSrc,
pWhere,
0, 0, 0, 0, 0
);
@@ -131456,17 +137979,17 @@ SQLITE_PRIVATE void sqlcipher_sqlite3FkDelete(sqlcipher_sqlite3 *db, Table *pTab
FKey *pNext; /* Copy of pFKey->pNextFrom */
assert( IsOrdinaryTable(pTab) );
+ assert( db!=0 );
for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pNext){
assert( db==0 || sqlcipher_sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
/* Remove the FK from the fkeyHash hash table. */
- if( !db || db->pnBytesFreed==0 ){
+ if( db->pnBytesFreed==0 ){
if( pFKey->pPrevTo ){
pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
}else{
- void *p = (void *)pFKey->pNextTo;
- const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo);
- sqlcipher_sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p);
+ const char *z = (pFKey->pNextTo ? pFKey->pNextTo->zTo : pFKey->zTo);
+ sqlcipher_sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, pFKey->pNextTo);
}
if( pFKey->pNextTo ){
pFKey->pNextTo->pPrevTo = pFKey->pPrevTo;
@@ -131529,8 +138052,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3OpenTable(
assert( pParse->pVdbe!=0 );
v = pParse->pVdbe;
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
- sqlcipher_sqlite3TableLock(pParse, iDb, pTab->tnum,
- (opcode==OP_OpenWrite)?1:0, pTab->zName);
+ if( !pParse->db->noSharedCache ){
+ sqlcipher_sqlite3TableLock(pParse, iDb, pTab->tnum,
+ (opcode==OP_OpenWrite)?1:0, pTab->zName);
+ }
if( HasRowid(pTab) ){
sqlcipher_sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol);
VdbeComment((v, "%s", pTab->zName));
@@ -131564,43 +138089,68 @@ SQLITE_PRIVATE void sqlcipher_sqlite3OpenTable(
** is managed along with the rest of the Index structure. It will be
** released when sqlcipher_sqlite3DeleteIndex() is called.
*/
-SQLITE_PRIVATE const char *sqlcipher_sqlite3IndexAffinityStr(sqlcipher_sqlite3 *db, Index *pIdx){
+static SQLITE_NOINLINE const char *computeIndexAffStr(sqlcipher_sqlite3 *db, Index *pIdx){
+ /* The first time a column affinity string for a particular index is
+ ** required, it is allocated and populated here. It is then stored as
+ ** a member of the Index structure for subsequent use.
+ **
+ ** The column affinity string will eventually be deleted by
+ ** sqliteDeleteIndex() when the Index structure itself is cleaned
+ ** up.
+ */
+ int n;
+ Table *pTab = pIdx->pTable;
+ pIdx->zColAff = (char *)sqlcipher_sqlite3DbMallocRaw(0, pIdx->nColumn+1);
if( !pIdx->zColAff ){
- /* The first time a column affinity string for a particular index is
- ** required, it is allocated and populated here. It is then stored as
- ** a member of the Index structure for subsequent use.
- **
- ** The column affinity string will eventually be deleted by
- ** sqliteDeleteIndex() when the Index structure itself is cleaned
- ** up.
- */
- int n;
- Table *pTab = pIdx->pTable;
- pIdx->zColAff = (char *)sqlcipher_sqlite3DbMallocRaw(0, pIdx->nColumn+1);
- if( !pIdx->zColAff ){
- sqlcipher_sqlite3OomFault(db);
- return 0;
+ sqlcipher_sqlite3OomFault(db);
+ return 0;
+ }
+ for(n=0; n<pIdx->nColumn; n++){
+ i16 x = pIdx->aiColumn[n];
+ char aff;
+ if( x>=0 ){
+ aff = pTab->aCol[x].affinity;
+ }else if( x==XN_ROWID ){
+ aff = SQLITE_AFF_INTEGER;
+ }else{
+ assert( x==XN_EXPR );
+ assert( pIdx->bHasExpr );
+ assert( pIdx->aColExpr!=0 );
+ aff = sqlcipher_sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
}
- for(n=0; n<pIdx->nColumn; n++){
- i16 x = pIdx->aiColumn[n];
- char aff;
- if( x>=0 ){
- aff = pTab->aCol[x].affinity;
- }else if( x==XN_ROWID ){
- aff = SQLITE_AFF_INTEGER;
- }else{
- assert( x==XN_EXPR );
- assert( pIdx->aColExpr!=0 );
- aff = sqlcipher_sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
+ if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
+ if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
+ pIdx->zColAff[n] = aff;
+ }
+ pIdx->zColAff[n] = 0;
+ return pIdx->zColAff;
+}
+SQLITE_PRIVATE const char *sqlcipher_sqlite3IndexAffinityStr(sqlcipher_sqlite3 *db, Index *pIdx){
+ if( !pIdx->zColAff ) return computeIndexAffStr(db, pIdx);
+ return pIdx->zColAff;
+}
+
+
+/*
+** Compute an affinity string for a table. Space is obtained
+** from sqlcipher_sqlite3DbMalloc(). The caller is responsible for freeing
+** the space when done.
+*/
+SQLITE_PRIVATE char *sqlcipher_sqlite3TableAffinityStr(sqlcipher_sqlite3 *db, const Table *pTab){
+ char *zColAff;
+ zColAff = (char *)sqlcipher_sqlite3DbMallocRaw(db, pTab->nCol+1);
+ if( zColAff ){
+ int i, j;
+ for(i=j=0; i<pTab->nCol; i++){
+ if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
+ zColAff[j++] = pTab->aCol[i].affinity;
}
- if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
- if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
- pIdx->zColAff[n] = aff;
}
- pIdx->zColAff[n] = 0;
+ do{
+ zColAff[j--] = 0;
+ }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
}
-
- return pIdx->zColAff;
+ return zColAff;
}
/*
@@ -131634,7 +138184,7 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3IndexAffinityStr(sqlcipher_sqlite3 *
** For STRICT tables:
** ------------------
**
-** Generate an appropropriate OP_TypeCheck opcode that will verify the
+** Generate an appropriate OP_TypeCheck opcode that will verify the
** datatypes against the column definitions in pTab. If iReg==0, that
** means an OP_MakeRecord opcode has already been generated and should be
** the last opcode generated. The new OP_TypeCheck needs to be inserted
@@ -131644,7 +138194,7 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3IndexAffinityStr(sqlcipher_sqlite3 *
** Apply the type checking to that array of registers.
*/
SQLITE_PRIVATE void sqlcipher_sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
- int i, j;
+ int i;
char *zColAff;
if( pTab->tabFlags & TF_Strict ){
if( iReg==0 ){
@@ -131653,7 +138203,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TableAffinity(Vdbe *v, Table *pTab, int iRe
** OP_MakeRecord is found */
VdbeOp *pPrev;
sqlcipher_sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
- pPrev = sqlcipher_sqlite3VdbeGetOp(v, -1);
+ pPrev = sqlcipher_sqlite3VdbeGetLastOp(v);
assert( pPrev!=0 );
assert( pPrev->opcode==OP_MakeRecord || sqlcipher_sqlite3VdbeDb(v)->mallocFailed );
pPrev->opcode = OP_TypeCheck;
@@ -131667,22 +138217,11 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TableAffinity(Vdbe *v, Table *pTab, int iRe
}
zColAff = pTab->zColAff;
if( zColAff==0 ){
- sqlcipher_sqlite3 *db = sqlcipher_sqlite3VdbeDb(v);
- zColAff = (char *)sqlcipher_sqlite3DbMallocRaw(0, pTab->nCol+1);
+ zColAff = sqlcipher_sqlite3TableAffinityStr(0, pTab);
if( !zColAff ){
- sqlcipher_sqlite3OomFault(db);
+ sqlcipher_sqlite3OomFault(sqlcipher_sqlite3VdbeDb(v));
return;
}
-
- for(i=j=0; i<pTab->nCol; i++){
- assert( pTab->aCol[i].affinity!=0 || sqlcipher_sqlite3VdbeParser(v)->nErr>0 );
- if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
- zColAff[j++] = pTab->aCol[i].affinity;
- }
- }
- do{
- zColAff[j--] = 0;
- }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
pTab->zColAff = zColAff;
}
assert( zColAff!=0 );
@@ -131691,7 +138230,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3TableAffinity(Vdbe *v, Table *pTab, int iRe
if( iReg ){
sqlcipher_sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
}else{
- assert( sqlcipher_sqlite3VdbeGetOp(v, -1)->opcode==OP_MakeRecord
+ assert( sqlcipher_sqlite3VdbeGetLastOp(v)->opcode==OP_MakeRecord
|| sqlcipher_sqlite3VdbeDb(v)->mallocFailed );
sqlcipher_sqlite3VdbeChangeP4(v, -1, zColAff, i);
}
@@ -131777,7 +138316,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ComputeGeneratedColumns(
*/
sqlcipher_sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore);
if( (pTab->tabFlags & TF_HasStored)!=0 ){
- pOp = sqlcipher_sqlite3VdbeGetOp(pParse->pVdbe,-1);
+ pOp = sqlcipher_sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Affinity ){
/* Change the OP_Affinity argument to '@' (NONE) for all stored
** columns. '@' is the no-op affinity and those columns have not
@@ -132055,6 +138594,196 @@ SQLITE_PRIVATE void sqlcipher_sqlite3AutoincrementEnd(Parse *pParse){
# define autoIncStep(A,B,C)
#endif /* SQLITE_OMIT_AUTOINCREMENT */
+/*
+** If argument pVal is a Select object returned by an sqlcipher_sqlite3MultiValues()
+** that was able to use the co-routine optimization, finish coding the
+** co-routine.
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
+ if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){
+ SrcItem *pItem = &pVal->pSrc->a[0];
+ sqlcipher_sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn);
+ sqlcipher_sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1);
+ }
+}
+
+/*
+** Return true if all expressions in the expression-list passed as the
+** only argument are constant.
+*/
+static int exprListIsConstant(Parse *pParse, ExprList *pRow){
+ int ii;
+ for(ii=0; ii<pRow->nExpr; ii++){
+ if( 0==sqlcipher_sqlite3ExprIsConstant(pParse, pRow->a[ii].pExpr) ) return 0;
+ }
+ return 1;
+}
+
+/*
+** Return true if all expressions in the expression-list passed as the
+** only argument are both constant and have no affinity.
+*/
+static int exprListIsNoAffinity(Parse *pParse, ExprList *pRow){
+ int ii;
+ if( exprListIsConstant(pParse,pRow)==0 ) return 0;
+ for(ii=0; ii<pRow->nExpr; ii++){
+ Expr *pExpr = pRow->a[ii].pExpr;
+ assert( pExpr->op!=TK_RAISE );
+ assert( pExpr->affExpr==0 );
+ if( 0!=sqlcipher_sqlite3ExprAffinity(pExpr) ) return 0;
+ }
+ return 1;
+
+}
+
+/*
+** This function is called by the parser for the second and subsequent
+** rows of a multi-row VALUES clause. Argument pLeft is the part of
+** the VALUES clause already parsed, argument pRow is the vector of values
+** for the new row. The Select object returned represents the complete
+** VALUES clause, including the new row.
+**
+** There are two ways in which this may be achieved - by incremental
+** coding of a co-routine (the "co-routine" method) or by returning a
+** Select object equivalent to the following (the "UNION ALL" method):
+**
+** "pLeft UNION ALL SELECT pRow"
+**
+** If the VALUES clause contains a lot of rows, this compound Select
+** object may consume a lot of memory.
+**
+** When the co-routine method is used, each row that will be returned
+** by the VALUES clause is coded into part of a co-routine as it is
+** passed to this function. The returned Select object is equivalent to:
+**
+** SELECT * FROM (
+** Select object to read co-routine
+** )
+**
+** The co-routine method is used in most cases. Exceptions are:
+**
+** a) If the current statement has a WITH clause. This is to avoid
+** statements like:
+**
+** WITH cte AS ( VALUES('x'), ('y') ... )
+** SELECT * FROM cte AS a, cte AS b;
+**
+** This will not work, as the co-routine uses a hard-coded register
+** for its OP_Yield instructions, and so it is not possible for two
+** cursors to iterate through it concurrently.
+**
+** b) The schema is currently being parsed (i.e. the VALUES clause is part
+** of a schema item like a VIEW or TRIGGER). In this case there is no VM
+** being generated when parsing is taking place, and so generating
+** a co-routine is not possible.
+**
+** c) There are non-constant expressions in the VALUES clause (e.g.
+** the VALUES clause is part of a correlated sub-query).
+**
+** d) One or more of the values in the first row of the VALUES clause
+** has an affinity (i.e. is a CAST expression). This causes problems
+** because the complex rules SQLite uses (see function
+** sqlcipher_sqlite3SubqueryColumnTypes() in select.c) to determine the effective
+** affinity of such a column for all rows require access to all values in
+** the column simultaneously.
+*/
+SQLITE_PRIVATE Select *sqlcipher_sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
+
+ if( pParse->bHasWith /* condition (a) above */
+ || pParse->db->init.busy /* condition (b) above */
+ || exprListIsConstant(pParse,pRow)==0 /* condition (c) above */
+ || (pLeft->pSrc->nSrc==0 &&
+ exprListIsNoAffinity(pParse,pLeft->pEList)==0) /* condition (d) above */
+ || IN_SPECIAL_PARSE
+ ){
+ /* The co-routine method cannot be used. Fall back to UNION ALL. */
+ Select *pSelect = 0;
+ int f = SF_Values | SF_MultiValue;
+ if( pLeft->pSrc->nSrc ){
+ sqlcipher_sqlite3MultiValuesEnd(pParse, pLeft);
+ f = SF_Values;
+ }else if( pLeft->pPrior ){
+ /* In this case set the SF_MultiValue flag only if it was set on pLeft */
+ f = (f & pLeft->selFlags);
+ }
+ pSelect = sqlcipher_sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0);
+ pLeft->selFlags &= ~SF_MultiValue;
+ if( pSelect ){
+ pSelect->op = TK_ALL;
+ pSelect->pPrior = pLeft;
+ pLeft = pSelect;
+ }
+ }else{
+ SrcItem *p = 0; /* SrcItem that reads from co-routine */
+
+ if( pLeft->pSrc->nSrc==0 ){
+ /* Co-routine has not yet been started and the special Select object
+ ** that accesses the co-routine has not yet been created. This block
+ ** does both those things. */
+ Vdbe *v = sqlcipher_sqlite3GetVdbe(pParse);
+ Select *pRet = sqlcipher_sqlite3SelectNew(pParse, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ /* Ensure the database schema has been read. This is to ensure we have
+ ** the correct text encoding. */
+ if( (pParse->db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ){
+ sqlcipher_sqlite3ReadSchema(pParse);
+ }
+
+ if( pRet ){
+ SelectDest dest;
+ pRet->pSrc->nSrc = 1;
+ pRet->pPrior = pLeft->pPrior;
+ pRet->op = pLeft->op;
+ if( pRet->pPrior ) pRet->selFlags |= SF_Values;
+ pLeft->pPrior = 0;
+ pLeft->op = TK_SELECT;
+ assert( pLeft->pNext==0 );
+ assert( pRet->pNext==0 );
+ p = &pRet->pSrc->a[0];
+ p->pSelect = pLeft;
+ p->fg.viaCoroutine = 1;
+ p->addrFillSub = sqlcipher_sqlite3VdbeCurrentAddr(v) + 1;
+ p->regReturn = ++pParse->nMem;
+ p->iCursor = -1;
+ p->u1.nRow = 2;
+ sqlcipher_sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub);
+ sqlcipher_sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn);
+
+ /* Allocate registers for the output of the co-routine. Do so so
+ ** that there are two unused registers immediately before those
+ ** used by the co-routine. This allows the code in sqlcipher_sqlite3Insert()
+ ** to use these registers directly, instead of copying the output
+ ** of the co-routine to a separate array for processing. */
+ dest.iSdst = pParse->nMem + 3;
+ dest.nSdst = pLeft->pEList->nExpr;
+ pParse->nMem += 2 + dest.nSdst;
+
+ pLeft->selFlags |= SF_MultiValue;
+ sqlcipher_sqlite3Select(pParse, pLeft, &dest);
+ p->regResult = dest.iSdst;
+ assert( pParse->nErr || dest.iSdst>0 );
+ pLeft = pRet;
+ }
+ }else{
+ p = &pLeft->pSrc->a[0];
+ assert( !p->fg.isTabFunc && !p->fg.isIndexedBy );
+ p->u1.nRow++;
+ }
+
+ if( pParse->nErr==0 ){
+ assert( p!=0 );
+ if( p->pSelect->pEList->nExpr!=pRow->nExpr ){
+ sqlcipher_sqlite3SelectWrongNumTermsError(pParse, p->pSelect);
+ }else{
+ sqlcipher_sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0);
+ sqlcipher_sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn);
+ }
+ }
+ sqlcipher_sqlite3ExprListDelete(pParse->db, pRow);
+ }
+
+ return pLeft;
+}
/* Forward declaration */
static int xferOptimization(
@@ -132276,7 +139005,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Insert(
/* Cannot insert into a read-only table.
*/
- if( sqlcipher_sqlite3IsReadOnly(pParse, pTab, tmask) ){
+ if( sqlcipher_sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto insert_cleanup;
}
@@ -132391,25 +139120,40 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Insert(
if( pSelect ){
/* Data is coming from a SELECT or from a multi-row VALUES clause.
** Generate a co-routine to run the SELECT. */
- int regYield; /* Register holding co-routine entry-point */
- int addrTop; /* Top of the co-routine */
int rc; /* Result code */
- regYield = ++pParse->nMem;
- addrTop = sqlcipher_sqlite3VdbeCurrentAddr(v) + 1;
- sqlcipher_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
- sqlcipher_sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
- dest.iSdst = bIdListInOrder ? regData : 0;
- dest.nSdst = pTab->nCol;
- rc = sqlcipher_sqlite3Select(pParse, pSelect, &dest);
- regFromSelect = dest.iSdst;
- assert( db->pParse==pParse );
- if( rc || pParse->nErr ) goto insert_cleanup;
- assert( db->mallocFailed==0 );
- sqlcipher_sqlite3VdbeEndCoroutine(v, regYield);
- sqlcipher_sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
- assert( pSelect->pEList );
- nColumn = pSelect->pEList->nExpr;
+ if( pSelect->pSrc->nSrc==1
+ && pSelect->pSrc->a[0].fg.viaCoroutine
+ && pSelect->pPrior==0
+ ){
+ SrcItem *pItem = &pSelect->pSrc->a[0];
+ dest.iSDParm = pItem->regReturn;
+ regFromSelect = pItem->regResult;
+ nColumn = pItem->pSelect->pEList->nExpr;
+ ExplainQueryPlan((pParse, 0, "SCAN %S", pItem));
+ if( bIdListInOrder && nColumn==pTab->nCol ){
+ regData = regFromSelect;
+ regRowid = regData - 1;
+ regIns = regRowid - (IsVirtual(pTab) ? 1 : 0);
+ }
+ }else{
+ int addrTop; /* Top of the co-routine */
+ int regYield = ++pParse->nMem;
+ addrTop = sqlcipher_sqlite3VdbeCurrentAddr(v) + 1;
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
+ sqlcipher_sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
+ dest.iSdst = bIdListInOrder ? regData : 0;
+ dest.nSdst = pTab->nCol;
+ rc = sqlcipher_sqlite3Select(pParse, pSelect, &dest);
+ regFromSelect = dest.iSdst;
+ assert( db->pParse==pParse );
+ if( rc || pParse->nErr ) goto insert_cleanup;
+ assert( db->mallocFailed==0 );
+ sqlcipher_sqlite3VdbeEndCoroutine(v, regYield);
+ sqlcipher_sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
+ assert( pSelect->pEList );
+ nColumn = pSelect->pEList->nExpr;
+ }
/* Set useTempTable to TRUE if the result of the SELECT statement
** should be written into a temporary table (template 4). Set to
@@ -132564,7 +139308,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Insert(
pNx->iDataCur = iDataCur;
pNx->iIdxCur = iIdxCur;
if( pNx->pUpsertTarget ){
- if( sqlcipher_sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){
+ if( sqlcipher_sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx, pUpsert) ){
goto insert_cleanup;
}
}
@@ -132683,7 +139427,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Insert(
sqlcipher_sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore);
}
}else{
- sqlcipher_sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore);
+ Expr *pX = pList->a[k].pExpr;
+ int y = sqlcipher_sqlite3ExprCodeTarget(pParse, pX, iRegStore);
+ if( y!=iRegStore ){
+ sqlcipher_sqlite3VdbeAddOp2(v,
+ ExprHasProperty(pX, EP_Subquery) ? OP_Copy : OP_SCopy, y, iRegStore);
+ }
}
}
@@ -132718,7 +139467,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Insert(
}
/* Copy the new data already generated. */
- assert( pTab->nNVCol>0 );
+ assert( pTab->nNVCol>0 || pParse->nErr>0 );
sqlcipher_sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
@@ -132820,7 +139569,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Insert(
sqlcipher_sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
);
- sqlcipher_sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
+ if( db->flags & SQLITE_ForeignKeys ){
+ sqlcipher_sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
+ }
/* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
** constraints or (b) there are no triggers and this table is not a
@@ -132904,7 +139655,7 @@ insert_cleanup:
sqlcipher_sqlite3UpsertDelete(db, pUpsert);
sqlcipher_sqlite3SelectDelete(db, pSelect);
sqlcipher_sqlite3IdListDelete(db, pColumn);
- sqlcipher_sqlite3DbFree(db, aRegIdx);
+ if( aRegIdx ) sqlcipher_sqlite3DbNNFreeNN(db, aRegIdx);
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
@@ -132930,7 +139681,7 @@ insert_cleanup:
/* This is the Walker callback from sqlcipher_sqlite3ExprReferencesUpdatedColumn().
* Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this
** expression node references any of the
-** columns that are being modifed by an UPDATE statement.
+** columns that are being modified by an UPDATE statement.
*/
static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_COLUMN ){
@@ -133153,7 +139904,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3GenerateConstraintChecks(
int *aiChng, /* column i is unchanged if aiChng[i]<0 */
Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */
){
- Vdbe *v; /* VDBE under constrution */
+ Vdbe *v; /* VDBE under construction */
Index *pIdx; /* Pointer to one of the indices */
Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */
sqlcipher_sqlite3 *db; /* Database connection */
@@ -133268,6 +140019,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3GenerateConstraintChecks(
case OE_Fail: {
char *zMsg = sqlcipher_sqlite3MPrintf(db, "%s.%s", pTab->zName,
pCol->zCnName);
+ testcase( zMsg==0 && db->mallocFailed==0 );
sqlcipher_sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
onError, iReg);
sqlcipher_sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
@@ -133635,7 +140387,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3GenerateConstraintChecks(
pIdx;
pIdx = indexIteratorNext(&sIdxIter, &ix)
){
- int regIdx; /* Range of registers hold conent for pIdx */
+ int regIdx; /* Range of registers holding content for pIdx */
int regR; /* Range of registers holding conflicting PK */
int iThisCur; /* Cursor for this UNIQUE index */
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
@@ -134130,6 +140882,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3OpenTableAndIndices(
assert( op==OP_OpenRead || op==OP_OpenWrite );
assert( op==OP_OpenWrite || p5==0 );
+ assert( piDataCur!=0 );
+ assert( piIdxCur!=0 );
if( IsVirtual(pTab) ){
/* This routine is a no-op for virtual tables. Leave the output
** variables *piDataCur and *piIdxCur set to illegal cursor numbers
@@ -134142,18 +140896,18 @@ SQLITE_PRIVATE int sqlcipher_sqlite3OpenTableAndIndices(
assert( v!=0 );
if( iBase<0 ) iBase = pParse->nTab;
iDataCur = iBase++;
- if( piDataCur ) *piDataCur = iDataCur;
+ *piDataCur = iDataCur;
if( HasRowid(pTab) && (aToOpen==0 || aToOpen[0]) ){
sqlcipher_sqlite3OpenTable(pParse, iDataCur, iDb, pTab, op);
- }else{
+ }else if( pParse->db->noSharedCache==0 ){
sqlcipher_sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
}
- if( piIdxCur ) *piIdxCur = iBase;
+ *piIdxCur = iBase;
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
int iIdxCur = iBase++;
assert( pIdx->pSchema==pTab->pSchema );
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
- if( piDataCur ) *piDataCur = iIdxCur;
+ *piDataCur = iIdxCur;
p5 = 0;
}
if( aToOpen==0 || aToOpen[i+1] ){
@@ -134446,12 +141200,15 @@ static int xferOptimization(
}
}
#ifndef SQLITE_OMIT_CHECK
- if( pDest->pCheck && sqlcipher_sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){
+ if( pDest->pCheck
+ && (db->mDbFlags & DBFLAG_Vacuum)==0
+ && sqlcipher_sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1)
+ ){
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
}
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
- /* Disallow the transfer optimization if the destination table constains
+ /* Disallow the transfer optimization if the destination table contains
** any foreign key constraints. This is more restrictive than necessary.
** But the main beneficiary of the transfer optimization is the VACUUM
** command, and the VACUUM command disables foreign key constraints. So
@@ -135131,9 +141888,9 @@ struct sqlcipher_sqlite3_api_routines {
const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*);
/* Version 3.32.0 and later */
- char *(*create_filename)(const char*,const char*,const char*,
+ const char *(*create_filename)(const char*,const char*,const char*,
int,const char**);
- void (*free_filename)(char*);
+ void (*free_filename)(const char*);
sqlcipher_sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */
int (*txn_state)(sqlcipher_sqlite3*,const char*);
@@ -135157,6 +141914,15 @@ struct sqlcipher_sqlite3_api_routines {
unsigned char *(*serialize)(sqlcipher_sqlite3*,const char *,sqlcipher_sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlcipher_sqlite3*,int);
+ /* Version 3.40.0 and later */
+ int (*value_encoding)(sqlcipher_sqlite3_value*);
+ /* Version 3.41.0 and later */
+ int (*is_interrupted)(sqlcipher_sqlite3*);
+ /* Version 3.43.0 and later */
+ int (*stmt_explain)(sqlcipher_sqlite3_stmt*,int);
+ /* Version 3.44.0 and later */
+ void *(*get_clientdata)(sqlcipher_sqlite3*,const char*);
+ int (*set_clientdata)(sqlcipher_sqlite3*, const char*, void*, void(*)(void*));
};
/*
@@ -135481,6 +142247,15 @@ typedef int (*sqlcipher_sqlite3_loadext_entry)(
#define sqlcipher_sqlite3_serialize sqlcipher_sqlite3_api->serialize
#endif
#define sqlcipher_sqlite3_db_name sqlcipher_sqlite3_api->db_name
+/* Version 3.40.0 and later */
+#define sqlcipher_sqlite3_value_encoding sqlcipher_sqlite3_api->value_encoding
+/* Version 3.41.0 and later */
+#define sqlcipher_sqlite3_is_interrupted sqlcipher_sqlite3_api->is_interrupted
+/* Version 3.43.0 and later */
+#define sqlcipher_sqlite3_stmt_explain sqlcipher_sqlite3_api->stmt_explain
+/* Version 3.44.0 and later */
+#define sqlcipher_sqlite3_get_clientdata sqlcipher_sqlite3_api->get_clientdata
+#define sqlcipher_sqlite3_set_clientdata sqlcipher_sqlite3_api->set_clientdata
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -135993,7 +142768,16 @@ static const sqlcipher_sqlite3_api_routines sqlcipher_sqlite3Apis = {
0,
0,
#endif
- sqlcipher_sqlite3_db_name
+ sqlcipher_sqlite3_db_name,
+ /* Version 3.40.0 and later */
+ sqlcipher_sqlite3_value_encoding,
+ /* Version 3.41.0 and later */
+ sqlcipher_sqlite3_is_interrupted,
+ /* Version 3.43.0 and later */
+ sqlcipher_sqlite3_stmt_explain,
+ /* Version 3.44.0 and later */
+ sqlcipher_sqlite3_get_clientdata,
+ sqlcipher_sqlite3_set_clientdata
};
/* True if x is the directory separator character
@@ -136066,15 +142850,25 @@ static int sqlcipher_sqlite3LoadExtension(
/* tag-20210611-1. Some dlopen() implementations will segfault if given
** an oversize filename. Most filesystems have a pathname limit of 4K,
** so limit the extension filename length to about twice that.
- ** https://sqlite.org/forum/forumpost/08a0d6d9bf */
+ ** https://sqlite.org/forum/forumpost/08a0d6d9bf
+ **
+ ** Later (2023-03-25): Save an extra 6 bytes for the filename suffix.
+ ** See https://sqlite.org/forum/forumpost/24083b579d.
+ */
if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found;
+ /* Do not allow sqlcipher_sqlite3_load_extension() to link to a copy of the
+ ** running application, by passing in an empty filename. */
+ if( nMsg==0 ) goto extension_not_found;
+
handle = sqlcipher_sqlite3OsDlOpen(pVfs, zFile);
#if SQLITE_OS_UNIX || SQLITE_OS_WIN
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
char *zAltFile = sqlcipher_sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
- handle = sqlcipher_sqlite3OsDlOpen(pVfs, zAltFile);
+ if( nMsg+strlen(azEndings[ii])+1<=SQLITE_MAX_PATHLEN ){
+ handle = sqlcipher_sqlite3OsDlOpen(pVfs, zAltFile);
+ }
sqlcipher_sqlite3_free(zAltFile);
}
#endif
@@ -136199,6 +142993,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3CloseExtensions(sqlcipher_sqlite3 *db){
** default so as not to open security holes in older applications.
*/
SQLITE_API int sqlcipher_sqlite3_enable_load_extension(sqlcipher_sqlite3 *db, int onoff){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlcipher_sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlcipher_sqlite3_mutex_enter(db->mutex);
if( onoff ){
db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
@@ -136248,6 +143045,9 @@ SQLITE_API int sqlcipher_sqlite3_auto_extension(
void (*xInit)(void)
){
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( xInit==0 ) return SQLITE_MISUSE_BKPT;
+#endif
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlcipher_sqlite3_initialize();
if( rc ){
@@ -136300,6 +143100,9 @@ SQLITE_API int sqlcipher_sqlite3_cancel_auto_extension(
int i;
int n = 0;
wsdAutoextInit;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( xInit==0 ) return 0;
+#endif
sqlcipher_sqlite3_mutex_enter(mutex);
for(i=(int)wsdAutoext.nExt-1; i>=0; i--){
if( wsdAutoext.aExt[i]==xInit ){
@@ -137125,6 +143928,34 @@ static const PragmaName aPragmaName[] = {
/************** Continuing where we left off in pragma.c *********************/
/*
+** When the 0x10 bit of PRAGMA optimize is set, any ANALYZE commands
+** will be run with an analysis_limit set to the lessor of the value of
+** the following macro or to the actual analysis_limit if it is non-zero,
+** in order to prevent PRAGMA optimize from running for too long.
+**
+** The value of 2000 is chosen emperically so that the worst-case run-time
+** for PRAGMA optimize does not exceed 100 milliseconds against a variety
+** of test databases on a RaspberryPI-4 compiled using -Os and without
+** -DSQLITE_DEBUG. Of course, your mileage may vary. For the purpose of
+** this paragraph, "worst-case" means that ANALYZE ends up being
+** run on every table in the database. The worst case typically only
+** happens if PRAGMA optimize is run on a database file for which ANALYZE
+** has not been previously run and the 0x10000 flag is included so that
+** all tables are analyzed. The usual case for PRAGMA optimize is that
+** no ANALYZE commands will be run at all, or if any ANALYZE happens it
+** will be against a single table, so that expected timing for PRAGMA
+** optimize on a PI-4 is more like 1 millisecond or less with the 0x10000
+** flag or less than 100 microseconds without the 0x10000 flag.
+**
+** An analysis limit of 2000 is almost always sufficient for the query
+** planner to fully characterize an index. The additional accuracy from
+** a larger analysis is not usually helpful.
+*/
+#ifndef SQLITE_DEFAULT_OPTIMIZE_LIMIT
+# define SQLITE_DEFAULT_OPTIMIZE_LIMIT 2000
+#endif
+
+/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or
** unrecognized string argument. The FULL and EXTRA option is disallowed
@@ -137963,7 +144794,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
**
** The first form reports the current local setting for the
** page cache spill size. The second form turns cache spill on
- ** or off. When turnning cache spill on, the size is set to the
+ ** or off. When turning cache spill on, the size is set to the
** current cache_size. The third form sets a spill size that
** may be different form the cache size.
** If N is positive then that is the
@@ -138233,7 +145064,11 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
#endif
if( sqlcipher_sqlite3GetBoolean(zRight, 0) ){
- db->flags |= mask;
+ if( (mask & SQLITE_WriteSchema)==0
+ || (db->flags & SQLITE_Defensive)==0
+ ){
+ db->flags |= mask;
+ }
}else{
db->flags &= ~mask;
if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
@@ -138633,7 +145468,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
zDb = db->aDb[iDb].zDbSName;
sqlcipher_sqlite3CodeVerifySchema(pParse, iDb);
sqlcipher_sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
- if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
+ sqlcipher_sqlite3TouchRegister(pParse, pTab->nCol+regRow);
sqlcipher_sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
sqlcipher_sqlite3VdbeLoadString(v, regResult, pTab->zName);
assert( IsOrdinaryTable(pTab) );
@@ -138674,7 +145509,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
** regRow..regRow+n. If any of the child key values are NULL, this
** row cannot cause an FK violation. Jump directly to addrOk in
** this case. */
- if( regRow+pFK->nCol>pParse->nMem ) pParse->nMem = regRow+pFK->nCol;
+ sqlcipher_sqlite3TouchRegister(pParse, regRow + pFK->nCol);
for(j=0; j<pFK->nCol; j++){
int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
sqlcipher_sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
@@ -138741,9 +145576,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
** The "quick_check" is reduced version of
** integrity_check designed to detect most database corruption
** without the overhead of cross-checking indexes. Quick_check
- ** is linear time wherease integrity_check is O(NlogN).
+ ** is linear time whereas integrity_check is O(NlogN).
**
- ** The maximum nubmer of errors is 100 by default. A different default
+ ** The maximum number of errors is 100 by default. A different default
** can be specified using a numeric parameter N.
**
** Or, the parameter N can be the name of a table. In that case, only
@@ -138780,7 +145615,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
/* Set the maximum error count */
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
if( zRight ){
- if( sqlcipher_sqlite3GetInt32(zRight, &mxErr) ){
+ if( sqlcipher_sqlite3GetInt32(pValue->z, &mxErr) ){
if( mxErr<=0 ){
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
}
@@ -138797,12 +145632,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
Hash *pTbls; /* Set of all tables in the schema */
int *aRoot; /* Array of root page numbers of all btrees */
int cnt = 0; /* Number of entries in aRoot[] */
- int mxIdx = 0; /* Maximum number of indexes for any table */
if( OMIT_TEMPDB && i==1 ) continue;
if( iDb>=0 && i!=iDb ) continue;
sqlcipher_sqlite3CodeVerifySchema(pParse, i);
+ pParse->okConstFactor = 0; /* tag-20230327-1 */
/* Do an integrity check of the B-Tree
**
@@ -138818,7 +145653,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
if( pObjTab && pObjTab!=pTab ) continue;
if( HasRowid(pTab) ) cnt++;
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
- if( nIdx>mxIdx ) mxIdx = nIdx;
}
if( cnt==0 ) continue;
if( pObjTab ) cnt++;
@@ -138838,11 +145672,11 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
aRoot[0] = cnt;
/* Make sure sufficient number of registers have been allocated */
- pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
+ sqlcipher_sqlite3TouchRegister(pParse, 8+cnt);
sqlcipher_sqlite3ClearTempRegCache(pParse);
/* Do the b-tree integrity checks */
- sqlcipher_sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
+ sqlcipher_sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY);
sqlcipher_sqlite3VdbeChangeP5(v, (u8)i);
addr = sqlcipher_sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
sqlcipher_sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
@@ -138852,20 +145686,59 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
integrityCheckResultRow(v);
sqlcipher_sqlite3VdbeJumpHere(v, addr);
+ /* Check that the indexes all have the right number of rows */
+ cnt = pObjTab ? 1 : 0;
+ sqlcipher_sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ int iTab = 0;
+ Table *pTab = sqliteHashData(x);
+ Index *pIdx;
+ if( pObjTab && pObjTab!=pTab ) continue;
+ if( HasRowid(pTab) ){
+ iTab = cnt++;
+ }else{
+ iTab = cnt;
+ for(pIdx=pTab->pIndex; ALWAYS(pIdx); pIdx=pIdx->pNext){
+ if( IsPrimaryKeyIndex(pIdx) ) break;
+ iTab++;
+ }
+ }
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->pPartIdxWhere==0 ){
+ addr = sqlcipher_sqlite3VdbeAddOp3(v, OP_Eq, 8+cnt, 0, 8+iTab);
+ VdbeCoverageNeverNull(v);
+ sqlcipher_sqlite3VdbeLoadString(v, 4, pIdx->zName);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
+ integrityCheckResultRow(v);
+ sqlcipher_sqlite3VdbeJumpHere(v, addr);
+ }
+ cnt++;
+ }
+ }
+
/* Make sure all the indices are constructed correctly.
*/
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx, *pPk;
- Index *pPrior = 0;
+ Index *pPrior = 0; /* Previous index */
int loopTop;
int iDataCur, iIdxCur;
int r1 = -1;
- int bStrict;
+ int bStrict; /* True for a STRICT table */
+ int r2; /* Previous key for WITHOUT ROWID tables */
+ int mxCol; /* Maximum non-virtual column number */
- if( !IsOrdinaryTable(pTab) ) continue;
if( pObjTab && pObjTab!=pTab ) continue;
- pPk = HasRowid(pTab) ? 0 : sqlcipher_sqlite3PrimaryKeyIndex(pTab);
+ if( !IsOrdinaryTable(pTab) ) continue;
+ if( isQuick || HasRowid(pTab) ){
+ pPk = 0;
+ r2 = 0;
+ }else{
+ pPk = sqlcipher_sqlite3PrimaryKeyIndex(pTab);
+ r2 = sqlcipher_sqlite3GetTempRange(pParse, pPk->nKeyCol);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Null, 1, r2, r2+pPk->nKeyCol-1);
+ }
sqlcipher_sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
1, 0, &iDataCur, &iIdxCur);
/* reg[7] counts the number of entries in the table.
@@ -138879,52 +145752,181 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
assert( sqlcipher_sqlite3NoTempsInRange(pParse,1,7+j) );
sqlcipher_sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlcipher_sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
+
+ /* Fetch the right-most column from the table. This will cause
+ ** the entire record header to be parsed and sanity checked. It
+ ** will also prepopulate the cursor column cache that is used
+ ** by the OP_IsType code, so it is a required step.
+ */
+ assert( !IsVirtual(pTab) );
+ if( HasRowid(pTab) ){
+ mxCol = -1;
+ for(j=0; j<pTab->nCol; j++){
+ if( (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)==0 ) mxCol++;
+ }
+ if( mxCol==pTab->iPKey ) mxCol--;
+ }else{
+ /* COLFLAG_VIRTUAL columns are not included in the WITHOUT ROWID
+ ** PK index column-count, so there is no need to account for them
+ ** in this case. */
+ mxCol = sqlcipher_sqlite3PrimaryKeyIndex(pTab)->nColumn-1;
+ }
+ if( mxCol>=0 ){
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, iDataCur, mxCol, 3);
+ sqlcipher_sqlite3VdbeTypeofColumn(v, 3);
+ }
+
if( !isQuick ){
- /* Sanity check on record header decoding */
- sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3);
- sqlcipher_sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
- VdbeComment((v, "(right-most column)"));
+ if( pPk ){
+ /* Verify WITHOUT ROWID keys are in ascending order */
+ int a1;
+ char *zErr;
+ a1 = sqlcipher_sqlite3VdbeAddOp4Int(v, OP_IdxGT, iDataCur, 0,r2,pPk->nKeyCol);
+ VdbeCoverage(v);
+ sqlcipher_sqlite3VdbeAddOp1(v, OP_IsNull, r2); VdbeCoverage(v);
+ zErr = sqlcipher_sqlite3MPrintf(db,
+ "row not in PRIMARY KEY order for %s",
+ pTab->zName);
+ sqlcipher_sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
+ integrityCheckResultRow(v);
+ sqlcipher_sqlite3VdbeJumpHere(v, a1);
+ sqlcipher_sqlite3VdbeJumpHere(v, a1+1);
+ for(j=0; j<pPk->nKeyCol; j++){
+ sqlcipher_sqlite3ExprCodeLoadIndexColumn(pParse, pPk, iDataCur, j, r2+j);
+ }
+ }
}
- /* Verify that all NOT NULL columns really are NOT NULL. At the
- ** same time verify the type of the content of STRICT tables */
+ /* Verify datatypes for all columns:
+ **
+ ** (1) NOT NULL columns may not contain a NULL
+ ** (2) Datatype must be exact for non-ANY columns in STRICT tables
+ ** (3) Datatype for TEXT columns in non-STRICT tables must be
+ ** NULL, TEXT, or BLOB.
+ ** (4) Datatype for numeric columns in non-STRICT tables must not
+ ** be a TEXT value that can be losslessly converted to numeric.
+ */
bStrict = (pTab->tabFlags & TF_Strict)!=0;
for(j=0; j<pTab->nCol; j++){
char *zErr;
- Column *pCol = pTab->aCol + j;
- int doError, jmp2;
+ Column *pCol = pTab->aCol + j; /* The column to be checked */
+ int labelError; /* Jump here to report an error */
+ int labelOk; /* Jump here if all looks ok */
+ int p1, p3, p4; /* Operands to the OP_IsType opcode */
+ int doTypeCheck; /* Check datatypes (besides NOT NULL) */
+
if( j==pTab->iPKey ) continue;
- if( pCol->notNull==0 && !bStrict ) continue;
- doError = bStrict ? sqlcipher_sqlite3VdbeMakeLabel(pParse) : 0;
- sqlcipher_sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
- if( sqlcipher_sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){
- sqlcipher_sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ if( bStrict ){
+ doTypeCheck = pCol->eCType>COLTYPE_ANY;
+ }else{
+ doTypeCheck = pCol->affinity>SQLITE_AFF_BLOB;
+ }
+ if( pCol->notNull==0 && !doTypeCheck ) continue;
+
+ /* Compute the operands that will be needed for OP_IsType */
+ p4 = SQLITE_NULL;
+ if( pCol->colFlags & COLFLAG_VIRTUAL ){
+ sqlcipher_sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
+ p1 = -1;
+ p3 = 3;
+ }else{
+ if( pCol->iDflt ){
+ sqlcipher_sqlite3_value *pDfltValue = 0;
+ sqlcipher_sqlite3ValueFromExpr(db, sqlcipher_sqlite3ColumnExpr(pTab,pCol), ENC(db),
+ pCol->affinity, &pDfltValue);
+ if( pDfltValue ){
+ p4 = sqlcipher_sqlite3_value_type(pDfltValue);
+ sqlcipher_sqlite3ValueFree(pDfltValue);
+ }
+ }
+ p1 = iDataCur;
+ if( !HasRowid(pTab) ){
+ testcase( j!=sqlcipher_sqlite3TableColumnToStorage(pTab, j) );
+ p3 = sqlcipher_sqlite3TableColumnToIndex(sqlcipher_sqlite3PrimaryKeyIndex(pTab), j);
+ }else{
+ p3 = sqlcipher_sqlite3TableColumnToStorage(pTab,j);
+ testcase( p3!=j);
+ }
}
+
+ labelError = sqlcipher_sqlite3VdbeMakeLabel(pParse);
+ labelOk = sqlcipher_sqlite3VdbeMakeLabel(pParse);
if( pCol->notNull ){
- jmp2 = sqlcipher_sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
+ /* (1) NOT NULL columns may not contain a NULL */
+ int jmp3;
+ int jmp2 = sqlcipher_sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ VdbeCoverage(v);
+ if( p1<0 ){
+ sqlcipher_sqlite3VdbeChangeP5(v, 0x0f); /* INT, REAL, TEXT, or BLOB */
+ jmp3 = jmp2;
+ }else{
+ sqlcipher_sqlite3VdbeChangeP5(v, 0x0d); /* INT, TEXT, or BLOB */
+ /* OP_IsType does not detect NaN values in the database file
+ ** which should be treated as a NULL. So if the header type
+ ** is REAL, we have to load the actual data using OP_Column
+ ** to reliably determine if the value is a NULL. */
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3);
+ sqlcipher_sqlite3ColumnDefault(v, pTab, j, 3);
+ jmp3 = sqlcipher_sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk);
+ VdbeCoverage(v);
+ }
zErr = sqlcipher_sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pCol->zCnName);
sqlcipher_sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- if( bStrict && pCol->eCType!=COLTYPE_ANY ){
- sqlcipher_sqlite3VdbeGoto(v, doError);
+ if( doTypeCheck ){
+ sqlcipher_sqlite3VdbeGoto(v, labelError);
+ sqlcipher_sqlite3VdbeJumpHere(v, jmp2);
+ sqlcipher_sqlite3VdbeJumpHere(v, jmp3);
}else{
- integrityCheckResultRow(v);
+ /* VDBE byte code will fall thru */
}
- sqlcipher_sqlite3VdbeJumpHere(v, jmp2);
}
- if( (pTab->tabFlags & TF_Strict)!=0
- && pCol->eCType!=COLTYPE_ANY
- ){
- jmp2 = sqlcipher_sqlite3VdbeAddOp3(v, OP_IsNullOrType, 3, 0,
- sqlcipher_sqlite3StdTypeMap[pCol->eCType-1]);
+ if( bStrict && doTypeCheck ){
+ /* (2) Datatype must be exact for non-ANY columns in STRICT tables*/
+ static unsigned char aStdTypeMask[] = {
+ 0x1f, /* ANY */
+ 0x18, /* BLOB */
+ 0x11, /* INT */
+ 0x11, /* INTEGER */
+ 0x13, /* REAL */
+ 0x14 /* TEXT */
+ };
+ sqlcipher_sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ assert( pCol->eCType>=1 && pCol->eCType<=sizeof(aStdTypeMask) );
+ sqlcipher_sqlite3VdbeChangeP5(v, aStdTypeMask[pCol->eCType-1]);
VdbeCoverage(v);
zErr = sqlcipher_sqlite3MPrintf(db, "non-%s value in %s.%s",
sqlcipher_sqlite3StdType[pCol->eCType-1],
pTab->zName, pTab->aCol[j].zCnName);
sqlcipher_sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- sqlcipher_sqlite3VdbeResolveLabel(v, doError);
- integrityCheckResultRow(v);
- sqlcipher_sqlite3VdbeJumpHere(v, jmp2);
+ }else if( !bStrict && pCol->affinity==SQLITE_AFF_TEXT ){
+ /* (3) Datatype for TEXT columns in non-STRICT tables must be
+ ** NULL, TEXT, or BLOB. */
+ sqlcipher_sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ sqlcipher_sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
+ VdbeCoverage(v);
+ zErr = sqlcipher_sqlite3MPrintf(db, "NUMERIC value in %s.%s",
+ pTab->zName, pTab->aCol[j].zCnName);
+ sqlcipher_sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
+ }else if( !bStrict && pCol->affinity>=SQLITE_AFF_NUMERIC ){
+ /* (4) Datatype for numeric columns in non-STRICT tables must not
+ ** be a TEXT value that can be converted to numeric. */
+ sqlcipher_sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ sqlcipher_sqlite3VdbeChangeP5(v, 0x1b); /* NULL, INT, FLOAT, or BLOB */
+ VdbeCoverage(v);
+ if( p1>=0 ){
+ sqlcipher_sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
+ }
+ sqlcipher_sqlite3VdbeAddOp4(v, OP_Affinity, 3, 1, 0, "C", P4_STATIC);
+ sqlcipher_sqlite3VdbeAddOp4Int(v, OP_IsType, -1, labelOk, 3, p4);
+ sqlcipher_sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
+ VdbeCoverage(v);
+ zErr = sqlcipher_sqlite3MPrintf(db, "TEXT value in %s.%s",
+ pTab->zName, pTab->aCol[j].zCnName);
+ sqlcipher_sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
}
+ sqlcipher_sqlite3VdbeResolveLabel(v, labelError);
+ integrityCheckResultRow(v);
+ sqlcipher_sqlite3VdbeResolveLabel(v, labelOk);
}
/* Verify CHECK constraints */
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
@@ -138953,7 +145955,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
if( !isQuick ){ /* Omit the remaining tests for quick_check */
/* Validate index entries for the current row */
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
- int jmp2, jmp3, jmp4, jmp5;
+ int jmp2, jmp3, jmp4, jmp5, label6;
+ int kk;
int ckUniq = sqlcipher_sqlite3VdbeMakeLabel(pParse);
if( pPk==pIdx ) continue;
r1 = sqlcipher_sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
@@ -138971,13 +145974,49 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
sqlcipher_sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
jmp4 = integrityCheckResultRow(v);
sqlcipher_sqlite3VdbeJumpHere(v, jmp2);
+
+ /* The OP_IdxRowid opcode is an optimized version of OP_Column
+ ** that extracts the rowid off the end of the index record.
+ ** But it only works correctly if index record does not have
+ ** any extra bytes at the end. Verify that this is the case. */
+ if( HasRowid(pTab) ){
+ int jmp7;
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur+j, 3);
+ jmp7 = sqlcipher_sqlite3VdbeAddOp3(v, OP_Eq, 3, 0, r1+pIdx->nColumn-1);
+ VdbeCoverageNeverNull(v);
+ sqlcipher_sqlite3VdbeLoadString(v, 3,
+ "rowid not at end-of-record for row ");
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
+ sqlcipher_sqlite3VdbeLoadString(v, 4, " of index ");
+ sqlcipher_sqlite3VdbeGoto(v, jmp5-1);
+ sqlcipher_sqlite3VdbeJumpHere(v, jmp7);
+ }
+
+ /* Any indexed columns with non-BINARY collations must still hold
+ ** the exact same text value as the table. */
+ label6 = 0;
+ for(kk=0; kk<pIdx->nKeyCol; kk++){
+ if( pIdx->azColl[kk]==sqlcipher_sqlite3StrBINARY ) continue;
+ if( label6==0 ) label6 = sqlcipher_sqlite3VdbeMakeLabel(pParse);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, iIdxCur+j, kk, 3);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Ne, 3, label6, r1+kk); VdbeCoverage(v);
+ }
+ if( label6 ){
+ int jmp6 = sqlcipher_sqlite3VdbeAddOp0(v, OP_Goto);
+ sqlcipher_sqlite3VdbeResolveLabel(v, label6);
+ sqlcipher_sqlite3VdbeLoadString(v, 3, "row ");
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
+ sqlcipher_sqlite3VdbeLoadString(v, 4, " values differ from index ");
+ sqlcipher_sqlite3VdbeGoto(v, jmp5-1);
+ sqlcipher_sqlite3VdbeJumpHere(v, jmp6);
+ }
+
/* For UNIQUE indexes, verify that only one entry exists with the
** current key. The entry is unique if (1) any column is NULL
** or (2) the next entry has a different key */
if( IsUniqueIndex(pIdx) ){
int uniqOk = sqlcipher_sqlite3VdbeMakeLabel(pParse);
int jmp6;
- int kk;
for(kk=0; kk<pIdx->nKeyCol; kk++){
int iCol = pIdx->aiColumn[kk];
assert( iCol!=XN_ROWID && iCol<pTab->nCol );
@@ -139000,20 +146039,43 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
}
sqlcipher_sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlcipher_sqlite3VdbeJumpHere(v, loopTop-1);
- if( !isQuick ){
- sqlcipher_sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
- for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
- if( pPk==pIdx ) continue;
- sqlcipher_sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
- addr = sqlcipher_sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
- sqlcipher_sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
- sqlcipher_sqlite3VdbeLoadString(v, 4, pIdx->zName);
- sqlcipher_sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
- integrityCheckResultRow(v);
- sqlcipher_sqlite3VdbeJumpHere(v, addr);
- }
+ if( pPk ){
+ assert( !isQuick );
+ sqlcipher_sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
}
}
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ /* Second pass to invoke the xIntegrity method on all virtual
+ ** tables.
+ */
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ Table *pTab = sqliteHashData(x);
+ sqlcipher_sqlite3_vtab *pVTab;
+ int a1;
+ if( pObjTab && pObjTab!=pTab ) continue;
+ if( IsOrdinaryTable(pTab) ) continue;
+ if( !IsVirtual(pTab) ) continue;
+ if( pTab->nCol<=0 ){
+ const char *zMod = pTab->u.vtab.azArg[0];
+ if( sqlcipher_sqlite3HashFind(&db->aModule, zMod)==0 ) continue;
+ }
+ sqlcipher_sqlite3ViewGetColumnNames(pParse, pTab);
+ if( pTab->u.vtab.p==0 ) continue;
+ pVTab = pTab->u.vtab.p->pVtab;
+ if( NEVER(pVTab==0) ) continue;
+ if( NEVER(pVTab->pModule==0) ) continue;
+ if( pVTab->pModule->iVersion<4 ) continue;
+ if( pVTab->pModule->xIntegrity==0 ) continue;
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick);
+ pTab->nTabRef++;
+ sqlcipher_sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF);
+ a1 = sqlcipher_sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
+ integrityCheckResultRow(v);
+ sqlcipher_sqlite3VdbeJumpHere(v, a1);
+ continue;
+ }
+#endif
}
{
static const int iLn = VDBE_OFFSET_LINENO(2);
@@ -139162,6 +146224,11 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
aOp[1].p2 = iCookie;
aOp[1].p3 = sqlcipher_sqlite3Atoi(zRight);
aOp[1].p5 = 1;
+ if( iCookie==BTREE_SCHEMA_VERSION && (db->flags & SQLITE_Defensive)!=0 ){
+ /* Do not allow the use of PRAGMA schema_version=VALUE in defensive
+ ** mode. Change the OP_SetCookie opcode into a no-op. */
+ aOp[1].opcode = OP_Noop;
+ }
}else{
/* Read the specified cookie value */
static const VdbeOpList readCookie[] = {
@@ -139272,44 +146339,63 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
**
** The optional argument is a bitmask of optimizations to perform:
**
- ** 0x0001 Debugging mode. Do not actually perform any optimizations
- ** but instead return one line of text for each optimization
- ** that would have been done. Off by default.
+ ** 0x00001 Debugging mode. Do not actually perform any optimizations
+ ** but instead return one line of text for each optimization
+ ** that would have been done. Off by default.
**
- ** 0x0002 Run ANALYZE on tables that might benefit. On by default.
- ** See below for additional information.
+ ** 0x00002 Run ANALYZE on tables that might benefit. On by default.
+ ** See below for additional information.
**
- ** 0x0004 (Not yet implemented) Record usage and performance
- ** information from the current session in the
- ** database file so that it will be available to "optimize"
- ** pragmas run by future database connections.
+ ** 0x00010 Run all ANALYZE operations using an analysis_limit that
+ ** is the lessor of the current analysis_limit and the
+ ** SQLITE_DEFAULT_OPTIMIZE_LIMIT compile-time option.
+ ** The default value of SQLITE_DEFAULT_OPTIMIZE_LIMIT is
+ ** currently (2024-02-19) set to 2000, which is such that
+ ** the worst case run-time for PRAGMA optimize on a 100MB
+ ** database will usually be less than 100 milliseconds on
+ ** a RaspberryPI-4 class machine. On by default.
**
- ** 0x0008 (Not yet implemented) Create indexes that might have
- ** been helpful to recent queries
+ ** 0x10000 Look at tables to see if they need to be reanalyzed
+ ** due to growth or shrinkage even if they have not been
+ ** queried during the current connection. Off by default.
**
- ** The default MASK is and always shall be 0xfffe. 0xfffe means perform all
- ** of the optimizations listed above except Debug Mode, including new
- ** optimizations that have not yet been invented. If new optimizations are
- ** ever added that should be off by default, those off-by-default
- ** optimizations will have bitmasks of 0x10000 or larger.
+ ** The default MASK is and always shall be 0x0fffe. In the current
+ ** implementation, the default mask only covers the 0x00002 optimization,
+ ** though additional optimizations that are covered by 0x0fffe might be
+ ** added in the future. Optimizations that are off by default and must
+ ** be explicitly requested have masks of 0x10000 or greater.
**
** DETERMINATION OF WHEN TO RUN ANALYZE
**
** In the current implementation, a table is analyzed if only if all of
** the following are true:
**
- ** (1) MASK bit 0x02 is set.
+ ** (1) MASK bit 0x00002 is set.
**
- ** (2) The query planner used sqlite_stat1-style statistics for one or
- ** more indexes of the table at some point during the lifetime of
- ** the current connection.
+ ** (2) The table is an ordinary table, not a virtual table or view.
**
- ** (3) One or more indexes of the table are currently unanalyzed OR
- ** the number of rows in the table has increased by 25 times or more
- ** since the last time ANALYZE was run.
+ ** (3) The table name does not begin with "sqlite_".
+ **
+ ** (4) One or more of the following is true:
+ ** (4a) The 0x10000 MASK bit is set.
+ ** (4b) One or more indexes on the table lacks an entry
+ ** in the sqlite_stat1 table.
+ ** (4c) The query planner used sqlite_stat1-style statistics for one
+ ** or more indexes of the table at some point during the lifetime
+ ** of the current connection.
+ **
+ ** (5) One or more of the following is true:
+ ** (5a) One or more indexes on the table lacks an entry
+ ** in the sqlite_stat1 table. (Same as 4a)
+ ** (5b) The number of rows in the table has increased or decreased by
+ ** 10-fold. In other words, the current size of the table is
+ ** 10 times larger than the size in sqlite_stat1 or else the
+ ** current size is less than 1/10th the size in sqlite_stat1.
**
** The rules for when tables are analyzed are likely to change in
- ** future releases.
+ ** future releases. Future versions of SQLite might accept a string
+ ** literal argument to this pragma that contains a mnemonic description
+ ** of the options rather than a bitmap.
*/
case PragTyp_OPTIMIZE: {
int iDbLast; /* Loop termination point for the schema loop */
@@ -139318,9 +146404,13 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
Schema *pSchema; /* The current schema */
Table *pTab; /* A table in the schema */
Index *pIdx; /* An index of the table */
- LogEst szThreshold; /* Size threshold above which reanalysis is needd */
+ LogEst szThreshold; /* Size threshold above which reanalysis needed */
char *zSubSql; /* SQL statement for the OP_SqlExec opcode */
u32 opMask; /* Mask of operations to perform */
+ int nLimit; /* Analysis limit to use */
+ int nCheck = 0; /* Number of tables to be optimized */
+ int nBtree = 0; /* Number of btrees to scan */
+ int nIndex; /* Number of indexes on the current table */
if( zRight ){
opMask = (u32)sqlcipher_sqlite3Atoi(zRight);
@@ -139328,6 +146418,14 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
}else{
opMask = 0xfffe;
}
+ if( (opMask & 0x10)==0 ){
+ nLimit = 0;
+ }else if( db->nAnalysisLimit>0
+ && db->nAnalysisLimit<SQLITE_DEFAULT_OPTIMIZE_LIMIT ){
+ nLimit = 0;
+ }else{
+ nLimit = SQLITE_DEFAULT_OPTIMIZE_LIMIT;
+ }
iTabCur = pParse->nTab++;
for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){
if( iDb==1 ) continue;
@@ -139336,23 +146434,61 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
pTab = (Table*)sqliteHashData(k);
- /* If table pTab has not been used in a way that would benefit from
- ** having analysis statistics during the current session, then skip it.
- ** This also has the effect of skipping virtual tables and views */
- if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue;
+ /* This only works for ordinary tables */
+ if( !IsOrdinaryTable(pTab) ) continue;
- /* Reanalyze if the table is 25 times larger than the last analysis */
- szThreshold = pTab->nRowLogEst + 46; assert( sqlcipher_sqlite3LogEst(25)==46 );
+ /* Do not scan system tables */
+ if( 0==sqlcipher_sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ) continue;
+
+ /* Find the size of the table as last recorded in sqlite_stat1.
+ ** If any index is unanalyzed, then the threshold is -1 to
+ ** indicate a new, unanalyzed index
+ */
+ szThreshold = pTab->nRowLogEst;
+ nIndex = 0;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ nIndex++;
if( !pIdx->hasStat1 ){
- szThreshold = 0; /* Always analyze if any index lacks statistics */
- break;
+ szThreshold = -1; /* Always analyze if any index lacks statistics */
}
}
- if( szThreshold ){
- sqlcipher_sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
- sqlcipher_sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur,
- sqlcipher_sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold);
+
+ /* If table pTab has not been used in a way that would benefit from
+ ** having analysis statistics during the current session, then skip it,
+ ** unless the 0x10000 MASK bit is set. */
+ if( (pTab->tabFlags & TF_MaybeReanalyze)!=0 ){
+ /* Check for size change if stat1 has been used for a query */
+ }else if( opMask & 0x10000 ){
+ /* Check for size change if 0x10000 is set */
+ }else if( pTab->pIndex!=0 && szThreshold<0 ){
+ /* Do analysis if unanalyzed indexes exists */
+ }else{
+ /* Otherwise, we can skip this table */
+ continue;
+ }
+
+ nCheck++;
+ if( nCheck==2 ){
+ /* If ANALYZE might be invoked two or more times, hold a write
+ ** transaction for efficiency */
+ sqlcipher_sqlite3BeginWriteOperation(pParse, 0, iDb);
+ }
+ nBtree += nIndex+1;
+
+ /* Reanalyze if the table is 10 times larger or smaller than
+ ** the last analysis. Unconditional reanalysis if there are
+ ** unanalyzed indexes. */
+ sqlcipher_sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
+ if( szThreshold>=0 ){
+ const LogEst iRange = 33; /* 10x size change */
+ sqlcipher_sqlite3VdbeAddOp4Int(v, OP_IfSizeBetween, iTabCur,
+ sqlcipher_sqlite3VdbeCurrentAddr(v)+2+(opMask&1),
+ szThreshold>=iRange ? szThreshold-iRange : -1,
+ szThreshold+iRange);
+ VdbeCoverage(v);
+ }else{
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_Rewind, iTabCur,
+ sqlcipher_sqlite3VdbeCurrentAddr(v)+2+(opMask&1));
VdbeCoverage(v);
}
zSubSql = sqlcipher_sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"",
@@ -139362,11 +146498,27 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
sqlcipher_sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC);
sqlcipher_sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1);
}else{
- sqlcipher_sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC);
+ sqlcipher_sqlite3VdbeAddOp4(v, OP_SqlExec, nLimit ? 0x02 : 00, nLimit, 0,
+ zSubSql, P4_DYNAMIC);
}
}
}
sqlcipher_sqlite3VdbeAddOp0(v, OP_Expire);
+
+ /* In a schema with a large number of tables and indexes, scale back
+ ** the analysis_limit to avoid excess run-time in the worst case.
+ */
+ if( !db->mallocFailed && nLimit>0 && nBtree>100 ){
+ int iAddr, iEnd;
+ VdbeOp *aOp;
+ nLimit = 100*nLimit/nBtree;
+ if( nLimit<100 ) nLimit = 100;
+ aOp = sqlcipher_sqlite3VdbeGetOp(v, 0);
+ iEnd = sqlcipher_sqlite3VdbeCurrentAddr(v);
+ for(iAddr=0; iAddr<iEnd; iAddr++){
+ if( aOp[iAddr].opcode==OP_SqlExec ) aOp[iAddr].p2 = nLimit;
+ }
+ }
break;
}
@@ -139532,6 +146684,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Pragma(
sqlcipher_sqlite3VdbeSetNumCols(v, 1);
sqlcipher_sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "ok", SQLITE_STATIC);
returnSingleText(v, "ok");
+ } else {
+ sqlcipher_sqlite3ErrorMsg(pParse, "An error occurred with PRAGMA key or rekey. "
+ "PRAGMA key requires a key of one or more characters. "
+ "PRAGMA rekey can only be run on an existing encrypted database. "
+ "Use sqlcipher_export() and ATTACH to convert encrypted/plaintext databases.");
+ goto pragma_out;
}
}
break;
@@ -139673,9 +146831,9 @@ static int pragmaVtabBestIndex(sqlcipher_sqlite3_vtab *tab, sqlcipher_sqlite3_in
seen[0] = 0;
seen[1] = 0;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
- if( pConstraint->usable==0 ) continue;
- if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
if( pConstraint->iColumn < pTab->iHidden ) continue;
+ if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ if( pConstraint->usable==0 ) return SQLITE_CONSTRAINT;
j = pConstraint->iColumn - pTab->iHidden;
assert( j < 2 );
seen[j] = i+1;
@@ -139688,12 +146846,13 @@ static int pragmaVtabBestIndex(sqlcipher_sqlite3_vtab *tab, sqlcipher_sqlite3_in
j = seen[0]-1;
pIdxInfo->aConstraintUsage[j].argvIndex = 1;
pIdxInfo->aConstraintUsage[j].omit = 1;
- if( seen[1]==0 ) return SQLITE_OK;
pIdxInfo->estimatedCost = (double)20;
pIdxInfo->estimatedRows = 20;
- j = seen[1]-1;
- pIdxInfo->aConstraintUsage[j].argvIndex = 2;
- pIdxInfo->aConstraintUsage[j].omit = 1;
+ if( seen[1] ){
+ j = seen[1]-1;
+ pIdxInfo->aConstraintUsage[j].argvIndex = 2;
+ pIdxInfo->aConstraintUsage[j].omit = 1;
+ }
return SQLITE_OK;
}
@@ -139713,6 +146872,7 @@ static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){
int i;
sqlcipher_sqlite3_finalize(pCsr->pPragma);
pCsr->pPragma = 0;
+ pCsr->iRowid = 0;
for(i=0; i<ArraySize(pCsr->azArg); i++){
sqlcipher_sqlite3_free(pCsr->azArg[i]);
pCsr->azArg[i] = 0;
@@ -139853,7 +147013,8 @@ static const sqlcipher_sqlite3_module pragmaVtabModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
/*
@@ -140185,7 +147346,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3InitOne(sqlcipher_sqlite3 *db, int iDb, char
#else
encoding = SQLITE_UTF8;
#endif
- sqlcipher_sqlite3SetTextEncoding(db, encoding);
+ if( db->nVdbeActive>0 && encoding!=ENC(db)
+ && (db->mDbFlags & DBFLAG_Vacuum)==0
+ ){
+ rc = SQLITE_LOCKED;
+ goto initone_error_out;
+ }else{
+ sqlcipher_sqlite3SetTextEncoding(db, encoding);
+ }
}else{
/* If opening an attached database, the encoding much match ENC(db) */
if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){
@@ -140399,8 +147567,8 @@ static void schemaIsValid(Parse *pParse){
sqlcipher_sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie);
assert( sqlcipher_sqlite3SchemaMutexHeld(db, iDb, 0) );
if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){
+ if( DbHasProperty(db, iDb, DB_SchemaLoaded) ) pParse->rc = SQLITE_SCHEMA;
sqlcipher_sqlite3ResetOneSchema(db, iDb);
- pParse->rc = SQLITE_SCHEMA;
}
/* Close the transaction, if one was opened. */
@@ -140453,15 +147621,15 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ParseObjectReset(Parse *pParse){
assert( db->pParse==pParse );
assert( pParse->nested==0 );
#ifndef SQLITE_OMIT_SHARED_CACHE
- sqlcipher_sqlite3DbFree(db, pParse->aTableLock);
+ if( pParse->aTableLock ) sqlcipher_sqlite3DbNNFreeNN(db, pParse->aTableLock);
#endif
while( pParse->pCleanup ){
ParseCleanup *pCleanup = pParse->pCleanup;
pParse->pCleanup = pCleanup->pNext;
pCleanup->xCleanup(db, pCleanup->pPtr);
- sqlcipher_sqlite3DbFreeNN(db, pCleanup);
+ sqlcipher_sqlite3DbNNFreeNN(db, pCleanup);
}
- sqlcipher_sqlite3DbFree(db, pParse->aLabel);
+ if( pParse->aLabel ) sqlcipher_sqlite3DbNNFreeNN(db, pParse->aLabel);
if( pParse->pConstExpr ){
sqlcipher_sqlite3ExprListDelete(db, pParse->pConstExpr);
}
@@ -140470,8 +147638,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ParseObjectReset(Parse *pParse){
db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
assert( pParse->db->pParse==pParse );
db->pParse = pParse->pOuterParse;
- pParse->db = 0;
- pParse->disableLookaside = 0;
}
/*
@@ -140480,7 +147646,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ParseObjectReset(Parse *pParse){
** immediately.
**
** Use this mechanism for uncommon cleanups. There is a higher setup
-** cost for this mechansim (an extra malloc), so it should not be used
+** cost for this mechanism (an extra malloc), so it should not be used
** for common cleanups that happen on most calls. But for less
** common cleanups, we save a single NULL-pointer comparison in
** sqlcipher_sqlite3ParseObjectReset(), which reduces the total CPU cycle count.
@@ -140507,7 +147673,13 @@ SQLITE_PRIVATE void *sqlcipher_sqlite3ParserAddCleanup(
void (*xCleanup)(sqlcipher_sqlite3*,void*), /* The cleanup routine */
void *pPtr /* Pointer to object to be cleaned up */
){
- ParseCleanup *pCleanup = sqlcipher_sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup));
+ ParseCleanup *pCleanup;
+ if( sqlcipher_sqlite3FaultSim(300) ){
+ pCleanup = 0;
+ sqlcipher_sqlite3OomFault(pParse->db);
+ }else{
+ pCleanup = sqlcipher_sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup));
+ }
if( pCleanup ){
pCleanup->pNext = pParse->pCleanup;
pParse->pCleanup = pCleanup;
@@ -140572,9 +147744,18 @@ static int sqlcipher_sqlite3Prepare(
sParse.pOuterParse = db->pParse;
db->pParse = &sParse;
sParse.db = db;
- sParse.pReprepare = pReprepare;
+ if( pReprepare ){
+ sParse.pReprepare = pReprepare;
+ sParse.explain = sqlcipher_sqlite3_stmt_isexplain((sqlcipher_sqlite3_stmt*)pReprepare);
+ }else{
+ assert( sParse.pReprepare==0 );
+ }
assert( ppStmt && *ppStmt==0 );
- if( db->mallocFailed ) sqlcipher_sqlite3ErrorMsg(&sParse, "out of memory");
+ if( db->mallocFailed ){
+ sqlcipher_sqlite3ErrorMsg(&sParse, "out of memory");
+ db->errCode = rc = SQLITE_NOMEM;
+ goto end_prepare;
+ }
assert( sqlcipher_sqlite3_mutex_held(db->mutex) );
/* For a long-term use prepared statement avoid the use of
@@ -140584,7 +147765,7 @@ static int sqlcipher_sqlite3Prepare(
sParse.disableLookaside++;
DisableLookaside;
}
- sParse.disableVtab = (prepFlags & SQLITE_PREPARE_NO_VTAB)!=0;
+ sParse.prepFlags = prepFlags & 0xff;
/* Check to verify that it is possible to get a read lock on all
** database schemas. The inability to get a read lock indicates that
@@ -140625,7 +147806,9 @@ static int sqlcipher_sqlite3Prepare(
}
}
- sqlcipher_sqlite3VtabUnlockList(db);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( db->pDisconnect ) sqlcipher_sqlite3VtabUnlockList(db);
+#endif
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy;
@@ -140731,6 +147914,7 @@ static int sqlcipher_sqlite3LockAndPrepare(
assert( (rc&db->errMask)==rc );
db->busyHandler.nBusy = 0;
sqlcipher_sqlite3_mutex_leave(db->mutex);
+ assert( rc==SQLITE_OK || (*ppStmt)==0 );
return rc;
}
@@ -141009,6 +148193,10 @@ struct SortCtx {
} aDefer[4];
#endif
struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrPush; /* First instruction to push data into sorter */
+ int addrPushEnd; /* Last instruction that pushes data into sorter */
+#endif
};
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
@@ -141020,6 +148208,7 @@ struct SortCtx {
** If bFree==0, Leave the first Select object unfreed
*/
static void clearSelect(sqlcipher_sqlite3 *db, Select *p, int bFree){
+ assert( db!=0 );
while( p ){
Select *pPrior = p->pPrior;
sqlcipher_sqlite3ExprListDelete(db, p->pEList);
@@ -141039,7 +148228,7 @@ static void clearSelect(sqlcipher_sqlite3 *db, Select *p, int bFree){
sqlcipher_sqlite3WindowUnlinkFromSelect(p->pWin);
}
#endif
- if( bFree ) sqlcipher_sqlite3DbFreeNN(db, p);
+ if( bFree ) sqlcipher_sqlite3DbNNFreeNN(db, p);
p = pPrior;
bFree = 1;
}
@@ -141123,6 +148312,9 @@ SQLITE_PRIVATE Select *sqlcipher_sqlite3SelectNew(
SQLITE_PRIVATE void sqlcipher_sqlite3SelectDelete(sqlcipher_sqlite3 *db, Select *p){
if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
}
+SQLITE_PRIVATE void sqlcipher_sqlite3SelectDeleteGeneric(sqlcipher_sqlite3 *db, void *p){
+ if( ALWAYS(p) ) clearSelect(db, (Select*)p, 1);
+}
/*
** Return a pointer to the right-most SELECT statement in a compound.
@@ -141171,7 +148363,7 @@ static Select *findRightmost(Select *p){
** NATURAL FULL OUTER JT_NATRUAL|JT_LEFT|JT_RIGHT
**
** To preserve historical compatibly, SQLite also accepts a variety
-** of other non-standard and in many cases non-sensical join types.
+** of other non-standard and in many cases nonsensical join types.
** This routine makes as much sense at it can from the nonsense join
** type and returns a result. Examples of accepted nonsense join types
** include but are not limited to:
@@ -141393,6 +148585,7 @@ static void unsetJoinExpr(Expr *p, int iTable, int nullable){
}
if( p->op==TK_FUNCTION ){
assert( ExprUseXList(p) );
+ assert( p->pLeft==0 );
if( p->x.pList ){
int i;
for(i=0; i<p->x.pList->nExpr; i++){
@@ -141442,7 +148635,7 @@ static int sqlcipher_sqlite3ProcessJoin(Parse *pParse, Select *p){
if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
- /* If this is a NATURAL join, synthesize an approprate USING clause
+ /* If this is a NATURAL join, synthesize an appropriate USING clause
** to specify which columns should be joined.
*/
if( pRight->fg.jointype & JT_NATURAL ){
@@ -141656,14 +148849,18 @@ static void pushOntoSorter(
** (2) All output columns are included in the sort record. In that
** case regData==regOrigData.
** (3) Some output columns are omitted from the sort record due to
- ** the SQLITE_ENABLE_SORTER_REFERENCE optimization, or due to the
+ ** the SQLITE_ENABLE_SORTER_REFERENCES optimization, or due to the
** SQLITE_ECEL_OMITREF optimization, or due to the
- ** SortCtx.pDeferredRowLoad optimiation. In any of these cases
+ ** SortCtx.pDeferredRowLoad optimization. In any of these cases
** regOrigData is 0 to prevent this routine from trying to copy
** values that might not yet exist.
*/
assert( nData==1 || regData==regOrigData || regOrigData==0 );
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ pSort->addrPush = sqlcipher_sqlite3VdbeCurrentAddr(v);
+#endif
+
if( nPrefixReg ){
assert( nPrefixReg==nExpr+bSeq );
regBase = regData - nPrefixReg;
@@ -141710,7 +148907,7 @@ static void pushOntoSorter(
testcase( pKI->nAllField > pKI->nKeyField+2 );
pOp->p4.pKeyInfo = sqlcipher_sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat,
pKI->nAllField-pKI->nKeyField-1);
- pOp = 0; /* Ensure pOp not used after sqltie3VdbeAddOp3() */
+ pOp = 0; /* Ensure pOp not used after sqlcipher_sqlite3VdbeAddOp3() */
addrJmp = sqlcipher_sqlite3VdbeCurrentAddr(v);
sqlcipher_sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
pSort->labelBkOut = sqlcipher_sqlite3VdbeMakeLabel(pParse);
@@ -141764,6 +148961,9 @@ static void pushOntoSorter(
sqlcipher_sqlite3VdbeChangeP2(v, iSkip,
pSort->labelOBLopt ? pSort->labelOBLopt : sqlcipher_sqlite3VdbeCurrentAddr(v));
}
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ pSort->addrPushEnd = sqlcipher_sqlite3VdbeCurrentAddr(v)-1;
+#endif
}
/*
@@ -141801,7 +149001,7 @@ static void codeOffset(
** The returned value in this case is a copy of parameter iTab.
**
** WHERE_DISTINCT_ORDERED:
-** In this case rows are being delivered sorted order. The ephermal
+** In this case rows are being delivered sorted order. The ephemeral
** table is not required. Instead, the current set of values
** is compared against previous row. If they match, the new row
** is not distinct and control jumps to VM address addrRepeat. Otherwise,
@@ -142230,6 +149430,16 @@ static void selectInnerLoop(
testcase( eDest==SRT_Fifo );
testcase( eDest==SRT_DistFifo );
sqlcipher_sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg);
+#if !defined(SQLITE_ENABLE_NULL_TRIM) && defined(SQLITE_DEBUG)
+ /* A destination of SRT_Table and a non-zero iSDParm2 parameter means
+ ** that this is an "UPDATE ... FROM" on a virtual table or view. In this
+ ** case set the p5 parameter of the OP_MakeRecord to OPFLAG_NOCHNG_MAGIC.
+ ** This does not affect operation in any way - it just allows MakeRecord
+ ** to process OPFLAG_NOCHANGE values without an assert() failing. */
+ if( eDest==SRT_Table && pDest->iSDParm2 ){
+ sqlcipher_sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
+ }
+#endif
#ifndef SQLITE_OMIT_CTE
if( eDest==SRT_DistFifo ){
/* If the destination is DistFifo, then cursor (iParm+1) is open
@@ -142445,9 +149655,10 @@ SQLITE_PRIVATE KeyInfo *sqlcipher_sqlite3KeyInfoAlloc(sqlcipher_sqlite3 *db, int
*/
SQLITE_PRIVATE void sqlcipher_sqlite3KeyInfoUnref(KeyInfo *p){
if( p ){
+ assert( p->db!=0 );
assert( p->nRef>0 );
p->nRef--;
- if( p->nRef==0 ) sqlcipher_sqlite3DbFreeNN(p->db, p);
+ if( p->nRef==0 ) sqlcipher_sqlite3DbNNFreeNN(p->db, p);
}
}
@@ -142586,6 +149797,23 @@ static void generateSortTail(
int bSeq; /* True if sorter record includes seq. no. */
int nRefKey = 0;
struct ExprList_item *aOutEx = p->pEList->a;
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExplain; /* Address of OP_Explain instruction */
+#endif
+
+ nKey = pOrderBy->nExpr - pSort->nOBSat;
+ if( pSort->nOBSat==0 || nKey==1 ){
+ ExplainQueryPlan2(addrExplain, (pParse, 0,
+ "USE TEMP B-TREE FOR %sORDER BY", pSort->nOBSat?"LAST TERM OF ":""
+ ));
+ }else{
+ ExplainQueryPlan2(addrExplain, (pParse, 0,
+ "USE TEMP B-TREE FOR LAST %d TERMS OF ORDER BY", nKey
+ ));
+ }
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExplain,pSort->addrPush,pSort->addrPushEnd);
+ sqlcipher_sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, pSort->addrPush);
+
assert( addrBreak<0 );
if( pSort->labelBkOut ){
@@ -142620,7 +149848,6 @@ static void generateSortTail(
regRow = sqlcipher_sqlite3GetTempRange(pParse, nColumn);
}
}
- nKey = pOrderBy->nExpr - pSort->nOBSat;
if( pSort->sortFlags & SORTFLAG_UseSorter ){
int regSortOut = ++pParse->nMem;
iSortTab = pParse->nTab++;
@@ -142698,6 +149925,7 @@ static void generateSortTail(
VdbeComment((v, "%s", aOutEx[i].zEName));
}
}
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
switch( eDest ){
case SRT_Table:
case SRT_EphemTab: {
@@ -142759,6 +149987,7 @@ static void generateSortTail(
}else{
sqlcipher_sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
}
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExplain, sqlcipher_sqlite3VdbeCurrentAddr(v)-1, -1);
if( pSort->regReturn ) sqlcipher_sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn);
sqlcipher_sqlite3VdbeResolveLabel(v, addrBreak);
}
@@ -142767,9 +149996,6 @@ static void generateSortTail(
** Return a pointer to a string containing the 'declaration type' of the
** expression pExpr. The string may be treated as static by the caller.
**
-** Also try to estimate the size of the returned value and return that
-** result in *pEstWidth.
-**
** The declaration type is the exact datatype definition extracted from the
** original CREATE TABLE statement if the expression is a column. The
** declaration type for a ROWID field is INTEGER. Exactly when an expression
@@ -142861,11 +150087,7 @@ static const char *columnTypeImpl(
** data for the result-set column of the sub-select.
*/
if( iCol<pS->pEList->nExpr
-#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
- && iCol>=0
-#else
- && ALWAYS(iCol>=0)
-#endif
+ && (!ViewCanHaveRowid || iCol>=0)
){
/* If iCol is less than zero, then the expression requests the
** rowid of the sub-select or view. This expression is legal (see
@@ -143023,17 +150245,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3GenerateColumnNames(
int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */
int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */
-#ifndef SQLITE_OMIT_EXPLAIN
- /* If this is an EXPLAIN, skip this step */
- if( pParse->explain ){
- return;
- }
-#endif
-
if( pParse->colNamesSet ) return;
/* Column names are determined by the left-most term of a compound select */
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
- SELECTTRACE(1,pParse,pSelect,("generating column names\n"));
+ TREETRACE(0x80,pParse,pSelect,("generating column names\n"));
pTabList = pSelect->pSrc;
pEList = pSelect->pEList;
assert( v!=0 );
@@ -143133,7 +150348,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ColumnsFromExprList(
*pnCol = nCol;
*paCol = aCol;
- for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
+ for(i=0, pCol=aCol; i<nCol && !pParse->nErr; i++, pCol++){
struct ExprList_item *pX = &pEList->a[i];
struct ExprList_item *pCollide;
/* Get an appropriate name for the column
@@ -143183,7 +150398,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ColumnsFromExprList(
if( zName[j]==':' ) nName = j;
}
zName = sqlcipher_sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt);
- if( cnt>3 ) sqlcipher_sqlite3_randomness(sizeof(cnt), &cnt);
+ sqlcipher_sqlite3ProgressCheck(pParse);
+ if( cnt>3 ){
+ sqlcipher_sqlite3_randomness(sizeof(cnt), &cnt);
+ }
}
pCol->zCnName = zName;
pCol->hName = sqlcipher_sqlite3StrIHash(zName);
@@ -143196,71 +150414,109 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ColumnsFromExprList(
}
}
sqlcipher_sqlite3HashClear(&ht);
- if( db->mallocFailed ){
+ if( pParse->nErr ){
for(j=0; j<i; j++){
sqlcipher_sqlite3DbFree(db, aCol[j].zCnName);
}
sqlcipher_sqlite3DbFree(db, aCol);
*paCol = 0;
*pnCol = 0;
- return SQLITE_NOMEM_BKPT;
+ return pParse->rc;
}
return SQLITE_OK;
}
/*
-** Add type and collation information to a column list based on
-** a SELECT statement.
-**
-** The column list presumably came from selectColumnNamesFromExprList().
-** The column list has only names, not types or collations. This
-** routine goes through and adds the types and collations.
+** pTab is a transient Table object that represents a subquery of some
+** kind (maybe a parenthesized subquery in the FROM clause of a larger
+** query, or a VIEW, or a CTE). This routine computes type information
+** for that Table object based on the Select object that implements the
+** subquery. For the purposes of this routine, "type information" means:
**
-** This routine requires that all identifiers in the SELECT
-** statement be resolved.
+** * The datatype name, as it might appear in a CREATE TABLE statement
+** * Which collating sequence to use for the column
+** * The affinity of the column
*/
-SQLITE_PRIVATE void sqlcipher_sqlite3SelectAddColumnTypeAndCollation(
- Parse *pParse, /* Parsing contexts */
- Table *pTab, /* Add column type information to this table */
- Select *pSelect, /* SELECT used to determine types and collations */
- char aff /* Default affinity for columns */
+SQLITE_PRIVATE void sqlcipher_sqlite3SubqueryColumnTypes(
+ Parse *pParse, /* Parsing contexts */
+ Table *pTab, /* Add column type information to this table */
+ Select *pSelect, /* SELECT used to determine types and collations */
+ char aff /* Default affinity. */
){
sqlcipher_sqlite3 *db = pParse->db;
- NameContext sNC;
Column *pCol;
CollSeq *pColl;
- int i;
+ int i,j;
Expr *p;
struct ExprList_item *a;
+ NameContext sNC;
assert( pSelect!=0 );
assert( (pSelect->selFlags & SF_Resolved)!=0 );
- assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed );
- if( db->mallocFailed ) return;
+ assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 );
+ assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB );
+ if( db->mallocFailed || IN_RENAME_OBJECT ) return;
+ while( pSelect->pPrior ) pSelect = pSelect->pPrior;
+ a = pSelect->pEList->a;
memset(&sNC, 0, sizeof(sNC));
sNC.pSrcList = pSelect->pSrc;
- a = pSelect->pEList->a;
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
const char *zType;
- i64 n, m;
+ i64 n;
+ int m = 0;
+ Select *pS2 = pSelect;
pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT);
p = a[i].pExpr;
- zType = columnType(&sNC, p, 0, 0, 0);
/* pCol->szEst = ... // Column size est for SELECT tables never used */
pCol->affinity = sqlcipher_sqlite3ExprAffinity(p);
+ while( pCol->affinity<=SQLITE_AFF_NONE && pS2->pNext!=0 ){
+ m |= sqlcipher_sqlite3ExprDataType(pS2->pEList->a[i].pExpr);
+ pS2 = pS2->pNext;
+ pCol->affinity = sqlcipher_sqlite3ExprAffinity(pS2->pEList->a[i].pExpr);
+ }
+ if( pCol->affinity<=SQLITE_AFF_NONE ){
+ pCol->affinity = aff;
+ }
+ if( pCol->affinity>=SQLITE_AFF_TEXT && (pS2->pNext || pS2!=pSelect) ){
+ for(pS2=pS2->pNext; pS2; pS2=pS2->pNext){
+ m |= sqlcipher_sqlite3ExprDataType(pS2->pEList->a[i].pExpr);
+ }
+ if( pCol->affinity==SQLITE_AFF_TEXT && (m&0x01)!=0 ){
+ pCol->affinity = SQLITE_AFF_BLOB;
+ }else
+ if( pCol->affinity>=SQLITE_AFF_NUMERIC && (m&0x02)!=0 ){
+ pCol->affinity = SQLITE_AFF_BLOB;
+ }
+ if( pCol->affinity>=SQLITE_AFF_NUMERIC && p->op==TK_CAST ){
+ pCol->affinity = SQLITE_AFF_FLEXNUM;
+ }
+ }
+ zType = columnType(&sNC, p, 0, 0, 0);
+ if( zType==0 || pCol->affinity!=sqlcipher_sqlite3AffinityType(zType, 0) ){
+ if( pCol->affinity==SQLITE_AFF_NUMERIC
+ || pCol->affinity==SQLITE_AFF_FLEXNUM
+ ){
+ zType = "NUM";
+ }else{
+ zType = 0;
+ for(j=1; j<SQLITE_N_STDTYPE; j++){
+ if( sqlcipher_sqlite3StdTypeAffinity[j]==pCol->affinity ){
+ zType = sqlcipher_sqlite3StdType[j];
+ break;
+ }
+ }
+ }
+ }
if( zType ){
- m = sqlcipher_sqlite3Strlen30(zType);
+ const i64 k = sqlcipher_sqlite3Strlen30(zType);
n = sqlcipher_sqlite3Strlen30(pCol->zCnName);
- pCol->zCnName = sqlcipher_sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
+ pCol->zCnName = sqlcipher_sqlite3DbReallocOrFree(db, pCol->zCnName, n+k+2);
+ pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
if( pCol->zCnName ){
- memcpy(&pCol->zCnName[n+1], zType, m+1);
+ memcpy(&pCol->zCnName[n+1], zType, k+1);
pCol->colFlags |= COLFLAG_HASTYPE;
- }else{
- testcase( pCol->colFlags & COLFLAG_HASTYPE );
- pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
}
}
- if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff;
pColl = sqlcipher_sqlite3ExprCollSeq(pParse, p);
if( pColl ){
assert( pTab->pIndex==0 );
@@ -143294,7 +150550,7 @@ SQLITE_PRIVATE Table *sqlcipher_sqlite3ResultSetOfSelect(Parse *pParse, Select *
pTab->zName = 0;
pTab->nRowLogEst = 200; assert( 200==sqlcipher_sqlite3LogEst(1048576) );
sqlcipher_sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
- sqlcipher_sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect, aff);
+ sqlcipher_sqlite3SubqueryColumnTypes(pParse, pTab, pSelect, aff);
pTab->iPKey = -1;
if( db->mallocFailed ){
sqlcipher_sqlite3DeleteTable(db, pTab);
@@ -143509,7 +150765,7 @@ static void generateWithRecursiveQuery(
int iQueue; /* The Queue table */
int iDistinct = 0; /* To ensure unique results if UNION */
int eDest = SRT_Fifo; /* How to write to Queue */
- SelectDest destQueue; /* SelectDest targetting the Queue table */
+ SelectDest destQueue; /* SelectDest targeting the Queue table */
int i; /* Loop counter */
int rc; /* Result code */
ExprList *pOrderBy; /* The ORDER BY clause */
@@ -143819,7 +151075,7 @@ static int multiSelect(
pPrior->iLimit = p->iLimit;
pPrior->iOffset = p->iOffset;
pPrior->pLimit = p->pLimit;
- SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL left...\n"));
+ TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL left...\n"));
rc = sqlcipher_sqlite3Select(pParse, pPrior, &dest);
pPrior->pLimit = 0;
if( rc ){
@@ -143837,7 +151093,7 @@ static int multiSelect(
}
}
ExplainQueryPlan((pParse, 1, "UNION ALL"));
- SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL right...\n"));
+ TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL right...\n"));
rc = sqlcipher_sqlite3Select(pParse, p, &dest);
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
@@ -143890,7 +151146,7 @@ static int multiSelect(
*/
assert( !pPrior->pOrderBy );
sqlcipher_sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
- SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION left...\n"));
+ TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION left...\n"));
rc = sqlcipher_sqlite3Select(pParse, pPrior, &uniondest);
if( rc ){
goto multi_select_end;
@@ -143910,7 +151166,7 @@ static int multiSelect(
uniondest.eDest = op;
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
sqlcipher_sqlite3SelectOpName(p->op)));
- SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION right...\n"));
+ TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION right...\n"));
rc = sqlcipher_sqlite3Select(pParse, p, &uniondest);
testcase( rc!=SQLITE_OK );
assert( p->pOrderBy==0 );
@@ -143971,7 +151227,7 @@ static int multiSelect(
/* Code the SELECTs to our left into temporary table "tab1".
*/
sqlcipher_sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
- SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT left...\n"));
+ TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT left...\n"));
rc = sqlcipher_sqlite3Select(pParse, pPrior, &intersectdest);
if( rc ){
goto multi_select_end;
@@ -143988,7 +151244,7 @@ static int multiSelect(
intersectdest.iSDParm = tab2;
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
sqlcipher_sqlite3SelectOpName(p->op)));
- SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT right...\n"));
+ TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT right...\n"));
rc = sqlcipher_sqlite3Select(pParse, p, &intersectdest);
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
@@ -144085,9 +151341,7 @@ multi_select_end:
pDest->iSdst = dest.iSdst;
pDest->nSdst = dest.nSdst;
if( pDelete ){
- sqlcipher_sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlcipher_sqlite3*,void*))sqlcipher_sqlite3SelectDelete,
- pDelete);
+ sqlcipher_sqlite3ParserAddCleanup(pParse, sqlcipher_sqlite3SelectDeleteGeneric, pDelete);
}
return rc;
}
@@ -144109,7 +151363,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3SelectWrongNumTermsError(Parse *pParse, Sel
/*
** Code an output subroutine for a coroutine implementation of a
-** SELECT statment.
+** SELECT statement.
**
** The data to be output is contained in pIn->iSdst. There are
** pIn->nSdst columns to be output. pDest is where the output should
@@ -144331,7 +151585,7 @@ static int generateOutputSubroutine(
**
** We call AltB, AeqB, AgtB, EofA, and EofB "subroutines" but they are not
** actually called using Gosub and they do not Return. EofA and EofB loop
-** until all data is exhausted then jump to the "end" labe. AltB, AeqB,
+** until all data is exhausted then jump to the "end" label. AltB, AeqB,
** and AgtB jump to either L2 or to one of EofA or EofB.
*/
#ifndef SQLITE_OMIT_COMPOUND_SELECT
@@ -144368,7 +151622,7 @@ static int multiSelectOrderBy(
int savedOffset; /* Saved value of p->iOffset */
int labelCmpr; /* Label for the start of the merge algorithm */
int labelEnd; /* Label for the end of the overall SELECT stmt */
- int addr1; /* Jump instructions that get retargetted */
+ int addr1; /* Jump instructions that get retargeted */
int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
KeyInfo *pKeyMerge; /* Comparison information for merging rows */
@@ -144635,11 +151889,10 @@ static int multiSelectOrderBy(
*/
sqlcipher_sqlite3VdbeResolveLabel(v, labelEnd);
- /* Reassemble the compound query so that it will be freed correctly
- ** by the calling function */
+ /* Make arrangements to free the 2nd and subsequent arms of the compound
+ ** after the parse has finished */
if( pSplit->pPrior ){
- sqlcipher_sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlcipher_sqlite3*,void*))sqlcipher_sqlite3SelectDelete, pSplit->pPrior);
+ sqlcipher_sqlite3ParserAddCleanup(pParse, sqlcipher_sqlite3SelectDeleteGeneric, pSplit->pPrior);
}
pSplit->pPrior = pPrior;
pPrior->pNext = pSplit;
@@ -144669,7 +151922,7 @@ static int multiSelectOrderBy(
** the left operands of a RIGHT JOIN. In either case, we need to potentially
** bypass the substituted expression with OP_IfNullRow.
**
-** Suppose the original expression integer constant. Even though the table
+** Suppose the original expression is an integer constant. Even though the table
** has the nullRow flag set, because the expression is an integer constant,
** it will not be NULLed out. So instead, we insert an OP_IfNullRow opcode
** that checks to see if the nullRow flag is set on the table. If the nullRow
@@ -144695,6 +151948,7 @@ typedef struct SubstContext {
int iNewTable; /* New table number */
int isOuterJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */
ExprList *pEList; /* Replacement expressions */
+ ExprList *pCList; /* Collation sequences for replacement expr */
} SubstContext;
/* Forward Declarations */
@@ -144736,19 +151990,26 @@ static Expr *substExpr(
#endif
{
Expr *pNew;
- Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
+ int iColumn;
+ Expr *pCopy;
Expr ifNullRow;
- assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
+ iColumn = pExpr->iColumn;
+ assert( iColumn>=0 );
+ assert( pSubst->pEList!=0 && iColumn<pSubst->pEList->nExpr );
assert( pExpr->pRight==0 );
+ pCopy = pSubst->pEList->a[iColumn].pExpr;
if( sqlcipher_sqlite3ExprIsVector(pCopy) ){
sqlcipher_sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
}else{
sqlcipher_sqlite3 *db = pSubst->pParse->db;
- if( pSubst->isOuterJoin && pCopy->op!=TK_COLUMN ){
+ if( pSubst->isOuterJoin
+ && (pCopy->op!=TK_COLUMN || pCopy->iTable!=pSubst->iNewTable)
+ ){
memset(&ifNullRow, 0, sizeof(ifNullRow));
ifNullRow.op = TK_IF_NULL_ROW;
ifNullRow.pLeft = pCopy;
ifNullRow.iTable = pSubst->iNewTable;
+ ifNullRow.iColumn = -99;
ifNullRow.flags = EP_IfNullRow;
pCopy = &ifNullRow;
}
@@ -144775,11 +152036,16 @@ static Expr *substExpr(
/* Ensure that the expression now has an implicit collation sequence,
** just as it did when it was a column of a view or sub-query. */
- if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){
- CollSeq *pColl = sqlcipher_sqlite3ExprCollSeq(pSubst->pParse, pExpr);
- pExpr = sqlcipher_sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
- (pColl ? pColl->zName : "BINARY")
+ {
+ CollSeq *pNat = sqlcipher_sqlite3ExprCollSeq(pSubst->pParse, pExpr);
+ CollSeq *pColl = sqlcipher_sqlite3ExprCollSeq(pSubst->pParse,
+ pSubst->pCList->a[iColumn].pExpr
);
+ if( pNat!=pColl || (pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE) ){
+ pExpr = sqlcipher_sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
+ (pColl ? pColl->zName : "BINARY")
+ );
+ }
}
ExprClearProperty(pExpr, EP_Collate);
}
@@ -144972,6 +152238,46 @@ static void renumberCursors(
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
+/*
+** If pSel is not part of a compound SELECT, return a pointer to its
+** expression list. Otherwise, return a pointer to the expression list
+** of the leftmost SELECT in the compound.
+*/
+static ExprList *findLeftmostExprlist(Select *pSel){
+ while( pSel->pPrior ){
+ pSel = pSel->pPrior;
+ }
+ return pSel->pEList;
+}
+
+/*
+** Return true if any of the result-set columns in the compound query
+** have incompatible affinities on one or more arms of the compound.
+*/
+static int compoundHasDifferentAffinities(Select *p){
+ int ii;
+ ExprList *pList;
+ assert( p!=0 );
+ assert( p->pEList!=0 );
+ assert( p->pPrior!=0 );
+ pList = p->pEList;
+ for(ii=0; ii<pList->nExpr; ii++){
+ char aff;
+ Select *pSub1;
+ assert( pList->a[ii].pExpr!=0 );
+ aff = sqlcipher_sqlite3ExprAffinity(pList->a[ii].pExpr);
+ for(pSub1=p->pPrior; pSub1; pSub1=pSub1->pPrior){
+ assert( pSub1->pEList!=0 );
+ assert( pSub1->pEList->nExpr>ii );
+ assert( pSub1->pEList->a[ii].pExpr!=0 );
+ if( sqlcipher_sqlite3ExprAffinity(pSub1->pEList->a[ii].pExpr)!=aff ){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/*
** This routine attempts to flatten subqueries as a performance optimization.
@@ -145016,7 +152322,8 @@ static void renumberCursors(
** (3a) the subquery may not be a join and
** (3b) the FROM clause of the subquery may not contain a virtual
** table and
-** (3c) the outer query may not be an aggregate.
+** (**) Was: "The outer query may not have a GROUP BY." This case
+** is now managed correctly
** (3d) the outer query may not be DISTINCT.
** See also (26) for restrictions on RIGHT JOIN.
**
@@ -145039,7 +152346,7 @@ static void renumberCursors(
** (9) If the subquery uses LIMIT then the outer query may not be aggregate.
**
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
-** accidently carried the comment forward until 2014-09-15. Original
+** accidentally carried the comment forward until 2014-09-15. Original
** constraint: "If the subquery is aggregate then the outer query
** may not use LIMIT."
**
@@ -145073,6 +152380,8 @@ static void renumberCursors(
** (17g) either the subquery is the first element of the outer
** query or there are no RIGHT or FULL JOINs in any arm
** of the subquery. (This is a duplicate of condition (27b).)
+** (17h) The corresponding result set expressions in all arms of the
+** compound must have the same affinity.
**
** The parent and sub-query may contain WHERE clauses. Subject to
** rules (11), (13) and (14), they may also contain ORDER BY,
@@ -145124,18 +152433,13 @@ static void renumberCursors(
** See also (3) for restrictions on LEFT JOIN.
**
** (27) The subquery may not contain a FULL or RIGHT JOIN unless it
-** is the first element of the parent query. This must be the
-** the case if:
-** (27a) the subquery is not compound query, and
+** is the first element of the parent query. Two subcases:
+** (27a) the subquery is not a compound query.
** (27b) the subquery is a compound query and the RIGHT JOIN occurs
** in any arm of the compound query. (See also (17g).)
**
-** (28) The subquery is not a MATERIALIZED CTE.
-**
-** (29) Either the subquery is not the right-hand operand of a join with an
-** ON or USING clause nor the right-hand operand of a NATURAL JOIN, or
-** the right-most table within the FROM clause of the subquery
-** is not part of an outer join.
+** (28) The subquery is not a MATERIALIZED CTE. (This is handled
+** in the caller before ever reaching this routine.)
**
**
** In this routine, the "p" parameter is a pointer to the outer query.
@@ -145228,16 +152532,10 @@ static int flattenSubquery(
**
** which is not at all the same thing.
**
- ** If the subquery is the right operand of a LEFT JOIN, then the outer
- ** query cannot be an aggregate. (3c) This is an artifact of the way
- ** aggregates are processed - there is no mechanism to determine if
- ** the LEFT JOIN table should be all-NULL.
- **
** See also tickets #306, #350, and #3300.
*/
if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
if( pSubSrc->nSrc>1 /* (3a) */
- || isAgg /* (3c) */
|| IsVirtual(pSubSrc->a[0].pTab) /* (3b) */
|| (p->selFlags & SF_Distinct)!=0 /* (3d) */
|| (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
@@ -145246,52 +152544,14 @@ static int flattenSubquery(
}
isOuterJoin = 1;
}
-#ifdef SQLITE_EXTRA_IFNULLROW
- else if( iFrom>0 && !isAgg ){
- /* Setting isOuterJoin to -1 causes OP_IfNullRow opcodes to be generated for
- ** every reference to any result column from subquery in a join, even
- ** though they are not necessary. This will stress-test the OP_IfNullRow
- ** opcode. */
- isOuterJoin = -1;
- }
-#endif
assert( pSubSrc->nSrc>0 ); /* True by restriction (7) */
if( iFrom>0 && (pSubSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
return 0; /* Restriction (27a) */
}
- if( pSubitem->fg.isCte && pSubitem->u2.pCteUse->eM10d==M10d_Yes ){
- return 0; /* (28) */
- }
- /* Restriction (29):
- **
- ** We do not want two constraints on the same term of the flattened
- ** query where one constraint has EP_InnerON and the other is EP_OuterON.
- ** To prevent this, one or the other of the following conditions must be
- ** false:
- **
- ** (29a) The right-most entry in the FROM clause of the subquery
- ** must not be part of an outer join.
- **
- ** (29b) The subquery itself must not be the right operand of a
- ** NATURAL join or a join that as an ON or USING clause.
- **
- ** These conditions are sufficient to keep an EP_OuterON from being
- ** flattened into an EP_InnerON. Restrictions (3a) and (27a) prevent
- ** an EP_InnerON from being flattened into an EP_OuterON.
- */
- if( pSubSrc->nSrc>=2
- && (pSubSrc->a[pSubSrc->nSrc-1].fg.jointype & JT_OUTER)!=0
- ){
- if( (pSubitem->fg.jointype & JT_NATURAL)!=0
- || pSubitem->fg.isUsing
- || NEVER(pSubitem->u3.pOn!=0) /* ON clause already shifted into WHERE */
- || pSubitem->fg.isOn
- ){
- return 0;
- }
- }
+ /* Condition (28) is blocked by the caller */
+ assert( !pSubitem->fg.isCte || pSubitem->u2.pCteUse->eM10d!=M10d_Yes );
/* Restriction (17): If the sub-query is a compound SELECT, then it must
** use only the UNION ALL operator. And none of the simple select queries
@@ -145299,6 +152559,7 @@ static int flattenSubquery(
** queries.
*/
if( pSub->pPrior ){
+ int ii;
if( pSub->pOrderBy ){
return 0; /* Restriction (20) */
}
@@ -145331,7 +152592,6 @@ static int flattenSubquery(
/* Restriction (18). */
if( p->pOrderBy ){
- int ii;
for(ii=0; ii<p->pOrderBy->nExpr; ii++){
if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0;
}
@@ -145340,6 +152600,9 @@ static int flattenSubquery(
/* Restriction (23) */
if( (p->selFlags & SF_Recursive) ) return 0;
+ /* Restriction (17h) */
+ if( compoundHasDifferentAffinities(pSub) ) return 0;
+
if( pSrc->nSrc>1 ){
if( pParse->nSelect>500 ) return 0;
if( OptimizationDisabled(db, SQLITE_FlttnUnionAll) ) return 0;
@@ -145349,7 +152612,7 @@ static int flattenSubquery(
}
/***** If we reach this point, flattening is permitted. *****/
- SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n",
+ TREETRACE(0x4,pParse,p,("flatten %u.%p from term %d\n",
pSub->selId, pSub, iFrom));
/* Authorize the subquery */
@@ -145358,7 +152621,7 @@ static int flattenSubquery(
testcase( i==SQLITE_DENY );
pParse->zAuthContext = zSavedAuthContext;
- /* Delete the transient structures associated with thesubquery */
+ /* Delete the transient structures associated with the subquery */
pSub1 = pSubitem->pSelect;
sqlcipher_sqlite3DbFree(db, pSubitem->zDatabase);
sqlcipher_sqlite3DbFree(db, pSubitem->zName);
@@ -145428,7 +152691,7 @@ static int flattenSubquery(
if( pPrior ) pPrior->pNext = pNew;
pNew->pNext = p;
p->pPrior = pNew;
- SELECTTRACE(2,pParse,p,("compound-subquery flattener"
+ TREETRACE(0x4,pParse,p,("compound-subquery flattener"
" creates %u as peer\n",pNew->selId));
}
assert( pSubitem->pSelect==0 );
@@ -145450,9 +152713,7 @@ static int flattenSubquery(
Table *pTabToDel = pSubitem->pTab;
if( pTabToDel->nTabRef==1 ){
Parse *pToplevel = sqlcipher_sqlite3ParseToplevel(pParse);
- sqlcipher_sqlite3ParserAddCleanup(pToplevel,
- (void(*)(sqlcipher_sqlite3*,void*))sqlcipher_sqlite3DeleteTable,
- pTabToDel);
+ sqlcipher_sqlite3ParserAddCleanup(pToplevel, sqlcipher_sqlite3DeleteTableGeneric, pTabToDel);
testcase( pToplevel->earlyCleanup );
}else{
pTabToDel->nTabRef--;
@@ -145540,7 +152801,7 @@ static int flattenSubquery(
** ORDER BY column expression is identical to the iOrderByCol'th
** expression returned by SELECT statement pSub. Since these values
** do not necessarily correspond to columns in SELECT statement pParent,
- ** zero them before transfering the ORDER BY clause.
+ ** zero them before transferring the ORDER BY clause.
**
** Not doing this may cause an error if a subsequent call to this
** function attempts to flatten a compound sub-query into pParent
@@ -145573,6 +152834,7 @@ static int flattenSubquery(
x.iNewTable = iNewParent;
x.isOuterJoin = isOuterJoin;
x.pEList = pSub->pEList;
+ x.pCList = findLeftmostExprlist(pSub);
substSelect(&x, pParent, 0);
}
@@ -145592,23 +152854,22 @@ static int flattenSubquery(
pSub->pLimit = 0;
}
- /* Recompute the SrcList_item.colUsed masks for the flattened
+ /* Recompute the SrcItem.colUsed masks for the flattened
** tables. */
for(i=0; i<nSubSrc; i++){
recomputeColumnsUsed(pParent, &pSrc->a[i+iFrom]);
}
}
- /* Finially, delete what is left of the subquery and return
- ** success.
+ /* Finally, delete what is left of the subquery and return success.
*/
sqlcipher_sqlite3AggInfoPersistWalkerInit(&w, pParse);
sqlcipher_sqlite3WalkSelect(&w,pSub1);
sqlcipher_sqlite3SelectDelete(db, pSub1);
#if TREETRACE_ENABLED
- if( sqlcipher_sqlite3TreeTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
+ if( sqlcipher_sqlite3TreeTrace & 0x4 ){
+ TREETRACE(0x4,pParse,p,("After flattening:\n"));
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -145635,7 +152896,7 @@ struct WhereConst {
/*
** Add a new entry to the pConst object. Except, do not add duplicate
-** pColumn entires. Also, do not add if doing so would not be appropriate.
+** pColumn entries. Also, do not add if doing so would not be appropriate.
**
** The caller guarantees the pColumn is a column and pValue is a constant.
** This routine has to do some additional checks before completing the
@@ -145649,7 +152910,7 @@ static void constInsert(
){
int i;
assert( pColumn->op==TK_COLUMN );
- assert( sqlcipher_sqlite3ExprIsConstant(pValue) );
+ assert( sqlcipher_sqlite3ExprIsConstant(pConst->pParse, pValue) );
if( ExprHasProperty(pColumn, EP_FixedCol) ) return;
if( sqlcipher_sqlite3ExprAffinity(pValue)!=0 ) return;
@@ -145707,10 +152968,10 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
pLeft = pExpr->pLeft;
assert( pRight!=0 );
assert( pLeft!=0 );
- if( pRight->op==TK_COLUMN && sqlcipher_sqlite3ExprIsConstant(pLeft) ){
+ if( pRight->op==TK_COLUMN && sqlcipher_sqlite3ExprIsConstant(pConst->pParse, pLeft) ){
constInsert(pConst,pRight,pLeft,pExpr);
}
- if( pLeft->op==TK_COLUMN && sqlcipher_sqlite3ExprIsConstant(pRight) ){
+ if( pLeft->op==TK_COLUMN && sqlcipher_sqlite3ExprIsConstant(pConst->pParse, pRight) ){
constInsert(pConst,pLeft,pRight,pExpr);
}
}
@@ -145821,7 +153082,7 @@ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
** SELECT * FROM t1 WHERE a=123 AND b=123;
**
** The two SELECT statements above should return different answers. b=a
-** is alway true because the comparison uses numeric affinity, but b=123
+** is always true because the comparison uses numeric affinity, but b=123
** is false because it uses text affinity and '0123' is not the same as '123'.
** To work around this, the expression tree is not actually changed from
** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol
@@ -145905,7 +153166,7 @@ static int propagateConstants(
** At the time this function is called it is guaranteed that
**
** * the sub-query uses only one distinct window frame, and
-** * that the window frame has a PARTITION BY clase.
+** * that the window frame has a PARTITION BY clause.
*/
static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
assert( pSubq->pWin->pPartition );
@@ -145931,6 +153192,18 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
** The hope is that the terms added to the inner query will make it more
** efficient.
**
+** NAME AMBIGUITY
+**
+** This optimization is called the "WHERE-clause push-down optimization".
+**
+** Do not confuse this optimization with another unrelated optimization
+** with a similar name: The "MySQL push-down optimization" causes WHERE
+** clause terms that can be evaluated using only the index and without
+** reference to the table are run first, so that if they are false,
+** unnecessary table seeks are avoided.
+**
+** RULES
+**
** Do not attempt this optimization if:
**
** (1) (** This restriction was removed on 2017-09-29. We used to
@@ -145982,6 +153255,33 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
** be materialized. (This restriction is implemented in the calling
** routine.)
**
+** (8) If the subquery is a compound that uses UNION, INTERSECT,
+** or EXCEPT, then all of the result set columns for all arms of
+** the compound must use the BINARY collating sequence.
+**
+** (9) All three of the following are true:
+**
+** (9a) The WHERE clause expression originates in the ON or USING clause
+** of a join (either an INNER or an OUTER join), and
+**
+** (9b) The subquery is to the right of the ON/USING clause
+**
+** (9c) There is a RIGHT JOIN (or FULL JOIN) in between the ON/USING
+** clause and the subquery.
+**
+** Without this restriction, the WHERE-clause push-down optimization
+** might move the ON/USING filter expression from the left side of a
+** RIGHT JOIN over to the right side, which leads to incorrect answers.
+** See also restriction (6) in sqlcipher_sqlite3ExprIsSingleTableConstraint().
+**
+** (10) The inner query is not the right-hand table of a RIGHT JOIN.
+**
+** (11) The subquery is not a VALUES clause
+**
+** (12) The WHERE clause is not "rowid ISNULL" or the equivalent. This
+** case only comes up if SQLite is compiled using
+** SQLITE_ALLOW_ROWID_IN_VIEW.
+**
** Return 0 if no changes are made and non-zero if one or more WHERE clause
** terms are duplicated into the subquery.
*/
@@ -145989,24 +153289,56 @@ static int pushDownWhereTerms(
Parse *pParse, /* Parse context (for malloc() and error reporting) */
Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
Expr *pWhere, /* The WHERE clause of the outer query */
- SrcItem *pSrc /* The subquery term of the outer FROM clause */
+ SrcList *pSrcList, /* The complete from clause of the outer query */
+ int iSrc /* Which FROM clause term to try to push into */
){
Expr *pNew;
+ SrcItem *pSrc; /* The subquery FROM term into which WHERE is pushed */
int nChng = 0;
+ pSrc = &pSrcList->a[iSrc];
if( pWhere==0 ) return 0;
- if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0;
- if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ) return 0;
+ if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ){
+ return 0; /* restrictions (2) and (11) */
+ }
+ if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ){
+ return 0; /* restrictions (10) */
+ }
-#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSubq->pPrior ){
Select *pSel;
+ int notUnionAll = 0;
for(pSel=pSubq; pSel; pSel=pSel->pPrior){
+ u8 op = pSel->op;
+ assert( op==TK_ALL || op==TK_SELECT
+ || op==TK_UNION || op==TK_INTERSECT || op==TK_EXCEPT );
+ if( op!=TK_ALL && op!=TK_SELECT ){
+ notUnionAll = 1;
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSel->pWin ) return 0; /* restriction (6b) */
+#endif
+ }
+ if( notUnionAll ){
+ /* If any of the compound arms are connected using UNION, INTERSECT,
+ ** or EXCEPT, then we must ensure that none of the columns use a
+ ** non-BINARY collating sequence. */
+ for(pSel=pSubq; pSel; pSel=pSel->pPrior){
+ int ii;
+ const ExprList *pList = pSel->pEList;
+ assert( pList!=0 );
+ for(ii=0; ii<pList->nExpr; ii++){
+ CollSeq *pColl = sqlcipher_sqlite3ExprCollSeq(pParse, pList->a[ii].pExpr);
+ if( !sqlcipher_sqlite3IsBinary(pColl) ){
+ return 0; /* Restriction (8) */
+ }
+ }
+ }
}
}else{
+#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSubq->pWin && pSubq->pWin->pPartition==0 ) return 0;
- }
#endif
+ }
#ifdef SQLITE_DEBUG
/* Only the first term of a compound can have a WITH clause. But make
@@ -146025,11 +153357,28 @@ static int pushDownWhereTerms(
return 0; /* restriction (3) */
}
while( pWhere->op==TK_AND ){
- nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrc);
+ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrcList, iSrc);
pWhere = pWhere->pLeft;
}
-#if 0 /* Legacy code. Checks now done by sqlcipher_sqlite3ExprIsTableConstraint() */
+#if 0 /* These checks now done by sqlcipher_sqlite3ExprIsSingleTableConstraint() */
+ if( ExprHasProperty(pWhere, EP_OuterON|EP_InnerON) /* (9a) */
+ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (9c) */
+ ){
+ int jj;
+ for(jj=0; jj<iSrc; jj++){
+ if( pWhere->w.iJoin==pSrcList->a[jj].iCursor ){
+ /* If we reach this point, both (9a) and (9b) are satisfied.
+ ** The following loop checks (9c):
+ */
+ for(jj++; jj<iSrc; jj++){
+ if( (pSrcList->a[jj].fg.jointype & JT_RIGHT)!=0 ){
+ return 0; /* restriction (9) */
+ }
+ }
+ }
+ }
+ }
if( isLeftJoin
&& (ExprHasProperty(pWhere,EP_OuterON)==0
|| pWhere->w.iJoin!=iCursor)
@@ -146043,7 +153392,19 @@ static int pushDownWhereTerms(
}
#endif
- if( sqlcipher_sqlite3ExprIsTableConstraint(pWhere, pSrc) ){
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ if( ViewCanHaveRowid && (pWhere->op==TK_ISNULL || pWhere->op==TK_NOTNULL) ){
+ Expr *pLeft = pWhere->pLeft;
+ if( ALWAYS(pLeft)
+ && pLeft->op==TK_COLUMN
+ && pLeft->iColumn < 0
+ ){
+ return 0; /* Restriction (12) */
+ }
+ }
+#endif
+
+ if( sqlcipher_sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc, 1) ){
nChng++;
pSubq->selFlags |= SF_PushDown;
while( pSubq ){
@@ -146055,6 +153416,7 @@ static int pushDownWhereTerms(
x.iNewTable = pSrc->iCursor;
x.isOuterJoin = 0;
x.pEList = pSubq->pEList;
+ x.pCList = findLeftmostExprlist(pSubq);
pNew = substExpr(&x, pNew);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){
@@ -146077,6 +153439,78 @@ static int pushDownWhereTerms(
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
/*
+** Check to see if a subquery contains result-set columns that are
+** never used. If it does, change the value of those result-set columns
+** to NULL so that they do not cause unnecessary work to compute.
+**
+** Return the number of column that were changed to NULL.
+*/
+static int disableUnusedSubqueryResultColumns(SrcItem *pItem){
+ int nCol;
+ Select *pSub; /* The subquery to be simplified */
+ Select *pX; /* For looping over compound elements of pSub */
+ Table *pTab; /* The table that describes the subquery */
+ int j; /* Column number */
+ int nChng = 0; /* Number of columns converted to NULL */
+ Bitmask colUsed; /* Columns that may not be NULLed out */
+
+ assert( pItem!=0 );
+ if( pItem->fg.isCorrelated || pItem->fg.isCte ){
+ return 0;
+ }
+ assert( pItem->pTab!=0 );
+ pTab = pItem->pTab;
+ assert( pItem->pSelect!=0 );
+ pSub = pItem->pSelect;
+ assert( pSub->pEList->nExpr==pTab->nCol );
+ for(pX=pSub; pX; pX=pX->pPrior){
+ if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
+ testcase( pX->selFlags & SF_Distinct );
+ testcase( pX->selFlags & SF_Aggregate );
+ return 0;
+ }
+ if( pX->pPrior && pX->op!=TK_ALL ){
+ /* This optimization does not work for compound subqueries that
+ ** use UNION, INTERSECT, or EXCEPT. Only UNION ALL is allowed. */
+ return 0;
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( pX->pWin ){
+ /* This optimization does not work for subqueries that use window
+ ** functions. */
+ return 0;
+ }
+#endif
+ }
+ colUsed = pItem->colUsed;
+ if( pSub->pOrderBy ){
+ ExprList *pList = pSub->pOrderBy;
+ for(j=0; j<pList->nExpr; j++){
+ u16 iCol = pList->a[j].u.x.iOrderByCol;
+ if( iCol>0 ){
+ iCol--;
+ colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
+ }
+ }
+ }
+ nCol = pTab->nCol;
+ for(j=0; j<nCol; j++){
+ Bitmask m = j<BMS-1 ? MASKBIT(j) : TOPBIT;
+ if( (m & colUsed)!=0 ) continue;
+ for(pX=pSub; pX; pX=pX->pPrior) {
+ Expr *pY = pX->pEList->a[j].pExpr;
+ if( pY->op==TK_NULL ) continue;
+ pY->op = TK_NULL;
+ ExprClearProperty(pY, EP_Skip|EP_Unlikely);
+ pX->selFlags |= SF_PushDown;
+ nChng++;
+ }
+ }
+ return nChng;
+}
+
+
+/*
** The pFunc is the only aggregate function in the query. Check to see
** if the query is a candidate for the min/max optimization.
**
@@ -146354,8 +153788,7 @@ static struct Cte *searchWith(
SQLITE_PRIVATE With *sqlcipher_sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
if( pWith ){
if( bFree ){
- pWith = (With*)sqlcipher_sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlcipher_sqlite3*,void*))sqlcipher_sqlite3WithDelete,
+ pWith = (With*)sqlcipher_sqlite3ParserAddCleanup(pParse, sqlcipher_sqlite3WithDeleteGeneric,
pWith);
if( pWith==0 ) return 0;
}
@@ -146467,9 +153900,6 @@ static int resolveFromTermToCte(
pFrom->fg.isCte = 1;
pFrom->u2.pCteUse = pCteUse;
pCteUse->nUse++;
- if( pCteUse->nUse>=2 && pCteUse->eM10d==M10d_Any ){
- pCteUse->eM10d = M10d_Yes;
- }
/* Check if this is a recursive CTE. */
pRecTerm = pSel = pFrom->pSelect;
@@ -146579,9 +154009,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3SelectPopWith(Walker *pWalker, Select *p){
#endif
/*
-** The SrcList_item structure passed as the second argument represents a
+** The SrcItem structure passed as the second argument represents a
** sub-query in the FROM clause of a SELECT statement. This function
-** allocates and populates the SrcList_item.pTab object. If successful,
+** allocates and populates the SrcItem.pTab object. If successful,
** SQLITE_OK is returned. Otherwise, if an OOM error is encountered,
** SQLITE_NOMEM.
*/
@@ -146601,12 +154031,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom
while( pSel->pPrior ){ pSel = pSel->pPrior; }
sqlcipher_sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
pTab->iPKey = -1;
+ pTab->eTabType = TABTYP_VIEW;
pTab->nRowLogEst = 200; assert( 200==sqlcipher_sqlite3LogEst(1048576) );
#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
/* The usual case - do not allow ROWID on a subquery */
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
#else
- pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */
+ /* Legacy compatibility mode */
+ pTab->tabFlags |= TF_Ephemeral | sqlcipher_sqlite3Config.mNoVisibleRowid;
#endif
return pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
}
@@ -146843,12 +154275,20 @@ static int selectExpander(Walker *pWalker, Select *p){
** expanded. */
int tableSeen = 0; /* Set to 1 when TABLE matches */
char *zTName = 0; /* text of name of TABLE */
+ int iErrOfst;
if( pE->op==TK_DOT ){
+ assert( (selFlags & SF_NestedFrom)==0 );
assert( pE->pLeft!=0 );
assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
zTName = pE->pLeft->u.zToken;
+ assert( ExprUseWOfst(pE->pLeft) );
+ iErrOfst = pE->pRight->w.iOfst;
+ }else{
+ assert( ExprUseWOfst(pE) );
+ iErrOfst = pE->w.iOfst;
}
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
+ int nAdd; /* Number of cols including rowid */
Table *pTab = pFrom->pTab; /* Table for this data source */
ExprList *pNestedFrom; /* Result-set of a nested FROM clause */
char *zTabName; /* AS name for this data source */
@@ -146866,6 +154306,7 @@ static int selectExpander(Walker *pWalker, Select *p){
pNestedFrom = pFrom->pSelect->pEList;
assert( pNestedFrom!=0 );
assert( pNestedFrom->nExpr==pTab->nCol );
+ assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid );
}else{
if( zTName && sqlcipher_sqlite3StrICmp(zTName, zTabName)!=0 ){
continue;
@@ -146883,6 +154324,7 @@ static int selectExpander(Walker *pWalker, Select *p){
for(ii=0; ii<pUsing->nId; ii++){
const char *zUName = pUsing->a[ii].zName;
pRight = sqlcipher_sqlite3Expr(db, TK_ID, zUName);
+ sqlcipher_sqlite3ExprSetErrorOffset(pRight, iErrOfst);
pNew = sqlcipher_sqlite3ExprListAppend(pParse, pNew, pRight);
if( pNew ){
struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
@@ -146895,33 +154337,49 @@ static int selectExpander(Walker *pWalker, Select *p){
}else{
pUsing = 0;
}
- for(j=0; j<pTab->nCol; j++){
- char *zName = pTab->aCol[j].zCnName;
+
+ nAdd = pTab->nCol;
+ if( VisibleRowid(pTab) && (selFlags & SF_NestedFrom)!=0 ) nAdd++;
+ for(j=0; j<nAdd; j++){
+ const char *zName;
struct ExprList_item *pX; /* Newly added ExprList term */
- assert( zName );
- if( zTName
- && pNestedFrom
- && sqlcipher_sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 0)==0
- ){
- continue;
- }
+ if( j==pTab->nCol ){
+ zName = sqlcipher_sqlite3RowidAlias(pTab);
+ if( zName==0 ) continue;
+ }else{
+ zName = pTab->aCol[j].zCnName;
- /* If a column is marked as 'hidden', omit it from the expanded
- ** result-set list unless the SELECT has the SF_IncludeHidden
- ** bit set.
- */
- if( (p->selFlags & SF_IncludeHidden)==0
- && IsHiddenColumn(&pTab->aCol[j])
- ){
- continue;
- }
- if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
- && zTName==0
- && (selFlags & (SF_NestedFrom))==0
- ){
- continue;
+ /* If pTab is actually an SF_NestedFrom sub-select, do not
+ ** expand any ENAME_ROWID columns. */
+ if( pNestedFrom && pNestedFrom->a[j].fg.eEName==ENAME_ROWID ){
+ continue;
+ }
+
+ if( zTName
+ && pNestedFrom
+ && sqlcipher_sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 0, 0)==0
+ ){
+ continue;
+ }
+
+ /* If a column is marked as 'hidden', omit it from the expanded
+ ** result-set list unless the SELECT has the SF_IncludeHidden
+ ** bit set.
+ */
+ if( (p->selFlags & SF_IncludeHidden)==0
+ && IsHiddenColumn(&pTab->aCol[j])
+ ){
+ continue;
+ }
+ if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
+ && zTName==0
+ && (selFlags & (SF_NestedFrom))==0
+ ){
+ continue;
+ }
}
+ assert( zName );
tableSeen = 1;
if( i>0 && zTName==0 && (selFlags & SF_NestedFrom)==0 ){
@@ -146955,6 +154413,7 @@ static int selectExpander(Walker *pWalker, Select *p){
}else{
pExpr = pRight;
}
+ sqlcipher_sqlite3ExprSetErrorOffset(pExpr, iErrOfst);
pNew = sqlcipher_sqlite3ExprListAppend(pParse, pNew, pExpr);
if( pNew==0 ){
break; /* OOM */
@@ -146962,7 +154421,8 @@ static int selectExpander(Walker *pWalker, Select *p){
pX = &pNew->a[pNew->nExpr-1];
assert( pX->zEName==0 );
if( (selFlags & SF_NestedFrom)!=0 && !IN_RENAME_OBJECT ){
- if( pNestedFrom ){
+ if( pNestedFrom && (!ViewCanHaveRowid || j<pNestedFrom->nExpr) ){
+ assert( j<pNestedFrom->nExpr );
pX->zEName = sqlcipher_sqlite3DbStrDup(db, pNestedFrom->a[j].zEName);
testcase( pX->zEName==0 );
}else{
@@ -146970,11 +154430,11 @@ static int selectExpander(Walker *pWalker, Select *p){
zSchemaName, zTabName, zName);
testcase( pX->zEName==0 );
}
- pX->fg.eEName = ENAME_TAB;
+ pX->fg.eEName = (j==pTab->nCol ? ENAME_ROWID : ENAME_TAB);
if( (pFrom->fg.isUsing
&& sqlcipher_sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0)
|| (pUsing && sqlcipher_sqlite3IdListIndex(pUsing, zName)>=0)
- || (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
+ || (j<pTab->nCol && (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND))
){
pX->fg.bNoExpand = 1;
}
@@ -147009,8 +154469,8 @@ static int selectExpander(Walker *pWalker, Select *p){
}
}
#if TREETRACE_ENABLED
- if( sqlcipher_sqlite3TreeTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p,("After result-set wildcard expansion:\n"));
+ if( sqlcipher_sqlite3TreeTrace & 0x8 ){
+ TREETRACE(0x8,pParse,p,("After result-set wildcard expansion:\n"));
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -147061,14 +154521,14 @@ static void sqlcipher_sqlite3SelectExpand(Parse *pParse, Select *pSelect){
** This is a Walker.xSelectCallback callback for the sqlcipher_sqlite3SelectTypeInfo()
** interface.
**
-** For each FROM-clause subquery, add Column.zType and Column.zColl
-** information to the Table structure that represents the result set
-** of that subquery.
+** For each FROM-clause subquery, add Column.zType, Column.zColl, and
+** Column.affinity information to the Table structure that represents
+** the result set of that subquery.
**
** The Table structure that represents the result set was constructed
-** by selectExpander() but the type and collation information was omitted
-** at that point because identifiers had not yet been resolved. This
-** routine is called after identifier resolution.
+** by selectExpander() but the type and collation and affinity information
+** was omitted at that point because identifiers had not yet been resolved.
+** This routine is called after identifier resolution.
*/
static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
Parse *pParse;
@@ -147076,10 +154536,10 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
SrcList *pTabList;
SrcItem *pFrom;
- assert( p->selFlags & SF_Resolved );
if( p->selFlags & SF_HasTypeInfo ) return;
p->selFlags |= SF_HasTypeInfo;
pParse = pWalker->pParse;
+ assert( (p->selFlags & SF_Resolved) );
pTabList = p->pSrc;
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab = pFrom->pTab;
@@ -147088,9 +154548,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
/* A sub-query in the FROM clause of a SELECT */
Select *pSel = pFrom->pSelect;
if( pSel ){
- while( pSel->pPrior ) pSel = pSel->pPrior;
- sqlcipher_sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel,
- SQLITE_AFF_NONE);
+ sqlcipher_sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
}
}
}
@@ -147145,6 +154603,186 @@ SQLITE_PRIVATE void sqlcipher_sqlite3SelectPrep(
sqlcipher_sqlite3SelectAddTypeInfo(pParse, p);
}
+#if TREETRACE_ENABLED
+/*
+** Display all information about an AggInfo object
+*/
+static void printAggInfo(AggInfo *pAggInfo){
+ int ii;
+ sqlcipher_sqlite3DebugPrintf("AggInfo %d/%p:\n",
+ pAggInfo->selId, pAggInfo);
+ for(ii=0; ii<pAggInfo->nColumn; ii++){
+ struct AggInfo_col *pCol = &pAggInfo->aCol[ii];
+ sqlcipher_sqlite3DebugPrintf(
+ "agg-column[%d] pTab=%s iTable=%d iColumn=%d iMem=%d"
+ " iSorterColumn=%d %s\n",
+ ii, pCol->pTab ? pCol->pTab->zName : "NULL",
+ pCol->iTable, pCol->iColumn, pAggInfo->iFirstReg+ii,
+ pCol->iSorterColumn,
+ ii>=pAggInfo->nAccumulator ? "" : " Accumulator");
+ sqlcipher_sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
+ }
+ for(ii=0; ii<pAggInfo->nFunc; ii++){
+ sqlcipher_sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
+ ii, pAggInfo->iFirstReg+pAggInfo->nColumn+ii);
+ sqlcipher_sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0);
+ }
+}
+#endif /* TREETRACE_ENABLED */
+
+/*
+** Analyze the arguments to aggregate functions. Create new pAggInfo->aCol[]
+** entries for columns that are arguments to aggregate functions but which
+** are not otherwise used.
+**
+** The aCol[] entries in AggInfo prior to nAccumulator are columns that
+** are referenced outside of aggregate functions. These might be columns
+** that are part of the GROUP by clause, for example. Other database engines
+** would throw an error if there is a column reference that is not in the
+** GROUP BY clause and that is not part of an aggregate function argument.
+** But SQLite allows this.
+**
+** The aCol[] entries beginning with the aCol[nAccumulator] and following
+** are column references that are used exclusively as arguments to
+** aggregate functions. This routine is responsible for computing
+** (or recomputing) those aCol[] entries.
+*/
+static void analyzeAggFuncArgs(
+ AggInfo *pAggInfo,
+ NameContext *pNC
+){
+ int i;
+ assert( pAggInfo!=0 );
+ assert( pAggInfo->iFirstReg==0 );
+ pNC->ncFlags |= NC_InAggFunc;
+ for(i=0; i<pAggInfo->nFunc; i++){
+ Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
+ assert( pExpr->op==TK_FUNCTION || pExpr->op==TK_AGG_FUNCTION );
+ assert( ExprUseXList(pExpr) );
+ sqlcipher_sqlite3ExprAnalyzeAggList(pNC, pExpr->x.pList);
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ sqlcipher_sqlite3ExprAnalyzeAggList(pNC, pExpr->pLeft->x.pList);
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ assert( !IsWindowFunc(pExpr) );
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ sqlcipher_sqlite3ExprAnalyzeAggregates(pNC, pExpr->y.pWin->pFilter);
+ }
+#endif
+ }
+ pNC->ncFlags &= ~NC_InAggFunc;
+}
+
+/*
+** An index on expressions is being used in the inner loop of an
+** aggregate query with a GROUP BY clause. This routine attempts
+** to adjust the AggInfo object to take advantage of index and to
+** perhaps use the index as a covering index.
+**
+*/
+static void optimizeAggregateUseOfIndexedExpr(
+ Parse *pParse, /* Parsing context */
+ Select *pSelect, /* The SELECT statement being processed */
+ AggInfo *pAggInfo, /* The aggregate info */
+ NameContext *pNC /* Name context used to resolve agg-func args */
+){
+ assert( pAggInfo->iFirstReg==0 );
+ assert( pSelect!=0 );
+ assert( pSelect->pGroupBy!=0 );
+ pAggInfo->nColumn = pAggInfo->nAccumulator;
+ if( ALWAYS(pAggInfo->nSortingColumn>0) ){
+ int mx = pSelect->pGroupBy->nExpr - 1;
+ int j, k;
+ for(j=0; j<pAggInfo->nColumn; j++){
+ k = pAggInfo->aCol[j].iSorterColumn;
+ if( k>mx ) mx = k;
+ }
+ pAggInfo->nSortingColumn = mx+1;
+ }
+ analyzeAggFuncArgs(pAggInfo, pNC);
+#if TREETRACE_ENABLED
+ if( sqlcipher_sqlite3TreeTrace & 0x20 ){
+ IndexedExpr *pIEpr;
+ TREETRACE(0x20, pParse, pSelect,
+ ("AggInfo (possibly) adjusted for Indexed Exprs\n"));
+ sqlcipher_sqlite3TreeViewSelect(0, pSelect, 0);
+ for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){
+ printf("data-cursor=%d index={%d,%d}\n",
+ pIEpr->iDataCur, pIEpr->iIdxCur, pIEpr->iIdxCol);
+ sqlcipher_sqlite3TreeViewExpr(0, pIEpr->pExpr, 0);
+ }
+ printAggInfo(pAggInfo);
+ }
+#else
+ UNUSED_PARAMETER(pSelect);
+ UNUSED_PARAMETER(pParse);
+#endif
+}
+
+/*
+** Walker callback for aggregateConvertIndexedExprRefToColumn().
+*/
+static int aggregateIdxEprRefToColCallback(Walker *pWalker, Expr *pExpr){
+ AggInfo *pAggInfo;
+ struct AggInfo_col *pCol;
+ UNUSED_PARAMETER(pWalker);
+ if( pExpr->pAggInfo==0 ) return WRC_Continue;
+ if( pExpr->op==TK_AGG_COLUMN ) return WRC_Continue;
+ if( pExpr->op==TK_AGG_FUNCTION ) return WRC_Continue;
+ if( pExpr->op==TK_IF_NULL_ROW ) return WRC_Continue;
+ pAggInfo = pExpr->pAggInfo;
+ if( NEVER(pExpr->iAgg>=pAggInfo->nColumn) ) return WRC_Continue;
+ assert( pExpr->iAgg>=0 );
+ pCol = &pAggInfo->aCol[pExpr->iAgg];
+ pExpr->op = TK_AGG_COLUMN;
+ pExpr->iTable = pCol->iTable;
+ pExpr->iColumn = pCol->iColumn;
+ ExprClearProperty(pExpr, EP_Skip|EP_Collate|EP_Unlikely);
+ return WRC_Prune;
+}
+
+/*
+** Convert every pAggInfo->aFunc[].pExpr such that any node within
+** those expressions that has pAppInfo set is changed into a TK_AGG_COLUMN
+** opcode.
+*/
+static void aggregateConvertIndexedExprRefToColumn(AggInfo *pAggInfo){
+ int i;
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = aggregateIdxEprRefToColCallback;
+ for(i=0; i<pAggInfo->nFunc; i++){
+ sqlcipher_sqlite3WalkExpr(&w, pAggInfo->aFunc[i].pFExpr);
+ }
+}
+
+
+/*
+** Allocate a block of registers so that there is one register for each
+** pAggInfo->aCol[] and pAggInfo->aFunc[] entry in pAggInfo. The first
+** register in this block is stored in pAggInfo->iFirstReg.
+**
+** This routine may only be called once for each AggInfo object. Prior
+** to calling this routine:
+**
+** * The aCol[] and aFunc[] arrays may be modified
+** * The AggInfoColumnReg() and AggInfoFuncReg() macros may not be used
+**
+** After calling this routine:
+**
+** * The aCol[] and aFunc[] arrays are fixed
+** * The AggInfoColumnReg() and AggInfoFuncReg() macros may be used
+**
+*/
+static void assignAggregateRegisters(Parse *pParse, AggInfo *pAggInfo){
+ assert( pAggInfo!=0 );
+ assert( pAggInfo->iFirstReg==0 );
+ pAggInfo->iFirstReg = pParse->nMem + 1;
+ pParse->nMem += pAggInfo->nColumn + pAggInfo->nFunc;
+}
+
/*
** Reset the aggregate accumulator.
**
@@ -147158,24 +154796,13 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
int i;
struct AggInfo_func *pFunc;
int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
+ assert( pAggInfo->iFirstReg>0 );
assert( pParse->db->pParse==pParse );
assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 );
if( nReg==0 ) return;
if( pParse->nErr ) return;
-#ifdef SQLITE_DEBUG
- /* Verify that all AggInfo registers are within the range specified by
- ** AggInfo.mnReg..AggInfo.mxReg */
- assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 );
- for(i=0; i<pAggInfo->nColumn; i++){
- assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg
- && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg );
- }
- for(i=0; i<pAggInfo->nFunc; i++){
- assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg
- && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg );
- }
-#endif
- sqlcipher_sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->iFirstReg,
+ pAggInfo->iFirstReg+nReg-1);
for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
if( pFunc->iDistinct>=0 ){
Expr *pE = pFunc->pFExpr;
@@ -147192,6 +154819,36 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
pFunc->pFunc->zName));
}
}
+ if( pFunc->iOBTab>=0 ){
+ ExprList *pOBList;
+ KeyInfo *pKeyInfo;
+ int nExtra = 0;
+ assert( pFunc->pFExpr->pLeft!=0 );
+ assert( pFunc->pFExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pFunc->pFExpr->pLeft) );
+ assert( pFunc->pFunc!=0 );
+ pOBList = pFunc->pFExpr->pLeft->x.pList;
+ if( !pFunc->bOBUnique ){
+ nExtra++; /* One extra column for the OP_Sequence */
+ }
+ if( pFunc->bOBPayload ){
+ /* extra columns for the function arguments */
+ assert( ExprUseXList(pFunc->pFExpr) );
+ nExtra += pFunc->pFExpr->x.pList->nExpr;
+ }
+ if( pFunc->bUseSubtype ){
+ nExtra += pFunc->pFExpr->x.pList->nExpr;
+ }
+ pKeyInfo = sqlcipher_sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra);
+ if( !pFunc->bOBUnique && pParse->nErr==0 ){
+ pKeyInfo->nKeyField++;
+ }
+ sqlcipher_sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
+ pFunc->iOBTab, pOBList->nExpr+nExtra, 0,
+ (char*)pKeyInfo, P4_KEYINFO);
+ ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(ORDER BY)",
+ pFunc->pFunc->zName));
+ }
}
}
@@ -147207,20 +154864,71 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
ExprList *pList;
assert( ExprUseXList(pF->pFExpr) );
pList = pF->pFExpr->x.pList;
- sqlcipher_sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0);
+ if( pF->iOBTab>=0 ){
+ /* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs
+ ** were stored in emphermal table pF->iOBTab. Here, we extract those
+ ** inputs (in ORDER BY order) and make all calls to OP_AggStep
+ ** before doing the OP_AggFinal call. */
+ int iTop; /* Start of loop for extracting columns */
+ int nArg; /* Number of columns to extract */
+ int nKey; /* Key columns to be skipped */
+ int regAgg; /* Extract into this array */
+ int j; /* Loop counter */
+
+ assert( pF->pFunc!=0 );
+ nArg = pList->nExpr;
+ regAgg = sqlcipher_sqlite3GetTempRange(pParse, nArg);
+
+ if( pF->bOBPayload==0 ){
+ nKey = 0;
+ }else{
+ assert( pF->pFExpr->pLeft!=0 );
+ assert( ExprUseXList(pF->pFExpr->pLeft) );
+ assert( pF->pFExpr->pLeft->x.pList!=0 );
+ nKey = pF->pFExpr->pLeft->x.pList->nExpr;
+ if( ALWAYS(!pF->bOBUnique) ) nKey++;
+ }
+ iTop = sqlcipher_sqlite3VdbeAddOp1(v, OP_Rewind, pF->iOBTab); VdbeCoverage(v);
+ for(j=nArg-1; j>=0; j--){
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j);
+ }
+ if( pF->bUseSubtype ){
+ int regSubtype = sqlcipher_sqlite3GetTempReg(pParse);
+ int iBaseCol = nKey + nArg + (pF->bOBPayload==0 && pF->bOBUnique==0);
+ for(j=nArg-1; j>=0; j--){
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, iBaseCol+j, regSubtype);
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_SetSubtype, regSubtype, regAgg+j);
+ }
+ sqlcipher_sqlite3ReleaseTempReg(pParse, regSubtype);
+ }
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
+ sqlcipher_sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
+ sqlcipher_sqlite3VdbeChangeP5(v, (u8)nArg);
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v);
+ sqlcipher_sqlite3VdbeJumpHere(v, iTop);
+ sqlcipher_sqlite3ReleaseTempRange(pParse, regAgg, nArg);
+ }
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_AggFinal, AggInfoFuncReg(pAggInfo,i),
+ pList ? pList->nExpr : 0);
sqlcipher_sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
}
}
-
/*
-** Update the accumulator memory cells for an aggregate based on
-** the current cursor position.
+** Generate code that will update the accumulator memory cells for an
+** aggregate based on the current cursor position.
**
** If regAcc is non-zero and there are no min() or max() aggregates
** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator
** registers if register regAcc contains 0. The caller will take care
** of setting and clearing regAcc.
+**
+** For an ORDER BY aggregate, the actual accumulator memory cell update
+** is deferred until after all input rows have been received, so that they
+** can be run in the requested order. In that case, instead of invoking
+** OP_AggStep to update the accumulator, just add the arguments that would
+** have been passed into OP_AggStep into the sorting ephemeral table
+** (along with the appropriate sort key).
*/
static void updateAccumulator(
Parse *pParse,
@@ -147235,14 +154943,19 @@ static void updateAccumulator(
struct AggInfo_func *pF;
struct AggInfo_col *pC;
+ assert( pAggInfo->iFirstReg>0 );
+ if( pParse->nErr ) return;
pAggInfo->directMode = 1;
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
int nArg;
int addrNext = 0;
int regAgg;
+ int regAggSz = 0;
+ int regDistinct = 0;
ExprList *pList;
assert( ExprUseXList(pF->pFExpr) );
assert( !IsWindowFunc(pF->pFExpr) );
+ assert( pF->pFunc!=0 );
pList = pF->pFExpr->x.pList;
if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){
Expr *pFilter = pF->pFExpr->y.pWin->pFilter;
@@ -147266,9 +154979,55 @@ static void updateAccumulator(
addrNext = sqlcipher_sqlite3VdbeMakeLabel(pParse);
sqlcipher_sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL);
}
- if( pList ){
+ if( pF->iOBTab>=0 ){
+ /* Instead of invoking AggStep, we must push the arguments that would
+ ** have been passed to AggStep onto the sorting table. */
+ int jj; /* Registered used so far in building the record */
+ ExprList *pOBList; /* The ORDER BY clause */
+ assert( pList!=0 );
+ nArg = pList->nExpr;
+ assert( nArg>0 );
+ assert( pF->pFExpr->pLeft!=0 );
+ assert( pF->pFExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pF->pFExpr->pLeft) );
+ pOBList = pF->pFExpr->pLeft->x.pList;
+ assert( pOBList!=0 );
+ assert( pOBList->nExpr>0 );
+ regAggSz = pOBList->nExpr;
+ if( !pF->bOBUnique ){
+ regAggSz++; /* One register for OP_Sequence */
+ }
+ if( pF->bOBPayload ){
+ regAggSz += nArg;
+ }
+ if( pF->bUseSubtype ){
+ regAggSz += nArg;
+ }
+ regAggSz++; /* One extra register to hold result of MakeRecord */
+ regAgg = sqlcipher_sqlite3GetTempRange(pParse, regAggSz);
+ regDistinct = regAgg;
+ sqlcipher_sqlite3ExprCodeExprList(pParse, pOBList, regAgg, 0, SQLITE_ECEL_DUP);
+ jj = pOBList->nExpr;
+ if( !pF->bOBUnique ){
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_Sequence, pF->iOBTab, regAgg+jj);
+ jj++;
+ }
+ if( pF->bOBPayload ){
+ regDistinct = regAgg+jj;
+ sqlcipher_sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP);
+ jj += nArg;
+ }
+ if( pF->bUseSubtype ){
+ int kk;
+ int regBase = pF->bOBPayload ? regDistinct : regAgg;
+ for(kk=0; kk<nArg; kk++, jj++){
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_GetSubtype, regBase+kk, regAgg+jj);
+ }
+ }
+ }else if( pList ){
nArg = pList->nExpr;
regAgg = sqlcipher_sqlite3GetTempRange(pParse, nArg);
+ regDistinct = regAgg;
sqlcipher_sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP);
}else{
nArg = 0;
@@ -147279,26 +155038,37 @@ static void updateAccumulator(
addrNext = sqlcipher_sqlite3VdbeMakeLabel(pParse);
}
pF->iDistinct = codeDistinct(pParse, eDistinctType,
- pF->iDistinct, addrNext, pList, regAgg);
- }
- if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
- CollSeq *pColl = 0;
- struct ExprList_item *pItem;
- int j;
- assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */
- for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
- pColl = sqlcipher_sqlite3ExprCollSeq(pParse, pItem->pExpr);
- }
- if( !pColl ){
- pColl = pParse->db->pDfltColl;
+ pF->iDistinct, addrNext, pList, regDistinct);
+ }
+ if( pF->iOBTab>=0 ){
+ /* Insert a new record into the ORDER BY table */
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_MakeRecord, regAgg, regAggSz-1,
+ regAgg+regAggSz-1);
+ sqlcipher_sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pF->iOBTab, regAgg+regAggSz-1,
+ regAgg, regAggSz-1);
+ sqlcipher_sqlite3ReleaseTempRange(pParse, regAgg, regAggSz);
+ }else{
+ /* Invoke the AggStep function */
+ if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
+ CollSeq *pColl = 0;
+ struct ExprList_item *pItem;
+ int j;
+ assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */
+ for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
+ pColl = sqlcipher_sqlite3ExprCollSeq(pParse, pItem->pExpr);
+ }
+ if( !pColl ){
+ pColl = pParse->db->pDfltColl;
+ }
+ if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
+ sqlcipher_sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0,
+ (char *)pColl, P4_COLLSEQ);
}
- if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
- sqlcipher_sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
+ sqlcipher_sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
+ sqlcipher_sqlite3VdbeChangeP5(v, (u8)nArg);
+ sqlcipher_sqlite3ReleaseTempRange(pParse, regAgg, nArg);
}
- sqlcipher_sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem);
- sqlcipher_sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
- sqlcipher_sqlite3VdbeChangeP5(v, (u8)nArg);
- sqlcipher_sqlite3ReleaseTempRange(pParse, regAgg, nArg);
if( addrNext ){
sqlcipher_sqlite3VdbeResolveLabel(v, addrNext);
}
@@ -147310,7 +155080,7 @@ static void updateAccumulator(
addrHitTest = sqlcipher_sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
}
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
- sqlcipher_sqlite3ExprCode(pParse, pC->pCExpr, pC->iMem);
+ sqlcipher_sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i));
}
pAggInfo->directMode = 0;
@@ -147406,26 +155176,31 @@ static void havingToWhere(Parse *pParse, Select *p){
sqlcipher_sqlite3WalkExpr(&sWalker, p->pHaving);
#if TREETRACE_ENABLED
if( sWalker.eCode && (sqlcipher_sqlite3TreeTrace & 0x100)!=0 ){
- SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
+ TREETRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
}
/*
-** Check to see if the pThis entry of pTabList is a self-join of a prior view.
-** If it is, then return the SrcList_item for the prior view. If it is not,
-** then return 0.
+** Check to see if the pThis entry of pTabList is a self-join of another view.
+** Search FROM-clause entries in the range of iFirst..iEnd, including iFirst
+** but stopping before iEnd.
+**
+** If pThis is a self-join, then return the SrcItem for the first other
+** instance of that view found. If pThis is not a self-join then return 0.
*/
static SrcItem *isSelfJoinView(
SrcList *pTabList, /* Search for self-joins in this FROM clause */
- SrcItem *pThis /* Search for prior reference to this subquery */
+ SrcItem *pThis, /* Search for prior reference to this subquery */
+ int iFirst, int iEnd /* Range of FROM-clause entries to search. */
){
SrcItem *pItem;
assert( pThis->pSelect!=0 );
if( pThis->pSelect->selFlags & SF_PushDown ) return 0;
- for(pItem = pTabList->a; pItem<pThis; pItem++){
+ while( iFirst<iEnd ){
Select *pS1;
+ pItem = &pTabList->a[iFirst++];
if( pItem->pSelect==0 ) continue;
if( pItem->fg.viaCoroutine ) continue;
if( pItem->zName==0 ) continue;
@@ -147452,13 +155227,13 @@ static SrcItem *isSelfJoinView(
/*
** Deallocate a single AggInfo object
*/
-static void agginfoFree(sqlcipher_sqlite3 *db, AggInfo *p){
+static void agginfoFree(sqlcipher_sqlite3 *db, void *pArg){
+ AggInfo *p = (AggInfo*)pArg;
sqlcipher_sqlite3DbFree(db, p->aCol);
sqlcipher_sqlite3DbFree(db, p->aFunc);
sqlcipher_sqlite3DbFreeNN(db, p);
}
-#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
/*
** Attempt to transform a query of the form
**
@@ -147486,7 +155261,9 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
if( p->pWhere ) return 0;
+ if( p->pHaving ) return 0;
if( p->pGroupBy ) return 0;
+ if( p->pOrderBy ) return 0;
pExpr = p->pEList->a[0].pExpr;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */
assert( ExprUseUToken(pExpr) );
@@ -147494,15 +155271,18 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
assert( ExprUseXList(pExpr) );
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
+ if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */
pSub = p->pSrc->a[0].pSelect;
if( pSub==0 ) return 0; /* The FROM is a subquery */
- if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */
+ if( pSub->pPrior==0 ) return 0; /* Must be a compound */
+ if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
do{
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
if( pSub->pWhere ) return 0; /* No WHERE clause */
if( pSub->pLimit ) return 0; /* No LIMIT clause */
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
- pSub = pSub->pPrior; /* Repeat over compound */
+ assert( pSub->pHaving==0 ); /* Due to the previous */
+ pSub = pSub->pPrior; /* Repeat over compound */
}while( pSub );
/* If we reach this point then it is OK to perform the transformation */
@@ -147522,7 +155302,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
pSub->selFlags |= SF_Aggregate;
pSub->selFlags &= ~SF_Compound;
pSub->nSelectRow = 0;
- sqlcipher_sqlite3ExprListDelete(db, pSub->pEList);
+ sqlcipher_sqlite3ParserAddCleanup(pParse, sqlcipher_sqlite3ExprListDeleteGeneric, pSub->pEList);
pTerm = pPrior ? sqlcipher_sqlite3ExprDup(db, pCount, 0) : pCount;
pSub->pEList = sqlcipher_sqlite3ExprListAppend(pParse, 0, pTerm);
pTerm = sqlcipher_sqlite3PExpr(pParse, TK_SELECT, 0, 0);
@@ -147538,14 +155318,13 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
p->selFlags &= ~SF_Aggregate;
#if TREETRACE_ENABLED
- if( sqlcipher_sqlite3TreeTrace & 0x400 ){
- SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
+ if( sqlcipher_sqlite3TreeTrace & 0x200 ){
+ TREETRACE(0x200,pParse,p,("After count-of-view optimization:\n"));
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
return 1;
}
-#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
/*
** If any term of pSrc, or any SF_NestedFrom sub-query, is not the same
@@ -147571,6 +155350,68 @@ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){
}
/*
+** Return TRUE (non-zero) if the i-th entry in the pTabList SrcList can
+** be implemented as a co-routine. The i-th entry is guaranteed to be
+** a subquery.
+**
+** The subquery is implemented as a co-routine if all of the following are
+** true:
+**
+** (1) The subquery will likely be implemented in the outer loop of
+** the query. This will be the case if any one of the following
+** conditions hold:
+** (a) The subquery is the only term in the FROM clause
+** (b) The subquery is the left-most term and a CROSS JOIN or similar
+** requires it to be the outer loop
+** (c) All of the following are true:
+** (i) The subquery is the left-most subquery in the FROM clause
+** (ii) There is nothing that would prevent the subquery from
+** being used as the outer loop if the sqlcipher_sqlite3WhereBegin()
+** routine nominates it to that position.
+** (iii) The query is not a UPDATE ... FROM
+** (2) The subquery is not a CTE that should be materialized because
+** (a) the AS MATERIALIZED keyword is used, or
+** (b) the CTE is used multiple times and does not have the
+** NOT MATERIALIZED keyword
+** (3) The subquery is not part of a left operand for a RIGHT JOIN
+** (4) The SQLITE_Coroutine optimization disable flag is not set
+** (5) The subquery is not self-joined
+*/
+static int fromClauseTermCanBeCoroutine(
+ Parse *pParse, /* Parsing context */
+ SrcList *pTabList, /* FROM clause */
+ int i, /* Which term of the FROM clause holds the subquery */
+ int selFlags /* Flags on the SELECT statement */
+){
+ SrcItem *pItem = &pTabList->a[i];
+ if( pItem->fg.isCte ){
+ const CteUse *pCteUse = pItem->u2.pCteUse;
+ if( pCteUse->eM10d==M10d_Yes ) return 0; /* (2a) */
+ if( pCteUse->nUse>=2 && pCteUse->eM10d!=M10d_No ) return 0; /* (2b) */
+ }
+ if( pTabList->a[0].fg.jointype & JT_LTORJ ) return 0; /* (3) */
+ if( OptimizationDisabled(pParse->db, SQLITE_Coroutines) ) return 0; /* (4) */
+ if( isSelfJoinView(pTabList, pItem, i+1, pTabList->nSrc)!=0 ){
+ return 0; /* (5) */
+ }
+ if( i==0 ){
+ if( pTabList->nSrc==1 ) return 1; /* (1a) */
+ if( pTabList->a[1].fg.jointype & JT_CROSS ) return 1; /* (1b) */
+ if( selFlags & SF_UpdateFrom ) return 0; /* (1c-iii) */
+ return 1;
+ }
+ if( selFlags & SF_UpdateFrom ) return 0; /* (1c-iii) */
+ while( 1 /*exit-by-break*/ ){
+ if( pItem->fg.jointype & (JT_OUTER|JT_CROSS) ) return 0; /* (1c-ii) */
+ if( i==0 ) break;
+ i--;
+ pItem--;
+ if( pItem->pSelect!=0 ) return 0; /* (1c-i) */
+ }
+ return 1;
+}
+
+/*
** Generate code for the SELECT statement given in the p argument.
**
** The results are returned according to the SelectDest structure.
@@ -147615,8 +155456,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
assert( db->mallocFailed==0 );
if( sqlcipher_sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
#if TREETRACE_ENABLED
- SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
- if( sqlcipher_sqlite3TreeTrace & 0x10100 ){
+ TREETRACE(0x1,pParse,p, ("begin processing:\n", pParse->addrExplain));
+ if( sqlcipher_sqlite3TreeTrace & 0x10000 ){
if( (sqlcipher_sqlite3TreeTrace & 0x10001)==0x10000 ){
sqlcipher_sqlite3TreeViewLine(0, "In sqlcipher_sqlite3Select() at %s:%d",
__FILE__, __LINE__);
@@ -147636,14 +155477,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
/* All of these destinations are also able to ignore the ORDER BY clause */
if( p->pOrderBy ){
#if TREETRACE_ENABLED
- SELECTTRACE(1,pParse,p, ("dropping superfluous ORDER BY:\n"));
- if( sqlcipher_sqlite3TreeTrace & 0x100 ){
+ TREETRACE(0x800,pParse,p, ("dropping superfluous ORDER BY:\n"));
+ if( sqlcipher_sqlite3TreeTrace & 0x800 ){
sqlcipher_sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY");
}
#endif
- sqlcipher_sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlcipher_sqlite3*,void*))sqlcipher_sqlite3ExprListDelete,
- p->pOrderBy);
+ sqlcipher_sqlite3ParserAddCleanup(pParse, sqlcipher_sqlite3ExprListDeleteGeneric,
+ p->pOrderBy);
testcase( pParse->earlyCleanup );
p->pOrderBy = 0;
}
@@ -147657,8 +155497,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
assert( db->mallocFailed==0 );
assert( p->pEList!=0 );
#if TREETRACE_ENABLED
- if( sqlcipher_sqlite3TreeTrace & 0x104 ){
- SELECTTRACE(0x104,pParse,p, ("after name resolution:\n"));
+ if( sqlcipher_sqlite3TreeTrace & 0x10 ){
+ TREETRACE(0x10,pParse,p, ("after name resolution:\n"));
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -147699,8 +155539,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
goto select_end;
}
#if TREETRACE_ENABLED
- if( p->pWin && (sqlcipher_sqlite3TreeTrace & 0x108)!=0 ){
- SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
+ if( p->pWin && (sqlcipher_sqlite3TreeTrace & 0x40)!=0 ){
+ TREETRACE(0x40,pParse,p, ("after window rewrite:\n"));
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -147724,22 +155564,58 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
** to a real table */
assert( pTab!=0 );
- /* Convert LEFT JOIN into JOIN if there are terms of the right table
- ** of the LEFT JOIN used in the WHERE clause.
+ /* Try to simplify joins:
+ **
+ ** LEFT JOIN -> JOIN
+ ** RIGHT JOIN -> JOIN
+ ** FULL JOIN -> RIGHT JOIN
+ **
+ ** If terms of the i-th table are used in the WHERE clause in such a
+ ** way that the i-th table cannot be the NULL row of a join, then
+ ** perform the appropriate simplification. This is called
+ ** "OUTER JOIN strength reduction" in the SQLite documentation.
*/
- if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==JT_LEFT
- && sqlcipher_sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor)
+ if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
+ && sqlcipher_sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor,
+ pItem->fg.jointype & JT_LTORJ)
&& OptimizationEnabled(db, SQLITE_SimplifyJoin)
){
- SELECTTRACE(0x100,pParse,p,
- ("LEFT-JOIN simplifies to JOIN on term %d\n",i));
- pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER);
- assert( pItem->iCursor>=0 );
- unsetJoinExpr(p->pWhere, pItem->iCursor,
- pTabList->a[0].fg.jointype & JT_LTORJ);
+ if( pItem->fg.jointype & JT_LEFT ){
+ if( pItem->fg.jointype & JT_RIGHT ){
+ TREETRACE(0x1000,pParse,p,
+ ("FULL-JOIN simplifies to RIGHT-JOIN on term %d\n",i));
+ pItem->fg.jointype &= ~JT_LEFT;
+ }else{
+ TREETRACE(0x1000,pParse,p,
+ ("LEFT-JOIN simplifies to JOIN on term %d\n",i));
+ pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER);
+ unsetJoinExpr(p->pWhere, pItem->iCursor, 0);
+ }
+ }
+ if( pItem->fg.jointype & JT_LTORJ ){
+ for(j=i+1; j<pTabList->nSrc; j++){
+ SrcItem *pI2 = &pTabList->a[j];
+ if( pI2->fg.jointype & JT_RIGHT ){
+ if( pI2->fg.jointype & JT_LEFT ){
+ TREETRACE(0x1000,pParse,p,
+ ("FULL-JOIN simplifies to LEFT-JOIN on term %d\n",j));
+ pI2->fg.jointype &= ~JT_RIGHT;
+ }else{
+ TREETRACE(0x1000,pParse,p,
+ ("RIGHT-JOIN simplifies to JOIN on term %d\n",j));
+ pI2->fg.jointype &= ~(JT_RIGHT|JT_OUTER);
+ unsetJoinExpr(p->pWhere, pI2->iCursor, 1);
+ }
+ }
+ }
+ for(j=pTabList->nSrc-1; j>=0; j--){
+ pTabList->a[j].fg.jointype &= ~JT_LTORJ;
+ if( pTabList->a[j].fg.jointype & JT_RIGHT ) break;
+ }
+ }
}
- /* No futher action if this term of the FROM clause is no a subquery */
+ /* No further action if this term of the FROM clause is not a subquery */
if( pSub==0 ) continue;
/* Catch mismatch in the declared columns of a view and the number of
@@ -147750,6 +155626,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
goto select_end;
}
+ /* Do not attempt the usual optimizations (flattening and ORDER BY
+ ** elimination) on a MATERIALIZED common table expression because
+ ** a MATERIALIZED common table expression is an optimization fence.
+ */
+ if( pItem->fg.isCte && pItem->u2.pCteUse->eM10d==M10d_Yes ){
+ continue;
+ }
+
/* Do not try to flatten an aggregate subquery.
**
** Flattening an aggregate subquery is only possible if the outer query
@@ -147779,6 +155663,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
** (a) The outer query has a different ORDER BY clause
** (b) The subquery is part of a join
** See forum post 062d576715d277c8
+ **
+ ** Also retain the ORDER BY if the OmitOrderBy optimization is disabled.
*/
if( pSub->pOrderBy!=0
&& (p->pOrderBy!=0 || pTabList->nSrc>1) /* Condition (5) */
@@ -147787,11 +155673,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
&& (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */
&& OptimizationEnabled(db, SQLITE_OmitOrderBy)
){
- SELECTTRACE(0x100,pParse,p,
+ TREETRACE(0x800,pParse,p,
("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1));
- sqlcipher_sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlcipher_sqlite3*,void*))sqlcipher_sqlite3ExprListDelete,
- pSub->pOrderBy);
+ sqlcipher_sqlite3ParserAddCleanup(pParse, sqlcipher_sqlite3ExprListDeleteGeneric,
+ pSub->pOrderBy);
pSub->pOrderBy = 0;
}
@@ -147842,8 +155727,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
if( p->pPrior ){
rc = multiSelect(pParse, p, pDest);
#if TREETRACE_ENABLED
- SELECTTRACE(0x1,pParse,p,("end compound-select processing\n"));
- if( (sqlcipher_sqlite3TreeTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
+ TREETRACE(0x400,pParse,p,("end compound-select processing\n"));
+ if( (sqlcipher_sqlite3TreeTrace & 0x400)!=0 && ExplainQueryPlanParent(pParse)==0 ){
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -147863,24 +155748,21 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
&& propagateConstants(pParse, p)
){
#if TREETRACE_ENABLED
- if( sqlcipher_sqlite3TreeTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
+ if( sqlcipher_sqlite3TreeTrace & 0x2000 ){
+ TREETRACE(0x2000,pParse,p,("After constant propagation:\n"));
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
}else{
- SELECTTRACE(0x100,pParse,p,("Constant propagation not helpful\n"));
+ TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n"));
}
-#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
&& countOfViewOptimization(pParse, p)
){
if( db->mallocFailed ) goto select_end;
- pEList = p->pEList;
pTabList = p->pSrc;
}
-#endif
/* For each term in the FROM clause, do two things:
** (1) Authorized unreferenced tables
@@ -147919,7 +155801,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
/* Generate code for all sub-queries in the FROM clause
*/
pSub = pItem->pSelect;
- if( pSub==0 ) continue;
+ if( pSub==0 || pItem->addrFillSub!=0 ) continue;
/* The code for a subquery should only be generated once. */
assert( pItem->addrFillSub==0 );
@@ -147939,39 +155821,42 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
if( OptimizationEnabled(db, SQLITE_PushDown)
&& (pItem->fg.isCte==0
|| (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
- && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem)
+ && pushDownWhereTerms(pParse, pSub, p->pWhere, pTabList, i)
){
#if TREETRACE_ENABLED
- if( sqlcipher_sqlite3TreeTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p,
+ if( sqlcipher_sqlite3TreeTrace & 0x4000 ){
+ TREETRACE(0x4000,pParse,p,
("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 );
}else{
- SELECTTRACE(0x100,pParse,p,("Push-down not possible\n"));
+ TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n"));
+ }
+
+ /* Convert unused result columns of the subquery into simple NULL
+ ** expressions, to avoid unneeded searching and computation.
+ */
+ if( OptimizationEnabled(db, SQLITE_NullUnusedCols)
+ && disableUnusedSubqueryResultColumns(pItem)
+ ){
+#if TREETRACE_ENABLED
+ if( sqlcipher_sqlite3TreeTrace & 0x4000 ){
+ TREETRACE(0x4000,pParse,p,
+ ("Change unused result columns to NULL for subquery %d:\n",
+ pSub->selId));
+ sqlcipher_sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
}
zSavedAuthContext = pParse->zAuthContext;
pParse->zAuthContext = pItem->zName;
/* Generate code to implement the subquery
- **
- ** The subquery is implemented as a co-routine if all of the following are
- ** true:
- **
- ** (1) the subquery is guaranteed to be the outer loop (so that
- ** it does not need to be computed more than once), and
- ** (2) the subquery is not a CTE that should be materialized
- ** (3) the subquery is not part of a left operand for a RIGHT JOIN
*/
- if( i==0
- && (pTabList->nSrc==1
- || (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0) /* (1) */
- && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes) /* (2) */
- && (pTabList->a[0].fg.jointype & JT_LTORJ)==0 /* (3) */
- ){
+ if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){
/* Implement a co-routine that will return a single row of the result
** set on each invocation.
*/
@@ -147993,7 +155878,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
}else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){
/* This is a CTE for which materialization code has already been
** generated. Invoke the subroutine to compute the materialization,
- ** the make the pItem->iCursor be a copy of the ephemerial table that
+ ** the make the pItem->iCursor be a copy of the ephemeral table that
** holds the result of the materialization. */
CteUse *pCteUse = pItem->u2.pCteUse;
sqlcipher_sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
@@ -148002,7 +155887,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
VdbeComment((v, "%!S", pItem));
}
pSub->nSelectRow = pCteUse->nRowEst;
- }else if( (pPrior = isSelfJoinView(pTabList, pItem))!=0 ){
+ }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){
/* This view has already been materialized by a prior entry in
** this same FROM clause. Reuse it. */
if( pPrior->addrFillSub ){
@@ -148016,6 +155901,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
** the same view can reuse the materialization. */
int topAddr;
int onceAddr = 0;
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExplain;
+#endif
pItem->regReturn = ++pParse->nMem;
topAddr = sqlcipher_sqlite3VdbeAddOp0(v, OP_Goto);
@@ -148031,12 +155919,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
VdbeNoopComment((v, "materialize %!S", pItem));
}
sqlcipher_sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
- ExplainQueryPlan((pParse, 1, "MATERIALIZE %!S", pItem));
+
+ ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem));
sqlcipher_sqlite3Select(pParse, pSub, &dest);
pItem->pTab->nRowLogEst = pSub->nSelectRow;
if( onceAddr ) sqlcipher_sqlite3VdbeJumpHere(v, onceAddr);
sqlcipher_sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
VdbeComment((v, "end %!S", pItem));
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
sqlcipher_sqlite3VdbeJumpHere(v, topAddr);
sqlcipher_sqlite3ClearTempRegCache(pParse);
if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
@@ -148062,8 +155952,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
#if TREETRACE_ENABLED
- if( sqlcipher_sqlite3TreeTrace & 0x400 ){
- SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
+ if( sqlcipher_sqlite3TreeTrace & 0x8000 ){
+ TREETRACE(0x8000,pParse,p,("After all FROM-clause analysis:\n"));
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -148099,8 +155989,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
sDistinct.isTnct = 2;
#if TREETRACE_ENABLED
- if( sqlcipher_sqlite3TreeTrace & 0x400 ){
- SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
+ if( sqlcipher_sqlite3TreeTrace & 0x20000 ){
+ TREETRACE(0x20000,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -148152,7 +156042,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
if( (p->selFlags & SF_FixedLimit)==0 ){
p->nSelectRow = 320; /* 4 billion rows */
}
- computeLimitRegisters(pParse, p, iEnd);
+ if( p->pLimit ) computeLimitRegisters(pParse, p, iEnd);
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
sqlcipher_sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
sSort.sortFlags |= SORTFLAG_UseSorter;
@@ -148186,7 +156076,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
/* Begin the database scan. */
- SELECTTRACE(1,pParse,p,("WhereBegin\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin\n"));
pWInfo = sqlcipher_sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
p->pEList, p, wctrlFlags, p->nSelectRow);
if( pWInfo==0 ) goto select_end;
@@ -148203,7 +156093,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
sSort.pOrderBy = 0;
}
}
- SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin returns\n"));
/* If sorting index that was created by a prior OP_OpenEphemeral
** instruction ended up not being needed, then change the OP_OpenEphemeral
@@ -148242,7 +156132,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
/* End the database scan loop.
*/
- SELECTTRACE(1,pParse,p,("WhereEnd\n"));
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
sqlcipher_sqlite3WhereEnd(pWInfo);
}
}else{
@@ -148315,20 +156205,21 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
*/
pAggInfo = sqlcipher_sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
if( pAggInfo ){
- sqlcipher_sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlcipher_sqlite3*,void*))agginfoFree, pAggInfo);
+ sqlcipher_sqlite3ParserAddCleanup(pParse, agginfoFree, pAggInfo);
testcase( pParse->earlyCleanup );
}
if( db->mallocFailed ){
goto select_end;
}
pAggInfo->selId = p->selId;
+#ifdef SQLITE_DEBUG
+ pAggInfo->pSelect = p;
+#endif
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
sNC.uNC.pAggInfo = pAggInfo;
VVA_ONLY( sNC.ncFlags = NC_UAggInfo; )
- pAggInfo->mnReg = pParse->nMem+1;
pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
pAggInfo->pGroupBy = pGroupBy;
sqlcipher_sqlite3ExprAnalyzeAggList(&sNC, pEList);
@@ -148349,40 +156240,17 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
}else{
minMaxFlag = WHERE_ORDERBY_NORMAL;
}
- for(i=0; i<pAggInfo->nFunc; i++){
- Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
- assert( ExprUseXList(pExpr) );
- sNC.ncFlags |= NC_InAggFunc;
- sqlcipher_sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
-#ifndef SQLITE_OMIT_WINDOWFUNC
- assert( !IsWindowFunc(pExpr) );
- if( ExprHasProperty(pExpr, EP_WinFunc) ){
- sqlcipher_sqlite3ExprAnalyzeAggregates(&sNC, pExpr->y.pWin->pFilter);
- }
-#endif
- sNC.ncFlags &= ~NC_InAggFunc;
- }
- pAggInfo->mxReg = pParse->nMem;
+ analyzeAggFuncArgs(pAggInfo, &sNC);
if( db->mallocFailed ) goto select_end;
#if TREETRACE_ENABLED
- if( sqlcipher_sqlite3TreeTrace & 0x400 ){
- int ii;
- SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
+ if( sqlcipher_sqlite3TreeTrace & 0x20 ){
+ TREETRACE(0x20,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
if( minMaxFlag ){
sqlcipher_sqlite3DebugPrintf("MIN/MAX Optimization (0x%02x) adds:\n", minMaxFlag);
sqlcipher_sqlite3TreeViewExprList(0, pMinMaxOrderBy, 0, "ORDERBY");
}
- for(ii=0; ii<pAggInfo->nColumn; ii++){
- sqlcipher_sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
- ii, pAggInfo->aCol[ii].iMem);
- sqlcipher_sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
- }
- for(ii=0; ii<pAggInfo->nFunc; ii++){
- sqlcipher_sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
- ii, pAggInfo->aFunc[ii].iMem);
- sqlcipher_sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0);
- }
+ printAggInfo(pAggInfo);
}
#endif
@@ -148392,7 +156260,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
*/
if( pGroupBy ){
KeyInfo *pKeyInfo; /* Keying information for the group by clause */
- int addr1; /* A-vs-B comparision jump */
+ int addr1; /* A-vs-B comparison jump */
int addrOutputRow; /* Start of subroutine that outputs a result row */
int regOutputRow; /* Return address register for output subroutine */
int addrSetAbort; /* Set the abort flag and return */
@@ -148451,17 +156319,21 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
** in the right order to begin with.
*/
sqlcipher_sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
- SELECTTRACE(1,pParse,p,("WhereBegin\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin\n"));
pWInfo = sqlcipher_sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct,
- 0, (sDistinct.isTnct==2 ? WHERE_DISTINCTBY : WHERE_GROUPBY)
+ p, (sDistinct.isTnct==2 ? WHERE_DISTINCTBY : WHERE_GROUPBY)
| (orderByGrp ? WHERE_SORTBYGROUP : 0) | distFlag, 0
);
if( pWInfo==0 ){
sqlcipher_sqlite3ExprListDelete(db, pDistinct);
goto select_end;
}
+ if( pParse->pIdxEpr ){
+ optimizeAggregateUseOfIndexedExpr(pParse, p, pAggInfo, &sNC);
+ }
+ assignAggregateRegisters(pParse, pAggInfo);
eDist = sqlcipher_sqlite3WhereIsDistinct(pWInfo);
- SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin returns\n"));
if( sqlcipher_sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
/* The optimizer is able to deliver rows in group by order so
** we do not have to sort. The OP_OpenEphemeral table will be
@@ -148479,9 +156351,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
int nCol;
int nGroupBy;
- explainTempTable(pParse,
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExp; /* Address of OP_Explain instruction */
+#endif
+ ExplainQueryPlan2(addrExp, (pParse, 0, "USE TEMP B-TREE FOR %s",
(sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ?
- "DISTINCT" : "GROUP BY");
+ "DISTINCT" : "GROUP BY"
+ ));
groupBySort = 1;
nGroupBy = pGroupBy->nExpr;
@@ -148496,28 +156372,50 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
regBase = sqlcipher_sqlite3GetTempRange(pParse, nCol);
sqlcipher_sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
j = nGroupBy;
+ pAggInfo->directMode = 1;
for(i=0; i<pAggInfo->nColumn; i++){
struct AggInfo_col *pCol = &pAggInfo->aCol[i];
if( pCol->iSorterColumn>=j ){
- int r1 = j + regBase;
- sqlcipher_sqlite3ExprCodeGetColumnOfTable(v,
- pCol->pTab, pCol->iTable, pCol->iColumn, r1);
+ sqlcipher_sqlite3ExprCode(pParse, pCol->pCExpr, j + regBase);
j++;
}
}
+ pAggInfo->directMode = 0;
regRecord = sqlcipher_sqlite3GetTempReg(pParse);
+ sqlcipher_sqlite3VdbeScanStatusCounters(v, addrExp, 0, sqlcipher_sqlite3VdbeCurrentAddr(v));
sqlcipher_sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
sqlcipher_sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExp, sqlcipher_sqlite3VdbeCurrentAddr(v)-2, -1);
sqlcipher_sqlite3ReleaseTempReg(pParse, regRecord);
sqlcipher_sqlite3ReleaseTempRange(pParse, regBase, nCol);
- SELECTTRACE(1,pParse,p,("WhereEnd\n"));
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
sqlcipher_sqlite3WhereEnd(pWInfo);
pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
sortOut = sqlcipher_sqlite3GetTempReg(pParse);
+ sqlcipher_sqlite3VdbeScanStatusCounters(v, addrExp, sqlcipher_sqlite3VdbeCurrentAddr(v), 0);
sqlcipher_sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
sqlcipher_sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
pAggInfo->useSortingIdx = 1;
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExp, -1, sortPTab);
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExp, -1, pAggInfo->sortingIdx);
+ }
+
+ /* If there are entries in pAgggInfo->aFunc[] that contain subexpressions
+ ** that are indexed (and that were previously identified and tagged
+ ** in optimizeAggregateUseOfIndexedExpr()) then those subexpressions
+ ** must now be converted into a TK_AGG_COLUMN node so that the value
+ ** is correctly pulled from the index rather than being recomputed. */
+ if( pParse->pIdxEpr ){
+ aggregateConvertIndexedExprRefToColumn(pAggInfo);
+#if TREETRACE_ENABLED
+ if( sqlcipher_sqlite3TreeTrace & 0x20 ){
+ TREETRACE(0x20, pParse, p,
+ ("AggInfo function expressions converted to reference index\n"));
+ sqlcipher_sqlite3TreeViewSelect(0, p, 0);
+ printAggInfo(pAggInfo);
+ }
+#endif
}
/* If the index or temporary table used by the GROUP BY sort
@@ -148588,7 +156486,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
sqlcipher_sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx,addrTopOfLoop);
VdbeCoverage(v);
}else{
- SELECTTRACE(1,pParse,p,("WhereEnd\n"));
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
sqlcipher_sqlite3WhereEnd(pWInfo);
sqlcipher_sqlite3VdbeChangeToNoop(v, addrSortingIdx);
}
@@ -148698,7 +156596,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
if( pKeyInfo ){
sqlcipher_sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
}
- sqlcipher_sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem);
+ assignAggregateRegisters(pParse, pAggInfo);
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_Count, iCsr, AggInfoFuncReg(pAggInfo,0));
sqlcipher_sqlite3VdbeAddOp1(v, OP_Close, iCsr);
explainSimpleCount(pParse, pTab, pBest);
}else{
@@ -148734,6 +156633,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
pDistinct = pAggInfo->aFunc[0].pFExpr->x.pList;
distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0;
}
+ assignAggregateRegisters(pParse, pAggInfo);
/* This case runs if the aggregate has no GROUP BY clause. The
** processing is much simpler since there is only a single row
@@ -148750,13 +156650,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 );
assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 );
- SELECTTRACE(1,pParse,p,("WhereBegin\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin\n"));
pWInfo = sqlcipher_sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy,
- pDistinct, 0, minMaxFlag|distFlag, 0);
+ pDistinct, p, minMaxFlag|distFlag, 0);
if( pWInfo==0 ){
goto select_end;
}
- SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin returns\n"));
eDist = sqlcipher_sqlite3WhereIsDistinct(pWInfo);
updateAccumulator(pParse, regAcc, pAggInfo, eDist);
if( eDist!=WHERE_DISTINCT_NOOP ){
@@ -148770,7 +156670,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
if( minMaxFlag ){
sqlcipher_sqlite3WhereMinMaxOptEarlyOut(v, pWInfo);
}
- SELECTTRACE(1,pParse,p,("WhereEnd\n"));
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
sqlcipher_sqlite3WhereEnd(pWInfo);
finalizeAggFunctions(pParse, pAggInfo);
}
@@ -148792,8 +156692,6 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Select(
** and send them to the callback one by one.
*/
if( sSort.pOrderBy ){
- explainTempTable(pParse,
- sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
assert( p->pEList==pEList );
generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
}
@@ -148815,9 +156713,15 @@ select_end:
sqlcipher_sqlite3ExprListDelete(db, pMinMaxOrderBy);
#ifdef SQLITE_DEBUG
if( pAggInfo && !db->mallocFailed ){
+#if TREETRACE_ENABLED
+ if( sqlcipher_sqlite3TreeTrace & 0x20 ){
+ TREETRACE(0x20,pParse,p,("Finished with AggInfo\n"));
+ printAggInfo(pAggInfo);
+ }
+#endif
for(i=0; i<pAggInfo->nColumn; i++){
Expr *pExpr = pAggInfo->aCol[i].pCExpr;
- assert( pExpr!=0 );
+ if( pExpr==0 ) continue;
assert( pExpr->pAggInfo==pAggInfo );
assert( pExpr->iAgg==i );
}
@@ -148831,8 +156735,8 @@ select_end:
#endif
#if TREETRACE_ENABLED
- SELECTTRACE(0x1,pParse,p,("end processing\n"));
- if( (sqlcipher_sqlite3TreeTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
+ TREETRACE(0x1,pParse,p,("end processing\n"));
+ if( (sqlcipher_sqlite3TreeTrace & 0x40000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
sqlcipher_sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -149106,7 +157010,7 @@ SQLITE_PRIVATE Trigger *sqlcipher_sqlite3TriggerList(Parse *pParse, Table *pTab)
if( pTrig->pTabSchema==pTab->pSchema
&& pTrig->table
&& 0==sqlcipher_sqlite3StrICmp(pTrig->table, pTab->zName)
- && pTrig->pTabSchema!=pTmpSchema
+ && (pTrig->pTabSchema!=pTmpSchema || pTrig->bReturning)
){
pTrig->pNext = pList;
pList = pTrig;
@@ -149228,6 +157132,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3BeginTrigger(
sqlcipher_sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
goto trigger_orphan_error;
}
+ if( (pTab->tabFlags & TF_Shadow)!=0 && sqlcipher_sqlite3ReadOnlyShadowTables(db) ){
+ sqlcipher_sqlite3ErrorMsg(pParse, "cannot create triggers on shadow tables");
+ goto trigger_orphan_error;
+ }
/* Check that the trigger name is not reserved and that no trigger of the
** specified name exists */
@@ -149247,6 +157155,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3BeginTrigger(
}else{
assert( !db->init.busy );
sqlcipher_sqlite3CodeVerifySchema(pParse, iDb);
+ VVA_ONLY( pParse->ifNotExists = 1; )
}
goto trigger_cleanup;
}
@@ -149991,6 +157900,72 @@ static ExprList *sqlcipher_sqlite3ExpandReturning(
return pNew;
}
+/* If the Expr node is a subquery or an EXISTS operator or an IN operator that
+** uses a subquery, and if the subquery is SF_Correlated, then mark the
+** expression as EP_VarSelect.
+*/
+static int sqlcipher_sqlite3ReturningSubqueryVarSelect(Walker *NotUsed, Expr *pExpr){
+ UNUSED_PARAMETER(NotUsed);
+ if( ExprUseXSelect(pExpr)
+ && (pExpr->x.pSelect->selFlags & SF_Correlated)!=0
+ ){
+ testcase( ExprHasProperty(pExpr, EP_VarSelect) );
+ ExprSetProperty(pExpr, EP_VarSelect);
+ }
+ return WRC_Continue;
+}
+
+
+/*
+** If the SELECT references the table pWalker->u.pTab, then do two things:
+**
+** (1) Mark the SELECT as as SF_Correlated.
+** (2) Set pWalker->eCode to non-zero so that the caller will know
+** that (1) has happened.
+*/
+static int sqlcipher_sqlite3ReturningSubqueryCorrelated(Walker *pWalker, Select *pSelect){
+ int i;
+ SrcList *pSrc;
+ assert( pSelect!=0 );
+ pSrc = pSelect->pSrc;
+ assert( pSrc!=0 );
+ for(i=0; i<pSrc->nSrc; i++){
+ if( pSrc->a[i].pTab==pWalker->u.pTab ){
+ testcase( pSelect->selFlags & SF_Correlated );
+ pSelect->selFlags |= SF_Correlated;
+ pWalker->eCode = 1;
+ break;
+ }
+ }
+ return WRC_Continue;
+}
+
+/*
+** Scan the expression list that is the argument to RETURNING looking
+** for subqueries that depend on the table which is being modified in the
+** statement that is hosting the RETURNING clause (pTab). Mark all such
+** subqueries as SF_Correlated. If the subqueries are part of an
+** expression, mark the expression as EP_VarSelect.
+**
+** https://sqlite.org/forum/forumpost/2c83569ce8945d39
+*/
+static void sqlcipher_sqlite3ProcessReturningSubqueries(
+ ExprList *pEList,
+ Table *pTab
+){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = sqlcipher_sqlite3ExprWalkNoop;
+ w.xSelectCallback = sqlcipher_sqlite3ReturningSubqueryCorrelated;
+ w.u.pTab = pTab;
+ sqlcipher_sqlite3WalkExprList(&w, pEList);
+ if( w.eCode ){
+ w.xExprCallback = sqlcipher_sqlite3ReturningSubqueryVarSelect;
+ w.xSelectCallback = sqlcipher_sqlite3SelectWalkNoop;
+ sqlcipher_sqlite3WalkExprList(&w, pEList);
+ }
+}
+
/*
** Generate code for the RETURNING trigger. Unlike other triggers
** that invoke a subprogram in the bytecode, the code for RETURNING
@@ -150010,16 +157985,24 @@ static void codeReturningTrigger(
SrcList sFrom;
assert( v!=0 );
- assert( pParse->bReturning );
+ if( !pParse->bReturning ){
+ /* This RETURNING trigger must be for a different statement as
+ ** this statement lacks a RETURNING clause. */
+ return;
+ }
assert( db->pParse==pParse );
pReturning = pParse->u1.pReturning;
- assert( pTrigger == &(pReturning->retTrig) );
+ if( pTrigger != &(pReturning->retTrig) ){
+ /* This RETURNING trigger is for a different statement */
+ return;
+ }
memset(&sSelect, 0, sizeof(sSelect));
memset(&sFrom, 0, sizeof(sFrom));
sSelect.pEList = sqlcipher_sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
sSelect.pSrc = &sFrom;
sFrom.nSrc = 1;
sFrom.a[0].pTab = pTab;
+ sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */
sFrom.a[0].iCursor = -1;
sqlcipher_sqlite3SelectPrep(pParse, &sSelect, 0);
if( pParse->nErr==0 ){
@@ -150028,7 +158011,7 @@ static void codeReturningTrigger(
}
sqlcipher_sqlite3ExprListDelete(db, sSelect.pEList);
pNew = sqlcipher_sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab);
- if( !db->mallocFailed ){
+ if( pParse->nErr==0 ){
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
if( pReturning->nRetCol==0 ){
@@ -150046,6 +158029,7 @@ static void codeReturningTrigger(
int i;
int nCol = pNew->nExpr;
int reg = pParse->nMem+1;
+ sqlcipher_sqlite3ProcessReturningSubqueries(pNew, pTab);
pParse->nMem += nCol+2;
pReturning->iRetReg = reg;
for(i=0; i<nCol; i++){
@@ -150236,7 +158220,7 @@ static TriggerPrg *codeRowTrigger(
sSubParse.zAuthContext = pTrigger->zName;
sSubParse.eTriggerOp = pTrigger->op;
sSubParse.nQueryLoop = pParse->nQueryLoop;
- sSubParse.disableVtab = pParse->disableVtab;
+ sSubParse.prepFlags = pParse->prepFlags;
v = sqlcipher_sqlite3GetVdbe(&sSubParse);
if( v ){
@@ -150497,6 +158481,9 @@ SQLITE_PRIVATE u32 sqlcipher_sqlite3TriggerColmask(
Trigger *p;
assert( isNew==1 || isNew==0 );
+ if( IsView(pTab) ){
+ return 0xffffffff;
+ }
for(p=pTrigger; p; p=p->pNext){
if( p->op==op
&& (tr_tm&p->tr_tm)
@@ -150582,11 +158569,14 @@ static void updateVirtualTable(
** it has been converted into REAL.
*/
SQLITE_PRIVATE void sqlcipher_sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
+ Column *pCol;
assert( pTab!=0 );
- if( !IsView(pTab) ){
+ assert( pTab->nCol>i );
+ pCol = &pTab->aCol[i];
+ if( pCol->iDflt ){
sqlcipher_sqlite3_value *pValue = 0;
u8 enc = ENC(sqlcipher_sqlite3VdbeDb(v));
- Column *pCol = &pTab->aCol[i];
+ assert( !IsView(pTab) );
VdbeComment((v, "%s.%s", pTab->zName, pCol->zCnName));
assert( i<pTab->nCol );
sqlcipher_sqlite3ValueFromExpr(sqlcipher_sqlite3VdbeDb(v),
@@ -150597,7 +158587,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i,
}
}
#ifndef SQLITE_OMIT_FLOATING_POINT
- if( pTab->aCol[i].affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
+ if( pCol->affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
sqlcipher_sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
}
#endif
@@ -150744,7 +158734,7 @@ static void updateFromSelect(
assert( pTabList->nSrc>1 );
if( pSrc ){
- pSrc->a[0].fg.notCte = 1;
+ assert( pSrc->a[0].fg.notCte );
pSrc->a[0].iCursor = -1;
pSrc->a[0].pTab->nTabRef--;
pSrc->a[0].pTab = 0;
@@ -150783,7 +158773,8 @@ static void updateFromSelect(
}
}
pSelect = sqlcipher_sqlite3SelectNew(pParse, pList,
- pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UFSrcCheck|SF_IncludeHidden, pLimit2
+ pSrc, pWhere2, pGrp, 0, pOrderBy2,
+ SF_UFSrcCheck|SF_IncludeHidden|SF_UpdateFrom, pLimit2
);
if( pSelect ) pSelect->selFlags |= SF_OrderByReqd;
sqlcipher_sqlite3SelectDestInit(&dest, eDest, iEph);
@@ -150927,7 +158918,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Update(
if( sqlcipher_sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
- if( sqlcipher_sqlite3IsReadOnly(pParse, pTab, tmask) ){
+ if( sqlcipher_sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto update_cleanup;
}
@@ -151246,12 +159237,22 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Update(
/* Begin the database scan.
**
** Do not consider a single-pass strategy for a multi-row update if
- ** there are any triggers or foreign keys to process, or rows may
- ** be deleted as a result of REPLACE conflict handling. Any of these
- ** things might disturb a cursor being used to scan through the table
- ** or index, causing a single-pass approach to malfunction. */
+ ** there is anything that might disrupt the cursor being used to do
+ ** the UPDATE:
+ ** (1) This is a nested UPDATE
+ ** (2) There are triggers
+ ** (3) There are FOREIGN KEY constraints
+ ** (4) There are REPLACE conflict handlers
+ ** (5) There are subqueries in the WHERE clause
+ */
flags = WHERE_ONEPASS_DESIRED;
- if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
+ if( !pParse->nested
+ && !pTrigger
+ && !hasFK
+ && !chngKey
+ && !bReplace
+ && (pWhere==0 || !ExprHasProperty(pWhere, EP_Subquery))
+ ){
flags |= WHERE_ONEPASS_MULTIROW;
}
pWInfo = sqlcipher_sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur);
@@ -151322,6 +159323,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Update(
if( !isView ){
int addrOnce = 0;
+ int iNotUsed1 = 0;
+ int iNotUsed2 = 0;
/* Open every index that needs updating. */
if( eOnePass!=ONEPASS_OFF ){
@@ -151333,7 +159336,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Update(
addrOnce = sqlcipher_sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
sqlcipher_sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur,
- aToOpen, 0, 0);
+ aToOpen, &iNotUsed1, &iNotUsed2);
if( addrOnce ){
sqlcipher_sqlite3VdbeJumpHereOrPopInst(v, addrOnce);
}
@@ -151428,6 +159431,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Update(
}
}
if( chngRowid==0 && pPk==0 ){
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ if( isView ) sqlcipher_sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
+#endif
sqlcipher_sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
}
}
@@ -151624,8 +159630,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Update(
sqlcipher_sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
- sqlcipher_sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
- TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue);
+ if( pTrigger ){
+ sqlcipher_sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
+ TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue);
+ }
/* Repeat the above with the next record to be updated, until
** all record selected by the WHERE clause have been updated.
@@ -151720,7 +159728,7 @@ static void updateVirtualTable(
int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */
int regArg; /* First register in VUpdate arg array */
int regRec; /* Register in which to assemble record */
- int regRowid; /* Register for ephem table rowid */
+ int regRowid; /* Register for ephemeral table rowid */
int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */
int aDummy[2]; /* Unused arg for sqlcipher_sqlite3WhereOkOnePass() */
int eOnePass; /* True to use onepass strategy */
@@ -151764,7 +159772,9 @@ static void updateVirtualTable(
sqlcipher_sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0)
);
}else{
- pList = sqlcipher_sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
+ Expr *pRowExpr = exprRowColumn(pParse, i);
+ if( pRowExpr ) pRowExpr->op2 = OPFLAG_NOCHNG;
+ pList = sqlcipher_sqlite3ExprListAppend(pParse, pList, pRowExpr);
}
}
@@ -151841,7 +159851,7 @@ static void updateVirtualTable(
sqlcipher_sqlite3WhereEnd(pWInfo);
}
- /* Begin scannning through the ephemeral table. */
+ /* Begin scanning through the ephemeral table. */
addr = sqlcipher_sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v);
/* Extract arguments from the current row of the ephemeral table and
@@ -151961,7 +159971,8 @@ SQLITE_PRIVATE Upsert *sqlcipher_sqlite3UpsertNew(
SQLITE_PRIVATE int sqlcipher_sqlite3UpsertAnalyzeTarget(
Parse *pParse, /* The parsing context */
SrcList *pTabList, /* Table into which we are inserting */
- Upsert *pUpsert /* The ON CONFLICT clauses */
+ Upsert *pUpsert, /* The ON CONFLICT clauses */
+ Upsert *pAll /* Complete list of all ON CONFLICT clauses */
){
Table *pTab; /* That table into which we are inserting */
int rc; /* Result code */
@@ -152037,6 +160048,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3UpsertAnalyzeTarget(
if( pIdx->aiColumn[ii]==XN_EXPR ){
assert( pIdx->aColExpr!=0 );
assert( pIdx->aColExpr->nExpr>ii );
+ assert( pIdx->bHasExpr );
pExpr = pIdx->aColExpr->a[ii].pExpr;
if( pExpr->op!=TK_COLLATE ){
sCol[0].pLeft = pExpr;
@@ -152048,7 +160060,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3UpsertAnalyzeTarget(
pExpr = &sCol[0];
}
for(jj=0; jj<nn; jj++){
- if( sqlcipher_sqlite3ExprCompare(pParse,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
+ if( sqlcipher_sqlite3ExprCompare(0,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
break; /* Column ii of the index matches column jj of target */
}
}
@@ -152063,6 +160075,14 @@ SQLITE_PRIVATE int sqlcipher_sqlite3UpsertAnalyzeTarget(
continue;
}
pUpsert->pUpsertIdx = pIdx;
+ if( sqlcipher_sqlite3UpsertOfIndex(pAll,pIdx)!=pUpsert ){
+ /* Really this should be an error. The isDup ON CONFLICT clause will
+ ** never fire. But this problem was not discovered until three years
+ ** after multi-CONFLICT upsert was added, and so we silently ignore
+ ** the problem to prevent breaking applications that might actually
+ ** have redundant ON CONFLICT clauses. */
+ pUpsert->isDup = 1;
+ }
break;
}
if( pUpsert->pUpsertIdx==0 ){
@@ -152089,9 +160109,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3UpsertNextIsIPK(Upsert *pUpsert){
Upsert *pNext;
if( NEVER(pUpsert==0) ) return 0;
pNext = pUpsert->pNextUpsert;
- if( pNext==0 ) return 1;
- if( pNext->pUpsertTarget==0 ) return 1;
- if( pNext->pUpsertIdx==0 ) return 1;
+ while( 1 /*exit-by-return*/ ){
+ if( pNext==0 ) return 1;
+ if( pNext->pUpsertTarget==0 ) return 1;
+ if( pNext->pUpsertIdx==0 ) return 1;
+ if( !pNext->isDup ) return 0;
+ pNext = pNext->pNextUpsert;
+ }
return 0;
}
@@ -152350,6 +160374,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlcipher_sqlite3RunVacuum(
int nDb; /* Number of attached databases */
const char *zDbMain; /* Schema name of database to vacuum */
const char *zOut; /* Name of output file */
+ u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
if( !db->autoCommit ){
sqlcipher_sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -152396,7 +160421,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlcipher_sqlite3RunVacuum(
** (possibly synchronous) transaction opened on the main database before
** sqlcipher_sqlite3BtreeCopyFile() is called.
**
- ** An optimisation would be to use a non-journaled pager.
+ ** An optimization would be to use a non-journaled pager.
** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
** that actually made the VACUUM run slower. Very little journalling
** actually occurs when doing a vacuum since the vacuum_db is initially
@@ -152421,6 +160446,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlcipher_sqlite3RunVacuum(
goto end_of_vacuum;
}
db->mDbFlags |= DBFLAG_VacuumInto;
+
+ /* For a VACUUM INTO, the pager-flags are set to the same values as
+ ** they are for the database being vacuumed, except that PAGER_CACHESPILL
+ ** is always set. */
+ pgflags = db->aDb[iDb].safety_level | (db->flags & PAGER_FLAGS_MASK);
}
nRes = sqlcipher_sqlite3BtreeGetRequestedReserve(pMain);
@@ -152439,7 +160469,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlcipher_sqlite3RunVacuum(
sqlcipher_sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
sqlcipher_sqlite3BtreeSetSpillSize(pTemp, sqlcipher_sqlite3BtreeSetSpillSize(pMain,0));
- sqlcipher_sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);
+ sqlcipher_sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL);
/* Begin a transaction and take an exclusive lock on the main database
** file. This is done before the sqlcipher_sqlite3BtreeGetPageSize(pMain) call below,
@@ -152823,10 +160853,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VtabUnlock(VTable *pVTab){
pVTab->nRef--;
if( pVTab->nRef==0 ){
sqlcipher_sqlite3_vtab *p = pVTab->pVtab;
- sqlcipher_sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod);
if( p ){
p->pModule->xDisconnect(p);
}
+ sqlcipher_sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod);
sqlcipher_sqlite3DbFree(db, pVTab);
}
}
@@ -152927,7 +160957,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VtabUnlockList(sqlcipher_sqlite3 *db){
if( p ){
db->pDisconnect = 0;
- sqlcipher_sqlite3ExpirePreparedStatements(db, 0);
do {
VTable *pNext = p->pNext;
sqlcipher_sqlite3VtabUnlock(p);
@@ -152952,7 +160981,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VtabUnlockList(sqlcipher_sqlite3 *db){
*/
SQLITE_PRIVATE void sqlcipher_sqlite3VtabClear(sqlcipher_sqlite3 *db, Table *p){
assert( IsVirtual(p) );
- if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
+ assert( db!=0 );
+ if( db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
if( p->u.vtab.azArg ){
int i;
for(i=0; i<p->u.vtab.nArg; i++){
@@ -153092,7 +161122,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VtabFinishParse(Parse *pParse, Token *pEnd)
** the information we've collected.
**
** The VM register number pParse->regRowid holds the rowid of an
- ** entry in the sqlite_schema table tht was created for this vtab
+ ** entry in the sqlite_schema table that was created for this vtab
** by sqlcipher_sqlite3StartTable().
*/
iDb = sqlcipher_sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -153221,7 +161251,11 @@ static int vtabCallConstructor(
sCtx.pPrior = db->pVtabCtx;
sCtx.bDeclared = 0;
db->pVtabCtx = &sCtx;
+ pTab->nTabRef++;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
+ assert( pTab!=0 );
+ assert( pTab->nTabRef>1 || rc!=SQLITE_OK );
+ sqlcipher_sqlite3DeleteTable(db, pTab);
db->pVtabCtx = sCtx.pPrior;
if( rc==SQLITE_NOMEM ) sqlcipher_sqlite3OomFault(db);
assert( sCtx.pTab==pTab );
@@ -153243,7 +161277,7 @@ static int vtabCallConstructor(
pVTable->nRef = 1;
if( sCtx.bDeclared==0 ){
const char *zFormat = "vtable constructor did not declare schema: %s";
- *pzErr = sqlcipher_sqlite3MPrintf(db, zFormat, pTab->zName);
+ *pzErr = sqlcipher_sqlite3MPrintf(db, zFormat, zModuleName);
sqlcipher_sqlite3VtabUnlock(pVTable);
rc = SQLITE_ERROR;
}else{
@@ -153421,19 +161455,38 @@ SQLITE_API int sqlcipher_sqlite3_declare_vtab(sqlcipher_sqlite3 *db, const char
Table *pTab;
Parse sParse;
int initBusy;
+ int i;
+ const unsigned char *z;
+ static const u8 aKeyword[] = { TK_CREATE, TK_TABLE, 0 };
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlcipher_sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
+
+ /* Verify that the first two keywords in the CREATE TABLE statement
+ ** really are "CREATE" and "TABLE". If this is not the case, then
+ ** sqlcipher_sqlite3_declare_vtab() is being misused.
+ */
+ z = (const unsigned char*)zCreateTable;
+ for(i=0; aKeyword[i]; i++){
+ int tokenType = 0;
+ do{ z += sqlcipher_sqlite3GetToken(z, &tokenType); }while( tokenType==TK_SPACE );
+ if( tokenType!=aKeyword[i] ){
+ sqlcipher_sqlite3ErrorWithMsg(db, SQLITE_ERROR, "syntax error");
+ return SQLITE_ERROR;
+ }
+ }
+
sqlcipher_sqlite3_mutex_enter(db->mutex);
pCtx = db->pVtabCtx;
if( !pCtx || pCtx->bDeclared ){
- sqlcipher_sqlite3Error(db, SQLITE_MISUSE);
+ sqlcipher_sqlite3Error(db, SQLITE_MISUSE_BKPT);
sqlcipher_sqlite3_mutex_leave(db->mutex);
return SQLITE_MISUSE_BKPT;
}
+
pTab = pCtx->pTab;
assert( IsVirtual(pTab) );
@@ -153447,11 +161500,10 @@ SQLITE_API int sqlcipher_sqlite3_declare_vtab(sqlcipher_sqlite3 *db, const char
initBusy = db->init.busy;
db->init.busy = 0;
sParse.nQueryLoop = 1;
- if( SQLITE_OK==sqlcipher_sqlite3RunParser(&sParse, zCreateTable)
- && ALWAYS(sParse.pNewTable!=0)
- && ALWAYS(!db->mallocFailed)
- && IsOrdinaryTable(sParse.pNewTable)
- ){
+ if( SQLITE_OK==sqlcipher_sqlite3RunParser(&sParse, zCreateTable) ){
+ assert( sParse.pNewTable!=0 );
+ assert( !db->mallocFailed );
+ assert( IsOrdinaryTable(sParse.pNewTable) );
assert( sParse.zErrMsg==0 );
if( !pTab->aCol ){
Table *pNew = sParse.pNewTable;
@@ -153711,7 +161763,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3VtabSavepoint(sqlcipher_sqlite3 *db, int op,
break;
}
if( xMethod && pVTab->iSavepoint>iSavepoint ){
+ u64 savedFlags = (db->flags & SQLITE_Defensive);
+ db->flags &= ~(u64)SQLITE_Defensive;
rc = xMethod(pVTab->pVtab, iSavepoint);
+ db->flags |= savedFlags;
}
sqlcipher_sqlite3VtabUnlock(pVTab);
}
@@ -153752,7 +161807,7 @@ SQLITE_PRIVATE FuncDef *sqlcipher_sqlite3VtabOverloadFunction(
if( pExpr->op!=TK_COLUMN ) return pDef;
assert( ExprUseYTab(pExpr) );
pTab = pExpr->y.pTab;
- if( pTab==0 ) return pDef;
+ if( NEVER(pTab==0) ) return pDef;
if( !IsVirtual(pTab) ) return pDef;
pVtab = sqlcipher_sqlite3GetVTable(db, pTab)->pVtab;
assert( pVtab!=0 );
@@ -153831,7 +161886,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3VtabMakeWritable(Parse *pParse, Table *pTab
**
** An eponymous virtual table instance is one that is named after its
** module, and more importantly, does not require a CREATE VIRTUAL TABLE
-** statement in order to come into existance. Eponymous virtual table
+** statement in order to come into existence. Eponymous virtual table
** instances always exist. They cannot be DROP-ed.
**
** Any virtual table module for which xConnect and xCreate are the same
@@ -153940,6 +161995,10 @@ SQLITE_API int sqlcipher_sqlite3_vtab_config(sqlcipher_sqlite3 *db, int op, ...)
p->pVTable->eVtabRisk = SQLITE_VTABRISK_High;
break;
}
+ case SQLITE_VTAB_USES_ALL_SCHEMAS: {
+ p->pVTable->bAllSchemas = 1;
+ break;
+ }
default: {
rc = SQLITE_MISUSE_BKPT;
break;
@@ -154018,7 +162077,7 @@ typedef struct WhereRightJoin WhereRightJoin;
/*
** This object is a header on a block of allocated memory that will be
-** automatically freed when its WInfo oject is destructed.
+** automatically freed when its WInfo object is destructed.
*/
struct WhereMemBlock {
WhereMemBlock *pNext; /* Next block in the chain */
@@ -154079,7 +162138,7 @@ struct WhereLevel {
int iCur; /* The VDBE cursor used by this IN operator */
int addrInTop; /* Top of the IN loop */
int iBase; /* Base register of multi-key index record */
- int nPrefix; /* Number of prior entires in the key */
+ int nPrefix; /* Number of prior entries in the key */
u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */
} *aInLoop; /* Information about each nested IN operator */
} in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */
@@ -154329,7 +162388,7 @@ struct WhereClause {
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
int nBase; /* Number of terms through the last non-Virtual */
- WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
+ WhereTerm *a; /* Each a[] describes a term of the WHERE clause */
#if defined(SQLITE_SMALL_STACK)
WhereTerm aStatic[1]; /* Initial static space for a[] */
#else
@@ -154359,7 +162418,7 @@ struct WhereAndInfo {
** between VDBE cursor numbers and bits of the bitmasks in WhereTerm.
**
** The VDBE cursor numbers are small integers contained in
-** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE
+** SrcItem.iCursor and Expr.iTable fields. For any given WHERE
** clause, the cursor numbers might not begin with 0 and they might
** contain gaps in the numbering sequence. But we want to make maximum
** use of the bits in our bitmasks. This structure provides a mapping
@@ -154431,20 +162490,6 @@ struct WhereLoopBuilder {
#endif
/*
-** Each instance of this object records a change to a single node
-** in an expression tree to cause that node to point to a column
-** of an index rather than an expression or a virtual column. All
-** such transformations need to be undone at the end of WHERE clause
-** processing.
-*/
-typedef struct WhereExprMod WhereExprMod;
-struct WhereExprMod {
- WhereExprMod *pNext; /* Next translation on a list of them all */
- Expr *pExpr; /* The Expr node that was transformed */
- Expr orig; /* Original value of the Expr node */
-};
-
-/*
** The WHERE clause processing routine has two halves. The
** first part does the start of the WHERE loop and the second
** half does the tail of the WHERE loop. An instance of
@@ -154459,10 +162504,10 @@ struct WhereInfo {
SrcList *pTabList; /* List of tables in the join */
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
ExprList *pResultSet; /* Result set of the query */
+#if WHERETRACE_ENABLED
Expr *pWhere; /* The complete WHERE clause */
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- Select *pLimit; /* Used to access LIMIT expr/registers for vtabs */
#endif
+ Select *pSelect; /* The entire SELECT statement containing WHERE */
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */
@@ -154481,7 +162526,6 @@ struct WhereInfo {
int iTop; /* The very beginning of the WHERE loop */
int iEndWhere; /* End of the WHERE clause itself */
WhereLoop *pLoops; /* List of all WhereLoop objects */
- WhereExprMod *pExprMods; /* Expression modifications */
WhereMemBlock *pMemToFree;/* Memory to free when this object destroyed */
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
WhereClause sWC; /* Decomposition of the WHERE clause */
@@ -154498,7 +162542,7 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereGetMask(WhereMaskSet*,int);
#ifdef WHERETRACE_ENABLED
SQLITE_PRIVATE void sqlcipher_sqlite3WhereClausePrint(WhereClause *pWC);
SQLITE_PRIVATE void sqlcipher_sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm);
-SQLITE_PRIVATE void sqlcipher_sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC);
+SQLITE_PRIVATE void sqlcipher_sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC);
#endif
SQLITE_PRIVATE WhereTerm *sqlcipher_sqlite3WhereFindTerm(
WhereClause *pWC, /* The WHERE clause to be searched */
@@ -154629,6 +162673,8 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereCla
#define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */
#define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */
#define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */
+ /* 0x02000000 -- available for reuse */
+#define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */
#endif /* !defined(SQLITE_WHEREINT_H) */
@@ -154726,9 +162772,9 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
/*
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
-** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was
-** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
-** is added to the output to describe the table scan strategy in pLevel.
+** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG
+** was defined at compile-time. If it is not a no-op, a single OP_Explain
+** opcode is added to the output to describe the table scan strategy in pLevel.
**
** If an OP_Explain opcode is added to the VM, its address is returned.
** Otherwise, if no OP_Explain is coded, zero is returned.
@@ -154740,8 +162786,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WhereExplainOneScan(
u16 wctrlFlags /* Flags passed to sqlcipher_sqlite3WhereBegin() */
){
int ret = 0;
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
- if( sqlcipher_sqlite3ParseToplevel(pParse)->explain==2 )
+#if !defined(SQLITE_DEBUG)
+ if( sqlcipher_sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
#endif
{
SrcItem *pItem = &pTabList->a[pLevel->iFrom];
@@ -154885,6 +162931,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WhereExplainBloomFilter(
zMsg = sqlcipher_sqlite3StrAccumFinish(&str);
ret = sqlcipher_sqlite3VdbeAddOp4(v, OP_Explain, sqlcipher_sqlite3VdbeCurrentAddr(v),
pParse->addrExplain, 0, zMsg,P4_DYNAMIC);
+
+ sqlcipher_sqlite3VdbeScanStatus(v, sqlcipher_sqlite3VdbeCurrentAddr(v)-1, 0, 0, 0, 0);
return ret;
}
#endif /* SQLITE_OMIT_EXPLAIN */
@@ -154905,16 +162953,37 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereAddScanStatus(
WhereLevel *pLvl, /* Level to add scanstatus() entry for */
int addrExplain /* Address of OP_Explain (or 0) */
){
- const char *zObj = 0;
- WhereLoop *pLoop = pLvl->pWLoop;
- if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
- zObj = pLoop->u.btree.pIndex->zName;
- }else{
- zObj = pSrclist->a[pLvl->iFrom].zName;
+ if( IS_STMT_SCANSTATUS( sqlcipher_sqlite3VdbeDb(v) ) ){
+ const char *zObj = 0;
+ WhereLoop *pLoop = pLvl->pWLoop;
+ int wsFlags = pLoop->wsFlags;
+ int viaCoroutine = 0;
+
+ if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
+ zObj = pLoop->u.btree.pIndex->zName;
+ }else{
+ zObj = pSrclist->a[pLvl->iFrom].zName;
+ viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine;
+ }
+ sqlcipher_sqlite3VdbeScanStatus(
+ v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
+ );
+
+ if( viaCoroutine==0 ){
+ if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur);
+ }
+ if( wsFlags & WHERE_INDEXED ){
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
+ }
+ }else{
+ int addr = pSrclist->a[pLvl->iFrom].addrFillSub;
+ VdbeOp *pOp = sqlcipher_sqlite3VdbeGetOp(v, addr-1);
+ assert( sqlcipher_sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
+ assert( sqlcipher_sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
+ }
}
- sqlcipher_sqlite3VdbeScanStatus(
- v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
- );
}
#endif
@@ -154974,7 +163043,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
pTerm->wtFlags |= TERM_CODED;
}
#ifdef WHERETRACE_ENABLED
- if( sqlcipher_sqlite3WhereTrace & 0x20000 ){
+ if( (sqlcipher_sqlite3WhereTrace & 0x4001)==0x4001 ){
sqlcipher_sqlite3DebugPrintf("DISABLE-");
sqlcipher_sqlite3WhereTermPrint(pTerm, (int)(pTerm - (pTerm->pWC->a)));
}
@@ -155089,68 +163158,75 @@ static Expr *removeUnindexableInClauseTerms(
Expr *pX /* The IN expression to be reduced */
){
sqlcipher_sqlite3 *db = pParse->db;
+ Select *pSelect; /* Pointer to the SELECT on the RHS */
Expr *pNew;
pNew = sqlcipher_sqlite3ExprDup(db, pX, 0);
if( db->mallocFailed==0 ){
- ExprList *pOrigRhs; /* Original unmodified RHS */
- ExprList *pOrigLhs; /* Original unmodified LHS */
- ExprList *pRhs = 0; /* New RHS after modifications */
- ExprList *pLhs = 0; /* New LHS after mods */
- int i; /* Loop counter */
- Select *pSelect; /* Pointer to the SELECT on the RHS */
-
- assert( ExprUseXSelect(pNew) );
- pOrigRhs = pNew->x.pSelect->pEList;
- assert( pNew->pLeft!=0 );
- assert( ExprUseXList(pNew->pLeft) );
- pOrigLhs = pNew->pLeft->x.pList;
- for(i=iEq; i<pLoop->nLTerm; i++){
- if( pLoop->aLTerm[i]->pExpr==pX ){
- int iField;
- assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 );
- iField = pLoop->aLTerm[i]->u.x.iField - 1;
- if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */
- pRhs = sqlcipher_sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
- pOrigRhs->a[iField].pExpr = 0;
- assert( pOrigLhs->a[iField].pExpr!=0 );
- pLhs = sqlcipher_sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr);
- pOrigLhs->a[iField].pExpr = 0;
- }
- }
- sqlcipher_sqlite3ExprListDelete(db, pOrigRhs);
- sqlcipher_sqlite3ExprListDelete(db, pOrigLhs);
- pNew->pLeft->x.pList = pLhs;
- pNew->x.pSelect->pEList = pRhs;
- if( pLhs && pLhs->nExpr==1 ){
- /* Take care here not to generate a TK_VECTOR containing only a
- ** single value. Since the parser never creates such a vector, some
- ** of the subroutines do not handle this case. */
- Expr *p = pLhs->a[0].pExpr;
- pLhs->a[0].pExpr = 0;
- sqlcipher_sqlite3ExprDelete(db, pNew->pLeft);
- pNew->pLeft = p;
- }
- pSelect = pNew->x.pSelect;
- if( pSelect->pOrderBy ){
- /* If the SELECT statement has an ORDER BY clause, zero the
- ** iOrderByCol variables. These are set to non-zero when an
- ** ORDER BY term exactly matches one of the terms of the
- ** result-set. Since the result-set of the SELECT statement may
- ** have been modified or reordered, these variables are no longer
- ** set correctly. Since setting them is just an optimization,
- ** it's easiest just to zero them here. */
- ExprList *pOrderBy = pSelect->pOrderBy;
- for(i=0; i<pOrderBy->nExpr; i++){
- pOrderBy->a[i].u.x.iOrderByCol = 0;
+ for(pSelect=pNew->x.pSelect; pSelect; pSelect=pSelect->pPrior){
+ ExprList *pOrigRhs; /* Original unmodified RHS */
+ ExprList *pOrigLhs = 0; /* Original unmodified LHS */
+ ExprList *pRhs = 0; /* New RHS after modifications */
+ ExprList *pLhs = 0; /* New LHS after mods */
+ int i; /* Loop counter */
+
+ assert( ExprUseXSelect(pNew) );
+ pOrigRhs = pSelect->pEList;
+ assert( pNew->pLeft!=0 );
+ assert( ExprUseXList(pNew->pLeft) );
+ if( pSelect==pNew->x.pSelect ){
+ pOrigLhs = pNew->pLeft->x.pList;
+ }
+ for(i=iEq; i<pLoop->nLTerm; i++){
+ if( pLoop->aLTerm[i]->pExpr==pX ){
+ int iField;
+ assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 );
+ iField = pLoop->aLTerm[i]->u.x.iField - 1;
+ if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */
+ pRhs = sqlcipher_sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
+ pOrigRhs->a[iField].pExpr = 0;
+ if( pOrigLhs ){
+ assert( pOrigLhs->a[iField].pExpr!=0 );
+ pLhs = sqlcipher_sqlite3ExprListAppend(pParse,pLhs,pOrigLhs->a[iField].pExpr);
+ pOrigLhs->a[iField].pExpr = 0;
+ }
+ }
+ }
+ sqlcipher_sqlite3ExprListDelete(db, pOrigRhs);
+ if( pOrigLhs ){
+ sqlcipher_sqlite3ExprListDelete(db, pOrigLhs);
+ pNew->pLeft->x.pList = pLhs;
+ }
+ pSelect->pEList = pRhs;
+ if( pLhs && pLhs->nExpr==1 ){
+ /* Take care here not to generate a TK_VECTOR containing only a
+ ** single value. Since the parser never creates such a vector, some
+ ** of the subroutines do not handle this case. */
+ Expr *p = pLhs->a[0].pExpr;
+ pLhs->a[0].pExpr = 0;
+ sqlcipher_sqlite3ExprDelete(db, pNew->pLeft);
+ pNew->pLeft = p;
+ }
+ if( pSelect->pOrderBy ){
+ /* If the SELECT statement has an ORDER BY clause, zero the
+ ** iOrderByCol variables. These are set to non-zero when an
+ ** ORDER BY term exactly matches one of the terms of the
+ ** result-set. Since the result-set of the SELECT statement may
+ ** have been modified or reordered, these variables are no longer
+ ** set correctly. Since setting them is just an optimization,
+ ** it's easiest just to zero them here. */
+ ExprList *pOrderBy = pSelect->pOrderBy;
+ for(i=0; i<pOrderBy->nExpr; i++){
+ pOrderBy->a[i].u.x.iOrderByCol = 0;
+ }
}
- }
#if 0
- printf("For indexing, change the IN expr:\n");
- sqlcipher_sqlite3TreeViewExpr(0, pX, 0);
- printf("Into:\n");
- sqlcipher_sqlite3TreeViewExpr(0, pNew, 0);
+ printf("For indexing, change the IN expr:\n");
+ sqlcipher_sqlite3TreeViewExpr(0, pX, 0);
+ printf("Into:\n");
+ sqlcipher_sqlite3TreeViewExpr(0, pNew, 0);
#endif
+ }
}
return pNew;
}
@@ -155403,7 +163479,7 @@ static int codeAllEqualityTerms(
/* Figure out how many memory cells we will need then allocate them.
*/
regBase = pParse->nMem + 1;
- nReg = pLoop->u.btree.nEq + nExtraReg;
+ nReg = nEq + nExtraReg;
pParse->nMem += nReg;
zAff = sqlcipher_sqlite3DbStrDup(pParse->db,sqlcipher_sqlite3IndexAffinityStr(pParse->db,pIdx));
@@ -155450,9 +163526,6 @@ static int codeAllEqualityTerms(
sqlcipher_sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j);
}
}
- }
- for(j=nSkip; j<nEq; j++){
- pTerm = pLoop->aLTerm[j];
if( pTerm->eOperator & WO_IN ){
if( pTerm->pExpr->flags & EP_xIsSelect ){
/* No affinity ever needs to be (or should be) applied to a value
@@ -155508,7 +163581,7 @@ static void whereLikeOptimizationStringFixup(
if( pTerm->wtFlags & TERM_LIKEOPT ){
VdbeOp *pOp;
assert( pLevel->iLikeRepCntr>0 );
- pOp = sqlcipher_sqlite3VdbeGetOp(v, -1);
+ pOp = sqlcipher_sqlite3VdbeGetLastOp(v);
assert( pOp!=0 );
assert( pOp->opcode==OP_String8
|| pTerm->pWC->pWInfo->pParse->db->mallocFailed );
@@ -155595,18 +163668,19 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
** 2) transform the expression node to a TK_REGISTER node that reads
** from the newly populated register.
**
-** Also, if the node is a TK_COLUMN that does access the table idenified
+** Also, if the node is a TK_COLUMN that does access the table identified
** by pCCurHint.iTabCur, and an index is being used (which we will
** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into
** an access of the index rather than the original table.
*/
static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
int rc = WRC_Continue;
+ int reg;
struct CCurHint *pHint = pWalker->u.pCCurHint;
if( pExpr->op==TK_COLUMN ){
if( pExpr->iTable!=pHint->iTabCur ){
- int reg = ++pWalker->pParse->nMem; /* Register for column value */
- sqlcipher_sqlite3ExprCode(pWalker->pParse, pExpr, reg);
+ reg = ++pWalker->pParse->nMem; /* Register for column value */
+ reg = sqlcipher_sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
pExpr->op = TK_REGISTER;
pExpr->iTable = reg;
}else if( pHint->pIdx!=0 ){
@@ -155614,15 +163688,15 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
pExpr->iColumn = sqlcipher_sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn);
assert( pExpr->iColumn>=0 );
}
- }else if( pExpr->op==TK_AGG_FUNCTION ){
- /* An aggregate function in the WHERE clause of a query means this must
- ** be a correlated sub-query, and expression pExpr is an aggregate from
- ** the parent context. Do not walk the function arguments in this case.
- **
- ** todo: It should be possible to replace this node with a TK_REGISTER
- ** expression, as the result of the expression must be stored in a
- ** register at this point. The same holds for TK_AGG_COLUMN nodes. */
+ }else if( pExpr->pAggInfo ){
rc = WRC_Prune;
+ reg = ++pWalker->pParse->nMem; /* Register for column value */
+ reg = sqlcipher_sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
+ pExpr->op = TK_REGISTER;
+ pExpr->iTable = reg;
+ }else if( pExpr->op==TK_TRUEFALSE ){
+ /* Do not walk disabled expressions. tag-20230504-1 */
+ return WRC_Prune;
}
return rc;
}
@@ -155724,7 +163798,7 @@ static void codeCursorHint(
}
if( pExpr!=0 ){
sWalker.xExprCallback = codeCursorHintFixExpr;
- sqlcipher_sqlite3WalkExpr(&sWalker, pExpr);
+ if( pParse->nErr==0 ) sqlcipher_sqlite3WalkExpr(&sWalker, pExpr);
sqlcipher_sqlite3VdbeAddOp4(v, OP_CursorHint,
(sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
(const char*)pExpr, P4_EXPR);
@@ -155832,143 +163906,6 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
}
}
-/* An instance of the IdxExprTrans object carries information about a
-** mapping from an expression on table columns into a column in an index
-** down through the Walker.
-*/
-typedef struct IdxExprTrans {
- Expr *pIdxExpr; /* The index expression */
- int iTabCur; /* The cursor of the corresponding table */
- int iIdxCur; /* The cursor for the index */
- int iIdxCol; /* The column for the index */
- int iTabCol; /* The column for the table */
- WhereInfo *pWInfo; /* Complete WHERE clause information */
- sqlcipher_sqlite3 *db; /* Database connection (for malloc()) */
-} IdxExprTrans;
-
-/*
-** Preserve pExpr on the WhereETrans list of the WhereInfo.
-*/
-static void preserveExpr(IdxExprTrans *pTrans, Expr *pExpr){
- WhereExprMod *pNew;
- pNew = sqlcipher_sqlite3DbMallocRaw(pTrans->db, sizeof(*pNew));
- if( pNew==0 ) return;
- pNew->pNext = pTrans->pWInfo->pExprMods;
- pTrans->pWInfo->pExprMods = pNew;
- pNew->pExpr = pExpr;
- memcpy(&pNew->orig, pExpr, sizeof(*pExpr));
-}
-
-/* The walker node callback used to transform matching expressions into
-** a reference to an index column for an index on an expression.
-**
-** If pExpr matches, then transform it into a reference to the index column
-** that contains the value of pExpr.
-*/
-static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
- IdxExprTrans *pX = p->u.pIdxTrans;
- if( sqlcipher_sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
- pExpr = sqlcipher_sqlite3ExprSkipCollate(pExpr);
- preserveExpr(pX, pExpr);
- pExpr->affExpr = sqlcipher_sqlite3ExprAffinity(pExpr);
- pExpr->op = TK_COLUMN;
- pExpr->iTable = pX->iIdxCur;
- pExpr->iColumn = pX->iIdxCol;
- testcase( ExprHasProperty(pExpr, EP_Unlikely) );
- ExprClearProperty(pExpr, EP_Skip|EP_Unlikely|EP_WinFunc|EP_Subrtn);
- pExpr->y.pTab = 0;
- return WRC_Prune;
- }else{
- return WRC_Continue;
- }
-}
-
-#ifndef SQLITE_OMIT_GENERATED_COLUMNS
-/* A walker node callback that translates a column reference to a table
-** into a corresponding column reference of an index.
-*/
-static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){
- if( pExpr->op==TK_COLUMN ){
- IdxExprTrans *pX = p->u.pIdxTrans;
- if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){
- assert( ExprUseYTab(pExpr) && pExpr->y.pTab!=0 );
- preserveExpr(pX, pExpr);
- pExpr->affExpr = sqlcipher_sqlite3TableColumnAffinity(pExpr->y.pTab,pExpr->iColumn);
- pExpr->iTable = pX->iIdxCur;
- pExpr->iColumn = pX->iIdxCol;
- pExpr->y.pTab = 0;
- }
- }
- return WRC_Continue;
-}
-#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
-
-/*
-** For an indexes on expression X, locate every instance of expression X
-** in pExpr and change that subexpression into a reference to the appropriate
-** column of the index.
-**
-** 2019-10-24: Updated to also translate references to a VIRTUAL column in
-** the table into references to the corresponding (stored) column of the
-** index.
-*/
-static void whereIndexExprTrans(
- Index *pIdx, /* The Index */
- int iTabCur, /* Cursor of the table that is being indexed */
- int iIdxCur, /* Cursor of the index itself */
- WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
-){
- int iIdxCol; /* Column number of the index */
- ExprList *aColExpr; /* Expressions that are indexed */
- Table *pTab;
- Walker w;
- IdxExprTrans x;
- aColExpr = pIdx->aColExpr;
- if( aColExpr==0 && !pIdx->bHasVCol ){
- /* The index does not reference any expressions or virtual columns
- ** so no translations are needed. */
- return;
- }
- pTab = pIdx->pTable;
- memset(&w, 0, sizeof(w));
- w.u.pIdxTrans = &x;
- x.iTabCur = iTabCur;
- x.iIdxCur = iIdxCur;
- x.pWInfo = pWInfo;
- x.db = pWInfo->pParse->db;
- for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
- i16 iRef = pIdx->aiColumn[iIdxCol];
- if( iRef==XN_EXPR ){
- assert( aColExpr!=0 && aColExpr->a[iIdxCol].pExpr!=0 );
- x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
- if( sqlcipher_sqlite3ExprIsConstant(x.pIdxExpr) ) continue;
- w.xExprCallback = whereIndexExprTransNode;
-#ifndef SQLITE_OMIT_GENERATED_COLUMNS
- }else if( iRef>=0
- && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0
- && ((pTab->aCol[iRef].colFlags & COLFLAG_HASCOLL)==0
- || sqlcipher_sqlite3StrICmp(sqlcipher_sqlite3ColumnColl(&pTab->aCol[iRef]),
- sqlcipher_sqlite3StrBINARY)==0)
- ){
- /* Check to see if there are direct references to generated columns
- ** that are contained in the index. Pulling the generated column
- ** out of the index is an optimization only - the main table is always
- ** available if the index cannot be used. To avoid unnecessary
- ** complication, omit this optimization if the collating sequence for
- ** the column is non-standard */
- x.iTabCol = iRef;
- w.xExprCallback = whereIndexExprTransColumn;
-#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
- }else{
- continue;
- }
- x.iIdxCol = iIdxCol;
- sqlcipher_sqlite3WalkExpr(&w, pWInfo->pWhere);
- sqlcipher_sqlite3WalkExprList(&w, pWInfo->pOrderBy);
- sqlcipher_sqlite3WalkExprList(&w, pWInfo->pResultSet);
- }
-}
-
/*
** The pTruth expression is always true because it is the WHERE clause
** a partial index that is driving a query loop. Look through all of the
@@ -156037,6 +163974,8 @@ static SQLITE_NOINLINE void filterPullDown(
testcase( pTerm->wtFlags & TERM_VIRTUAL );
regRowid = sqlcipher_sqlite3GetTempReg(pParse);
regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid);
+ sqlcipher_sqlite3VdbeAddOp2(pParse->pVdbe, OP_MustBeInt, regRowid, addrNxt);
+ VdbeCoverage(pParse->pVdbe);
sqlcipher_sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter,
addrNxt, regRowid, 1);
VdbeCoverage(pParse->pVdbe);
@@ -156060,6 +163999,27 @@ static SQLITE_NOINLINE void filterPullDown(
}
/*
+** Loop pLoop is a WHERE_INDEXED level that uses at least one IN(...)
+** operator. Return true if level pLoop is guaranteed to visit only one
+** row for each key generated for the index.
+*/
+static int whereLoopIsOneRow(WhereLoop *pLoop){
+ if( pLoop->u.btree.pIndex->onError
+ && pLoop->nSkip==0
+ && pLoop->u.btree.nEq==pLoop->u.btree.pIndex->nKeyCol
+ ){
+ int ii;
+ for(ii=0; ii<pLoop->u.btree.nEq; ii++){
+ if( pLoop->aLTerm[ii]->eOperator & (WO_IS|WO_ISNULL) ){
+ return 0;
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
*/
@@ -156096,13 +164056,15 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
pLevel->notReady = notReady & ~sqlcipher_sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
bRev = (pWInfo->revMask>>iLevel)&1;
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
-#if WHERETRACE_ENABLED /* 0x20800 */
- if( sqlcipher_sqlite3WhereTrace & 0x800 ){
+#if WHERETRACE_ENABLED /* 0x4001 */
+ if( sqlcipher_sqlite3WhereTrace & 0x1 ){
sqlcipher_sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom);
- sqlcipher_sqlite3WhereLoopPrint(pLoop, pWC);
+ if( sqlcipher_sqlite3WhereTrace & 0x1000 ){
+ sqlcipher_sqlite3WhereLoopPrint(pLoop, pWC);
+ }
}
- if( sqlcipher_sqlite3WhereTrace & 0x20000 ){
+ if( (sqlcipher_sqlite3WhereTrace & 0x4001)==0x4001 ){
if( iLevel==0 ){
sqlcipher_sqlite3DebugPrintf("WHERE clause being coded:\n");
sqlcipher_sqlite3TreeViewExpr(0, pWInfo->pWhere, 0);
@@ -156135,7 +164097,7 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){
pLevel->iLeftJoin = ++pParse->nMem;
sqlcipher_sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin);
- VdbeComment((v, "init LEFT JOIN no-match flag"));
+ VdbeComment((v, "init LEFT JOIN match flag"));
}
/* Compute a safe address to jump to if we discover that the table for
@@ -156188,9 +164150,9 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
&& pLoop->u.vtab.bOmitOffset
){
assert( pTerm->eOperator==WO_AUX );
- assert( pWInfo->pLimit!=0 );
- assert( pWInfo->pLimit->iOffset>0 );
- sqlcipher_sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pLimit->iOffset);
+ assert( pWInfo->pSelect!=0 );
+ assert( pWInfo->pSelect->iOffset>0 );
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pSelect->iOffset);
VdbeComment((v,"Zero OFFSET counter"));
}
}
@@ -156298,6 +164260,8 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
if( iRowidReg!=iReleaseReg ) sqlcipher_sqlite3ReleaseTempReg(pParse, iReleaseReg);
addrNxt = pLevel->addrNxt;
if( pLevel->regFilter ){
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
+ VdbeCoverage(v);
sqlcipher_sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt,
iRowidReg, 1);
VdbeCoverage(v);
@@ -156343,7 +164307,7 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
};
assert( TK_LE==TK_GT+1 ); /* Make sure the ordering.. */
assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */
- assert( TK_GE==TK_GT+3 ); /* ... is correcct. */
+ assert( TK_GE==TK_GT+3 ); /* ... is correct. */
assert( (pStart->wtFlags & TERM_VNULL)==0 );
testcase( pStart->wtFlags & TERM_VIRTUAL );
@@ -156649,6 +164613,11 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
** guess. */
addrSeekScan = sqlcipher_sqlite3VdbeAddOp1(v, OP_SeekScan,
(pIdx->aiRowLogEst[0]+9)/10);
+ if( pRangeStart || pRangeEnd ){
+ sqlcipher_sqlite3VdbeChangeP5(v, 1);
+ sqlcipher_sqlite3VdbeChangeP2(v, addrSeekScan, sqlcipher_sqlite3VdbeCurrentAddr(v)+1);
+ addrSeekScan = 0;
+ }
VdbeCoverage(v);
}
sqlcipher_sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
@@ -156685,16 +164654,7 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
assert( pLevel->p2==0 );
if( pRangeEnd ){
Expr *pRight = pRangeEnd->pExpr->pRight;
- if( addrSeekScan ){
- /* For a seek-scan that has a range on the lowest term of the index,
- ** we have to make the top of the loop be code that sets the end
- ** condition of the range. Otherwise, the OP_SeekScan might jump
- ** over that initialization, leaving the range-end value set to the
- ** range-start value, resulting in a wrong answer.
- ** See ticket 5981a8c041a3c2f3 (2021-11-02).
- */
- pLevel->p2 = sqlcipher_sqlite3VdbeCurrentAddr(v);
- }
+ assert( addrSeekScan==0 );
codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
@@ -156724,11 +164684,11 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
}
nConstraint++;
}
- sqlcipher_sqlite3DbFree(db, zStartAff);
- sqlcipher_sqlite3DbFree(db, zEndAff);
+ if( zStartAff ) sqlcipher_sqlite3DbNNFreeNN(db, zStartAff);
+ if( zEndAff ) sqlcipher_sqlite3DbNNFreeNN(db, zEndAff);
/* Top of the loop body */
- if( pLevel->p2==0 ) pLevel->p2 = sqlcipher_sqlite3VdbeCurrentAddr(v);
+ pLevel->p2 = sqlcipher_sqlite3VdbeCurrentAddr(v);
/* Check if the index cursor is past the end of the range. */
if( nConstraint ){
@@ -156787,27 +164747,6 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
}
if( pLevel->iLeftJoin==0 ){
- /* If pIdx is an index on one or more expressions, then look through
- ** all the expressions in pWInfo and try to transform matching expressions
- ** into reference to index columns. Also attempt to translate references
- ** to virtual columns in the table into references to (stored) columns
- ** of the index.
- **
- ** Do not do this for the RHS of a LEFT JOIN. This is because the
- ** expression may be evaluated after OP_NullRow has been executed on
- ** the cursor. In this case it is important to do the full evaluation,
- ** as the result of the expression may not be NULL, even if all table
- ** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a
- **
- ** Also, do not do this when processing one index an a multi-index
- ** OR clause, since the transformation will become invalid once we
- ** move forward to the next index.
- ** https://sqlite.org/src/info/4e8e4857d32d401f
- */
- if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 ){
- whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
- }
-
/* If a partial index is driving the loop, try to eliminate WHERE clause
** terms from the query that must be true due to the WHERE clause of
** the partial index.
@@ -156827,7 +164766,9 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
}
/* Record the instruction used to terminate the loop. */
- if( pLoop->wsFlags & WHERE_ONEROW ){
+ if( (pLoop->wsFlags & WHERE_ONEROW)
+ || (pLevel->u.in.nIn && regBignull==0 && whereLoopIsOneRow(pLoop))
+ ){
pLevel->op = OP_Noop;
}else if( bRev ){
pLevel->op = OP_Prev;
@@ -156920,7 +164861,7 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
int nNotReady; /* The number of notReady tables */
SrcItem *origSrc; /* Original list of tables */
nNotReady = pWInfo->nLevel - iLevel - 1;
- pOrTab = sqlcipher_sqlite3StackAllocRaw(db,
+ pOrTab = sqlcipher_sqlite3DbMallocRawNN(db,
sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
if( pOrTab==0 ) return notReady;
pOrTab->nAlloc = (u8)(nNotReady + 1);
@@ -157040,7 +164981,7 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
}
/* Loop through table entries that match term pOrTerm. */
ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1));
- WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));
+ WHERETRACE(0xffffffff, ("Subplan for OR-clause:\n"));
pSubWInfo = sqlcipher_sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, 0,
WHERE_OR_SUBCLAUSE, iCovCur);
assert( pSubWInfo || pParse->nErr );
@@ -157173,7 +165114,7 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
assert( pLevel->op==OP_Return );
pLevel->p2 = sqlcipher_sqlite3VdbeCurrentAddr(v);
- if( pWInfo->nLevel>1 ){ sqlcipher_sqlite3StackFree(db, pOrTab); }
+ if( pWInfo->nLevel>1 ){ sqlcipher_sqlite3DbFreeNN(db, pOrTab); }
if( !untestedTerms ) disableTerm(pLevel, pTerm);
}else
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
@@ -157217,6 +165158,12 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
** iLoop==3: Code all remaining expressions.
**
** An effort is made to skip unnecessary iterations of the loop.
+ **
+ ** This optimization of causing simple query restrictions to occur before
+ ** more complex one is call the "push-down" optimization in MySQL. Here
+ ** in SQLite, the name is "MySQL push-down", since there is also another
+ ** totally unrelated optimization called "WHERE-clause push-down".
+ ** Sometimes the qualifier is omitted, resulting in an ambiguity, so beware.
*/
iLoop = (pIdx ? 1 : 2);
do{
@@ -157277,12 +165224,12 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
}
#endif
}
-#ifdef WHERETRACE_ENABLED /* 0xffff */
+#ifdef WHERETRACE_ENABLED /* 0xffffffff */
if( sqlcipher_sqlite3WhereTrace ){
VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d",
pWC->nTerm-j, pTerm, iLoop));
}
- if( sqlcipher_sqlite3WhereTrace & 0x800 ){
+ if( sqlcipher_sqlite3WhereTrace & 0x4000 ){
sqlcipher_sqlite3DebugPrintf("Coding auxiliary constraint:\n");
sqlcipher_sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
}
@@ -157311,8 +165258,8 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
if( pTerm->leftCursor!=iCur ) continue;
if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ) continue;
pE = pTerm->pExpr;
-#ifdef WHERETRACE_ENABLED /* 0x800 */
- if( sqlcipher_sqlite3WhereTrace & 0x800 ){
+#ifdef WHERETRACE_ENABLED /* 0x4001 */
+ if( (sqlcipher_sqlite3WhereTrace & 0x4001)==0x4001 ){
sqlcipher_sqlite3DebugPrintf("Coding transitive constraint:\n");
sqlcipher_sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
}
@@ -157427,13 +165374,13 @@ SQLITE_PRIVATE Bitmask sqlcipher_sqlite3WhereCodeOneLoopStart(
}
}
-#if WHERETRACE_ENABLED /* 0x20800 */
- if( sqlcipher_sqlite3WhereTrace & 0x20000 ){
+#if WHERETRACE_ENABLED /* 0x4001 */
+ if( sqlcipher_sqlite3WhereTrace & 0x4000 ){
sqlcipher_sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n",
iLevel);
sqlcipher_sqlite3WhereClausePrint(pWC);
}
- if( sqlcipher_sqlite3WhereTrace & 0x800 ){
+ if( sqlcipher_sqlite3WhereTrace & 0x1 ){
sqlcipher_sqlite3DebugPrintf("End Coding level %d: notReady=%llx\n",
iLevel, (u64)pLevel->notReady);
}
@@ -157467,7 +165414,16 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlcipher_sqlite3WhereRightJoinLoop(
pRJ->regReturn);
for(k=0; k<iLevel; k++){
int iIdxCur;
+ SrcItem *pRight;
+ assert( pWInfo->a[k].pWLoop->iTab == pWInfo->a[k].iFrom );
+ pRight = &pWInfo->pTabList->a[pWInfo->a[k].iFrom];
mAll |= pWInfo->a[k].pWLoop->maskSelf;
+ if( pRight->fg.viaCoroutine ){
+ sqlcipher_sqlite3VdbeAddOp3(
+ v, OP_Null, 0, pRight->regResult,
+ pRight->regResult + pRight->pSelect->pEList->nExpr-1
+ );
+ }
sqlcipher_sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
iIdxCur = pWInfo->a[k].iIdxCur;
if( iIdxCur ){
@@ -157548,7 +165504,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlcipher_sqlite3WhereRightJoinLoop(
** the WHERE clause of SQL statements.
**
** This file was originally part of where.c but was split out to improve
-** readability and editabiliity. This file contains utility routines for
+** readability and editability. This file contains utility routines for
** analyzing Expr objects in the WHERE clause.
*/
/* #include "sqliteInt.h" */
@@ -157764,7 +165720,7 @@ static int isLikeOrGlob(
** range search. The third is because the caller assumes that the pattern
** consists of at least one character after all escapes have been
** removed. */
- if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){
+ if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){
Expr *pPrefix;
/* A "complete" match if the pattern ends with "*" or "%" */
@@ -157801,7 +165757,7 @@ static int isLikeOrGlob(
if( pLeft->op!=TK_COLUMN
|| sqlcipher_sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|| (ALWAYS( ExprUseYTab(pLeft) )
- && pLeft->y.pTab
+ && ALWAYS(pLeft->y.pTab)
&& IsVirtual(pLeft->y.pTab)) /* Might be numeric */
){
int isNum;
@@ -157918,8 +165874,7 @@ static int isAuxiliaryVtabOperator(
** MATCH(expression,vtab_column)
*/
pCol = pList->a[1].pExpr;
- assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) );
- testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
+ assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) );
if( ExprIsVtab(pCol) ){
for(i=0; i<ArraySize(aOp); i++){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
@@ -157944,7 +165899,7 @@ static int isAuxiliaryVtabOperator(
*/
pCol = pList->a[0].pExpr;
assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) );
- testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
+ assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) );
if( ExprIsVtab(pCol) ){
sqlcipher_sqlite3_vtab *pVtab;
sqlcipher_sqlite3_module *pMod;
@@ -157969,13 +165924,12 @@ static int isAuxiliaryVtabOperator(
int res = 0;
Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight;
- assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) );
- testcase( pLeft->op==TK_COLUMN && pLeft->y.pTab==0 );
+ assert( pLeft->op!=TK_COLUMN || (ExprUseYTab(pLeft) && pLeft->y.pTab!=0) );
if( ExprIsVtab(pLeft) ){
res++;
}
- assert( pRight==0 || pRight->op!=TK_COLUMN || ExprUseYTab(pRight) );
- testcase( pRight && pRight->op==TK_COLUMN && pRight->y.pTab==0 );
+ assert( pRight==0 || pRight->op!=TK_COLUMN
+ || (ExprUseYTab(pRight) && pRight->y.pTab!=0) );
if( pRight && ExprIsVtab(pRight) ){
res++;
SWAP(Expr*, pLeft, pRight);
@@ -158339,7 +166293,7 @@ static void exprAnalyzeOrTerm(
pOrTerm->leftCursor))==0 ){
/* This term must be of the form t1.a==t2.b where t2 is in the
** chngToIN set but t1 is not. This term will be either preceded
- ** or follwed by an inverted copy (t2.b==t1.a). Skip this term
+ ** or followed by an inverted copy (t2.b==t1.a). Skip this term
** and use its inversion. */
testcase( pOrTerm->wtFlags & TERM_COPIED );
testcase( pOrTerm->wtFlags & TERM_VIRTUAL );
@@ -158511,35 +166465,40 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
*/
static SQLITE_NOINLINE int exprMightBeIndexed2(
SrcList *pFrom, /* The FROM clause */
- Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
int *aiCurCol, /* Write the referenced table cursor and column here */
- Expr *pExpr /* An operand of a comparison operator */
+ Expr *pExpr, /* An operand of a comparison operator */
+ int j /* Start looking with the j-th pFrom entry */
){
Index *pIdx;
int i;
int iCur;
- for(i=0; mPrereq>1; i++, mPrereq>>=1){}
- iCur = pFrom->a[i].iCursor;
- for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->aColExpr==0 ) continue;
- for(i=0; i<pIdx->nKeyCol; i++){
- if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
- if( sqlcipher_sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
- aiCurCol[0] = iCur;
- aiCurCol[1] = XN_EXPR;
- return 1;
+ do{
+ iCur = pFrom->a[j].iCursor;
+ for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->aColExpr==0 ) continue;
+ for(i=0; i<pIdx->nKeyCol; i++){
+ if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
+ assert( pIdx->bHasExpr );
+ if( sqlcipher_sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0
+ && !sqlcipher_sqlite3ExprIsConstant(0,pIdx->aColExpr->a[i].pExpr)
+ ){
+ aiCurCol[0] = iCur;
+ aiCurCol[1] = XN_EXPR;
+ return 1;
+ }
}
}
- }
+ }while( ++j < pFrom->nSrc );
return 0;
}
static int exprMightBeIndexed(
SrcList *pFrom, /* The FROM clause */
- Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
int *aiCurCol, /* Write the referenced table cursor & column here */
Expr *pExpr, /* An operand of a comparison operator */
int op /* The specific comparison operator */
){
+ int i;
+
/* If this expression is a vector to the left or right of a
** inequality constraint (>, <, >= or <=), perform the processing
** on the first element of the vector. */
@@ -158549,7 +166508,6 @@ static int exprMightBeIndexed(
if( pExpr->op==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){
assert( ExprUseXList(pExpr) );
pExpr = pExpr->x.pList->a[0].pExpr;
-
}
if( pExpr->op==TK_COLUMN ){
@@ -158557,9 +166515,16 @@ static int exprMightBeIndexed(
aiCurCol[1] = pExpr->iColumn;
return 1;
}
- if( mPrereq==0 ) return 0; /* No table references */
- if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */
- return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr);
+
+ for(i=0; i<pFrom->nSrc; i++){
+ Index *pIdx;
+ for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->aColExpr ){
+ return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i);
+ }
+ }
+ }
+ return 0;
}
@@ -158590,8 +166555,8 @@ static void exprAnalyze(
WhereTerm *pTerm; /* The term to be analyzed */
WhereMaskSet *pMaskSet; /* Set of table index masks */
Expr *pExpr; /* The expression to be analyzed */
- Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */
- Bitmask prereqAll; /* Prerequesites of pExpr */
+ Bitmask prereqLeft; /* Prerequisites of the pExpr->pLeft */
+ Bitmask prereqAll; /* Prerequisites of pExpr */
Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */
Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */
int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */
@@ -158685,7 +166650,7 @@ static void exprAnalyze(
pLeft = pLeft->x.pList->a[pTerm->u.x.iField-1].pExpr;
}
- if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){
+ if( exprMightBeIndexed(pSrc, aiCurCol, pLeft, op) ){
pTerm->leftCursor = aiCurCol[0];
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
pTerm->u.x.leftColumn = aiCurCol[1];
@@ -158693,7 +166658,7 @@ static void exprAnalyze(
}
if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
if( pRight
- && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op)
+ && exprMightBeIndexed(pSrc, aiCurCol, pRight, op)
&& !ExprHasProperty(pRight, EP_FixedCol)
){
WhereTerm *pNew;
@@ -158737,7 +166702,7 @@ static void exprAnalyze(
&& 0==sqlcipher_sqlite3ExprCanBeNull(pLeft)
){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- pExpr->op = TK_TRUEFALSE;
+ pExpr->op = TK_TRUEFALSE; /* See tag-20230504-1 */
pExpr->u.zToken = "false";
ExprSetProperty(pExpr, EP_IsFalse);
pTerm->prereqAll = 0;
@@ -158904,7 +166869,6 @@ static void exprAnalyze(
transferJoinMarkings(pNewExpr1, pExpr);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
testcase( idxNew1==0 );
- exprAnalyze(pSrc, pWC, idxNew1);
pNewExpr2 = sqlcipher_sqlite3ExprDup(db, pLeft, 0);
pNewExpr2 = sqlcipher_sqlite3PExpr(pParse, TK_LT,
sqlcipher_sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName),
@@ -158912,6 +166876,7 @@ static void exprAnalyze(
transferJoinMarkings(pNewExpr2, pExpr);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
testcase( idxNew2==0 );
+ exprAnalyze(pSrc, pWC, idxNew1);
exprAnalyze(pSrc, pWC, idxNew2);
pTerm = &pWC->a[idxTerm];
if( isComplete ){
@@ -158968,7 +166933,7 @@ static void exprAnalyze(
&& pTerm->u.x.iField==0
&& pExpr->pLeft->op==TK_VECTOR
&& ALWAYS( ExprUseXSelect(pExpr) )
- && pExpr->x.pSelect->pPrior==0
+ && (pExpr->x.pSelect->pPrior==0 || (pExpr->x.pSelect->selFlags & SF_Values))
#ifndef SQLITE_OMIT_WINDOWFUNC
&& pExpr->x.pSelect->pWin==0
#endif
@@ -159137,9 +167102,9 @@ static void whereAddLimitExpr(
** exist only so that they may be passed to the xBestIndex method of the
** single virtual table in the FROM clause of the SELECT.
*/
-SQLITE_PRIVATE void sqlcipher_sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
- assert( p==0 || (p->pGroupBy==0 && (p->selFlags & SF_Aggregate)==0) );
- if( (p && p->pLimit) /* 1 */
+SQLITE_PRIVATE void SQLITE_NOINLINE sqlcipher_sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
+ assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
+ if( p->pGroupBy==0
&& (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
&& (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
){
@@ -159156,7 +167121,15 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
assert( pWC->a[ii].eOperator==WO_ROWVAL );
continue;
}
+ if( pWC->a[ii].nChild ){
+ /* If this term has child terms, then they are also part of the
+ ** pWC->a[] array. So this term can be ignored, as a LIMIT clause
+ ** will only be added if each of the child terms passes the
+ ** (leftCursor==iCsr) test below. */
+ continue;
+ }
if( pWC->a[ii].leftCursor!=iCsr ) return;
+ if( pWC->a[ii].prereqRight!=0 ) return;
}
/* Check condition (5). Return early if it is not met. */
@@ -159171,12 +167144,14 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
/* All conditions are met. Add the terms to the where-clause object. */
assert( p->pLimit->op==TK_LIMIT );
- whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft,
- iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT);
- if( p->iOffset>0 ){
+ if( p->iOffset!=0 && (p->selFlags & SF_Compound)==0 ){
whereAddLimitExpr(pWC, p->iOffset, p->pLimit->pRight,
iCsr, SQLITE_INDEX_CONSTRAINT_OFFSET);
}
+ if( p->iOffset==0 || (p->selFlags & SF_Compound)==0 ){
+ whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft,
+ iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT);
+ }
}
}
@@ -159375,9 +167350,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereTabFuncArgs(
pRhs = sqlcipher_sqlite3PExpr(pParse, TK_UPLUS,
sqlcipher_sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
pTerm = sqlcipher_sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
- if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){
+ if( pItem->fg.jointype & (JT_LEFT|JT_RIGHT) ){
+ testcase( pItem->fg.jointype & JT_LEFT ); /* testtag-20230227a */
+ testcase( pItem->fg.jointype & JT_RIGHT ); /* testtag-20230227b */
joinType = EP_OuterON;
}else{
+ testcase( pItem->fg.jointype & JT_LTORJ ); /* testtag-20230227c */
joinType = EP_InnerON;
}
sqlcipher_sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType);
@@ -159456,7 +167434,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WhereIsDistinct(WhereInfo *pWInfo){
** block sorting is required.
*/
SQLITE_PRIVATE int sqlcipher_sqlite3WhereIsOrdered(WhereInfo *pWInfo){
- return pWInfo->nOBSat;
+ return pWInfo->nOBSat<0 ? 0 : pWInfo->nOBSat;
}
/*
@@ -159692,6 +167670,42 @@ static Expr *whereRightSubexprIsColumn(Expr *p){
}
/*
+** Term pTerm is guaranteed to be a WO_IN term. It may be a component term
+** of a vector IN expression of the form "(x, y, ...) IN (SELECT ...)".
+** This function checks to see if the term is compatible with an index
+** column with affinity idxaff (one of the SQLITE_AFF_XYZ values). If so,
+** it returns a pointer to the name of the collation sequence (e.g. "BINARY"
+** or "NOCASE") used by the comparison in pTerm. If it is not compatible
+** with affinity idxaff, NULL is returned.
+*/
+static SQLITE_NOINLINE const char *indexInAffinityOk(
+ Parse *pParse,
+ WhereTerm *pTerm,
+ u8 idxaff
+){
+ Expr *pX = pTerm->pExpr;
+ Expr inexpr;
+
+ assert( pTerm->eOperator & WO_IN );
+
+ if( sqlcipher_sqlite3ExprIsVector(pX->pLeft) ){
+ int iField = pTerm->u.x.iField - 1;
+ inexpr.flags = 0;
+ inexpr.op = TK_EQ;
+ inexpr.pLeft = pX->pLeft->x.pList->a[iField].pExpr;
+ assert( ExprUseXSelect(pX) );
+ inexpr.pRight = pX->x.pSelect->pEList->a[iField].pExpr;
+ pX = &inexpr;
+ }
+
+ if( sqlcipher_sqlite3IndexAffinityOk(pX, idxaff) ){
+ CollSeq *pRet = sqlcipher_sqlite3ExprCompareCollSeq(pParse, pX);
+ return pRet ? pRet->zName : sqlcipher_sqlite3StrBINARY;
+ }
+ return 0;
+}
+
+/*
** Advance to the next WhereTerm that matches according to the criteria
** established when the pScan object was initialized by whereScanInit().
** Return NULL if there are no more matching WhereTerms.
@@ -159741,16 +167755,24 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
if( (pTerm->eOperator & pScan->opMask)!=0 ){
/* Verify the affinity and collating sequence match */
if( pScan->zCollName && (pTerm->eOperator & WO_ISNULL)==0 ){
- CollSeq *pColl;
+ const char *zCollName;
Parse *pParse = pWC->pWInfo->pParse;
pX = pTerm->pExpr;
- if( !sqlcipher_sqlite3IndexAffinityOk(pX, pScan->idxaff) ){
- continue;
+
+ if( (pTerm->eOperator & WO_IN) ){
+ zCollName = indexInAffinityOk(pParse, pTerm, pScan->idxaff);
+ if( !zCollName ) continue;
+ }else{
+ CollSeq *pColl;
+ if( !sqlcipher_sqlite3IndexAffinityOk(pX, pScan->idxaff) ){
+ continue;
+ }
+ assert(pX->pLeft);
+ pColl = sqlcipher_sqlite3ExprCompareCollSeq(pParse, pX);
+ zCollName = pColl ? pColl->zName : sqlcipher_sqlite3StrBINARY;
}
- assert(pX->pLeft);
- pColl = sqlcipher_sqlite3ExprCompareCollSeq(pParse, pX);
- if( pColl==0 ) pColl = pParse->db->pDfltColl;
- if( sqlcipher_sqlite3StrICmp(pColl->zName, pScan->zCollName) ){
+
+ if( sqlcipher_sqlite3StrICmp(zCollName, pScan->zCollName) ){
continue;
}
}
@@ -160067,12 +168089,22 @@ static void translateColumnToCopy(
for(; iStart<iEnd; iStart++, pOp++){
if( pOp->p1!=iTabCur ) continue;
if( pOp->opcode==OP_Column ){
+#ifdef SQLITE_DEBUG
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
+ printf("TRANSLATE OP_Column to OP_Copy at %d\n", iStart);
+ }
+#endif
pOp->opcode = OP_Copy;
pOp->p1 = pOp->p2 + iRegister;
pOp->p2 = pOp->p3;
pOp->p3 = 0;
pOp->p5 = 2; /* Cause the MEM_Subtype flag to be cleared */
}else if( pOp->opcode==OP_Rowid ){
+#ifdef SQLITE_DEBUG
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
+ printf("TRANSLATE OP_Rowid to OP_Sequence at %d\n", iStart);
+ }
+#endif
pOp->opcode = OP_Sequence;
pOp->p1 = iAutoidxCur;
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
@@ -160092,9 +168124,13 @@ static void translateColumnToCopy(
** are no-ops.
*/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED)
-static void whereTraceIndexInfoInputs(sqlcipher_sqlite3_index_info *p){
+static void whereTraceIndexInfoInputs(
+ sqlcipher_sqlite3_index_info *p, /* The IndexInfo object */
+ Table *pTab /* The TABLE that is the virtual table */
+){
int i;
- if( !sqlcipher_sqlite3WhereTrace ) return;
+ if( (sqlcipher_sqlite3WhereTrace & 0x10)==0 ) return;
+ sqlcipher_sqlite3DebugPrintf("sqlcipher_sqlite3_index_info inputs for %s:\n", pTab->zName);
for(i=0; i<p->nConstraint; i++){
sqlcipher_sqlite3DebugPrintf(
" constraint[%d]: col=%d termid=%d op=%d usabled=%d collseq=%s\n",
@@ -160112,9 +168148,13 @@ static void whereTraceIndexInfoInputs(sqlcipher_sqlite3_index_info *p){
p->aOrderBy[i].desc);
}
}
-static void whereTraceIndexInfoOutputs(sqlcipher_sqlite3_index_info *p){
+static void whereTraceIndexInfoOutputs(
+ sqlcipher_sqlite3_index_info *p, /* The IndexInfo object */
+ Table *pTab /* The TABLE that is the virtual table */
+){
int i;
- if( !sqlcipher_sqlite3WhereTrace ) return;
+ if( (sqlcipher_sqlite3WhereTrace & 0x10)==0 ) return;
+ sqlcipher_sqlite3DebugPrintf("sqlcipher_sqlite3_index_info outputs for %s:\n", pTab->zName);
for(i=0; i<p->nConstraint; i++){
sqlcipher_sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n",
i,
@@ -160128,10 +168168,47 @@ static void whereTraceIndexInfoOutputs(sqlcipher_sqlite3_index_info *p){
sqlcipher_sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows);
}
#else
-#define whereTraceIndexInfoInputs(A)
-#define whereTraceIndexInfoOutputs(A)
+#define whereTraceIndexInfoInputs(A,B)
+#define whereTraceIndexInfoOutputs(A,B)
#endif
+/*
+** We know that pSrc is an operand of an outer join. Return true if
+** pTerm is a constraint that is compatible with that join.
+**
+** pTerm must be EP_OuterON if pSrc is the right operand of an
+** outer join. pTerm can be either EP_OuterON or EP_InnerON if pSrc
+** is the left operand of a RIGHT join.
+**
+** See https://sqlite.org/forum/forumpost/206d99a16dd9212f
+** for an example of a WHERE clause constraints that may not be used on
+** the right table of a RIGHT JOIN because the constraint implies a
+** not-NULL condition on the left table of the RIGHT JOIN.
+*/
+static int constraintCompatibleWithOuterJoin(
+ const WhereTerm *pTerm, /* WHERE clause term to check */
+ const SrcItem *pSrc /* Table we are trying to access */
+){
+ assert( (pSrc->fg.jointype&(JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ); /* By caller */
+ testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
+ testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
+ testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) )
+ testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
+ if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
+ || pTerm->pExpr->w.iJoin != pSrc->iCursor
+ ){
+ return 0;
+ }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_RIGHT))!=0
+ && ExprHasProperty(pTerm->pExpr, EP_InnerON)
+ ){
+ return 0;
+ }
+ return 1;
+}
+
+
+
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/*
** Return TRUE if the WHERE clause term pTerm is of a form where it
@@ -160147,16 +168224,10 @@ static int termCanDriveIndex(
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
assert( (pSrc->fg.jointype & JT_RIGHT)==0 );
- if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ){
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
- testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) )
- testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
- if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
- || pTerm->pExpr->w.iJoin != pSrc->iCursor
- ){
- return 0; /* See tag-20191211-001 */
- }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
+ ){
+ return 0; /* See https://sqlite.org/forum/forumpost/51e6959f61 */
}
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
@@ -160170,6 +168241,57 @@ static int termCanDriveIndex(
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+/*
+** Argument pIdx represents an automatic index that the current statement
+** will create and populate. Add an OP_Explain with text of the form:
+**
+** CREATE AUTOMATIC INDEX ON <table>(<cols>) [WHERE <expr>]
+**
+** This is only required if sqlcipher_sqlite3_stmt_scanstatus() is enabled, to
+** associate an SQLITE_SCANSTAT_NCYCLE and SQLITE_SCANSTAT_NLOOP
+** values with. In order to avoid breaking legacy code and test cases,
+** the OP_Explain is not added if this is an EXPLAIN QUERY PLAN command.
+*/
+static void explainAutomaticIndex(
+ Parse *pParse,
+ Index *pIdx, /* Automatic index to explain */
+ int bPartial, /* True if pIdx is a partial index */
+ int *pAddrExplain /* OUT: Address of OP_Explain */
+){
+ if( IS_STMT_SCANSTATUS(pParse->db) && pParse->explain!=2 ){
+ Table *pTab = pIdx->pTable;
+ const char *zSep = "";
+ char *zText = 0;
+ int ii = 0;
+ sqlcipher_sqlite3_str *pStr = sqlcipher_sqlite3_str_new(pParse->db);
+ sqlcipher_sqlite3_str_appendf(pStr,"CREATE AUTOMATIC INDEX ON %s(", pTab->zName);
+ assert( pIdx->nColumn>1 );
+ assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID );
+ for(ii=0; ii<(pIdx->nColumn-1); ii++){
+ const char *zName = 0;
+ int iCol = pIdx->aiColumn[ii];
+
+ zName = pTab->aCol[iCol].zCnName;
+ sqlcipher_sqlite3_str_appendf(pStr, "%s%s", zSep, zName);
+ zSep = ", ";
+ }
+ zText = sqlcipher_sqlite3_str_finish(pStr);
+ if( zText==0 ){
+ sqlcipher_sqlite3OomFault(pParse->db);
+ }else{
+ *pAddrExplain = sqlcipher_sqlite3VdbeExplain(
+ pParse, 0, "%s)%s", zText, (bPartial ? " WHERE <expr>" : "")
+ );
+ sqlcipher_sqlite3_free(zText);
+ }
+ }
+}
+#else
+# define explainAutomaticIndex(a,b,c,d)
+#endif
+
/*
** Generate code to construct the Index object for an automatic index
** and to set up the WhereLevel object pLevel so that the code generator
@@ -160177,8 +168299,7 @@ static int termCanDriveIndex(
*/
static SQLITE_NOINLINE void constructAutomaticIndex(
Parse *pParse, /* The parsing context */
- const WhereClause *pWC, /* The WHERE clause */
- const SrcItem *pSrc, /* The FROM clause term to get the next index */
+ WhereClause *pWC, /* The WHERE clause */
const Bitmask notReady, /* Mask of cursors that are not available */
WhereLevel *pLevel /* Write new index here */
){
@@ -160199,12 +168320,17 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
char *zNotUsed; /* Extra space on the end of pIdx */
Bitmask idxCols; /* Bitmap of columns used for indexing */
Bitmask extraCols; /* Bitmap of additional columns */
- u8 sentWarning = 0; /* True if a warnning has been issued */
+ u8 sentWarning = 0; /* True if a warning has been issued */
+ u8 useBloomFilter = 0; /* True to also add a Bloom filter */
Expr *pPartial = 0; /* Partial Index Expression */
int iContinue = 0; /* Jump here to skip excluded rows */
- SrcItem *pTabItem; /* FROM clause term being indexed */
+ SrcList *pTabList; /* The complete FROM clause */
+ SrcItem *pSrc; /* The FROM clause term to get the next index */
int addrCounter = 0; /* Address where integer counter is initialized */
int regBase; /* Array of registers where record is assembled */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExp = 0; /* Address of OP_Explain */
+#endif
/* Generate code to skip over the creation and initialization of the
** transient index on 2nd and subsequent iterations of the loop. */
@@ -160215,6 +168341,8 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
/* Count the number of columns that will be added to the index
** and used to match WHERE clause constraints */
nKeyCol = 0;
+ pTabList = pWC->pWInfo->pTabList;
+ pSrc = &pTabList->a[pLevel->iFrom];
pTable = pSrc->pTab;
pWCEnd = &pWC->a[pWC->nTerm];
pLoop = pLevel->pWLoop;
@@ -160225,7 +168353,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** WHERE clause (or the ON clause of a LEFT join) that constrain which
** rows of the target table (pSrc) that can be used. */
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && sqlcipher_sqlite3ExprIsTableConstraint(pExpr, pSrc)
+ && sqlcipher_sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom, 0)
){
pPartial = sqlcipher_sqlite3ExprAnd(pParse, pPartial,
sqlcipher_sqlite3ExprDup(pParse->db, pExpr, 0));
@@ -160266,7 +168394,11 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** original table changes and the index and table cannot both be used
** if they go out of sync.
*/
- extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
+ if( IsView(pTable) ){
+ extraCols = ALLBITS & ~idxCols;
+ }else{
+ extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
+ }
mxBitCol = MIN(BMS-1,pTable->nCol);
testcase( pTable->nCol==BMS-1 );
testcase( pTable->nCol==BMS-2 );
@@ -160302,6 +168434,16 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */
pIdx->azColl[n] = pColl ? pColl->zName : sqlcipher_sqlite3StrBINARY;
n++;
+ if( ALWAYS(pX->pLeft!=0)
+ && sqlcipher_sqlite3ExprAffinity(pX->pLeft)!=SQLITE_AFF_TEXT
+ ){
+ /* TUNING: only use a Bloom filter on an automatic index
+ ** if one or more key columns has the ability to hold numeric
+ ** values, since strings all have the same hash in the Bloom
+ ** filter implementation and hence a Bloom filter on a text column
+ ** is not usually helpful. */
+ useBloomFilter = 1;
+ }
}
}
}
@@ -160328,25 +168470,27 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
pIdx->azColl[n] = sqlcipher_sqlite3StrBINARY;
/* Create the automatic index */
+ explainAutomaticIndex(pParse, pIdx, pPartial!=0, &addrExp);
assert( pLevel->iIdxCur>=0 );
pLevel->iIdxCur = pParse->nTab++;
sqlcipher_sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1);
sqlcipher_sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "for %s", pTable->zName));
- if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){
+ if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) && useBloomFilter ){
+ sqlcipher_sqlite3WhereExplainBloomFilter(pParse, pWC->pWInfo, pLevel);
pLevel->regFilter = ++pParse->nMem;
sqlcipher_sqlite3VdbeAddOp2(v, OP_Blob, 10000, pLevel->regFilter);
}
/* Fill the automatic index with content */
- pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
- if( pTabItem->fg.viaCoroutine ){
- int regYield = pTabItem->regReturn;
+ assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] );
+ if( pSrc->fg.viaCoroutine ){
+ int regYield = pSrc->regReturn;
addrCounter = sqlcipher_sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
- sqlcipher_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub);
addrTop = sqlcipher_sqlite3VdbeAddOp1(v, OP_Yield, regYield);
VdbeCoverage(v);
- VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
+ VdbeComment((v, "next row of %s", pSrc->pTab->zName));
}else{
addrTop = sqlcipher_sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
}
@@ -160363,17 +168507,18 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
sqlcipher_sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0,
regBase, pLoop->u.btree.nEq);
}
+ sqlcipher_sqlite3VdbeScanStatusCounters(v, addrExp, addrExp, sqlcipher_sqlite3VdbeCurrentAddr(v));
sqlcipher_sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlcipher_sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlcipher_sqlite3VdbeResolveLabel(v, iContinue);
- if( pTabItem->fg.viaCoroutine ){
+ if( pSrc->fg.viaCoroutine ){
sqlcipher_sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
testcase( pParse->db->mallocFailed );
assert( pLevel->iIdxCur>0 );
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
- pTabItem->regResult, pLevel->iIdxCur);
+ pSrc->regResult, pLevel->iIdxCur);
sqlcipher_sqlite3VdbeGoto(v, addrTop);
- pTabItem->fg.viaCoroutine = 0;
+ pSrc->fg.viaCoroutine = 0;
}else{
sqlcipher_sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
sqlcipher_sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
@@ -160383,6 +168528,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
/* Jump here when skipping the initialization */
sqlcipher_sqlite3VdbeJumpHere(v, addrInit);
+ sqlcipher_sqlite3VdbeScanStatusRange(v, addrExp, addrExp, -1);
end_auto_index_create:
sqlcipher_sqlite3ExprDelete(pParse->db, pPartial);
@@ -160424,16 +168570,26 @@ static SQLITE_NOINLINE void sqlcipher_sqlite3ConstructBloomFilter(
Vdbe *v = pParse->pVdbe; /* VDBE under construction */
WhereLoop *pLoop = pLevel->pWLoop; /* The loop being coded */
int iCur; /* Cursor for table getting the filter */
+ IndexedExpr *saved_pIdxEpr; /* saved copy of Parse.pIdxEpr */
+ IndexedExpr *saved_pIdxPartExpr; /* saved copy of Parse.pIdxPartExpr */
+
+ saved_pIdxEpr = pParse->pIdxEpr;
+ saved_pIdxPartExpr = pParse->pIdxPartExpr;
+ pParse->pIdxEpr = 0;
+ pParse->pIdxPartExpr = 0;
assert( pLoop!=0 );
assert( v!=0 );
assert( pLoop->wsFlags & WHERE_BLOOMFILTER );
+ assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 );
addrOnce = sqlcipher_sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
do{
+ const SrcList *pTabList;
const SrcItem *pItem;
const Table *pTab;
u64 sz;
+ int iSrc;
sqlcipher_sqlite3WhereExplainBloomFilter(pParse, pWInfo, pLevel);
addrCont = sqlcipher_sqlite3VdbeMakeLabel(pParse);
iCur = pLevel->iTabCur;
@@ -160447,7 +168603,9 @@ static SQLITE_NOINLINE void sqlcipher_sqlite3ConstructBloomFilter(
** testing complicated. By basing the blob size on the value in the
** sqlite_stat1 table, testing is much easier.
*/
- pItem = &pWInfo->pTabList->a[pLevel->iFrom];
+ pTabList = pWInfo->pTabList;
+ iSrc = pLevel->iFrom;
+ pItem = &pTabList->a[iSrc];
assert( pItem!=0 );
pTab = pItem->pTab;
assert( pTab!=0 );
@@ -160464,7 +168622,7 @@ static SQLITE_NOINLINE void sqlcipher_sqlite3ConstructBloomFilter(
for(pTerm=pWInfo->sWC.a; pTerm<pWCEnd; pTerm++){
Expr *pExpr = pTerm->pExpr;
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && sqlcipher_sqlite3ExprIsTableConstraint(pExpr, pItem)
+ && sqlcipher_sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc, 0)
){
sqlcipher_sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
}
@@ -160480,9 +168638,8 @@ static SQLITE_NOINLINE void sqlcipher_sqlite3ConstructBloomFilter(
int r1 = sqlcipher_sqlite3GetTempRange(pParse, n);
int jj;
for(jj=0; jj<n; jj++){
- int iCol = pIdx->aiColumn[jj];
assert( pIdx->pTable==pItem->pTab );
- sqlcipher_sqlite3ExprCodeGetColumnOfTable(v, pIdx->pTable, iCur, iCol,r1+jj);
+ sqlcipher_sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
}
sqlcipher_sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
sqlcipher_sqlite3ReleaseTempRange(pParse, r1, n);
@@ -160513,6 +168670,8 @@ static SQLITE_NOINLINE void sqlcipher_sqlite3ConstructBloomFilter(
}
}while( iLevel < pWInfo->nLevel );
sqlcipher_sqlite3VdbeJumpHere(v, addrOnce);
+ pParse->pIdxEpr = saved_pIdxEpr;
+ pParse->pIdxPartExpr = saved_pIdxPartExpr;
}
@@ -160568,22 +168727,10 @@ static sqlcipher_sqlite3_index_info *allocateIndexInfo(
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
assert( pTerm->u.x.leftColumn>=XN_ROWID );
assert( pTerm->u.x.leftColumn<pTab->nCol );
-
- /* tag-20191211-002: WHERE-clause constraints are not useful to the
- ** right-hand table of a LEFT JOIN nor to the either table of a
- ** RIGHT JOIN. See tag-20191211-001 for the
- ** equivalent restriction for ordinary tables. */
- if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ){
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_RIGHT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
- testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) );
- testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
- if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
- || pTerm->pExpr->w.iJoin != pSrc->iCursor
- ){
- continue;
- }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
+ ){
+ continue;
}
nTerm++;
pTerm->wtFlags |= TERM_OK;
@@ -160601,7 +168748,7 @@ static sqlcipher_sqlite3_index_info *allocateIndexInfo(
Expr *pE2;
/* Skip over constant terms in the ORDER BY clause */
- if( sqlcipher_sqlite3ExprIsConstant(pExpr) ){
+ if( sqlcipher_sqlite3ExprIsConstant(0, pExpr) ){
continue;
}
@@ -160636,7 +168783,7 @@ static sqlcipher_sqlite3_index_info *allocateIndexInfo(
}
if( i==n ){
nOrderBy = n;
- if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) ){
+ if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) && !pSrc->fg.rowidUsed ){
eDistinct = 2 + ((pWInfo->wctrlFlags & WHERE_SORTBYGROUP)!=0);
}else if( pWInfo->wctrlFlags & WHERE_GROUPBY ){
eDistinct = 1;
@@ -160713,7 +168860,7 @@ static sqlcipher_sqlite3_index_info *allocateIndexInfo(
pIdxInfo->nConstraint = j;
for(i=j=0; i<nOrderBy; i++){
Expr *pExpr = pOrderBy->a[i].pExpr;
- if( sqlcipher_sqlite3ExprIsConstant(pExpr) ) continue;
+ if( sqlcipher_sqlite3ExprIsConstant(0, pExpr) ) continue;
assert( pExpr->op==TK_COLUMN
|| (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN
&& pExpr->iColumn==pExpr->pLeft->iColumn) );
@@ -160765,11 +168912,11 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlcipher_sqlite3_index_inf
sqlcipher_sqlite3_vtab *pVtab = sqlcipher_sqlite3GetVTable(pParse->db, pTab)->pVtab;
int rc;
- whereTraceIndexInfoInputs(p);
+ whereTraceIndexInfoInputs(p, pTab);
pParse->db->nSchemaLock++;
rc = pVtab->pModule->xBestIndex(pVtab, p);
pParse->db->nSchemaLock--;
- whereTraceIndexInfoOutputs(p);
+ whereTraceIndexInfoOutputs(p, pTab);
if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){
if( rc==SQLITE_NOMEM ){
@@ -160780,6 +168927,9 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlcipher_sqlite3_index_inf
sqlcipher_sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg);
}
}
+ if( pTab->u.vtab.p->bAllSchemas ){
+ sqlcipher_sqlite3VtabUsesAllSchemas(pParse);
+ }
sqlcipher_sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = 0;
return rc;
@@ -160824,6 +168974,7 @@ static int whereKeyStats(
assert( pIdx->nSample>0 );
assert( pRec->nField>0 );
+
/* Do a binary search to find the first sample greater than or equal
** to pRec. If pRec contains a single field, the set of samples to search
** is simply the aSample[] array. If the samples in aSample[] contain more
@@ -160868,7 +169019,12 @@ static int whereKeyStats(
** it is extended to two fields. The duplicates that this creates do not
** cause any problems.
*/
- nField = MIN(pRec->nField, pIdx->nSample);
+ if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
+ nField = pIdx->nKeyCol;
+ }else{
+ nField = pIdx->nColumn;
+ }
+ nField = MIN(pRec->nField, nField);
iCol = 0;
iSample = pIdx->nSample * nField;
do{
@@ -160934,12 +169090,12 @@ static int whereKeyStats(
if( iCol>0 ){
pRec->nField = iCol;
assert( sqlcipher_sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0
- || pParse->db->mallocFailed );
+ || pParse->db->mallocFailed || CORRUPT_DB );
}
if( i>0 ){
pRec->nField = nField;
assert( sqlcipher_sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0
- || pParse->db->mallocFailed );
+ || pParse->db->mallocFailed || CORRUPT_DB );
}
}
}
@@ -160956,7 +169112,7 @@ static int whereKeyStats(
** is larger than all samples in the array. */
tRowcnt iUpper, iGap;
if( i>=pIdx->nSample ){
- iUpper = sqlcipher_sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
+ iUpper = pIdx->nRowEst0;
}else{
iUpper = aSample[i].anLt[iCol];
}
@@ -161031,7 +169187,7 @@ SQLITE_PRIVATE char sqlcipher_sqlite3IndexColumnAffinity(sqlcipher_sqlite3 *db,
** Value pLoop->nOut is currently set to the estimated number of rows
** visited for scanning (a=? AND b=?). This function reduces that estimate
** by some factor to account for the (c BETWEEN ? AND ?) expression based
-** on the stat4 data for the index. this scan will be peformed multiple
+** on the stat4 data for the index. this scan will be performed multiple
** times (once for each (a,b) combination that matches a=?) is dealt with
** by the caller.
**
@@ -161112,7 +169268,7 @@ static int whereRangeSkipScanEst(
int nAdjust = (sqlcipher_sqlite3LogEst(p->nSample) - sqlcipher_sqlite3LogEst(nDiff));
pLoop->nOut -= nAdjust;
*pbDone = 1;
- WHERETRACE(0x10, ("range skip-scan regions: %u..%u adjust=%d est=%d\n",
+ WHERETRACE(0x20, ("range skip-scan regions: %u..%u adjust=%d est=%d\n",
nLower, nUpper, nAdjust*-1, pLoop->nOut));
}
@@ -161283,14 +169439,15 @@ static int whereRangeScanEst(
** sample, then assume they are 4x more selective. This brings
** the estimated selectivity more in line with what it would be
** if estimated without the use of STAT4 tables. */
- if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlcipher_sqlite3LogEst(4) );
+ if( iLwrIdx==iUprIdx ){ nNew -= 20; }
+ assert( 20==sqlcipher_sqlite3LogEst(4) );
}else{
nNew = 10; assert( 10==sqlcipher_sqlite3LogEst(2) );
}
if( nNew<nOut ){
nOut = nNew;
}
- WHERETRACE(0x10, ("STAT4 range scan: %u..%u est=%d\n",
+ WHERETRACE(0x20, ("STAT4 range scan: %u..%u est=%d\n",
(u32)iLower, (u32)iUpper, nOut));
}
}else{
@@ -161304,7 +169461,7 @@ static int whereRangeScanEst(
UNUSED_PARAMETER(pBuilder);
assert( pLower || pUpper );
#endif
- assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 );
+ assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 || pParse->nErr>0 );
nNew = whereRangeAdjust(pLower, nOut);
nNew = whereRangeAdjust(pUpper, nNew);
@@ -161323,7 +169480,7 @@ static int whereRangeScanEst(
if( nNew<nOut ) nOut = nNew;
#if defined(WHERETRACE_ENABLED)
if( pLoop->nOut>nOut ){
- WHERETRACE(0x10,("Range scan lowers nOut from %d to %d\n",
+ WHERETRACE(0x20,("Range scan lowers nOut from %d to %d\n",
pLoop->nOut, nOut));
}
#endif
@@ -161388,7 +169545,7 @@ static int whereEqualScanEst(
pBuilder->nRecValid = nEq;
whereKeyStats(pParse, p, pRec, 0, a);
- WHERETRACE(0x10,("equality scan regions %s(%d): %d\n",
+ WHERETRACE(0x20,("equality scan regions %s(%d): %d\n",
p->zName, nEq-1, (int)a[1]));
*pnRow = a[1];
@@ -161436,9 +169593,9 @@ static int whereInScanEst(
}
if( rc==SQLITE_OK ){
- if( nRowEst > nRow0 ) nRowEst = nRow0;
+ if( nRowEst > (tRowcnt)nRow0 ) nRowEst = nRow0;
*pnRow = nRowEst;
- WHERETRACE(0x10,("IN row estimate: est=%d\n", nRowEst));
+ WHERETRACE(0x20,("IN row estimate: est=%d\n", nRowEst));
}
assert( pBuilder->nRecValid==nRecValid );
return rc;
@@ -161507,17 +169664,34 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereClausePrint(WhereClause *pWC){
#ifdef WHERETRACE_ENABLED
/*
** Print a WhereLoop object for debugging purposes
-*/
-SQLITE_PRIVATE void sqlcipher_sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
- WhereInfo *pWInfo = pWC->pWInfo;
- int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
- SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
- Table *pTab = pItem->pTab;
- Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
- sqlcipher_sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
- p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
- sqlcipher_sqlite3DebugPrintf(" %12s",
- pItem->zAlias ? pItem->zAlias : pTab->zName);
+**
+** Format example:
+**
+** .--- Position in WHERE clause rSetup, rRun, nOut ---.
+** | |
+** | .--- selfMask nTerm ------. |
+** | | | |
+** | | .-- prereq Idx wsFlags----. | |
+** | | | Name | | |
+** | | | __|__ nEq ---. ___|__ | __|__
+** | / \ / \ / \ | / \ / \ / \
+** 1.002.001 t2.t2xy 2 f 010241 N 2 cost 0,56,31
+*/
+SQLITE_PRIVATE void sqlcipher_sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
+ if( pWC ){
+ WhereInfo *pWInfo = pWC->pWInfo;
+ int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
+ SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
+ Table *pTab = pItem->pTab;
+ Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
+ sqlcipher_sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
+ p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
+ sqlcipher_sqlite3DebugPrintf(" %12s",
+ pItem->zAlias ? pItem->zAlias : pTab->zName);
+ }else{
+ sqlcipher_sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d",
+ p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab);
+ }
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
const char *zName;
if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
@@ -161547,13 +169721,22 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *p
sqlcipher_sqlite3DebugPrintf(" f %06x N %d", p->wsFlags, p->nLTerm);
}
sqlcipher_sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
- if( p->nLTerm && (sqlcipher_sqlite3WhereTrace & 0x100)!=0 ){
+ if( p->nLTerm && (sqlcipher_sqlite3WhereTrace & 0x4000)!=0 ){
int i;
for(i=0; i<p->nLTerm; i++){
sqlcipher_sqlite3WhereTermPrint(p->aLTerm[i], i);
}
}
}
+SQLITE_PRIVATE void sqlcipher_sqlite3ShowWhereLoop(const WhereLoop *p){
+ if( p ) sqlcipher_sqlite3WhereLoopPrint(p, 0);
+}
+SQLITE_PRIVATE void sqlcipher_sqlite3ShowWhereLoopList(const WhereLoop *p){
+ while( p ){
+ sqlcipher_sqlite3ShowWhereLoop(p);
+ p = p->pNextLoop;
+ }
+}
#endif
/*
@@ -161585,12 +169768,18 @@ static void whereLoopClearUnion(sqlcipher_sqlite3 *db, WhereLoop *p){
}
/*
-** Deallocate internal memory used by a WhereLoop object
+** Deallocate internal memory used by a WhereLoop object. Leave the
+** object in an initialized state, as if it had been newly allocated.
*/
static void whereLoopClear(sqlcipher_sqlite3 *db, WhereLoop *p){
- if( p->aLTerm!=p->aLTermSpace ) sqlcipher_sqlite3DbFreeNN(db, p->aLTerm);
+ if( p->aLTerm!=p->aLTermSpace ){
+ sqlcipher_sqlite3DbFreeNN(db, p->aLTerm);
+ p->aLTerm = p->aLTermSpace;
+ p->nLSlot = ArraySize(p->aLTermSpace);
+ }
whereLoopClearUnion(db, p);
- whereLoopInit(p);
+ p->nLTerm = 0;
+ p->wsFlags = 0;
}
/*
@@ -161614,7 +169803,9 @@ static int whereLoopResize(sqlcipher_sqlite3 *db, WhereLoop *p, int n){
*/
static int whereLoopXfer(sqlcipher_sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
whereLoopClearUnion(db, pTo);
- if( whereLoopResize(db, pTo, pFrom->nLTerm) ){
+ if( pFrom->nLTerm > pTo->nLSlot
+ && whereLoopResize(db, pTo, pFrom->nLTerm)
+ ){
memset(pTo, 0, WHERE_LOOP_XFER_SZ);
return SQLITE_NOMEM_BKPT;
}
@@ -161632,8 +169823,9 @@ static int whereLoopXfer(sqlcipher_sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom
** Delete a WhereLoop object
*/
static void whereLoopDelete(sqlcipher_sqlite3 *db, WhereLoop *p){
+ assert( db!=0 );
whereLoopClear(db, p);
- sqlcipher_sqlite3DbFreeNN(db, p);
+ sqlcipher_sqlite3DbNNFreeNN(db, p);
}
/*
@@ -161641,73 +169833,76 @@ static void whereLoopDelete(sqlcipher_sqlite3 *db, WhereLoop *p){
*/
static void whereInfoFree(sqlcipher_sqlite3 *db, WhereInfo *pWInfo){
assert( pWInfo!=0 );
+ assert( db!=0 );
sqlcipher_sqlite3WhereClauseClear(&pWInfo->sWC);
while( pWInfo->pLoops ){
WhereLoop *p = pWInfo->pLoops;
pWInfo->pLoops = p->pNextLoop;
whereLoopDelete(db, p);
}
- assert( pWInfo->pExprMods==0 );
while( pWInfo->pMemToFree ){
WhereMemBlock *pNext = pWInfo->pMemToFree->pNext;
- sqlcipher_sqlite3DbFreeNN(db, pWInfo->pMemToFree);
+ sqlcipher_sqlite3DbNNFreeNN(db, pWInfo->pMemToFree);
pWInfo->pMemToFree = pNext;
}
- sqlcipher_sqlite3DbFreeNN(db, pWInfo);
-}
-
-/* Undo all Expr node modifications
-*/
-static void whereUndoExprMods(WhereInfo *pWInfo){
- while( pWInfo->pExprMods ){
- WhereExprMod *p = pWInfo->pExprMods;
- pWInfo->pExprMods = p->pNext;
- memcpy(p->pExpr, &p->orig, sizeof(p->orig));
- sqlcipher_sqlite3DbFree(pWInfo->pParse->db, p);
- }
+ sqlcipher_sqlite3DbNNFreeNN(db, pWInfo);
}
/*
-** Return TRUE if all of the following are true:
+** Return TRUE if X is a proper subset of Y but is of equal or less cost.
+** In other words, return true if all constraints of X are also part of Y
+** and Y has additional constraints that might speed the search that X lacks
+** but the cost of running X is not more than the cost of running Y.
+**
+** In other words, return true if the cost relationwship between X and Y
+** is inverted and needs to be adjusted.
+**
+** Case 1:
**
-** (1) X has the same or lower cost, or returns the same or fewer rows,
-** than Y.
-** (2) X uses fewer WHERE clause terms than Y
-** (3) Every WHERE clause term used by X is also used by Y
-** (4) X skips at least as many columns as Y
-** (5) If X is a covering index, than Y is too
+** (1a) X and Y use the same index.
+** (1b) X has fewer == terms than Y
+** (1c) Neither X nor Y use skip-scan
+** (1d) X does not have a a greater cost than Y
**
-** Conditions (2) and (3) mean that X is a "proper subset" of Y.
-** If X is a proper subset of Y then Y is a better choice and ought
-** to have a lower cost. This routine returns TRUE when that cost
-** relationship is inverted and needs to be adjusted. Constraint (4)
-** was added because if X uses skip-scan less than Y it still might
-** deserve a lower cost even if it is a proper subset of Y. Constraint (5)
-** was added because a covering index probably deserves to have a lower cost
-** than a non-covering index even if it is a proper subset.
+** Case 2:
+**
+** (2a) X has the same or lower cost, or returns the same or fewer rows,
+** than Y.
+** (2b) X uses fewer WHERE clause terms than Y
+** (2c) Every WHERE clause term used by X is also used by Y
+** (2d) X skips at least as many columns as Y
+** (2e) If X is a covering index, than Y is too
*/
static int whereLoopCheaperProperSubset(
const WhereLoop *pX, /* First WhereLoop to compare */
const WhereLoop *pY /* Compare against this WhereLoop */
){
int i, j;
+ if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; /* (1d) and (2a) */
+ assert( (pX->wsFlags & WHERE_VIRTUALTABLE)==0 );
+ assert( (pY->wsFlags & WHERE_VIRTUALTABLE)==0 );
+ if( pX->u.btree.nEq < pY->u.btree.nEq /* (1b) */
+ && pX->u.btree.pIndex==pY->u.btree.pIndex /* (1a) */
+ && pX->nSkip==0 && pY->nSkip==0 /* (1c) */
+ ){
+ return 1; /* Case 1 is true */
+ }
if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
- return 0; /* X is not a subset of Y */
+ return 0; /* (2b) */
}
- if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0;
- if( pY->nSkip > pX->nSkip ) return 0;
+ if( pY->nSkip > pX->nSkip ) return 0; /* (2d) */
for(i=pX->nLTerm-1; i>=0; i--){
if( pX->aLTerm[i]==0 ) continue;
for(j=pY->nLTerm-1; j>=0; j--){
if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
}
- if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */
+ if( j<0 ) return 0; /* (2c) */
}
if( (pX->wsFlags&WHERE_IDX_ONLY)!=0
&& (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
- return 0; /* Constraint (5) */
+ return 0; /* (2e) */
}
- return 1; /* All conditions meet */
+ return 1; /* Case 2 is true */
}
/*
@@ -161788,7 +169983,7 @@ static WhereLoop **whereLoopFindLesser(
** rSetup. Call this SETUP-INVARIANT */
assert( p->rSetup>=pTemplate->rSetup );
- /* Any loop using an appliation-defined index (or PRIMARY KEY or
+ /* Any loop using an application-defined index (or PRIMARY KEY or
** UNIQUE constraint) with one or more == constraints is better
** than an automatic index. Unless it is a skip-scan. */
if( (p->wsFlags & WHERE_AUTO_INDEX)!=0
@@ -161815,7 +170010,7 @@ static WhereLoop **whereLoopFindLesser(
/* If pTemplate is always better than p, then cause p to be overwritten
** with pTemplate. pTemplate is better than p if:
- ** (1) pTemplate has no more dependences than p, and
+ ** (1) pTemplate has no more dependencies than p, and
** (2) pTemplate has an equal or lower cost than p.
*/
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */
@@ -161933,7 +170128,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
}else{
/* We will be overwriting WhereLoop p[]. But before we do, first
** go through the rest of the list and delete any other entries besides
- ** p[] that are also supplated by pTemplate */
+ ** p[] that are also supplanted by pTemplate */
WhereLoop **ppTail = &p->pNextLoop;
WhereLoop *pToDel;
while( *ppTail ){
@@ -162013,6 +170208,7 @@ static void whereLoopOutputAdjust(
if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break;
}
if( j<0 ){
+ sqlcipher_sqlite3ProgressCheck(pWC->pWInfo->pParse);
if( pLoop->maskSelf==pTerm->prereqAll ){
/* If there are extra terms in the WHERE clause not used by an index
** that depend only on the table being scanned, and that will tend to
@@ -162132,7 +170328,7 @@ static int whereRangeVectorLen(
}
/*
-** Adjust the cost C by the costMult facter T. This only occurs if
+** Adjust the cost C by the costMult factor T. This only occurs if
** compiled with -DSQLITE_ENABLE_COSTMULT
*/
#ifdef SQLITE_ENABLE_COSTMULT
@@ -162159,7 +170355,7 @@ static int whereLoopAddBtreeIndex(
Index *pProbe, /* An index on pSrc */
LogEst nInMul /* log(Number of iterations due to IN) */
){
- WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */
+ WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyze context */
Parse *pParse = pWInfo->pParse; /* Parsing context */
sqlcipher_sqlite3 *db = pParse->db; /* Database connection malloc context */
WhereLoop *pNew; /* Template WhereLoop under construction */
@@ -162180,7 +170376,10 @@ static int whereLoopAddBtreeIndex(
WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
pNew = pBuilder->pNew;
- if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
+ assert( db->mallocFailed==0 || pParse->nErr>0 );
+ if( pParse->nErr ){
+ return pParse->rc;
+ }
WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d, rRun=%d\n",
pProbe->pTable->zName,pProbe->zName,
pNew->u.btree.nEq, pNew->nSkip, pNew->rRun));
@@ -162193,7 +170392,12 @@ static int whereLoopAddBtreeIndex(
assert( pNew->u.btree.nBtm==0 );
opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
}
- if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
+ if( pProbe->bUnordered || pProbe->bLowQual ){
+ if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
+ if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){
+ opMask &= ~(WO_EQ|WO_IN|WO_IS);
+ }
+ }
assert( pNew->u.btree.nEq<pProbe->nColumn );
assert( pNew->u.btree.nEq<pProbe->nKeyCol
@@ -162231,32 +170435,11 @@ static int whereLoopAddBtreeIndex(
** to mix with a lower range bound from some other source */
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
- /* tag-20191211-001: Do not allow constraints from the WHERE clause to
- ** be used by the right table of a LEFT JOIN nor by the left table of a
- ** RIGHT JOIN. Only constraints in the ON clause are allowed.
- ** See tag-20191211-002 for the vtab equivalent.
- **
- ** 2022-06-06: See https://sqlite.org/forum/forumpost/206d99a16dd9212f
- ** for an example of a WHERE clause constraints that may not be used on
- ** the right table of a RIGHT JOIN because the constraint implies a
- ** not-NULL condition on the left table of the RIGHT JOIN.
- **
- ** 2022-06-10: The same condition applies to termCanDriveIndex() above.
- ** https://sqlite.org/forum/forumpost/51e6959f61
- */
- if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ){
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_RIGHT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
- testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) )
- testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
- if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
- || pTerm->pExpr->w.iJoin != pSrc->iCursor
- ){
- continue;
- }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
+ ){
+ continue;
}
-
if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE;
}else{
@@ -162267,7 +170450,11 @@ static int whereLoopAddBtreeIndex(
pNew->u.btree.nBtm = saved_nBtm;
pNew->u.btree.nTop = saved_nTop;
pNew->nLTerm = saved_nLTerm;
- if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
+ if( pNew->nLTerm>=pNew->nLSlot
+ && whereLoopResize(db, pNew, pNew->nLTerm+1)
+ ){
+ break; /* OOM while trying to enlarge the pNew->aLTerm array */
+ }
pNew->aLTerm[pNew->nLTerm++] = pTerm;
pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf;
@@ -162360,38 +170547,39 @@ static int whereLoopAddBtreeIndex(
if( scan.iEquiv>1 ) pNew->wsFlags |= WHERE_TRANSCONS;
}else if( eOp & WO_ISNULL ){
pNew->wsFlags |= WHERE_COLUMN_NULL;
- }else if( eOp & (WO_GT|WO_GE) ){
- testcase( eOp & WO_GT );
- testcase( eOp & WO_GE );
- pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
- pNew->u.btree.nBtm = whereRangeVectorLen(
- pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
- );
- pBtm = pTerm;
- pTop = 0;
- if( pTerm->wtFlags & TERM_LIKEOPT ){
- /* Range constraints that come from the LIKE optimization are
- ** always used in pairs. */
- pTop = &pTerm[1];
- assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
- assert( pTop->wtFlags & TERM_LIKEOPT );
- assert( pTop->eOperator==WO_LT );
- if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
- pNew->aLTerm[pNew->nLTerm++] = pTop;
- pNew->wsFlags |= WHERE_TOP_LIMIT;
- pNew->u.btree.nTop = 1;
- }
- }else{
- assert( eOp & (WO_LT|WO_LE) );
- testcase( eOp & WO_LT );
- testcase( eOp & WO_LE );
- pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
- pNew->u.btree.nTop = whereRangeVectorLen(
+ }else{
+ int nVecLen = whereRangeVectorLen(
pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
);
- pTop = pTerm;
- pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
- pNew->aLTerm[pNew->nLTerm-2] : 0;
+ if( eOp & (WO_GT|WO_GE) ){
+ testcase( eOp & WO_GT );
+ testcase( eOp & WO_GE );
+ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
+ pNew->u.btree.nBtm = nVecLen;
+ pBtm = pTerm;
+ pTop = 0;
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
+ /* Range constraints that come from the LIKE optimization are
+ ** always used in pairs. */
+ pTop = &pTerm[1];
+ assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
+ assert( pTop->wtFlags & TERM_LIKEOPT );
+ assert( pTop->eOperator==WO_LT );
+ if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
+ pNew->aLTerm[pNew->nLTerm++] = pTop;
+ pNew->wsFlags |= WHERE_TOP_LIMIT;
+ pNew->u.btree.nTop = 1;
+ }
+ }else{
+ assert( eOp & (WO_LT|WO_LE) );
+ testcase( eOp & WO_LT );
+ testcase( eOp & WO_LE );
+ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
+ pNew->u.btree.nTop = nVecLen;
+ pTop = pTerm;
+ pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
+ pNew->aLTerm[pNew->nLTerm-2] : 0;
+ }
}
/* At this point pNew->nOut is set to the number of rows expected to
@@ -162443,7 +170631,7 @@ static int whereLoopAddBtreeIndex(
&& pNew->nOut+10 > pProbe->aiRowLogEst[0]
){
#if WHERETRACE_ENABLED /* 0x01 */
- if( sqlcipher_sqlite3WhereTrace & 0x01 ){
+ if( sqlcipher_sqlite3WhereTrace & 0x20 ){
sqlcipher_sqlite3DebugPrintf(
"STAT4 determines term has low selectivity:\n");
sqlcipher_sqlite3WhereTermPrint(pTerm, 999);
@@ -162475,14 +170663,33 @@ static int whereLoopAddBtreeIndex(
}
}
- /* Set rCostIdx to the cost of visiting selected rows in index. Add
- ** it to pNew->rRun, which is currently set to the cost of the index
- ** seek only. Then, if this is a non-covering index, add the cost of
- ** visiting the rows in the main table. */
+ /* Set rCostIdx to the estimated cost of visiting selected rows in the
+ ** index. The estimate is the sum of two values:
+ ** 1. The cost of doing one search-by-key to find the first matching
+ ** entry
+ ** 2. Stepping forward in the index pNew->nOut times to find all
+ ** additional matching entries.
+ */
assert( pSrc->pTab->szTabRow>0 );
- rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
- pNew->rRun = sqlcipher_sqlite3LogEstAdd(rLogSize, rCostIdx);
- if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
+ if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
+ /* The pProbe->szIdxRow is low for an IPK table since the interior
+ ** pages are small. Thus szIdxRow gives a good estimate of seek cost.
+ ** But the leaf pages are full-size, so pProbe->szIdxRow would badly
+ ** under-estimate the scanning cost. */
+ rCostIdx = pNew->nOut + 16;
+ }else{
+ rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
+ }
+ rCostIdx = sqlcipher_sqlite3LogEstAdd(rLogSize, rCostIdx);
+
+ /* Estimate the cost of running the loop. If all data is coming
+ ** from the index, then this is just the cost of doing the index
+ ** lookup and scan. But if some data is coming out of the main table,
+ ** we also have to add in the cost of doing pNew->nOut searches to
+ ** locate the row in the main table that corresponds to the index entry.
+ */
+ pNew->rRun = rCostIdx;
+ if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK|WHERE_EXPRIDX))==0 ){
pNew->rRun = sqlcipher_sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16);
}
ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult);
@@ -162504,6 +170711,9 @@ static int whereLoopAddBtreeIndex(
&& (pNew->u.btree.nEq<pProbe->nKeyCol ||
pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY)
){
+ if( pNew->u.btree.nEq>3 ){
+ sqlcipher_sqlite3ProgressCheck(pParse);
+ }
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn);
}
pNew->nOut = saved_nOut;
@@ -162584,7 +170794,9 @@ static int indexMightHelpWithOrderBy(
for(ii=0; ii<pOB->nExpr; ii++){
Expr *pExpr = sqlcipher_sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr);
if( NEVER(pExpr==0) ) continue;
- if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){
+ if( (pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN)
+ && pExpr->iTable==iCursor
+ ){
if( pExpr->iColumn<0 ) return 1;
for(jj=0; jj<pIndex->nKeyCol; jj++){
if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1;
@@ -162636,6 +170848,243 @@ static int whereUsablePartialIndex(
}
/*
+** pIdx is an index containing expressions. Check it see if any of the
+** expressions in the index match the pExpr expression.
+*/
+static int exprIsCoveredByIndex(
+ const Expr *pExpr,
+ const Index *pIdx,
+ int iTabCur
+){
+ int i;
+ for(i=0; i<pIdx->nColumn; i++){
+ if( pIdx->aiColumn[i]==XN_EXPR
+ && sqlcipher_sqlite3ExprCompare(0, pExpr, pIdx->aColExpr->a[i].pExpr, iTabCur)==0
+ ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+** Structure passed to the whereIsCoveringIndex Walker callback.
+*/
+typedef struct CoveringIndexCheck CoveringIndexCheck;
+struct CoveringIndexCheck {
+ Index *pIdx; /* The index */
+ int iTabCur; /* Cursor number for the corresponding table */
+ u8 bExpr; /* Uses an indexed expression */
+ u8 bUnidx; /* Uses an unindexed column not within an indexed expr */
+};
+
+/*
+** Information passed in is pWalk->u.pCovIdxCk. Call it pCk.
+**
+** If the Expr node references the table with cursor pCk->iTabCur, then
+** make sure that column is covered by the index pCk->pIdx. We know that
+** all columns less than 63 (really BMS-1) are covered, so we don't need
+** to check them. But we do need to check any column at 63 or greater.
+**
+** If the index does not cover the column, then set pWalk->eCode to
+** non-zero and return WRC_Abort to stop the search.
+**
+** If this node does not disprove that the index can be a covering index,
+** then just return WRC_Continue, to continue the search.
+**
+** If pCk->pIdx contains indexed expressions and one of those expressions
+** matches pExpr, then prune the search.
+*/
+static int whereIsCoveringIndexWalkCallback(Walker *pWalk, Expr *pExpr){
+ int i; /* Loop counter */
+ const Index *pIdx; /* The index of interest */
+ const i16 *aiColumn; /* Columns contained in the index */
+ u16 nColumn; /* Number of columns in the index */
+ CoveringIndexCheck *pCk; /* Info about this search */
+
+ pCk = pWalk->u.pCovIdxCk;
+ pIdx = pCk->pIdx;
+ if( (pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN) ){
+ /* if( pExpr->iColumn<(BMS-1) && pIdx->bHasExpr==0 ) return WRC_Continue;*/
+ if( pExpr->iTable!=pCk->iTabCur ) return WRC_Continue;
+ pIdx = pWalk->u.pCovIdxCk->pIdx;
+ aiColumn = pIdx->aiColumn;
+ nColumn = pIdx->nColumn;
+ for(i=0; i<nColumn; i++){
+ if( aiColumn[i]==pExpr->iColumn ) return WRC_Continue;
+ }
+ pCk->bUnidx = 1;
+ return WRC_Abort;
+ }else if( pIdx->bHasExpr
+ && exprIsCoveredByIndex(pExpr, pIdx, pWalk->u.pCovIdxCk->iTabCur) ){
+ pCk->bExpr = 1;
+ return WRC_Prune;
+ }
+ return WRC_Continue;
+}
+
+
+/*
+** pIdx is an index that covers all of the low-number columns used by
+** pWInfo->pSelect (columns from 0 through 62) or an index that has
+** expressions terms. Hence, we cannot determine whether or not it is
+** a covering index by using the colUsed bitmasks. We have to do a search
+** to see if the index is covering. This routine does that search.
+**
+** The return value is one of these:
+**
+** 0 The index is definitely not a covering index
+**
+** WHERE_IDX_ONLY The index is definitely a covering index
+**
+** WHERE_EXPRIDX The index is likely a covering index, but it is
+** difficult to determine precisely because of the
+** expressions that are indexed. Score it as a
+** covering index, but still keep the main table open
+** just in case we need it.
+**
+** This routine is an optimization. It is always safe to return zero.
+** But returning one of the other two values when zero should have been
+** returned can lead to incorrect bytecode and assertion faults.
+*/
+static SQLITE_NOINLINE u32 whereIsCoveringIndex(
+ WhereInfo *pWInfo, /* The WHERE clause context */
+ Index *pIdx, /* Index that is being tested */
+ int iTabCur /* Cursor for the table being indexed */
+){
+ int i, rc;
+ struct CoveringIndexCheck ck;
+ Walker w;
+ if( pWInfo->pSelect==0 ){
+ /* We don't have access to the full query, so we cannot check to see
+ ** if pIdx is covering. Assume it is not. */
+ return 0;
+ }
+ if( pIdx->bHasExpr==0 ){
+ for(i=0; i<pIdx->nColumn; i++){
+ if( pIdx->aiColumn[i]>=BMS-1 ) break;
+ }
+ if( i>=pIdx->nColumn ){
+ /* pIdx does not index any columns greater than 62, but we know from
+ ** colMask that columns greater than 62 are used, so this is not a
+ ** covering index */
+ return 0;
+ }
+ }
+ ck.pIdx = pIdx;
+ ck.iTabCur = iTabCur;
+ ck.bExpr = 0;
+ ck.bUnidx = 0;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = whereIsCoveringIndexWalkCallback;
+ w.xSelectCallback = sqlcipher_sqlite3SelectWalkNoop;
+ w.u.pCovIdxCk = &ck;
+ sqlcipher_sqlite3WalkSelect(&w, pWInfo->pSelect);
+ if( ck.bUnidx ){
+ rc = 0;
+ }else if( ck.bExpr ){
+ rc = WHERE_EXPRIDX;
+ }else{
+ rc = WHERE_IDX_ONLY;
+ }
+ return rc;
+}
+
+/*
+** This is an sqlcipher_sqlite3ParserAddCleanup() callback that is invoked to
+** free the Parse->pIdxEpr list when the Parse object is destroyed.
+*/
+static void whereIndexedExprCleanup(sqlcipher_sqlite3 *db, void *pObject){
+ IndexedExpr **pp = (IndexedExpr**)pObject;
+ while( *pp!=0 ){
+ IndexedExpr *p = *pp;
+ *pp = p->pIENext;
+ sqlcipher_sqlite3ExprDelete(db, p->pExpr);
+ sqlcipher_sqlite3DbFreeNN(db, p);
+ }
+}
+
+/*
+** This function is called for a partial index - one with a WHERE clause - in
+** two scenarios. In both cases, it determines whether or not the WHERE
+** clause on the index implies that a column of the table may be safely
+** replaced by a constant expression. For example, in the following
+** SELECT:
+**
+** CREATE INDEX i1 ON t1(b, c) WHERE a=<expr>;
+** SELECT a, b, c FROM t1 WHERE a=<expr> AND b=?;
+**
+** The "a" in the select-list may be replaced by <expr>, iff:
+**
+** (a) <expr> is a constant expression, and
+** (b) The (a=<expr>) comparison uses the BINARY collation sequence, and
+** (c) Column "a" has an affinity other than NONE or BLOB.
+**
+** If argument pItem is NULL, then pMask must not be NULL. In this case this
+** function is being called as part of determining whether or not pIdx
+** is a covering index. This function clears any bits in (*pMask)
+** corresponding to columns that may be replaced by constants as described
+** above.
+**
+** Otherwise, if pItem is not NULL, then this function is being called
+** as part of coding a loop that uses index pIdx. In this case, add entries
+** to the Parse.pIdxPartExpr list for each column that can be replaced
+** by a constant.
+*/
+static void wherePartIdxExpr(
+ Parse *pParse, /* Parse context */
+ Index *pIdx, /* Partial index being processed */
+ Expr *pPart, /* WHERE clause being processed */
+ Bitmask *pMask, /* Mask to clear bits in */
+ int iIdxCur, /* Cursor number for index */
+ SrcItem *pItem /* The FROM clause entry for the table */
+){
+ assert( pItem==0 || (pItem->fg.jointype & JT_RIGHT)==0 );
+ assert( (pItem==0 || pMask==0) && (pMask!=0 || pItem!=0) );
+
+ if( pPart->op==TK_AND ){
+ wherePartIdxExpr(pParse, pIdx, pPart->pRight, pMask, iIdxCur, pItem);
+ pPart = pPart->pLeft;
+ }
+
+ if( (pPart->op==TK_EQ || pPart->op==TK_IS) ){
+ Expr *pLeft = pPart->pLeft;
+ Expr *pRight = pPart->pRight;
+ u8 aff;
+
+ if( pLeft->op!=TK_COLUMN ) return;
+ if( !sqlcipher_sqlite3ExprIsConstant(0, pRight) ) return;
+ if( !sqlcipher_sqlite3IsBinary(sqlcipher_sqlite3ExprCompareCollSeq(pParse, pPart)) ) return;
+ if( pLeft->iColumn<0 ) return;
+ aff = pIdx->pTable->aCol[pLeft->iColumn].affinity;
+ if( aff>=SQLITE_AFF_TEXT ){
+ if( pItem ){
+ sqlcipher_sqlite3 *db = pParse->db;
+ IndexedExpr *p = (IndexedExpr*)sqlcipher_sqlite3DbMallocRaw(db, sizeof(*p));
+ if( p ){
+ int bNullRow = (pItem->fg.jointype&(JT_LEFT|JT_LTORJ))!=0;
+ p->pExpr = sqlcipher_sqlite3ExprDup(db, pRight, 0);
+ p->iDataCur = pItem->iCursor;
+ p->iIdxCur = iIdxCur;
+ p->iIdxCol = pLeft->iColumn;
+ p->bMaybeNullRow = bNullRow;
+ p->pIENext = pParse->pIdxPartExpr;
+ p->aff = aff;
+ pParse->pIdxPartExpr = p;
+ if( p->pIENext==0 ){
+ void *pArg = (void*)&pParse->pIdxPartExpr;
+ sqlcipher_sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg);
+ }
+ }
+ }else if( pLeft->iColumn<(BMS-1) ){
+ *pMask &= ~((Bitmask)1 << pLeft->iColumn);
+ }
+ }
+ }
+}
+
+
+/*
** Add all WhereLoop objects for a single table of the join where the table
** is identified by pBuilder->pNew->iTab. That table is guaranteed to be
** a b-tree table, not a virtual table.
@@ -162673,7 +171122,7 @@ static int whereUsablePartialIndex(
*/
static int whereLoopAddBtree(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
- Bitmask mPrereq /* Extra prerequesites for using this table */
+ Bitmask mPrereq /* Extra prerequisites for using this table */
){
WhereInfo *pWInfo; /* WHERE analysis context */
Index *pProbe; /* An index we are evaluating */
@@ -162717,7 +171166,7 @@ static int whereLoopAddBtree(
sPk.aiRowLogEst = aiRowEstPk;
sPk.onError = OE_Replace;
sPk.pTable = pTab;
- sPk.szIdxRow = pTab->szTabRow;
+ sPk.szIdxRow = 3; /* TUNING: Interior rows of IPK table are very small */
sPk.idxType = SQLITE_IDXTYPE_IPK;
aiRowEstPk[0] = pTab->nRowLogEst;
aiRowEstPk[1] = 0;
@@ -162768,7 +171217,8 @@ static int whereLoopAddBtree(
if( !IsView(pTab) && (pTab->tabFlags & TF_Ephemeral)==0 ){
pNew->rSetup += 28;
}else{
- pNew->rSetup -= 10;
+ pNew->rSetup -= 25; /* Greatly reduced setup cost for auto indexes
+ ** on ephemeral materializations of views */
}
ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
if( pNew->rSetup<0 ) pNew->rSetup = 0;
@@ -162845,11 +171295,45 @@ static int whereLoopAddBtree(
}else{
Bitmask m;
if( pProbe->isCovering ){
- pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
m = 0;
+ pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
}else{
m = pSrc->colUsed & pProbe->colNotIdxed;
- pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED;
+ if( pProbe->pPartIdxWhere ){
+ wherePartIdxExpr(
+ pWInfo->pParse, pProbe, pProbe->pPartIdxWhere, &m, 0, 0
+ );
+ }
+ pNew->wsFlags = WHERE_INDEXED;
+ if( m==TOPBIT || (pProbe->bHasExpr && !pProbe->bHasVCol && m!=0) ){
+ u32 isCov = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor);
+ if( isCov==0 ){
+ WHERETRACE(0x200,
+ ("-> %s is not a covering index"
+ " according to whereIsCoveringIndex()\n", pProbe->zName));
+ assert( m!=0 );
+ }else{
+ m = 0;
+ pNew->wsFlags |= isCov;
+ if( isCov & WHERE_IDX_ONLY ){
+ WHERETRACE(0x200,
+ ("-> %s is a covering expression index"
+ " according to whereIsCoveringIndex()\n", pProbe->zName));
+ }else{
+ assert( isCov==WHERE_EXPRIDX );
+ WHERETRACE(0x200,
+ ("-> %s might be a covering expression index"
+ " according to whereIsCoveringIndex()\n", pProbe->zName));
+ }
+ }
+ }else if( m==0
+ && (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlcipher_sqlite3FaultSim(700))
+ ){
+ WHERETRACE(0x200,
+ ("-> %s a covering index according to bitmasks\n",
+ pProbe->zName, m==0 ? "is" : "is not"));
+ pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
+ }
}
/* Full scan via index */
@@ -162920,7 +171404,7 @@ static int whereLoopAddBtree(
** unique index is used (making the index functionally non-unique)
** then the sqlite_stat1 data becomes important for scoring the
** plan */
- pTab->tabFlags |= TF_StatsUsed;
+ pTab->tabFlags |= TF_MaybeReanalyze;
}
#ifdef SQLITE_ENABLE_STAT4
sqlcipher_sqlite3Stat4ProbeFree(pBuilder->pRec);
@@ -162943,6 +171427,21 @@ static int isLimitTerm(WhereTerm *pTerm){
}
/*
+** Return true if the first nCons constraints in the pUsage array are
+** marked as in-use (have argvIndex>0). False otherwise.
+*/
+static int allConstraintsUsed(
+ struct sqlcipher_sqlite3_index_constraint_usage *aUsage,
+ int nCons
+){
+ int ii;
+ for(ii=0; ii<nCons; ii++){
+ if( aUsage[ii].argvIndex<=0 ) return 0;
+ }
+ return 1;
+}
+
+/*
** Argument pIdxInfo is already populated with all constraints that may
** be used by the virtual table identified by pBuilder->pNew->iTab. This
** function marks a subset of those constraints usable, invokes the
@@ -163022,7 +171521,7 @@ static int whereLoopAddVirtualOne(
** that the particular combination of parameters provided is unusable.
** Make no entries in the loop table.
*/
- WHERETRACE(0xffff, (" ^^^^--- non-viable plan rejected!\n"));
+ WHERETRACE(0xffffffff, (" ^^^^--- non-viable plan rejected!\n"));
return SQLITE_OK;
}
return rc;
@@ -163082,13 +171581,20 @@ static int whereLoopAddVirtualOne(
*pbIn = 1; assert( (mExclude & WO_IN)==0 );
}
+ /* Unless pbRetryLimit is non-NULL, there should be no LIMIT/OFFSET
+ ** terms. And if there are any, they should follow all other terms. */
assert( pbRetryLimit || !isLimitTerm(pTerm) );
- if( isLimitTerm(pTerm) && *pbIn ){
+ assert( !isLimitTerm(pTerm) || i>=nConstraint-2 );
+ assert( !isLimitTerm(pTerm) || i==nConstraint-1 || isLimitTerm(pTerm+1) );
+
+ if( isLimitTerm(pTerm) && (*pbIn || !allConstraintsUsed(pUsage, i)) ){
/* If there is an IN(...) term handled as an == (separate call to
** xFilter for each value on the RHS of the IN) and a LIMIT or
- ** OFFSET term handled as well, the plan is unusable. Set output
- ** variable *pbRetryLimit to true to tell the caller to retry with
- ** LIMIT and OFFSET disabled. */
+ ** OFFSET term handled as well, the plan is unusable. Similarly,
+ ** if there is a LIMIT/OFFSET and there are other unused terms,
+ ** the plan cannot be used. In these cases set variable *pbRetryLimit
+ ** to true to tell the caller to retry with LIMIT and OFFSET
+ ** disabled. */
if( pIdxInfo->needToFreeIdxStr ){
sqlcipher_sqlite3_free(pIdxInfo->idxStr);
pIdxInfo->idxStr = 0;
@@ -163133,7 +171639,7 @@ static int whereLoopAddVirtualOne(
sqlcipher_sqlite3_free(pNew->u.vtab.idxStr);
pNew->u.vtab.needFree = 0;
}
- WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
+ WHERETRACE(0xffffffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
*pbIn, (sqlcipher_sqlite3_uint64)mPrereq,
(sqlcipher_sqlite3_uint64)(pNew->prereq & ~mPrereq)));
@@ -163149,7 +171655,7 @@ static int whereLoopAddVirtualOne(
**
** Return a pointer to the collation name:
**
-** 1. If there is an explicit COLLATE operator on the constaint, return it.
+** 1. If there is an explicit COLLATE operator on the constraint, return it.
**
** 2. Else, if the column has an alternative collation, return that.
**
@@ -163204,7 +171710,7 @@ SQLITE_API int sqlcipher_sqlite3_vtab_rhs_value(
sqlcipher_sqlite3_value *pVal = 0;
int rc = SQLITE_OK;
if( iCons<0 || iCons>=pIdxInfo->nConstraint ){
- rc = SQLITE_MISUSE; /* EV: R-30545-25046 */
+ rc = SQLITE_MISUSE_BKPT; /* EV: R-30545-25046 */
}else{
if( pH->aRhs[iCons]==0 ){
WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset];
@@ -163234,32 +171740,27 @@ SQLITE_API int sqlcipher_sqlite3_vtab_distinct(sqlcipher_sqlite3_index_info *pId
return pHidden->eDistinct;
}
-#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
- && !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** Cause the prepared statement that is associated with a call to
-** xBestIndex to potentiall use all schemas. If the statement being
+** xBestIndex to potentially use all schemas. If the statement being
** prepared is read-only, then just start read transactions on all
** schemas. But if this is a write operation, start writes on all
** schemas.
**
** This is used by the (built-in) sqlite_dbpage virtual table.
*/
-SQLITE_PRIVATE void sqlcipher_sqlite3VtabUsesAllSchemas(sqlcipher_sqlite3_index_info *pIdxInfo){
- HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
- Parse *pParse = pHidden->pParse;
+SQLITE_PRIVATE void sqlcipher_sqlite3VtabUsesAllSchemas(Parse *pParse){
int nDb = pParse->db->nDb;
int i;
for(i=0; i<nDb; i++){
sqlcipher_sqlite3CodeVerifySchema(pParse, i);
}
- if( pParse->writeMask ){
+ if( DbMaskNonZero(pParse->writeMask) ){
for(i=0; i<nDb; i++){
sqlcipher_sqlite3BeginWriteOperation(pParse, 0, i);
}
}
}
-#endif
/*
** Add all WhereLoop objects for a table of the join identified by
@@ -163325,7 +171826,7 @@ static int whereLoopAddVirtual(
/* First call xBestIndex() with all constraints usable. */
WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName));
- WHERETRACE(0x40, (" VirtualOne: all usable\n"));
+ WHERETRACE(0x800, (" VirtualOne: all usable\n"));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
);
@@ -163350,7 +171851,7 @@ static int whereLoopAddVirtual(
/* If the plan produced by the earlier call uses an IN(...) term, call
** xBestIndex again, this time with IN(...) terms disabled. */
if( bIn ){
- WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n"));
+ WHERETRACE(0x800, (" VirtualOne: all usable w/o IN\n"));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn, 0);
assert( bIn==0 );
@@ -163376,7 +171877,7 @@ static int whereLoopAddVirtual(
mPrev = mNext;
if( mNext==ALLBITS ) break;
if( mNext==mBest || mNext==mBestNoIn ) continue;
- WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
+ WHERETRACE(0x800, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
(sqlcipher_sqlite3_uint64)mPrev, (sqlcipher_sqlite3_uint64)mNext));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn, 0);
@@ -163390,7 +171891,7 @@ static int whereLoopAddVirtual(
** that requires no source tables at all (i.e. one guaranteed to be
** usable), make a call here with all source tables disabled */
if( rc==SQLITE_OK && seenZero==0 ){
- WHERETRACE(0x40, (" VirtualOne: all disabled\n"));
+ WHERETRACE(0x800, (" VirtualOne: all disabled\n"));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn, 0);
if( bIn==0 ) seenZeroNoIN = 1;
@@ -163400,7 +171901,7 @@ static int whereLoopAddVirtual(
** that requires no source tables at all and does not use an IN(...)
** operator, make a final call to obtain one here. */
if( rc==SQLITE_OK && seenZeroNoIN==0 ){
- WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n"));
+ WHERETRACE(0x800, (" VirtualOne: all disabled and w/o IN\n"));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0);
}
@@ -163456,7 +171957,7 @@ static int whereLoopAddOr(
sSubBuild = *pBuilder;
sSubBuild.pOrSet = &sCur;
- WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm));
+ WHERETRACE(0x400, ("Begin processing OR-clause %p\n", pTerm));
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
if( (pOrTerm->eOperator & WO_AND)!=0 ){
sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc;
@@ -163473,9 +171974,9 @@ static int whereLoopAddOr(
}
sCur.n = 0;
#ifdef WHERETRACE_ENABLED
- WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n",
+ WHERETRACE(0x400, ("OR-term %d of %p has %d subterms:\n",
(int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm));
- if( sqlcipher_sqlite3WhereTrace & 0x400 ){
+ if( sqlcipher_sqlite3WhereTrace & 0x20000 ){
sqlcipher_sqlite3WhereClausePrint(sSubBuild.pWC);
}
#endif
@@ -163490,8 +171991,6 @@ static int whereLoopAddOr(
if( rc==SQLITE_OK ){
rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable);
}
- assert( rc==SQLITE_OK || rc==SQLITE_DONE || sCur.n==0
- || rc==SQLITE_NOMEM );
testcase( rc==SQLITE_NOMEM && sCur.n>0 );
testcase( rc==SQLITE_DONE );
if( sCur.n==0 ){
@@ -163537,7 +172036,7 @@ static int whereLoopAddOr(
pNew->prereq = sSum.a[i].prereq;
rc = whereLoopInsert(pBuilder, pNew);
}
- WHERETRACE(0x200, ("End processing OR-clause %p\n", pTerm));
+ WHERETRACE(0x400, ("End processing OR-clause %p\n", pTerm));
}
}
return rc;
@@ -163563,7 +172062,13 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
/* Loop over the tables in the join, from left to right */
pNew = pBuilder->pNew;
- whereLoopInit(pNew);
+
+ /* Verify that pNew has already been initialized */
+ assert( pNew->nLTerm==0 );
+ assert( pNew->wsFlags==0 );
+ assert( pNew->nLSlot>=ArraySize(pNew->aLTermSpace) );
+ assert( pNew->aLTerm!=0 );
+
pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT;
for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){
Bitmask mUnusable = 0;
@@ -163879,8 +172384,8 @@ static i8 wherePathSatisfiesOrderBy(
if( pOBExpr->iTable!=iCur ) continue;
if( pOBExpr->iColumn!=iColumn ) continue;
}else{
- Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr;
- if( sqlcipher_sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){
+ Expr *pIxExpr = pIndex->aColExpr->a[j].pExpr;
+ if( sqlcipher_sqlite3ExprCompareSkip(pOBExpr, pIxExpr, iCur) ){
continue;
}
}
@@ -163946,7 +172451,7 @@ static i8 wherePathSatisfiesOrderBy(
if( MASKBIT(i) & obSat ) continue;
p = pOrderBy->a[i].pExpr;
mTerm = sqlcipher_sqlite3WhereExprUsage(&pWInfo->sMaskSet,p);
- if( mTerm==0 && !sqlcipher_sqlite3ExprIsConstant(p) ) continue;
+ if( mTerm==0 && !sqlcipher_sqlite3ExprIsConstant(0,p) ) continue;
if( (mTerm&~orderDistinctMask)==0 ){
obSat |= MASKBIT(i);
}
@@ -164012,37 +172517,56 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){
** order.
*/
static LogEst whereSortingCost(
- WhereInfo *pWInfo,
- LogEst nRow,
- int nOrderBy,
- int nSorted
+ WhereInfo *pWInfo, /* Query planning context */
+ LogEst nRow, /* Estimated number of rows to sort */
+ int nOrderBy, /* Number of ORDER BY clause terms */
+ int nSorted /* Number of initial ORDER BY terms naturally in order */
){
- /* TUNING: Estimated cost of a full external sort, where N is
+ /* Estimated cost of a full external sort, where N is
** the number of rows to sort is:
**
- ** cost = (3.0 * N * log(N)).
+ ** cost = (K * N * log(N)).
**
** Or, if the order-by clause has X terms but only the last Y
** terms are out of order, then block-sorting will reduce the
** sorting cost to:
**
- ** cost = (3.0 * N * log(N)) * (Y/X)
+ ** cost = (K * N * log(N)) * (Y/X)
+ **
+ ** The constant K is at least 2.0 but will be larger if there are a
+ ** large number of columns to be sorted, as the sorting time is
+ ** proportional to the amount of content to be sorted. The algorithm
+ ** does not currently distinguish between fat columns (BLOBs and TEXTs)
+ ** and skinny columns (INTs). It just uses the number of columns as
+ ** an approximation for the row width.
**
- ** The (Y/X) term is implemented using stack variable rScale
- ** below.
+ ** And extra factor of 2.0 or 3.0 is added to the sorting cost if the sort
+ ** is built using OP_IdxInsert and OP_Sort rather than with OP_SorterInsert.
*/
- LogEst rScale, rSortCost;
- assert( nOrderBy>0 && 66==sqlcipher_sqlite3LogEst(100) );
- rScale = sqlcipher_sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
- rSortCost = nRow + rScale + 16;
+ LogEst rSortCost, nCol;
+ assert( pWInfo->pSelect!=0 );
+ assert( pWInfo->pSelect->pEList!=0 );
+ /* TUNING: sorting cost proportional to the number of output columns: */
+ nCol = sqlcipher_sqlite3LogEst((pWInfo->pSelect->pEList->nExpr+59)/30);
+ rSortCost = nRow + nCol;
+ if( nSorted>0 ){
+ /* Scale the result by (Y/X) */
+ rSortCost += sqlcipher_sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
+ }
/* Multiple by log(M) where M is the number of output rows.
** Use the LIMIT for M if it is smaller. Or if this sort is for
** a DISTINCT operator, M will be the number of distinct output
** rows, so fudge it downwards a bit.
*/
- if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){
- nRow = pWInfo->iLimit;
+ if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 ){
+ rSortCost += 10; /* TUNING: Extra 2.0x if using LIMIT */
+ if( nSorted!=0 ){
+ rSortCost += 6; /* TUNING: Extra 1.5x if also using partial sort */
+ }
+ if( pWInfo->iLimit<nRow ){
+ nRow = pWInfo->iLimit;
+ }
}else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){
/* TUNING: In the sort for a DISTINCT operator, assume that the DISTINCT
** reduces the number of output rows by a factor of 2 */
@@ -164068,7 +172592,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int mxChoice; /* Maximum number of simultaneous paths tracked */
int nLoop; /* Number of terms in the join */
Parse *pParse; /* Parsing context */
- sqlcipher_sqlite3 *db; /* The database connection */
int iLoop; /* Loop counter over the terms of the join */
int ii, jj; /* Loop counters */
int mxI = 0; /* Index of next entry to replace */
@@ -164087,14 +172610,14 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int nSpace; /* Bytes of space allocated at pSpace */
pParse = pWInfo->pParse;
- db = pParse->db;
nLoop = pWInfo->nLevel;
/* TUNING: For simple queries, only the best path is tracked.
** For 2-way joins, the 5 best paths are followed.
** For joins of 3 or more tables, track the 10 best paths */
mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10);
assert( nLoop<=pWInfo->pTabList->nSrc );
- WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst));
+ WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d, nQueryLoop=%d)\n",
+ nRowEst, pParse->nQueryLoop));
/* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this
** case the purpose of this call is to estimate the number of rows returned
@@ -164110,7 +172633,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* Allocate and initialize space for aTo, aFrom and aSortCost[] */
nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2;
nSpace += sizeof(LogEst) * nOrderBy;
- pSpace = sqlcipher_sqlite3DbMallocRawNN(db, nSpace);
+ pSpace = sqlcipher_sqlite3StackAllocRawNN(pParse->db, nSpace);
if( pSpace==0 ) return SQLITE_NOMEM_BKPT;
aTo = (WherePath*)pSpace;
aFrom = aTo+mxChoice;
@@ -164160,9 +172683,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
LogEst nOut; /* Rows visited by (pFrom+pWLoop) */
LogEst rCost; /* Cost of path (pFrom+pWLoop) */
LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */
- i8 isOrdered = pFrom->isOrdered; /* isOrdered for (pFrom+pWLoop) */
+ i8 isOrdered; /* isOrdered for (pFrom+pWLoop) */
Bitmask maskNew; /* Mask of src visited by (..) */
- Bitmask revMask = 0; /* Mask of rev-order loops for (..) */
+ Bitmask revMask; /* Mask of rev-order loops for (..) */
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
@@ -164181,7 +172704,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
rUnsorted = sqlcipher_sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
+ isOrdered = pFrom->isOrdered;
if( isOrdered<0 ){
+ revMask = 0;
isOrdered = wherePathSatisfiesOrderBy(pWInfo,
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
iLoop, pWLoop, &revMask);
@@ -164194,11 +172719,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pWInfo, nRowEst, nOrderBy, isOrdered
);
}
- /* TUNING: Add a small extra penalty (5) to sorting as an
- ** extra encouragment to the query planner to select a plan
+ /* TUNING: Add a small extra penalty (3) to sorting as an
+ ** extra encouragement to the query planner to select a plan
** where the rows emerge in the correct order without any sorting
** required. */
- rCost = sqlcipher_sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 5;
+ rCost = sqlcipher_sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 3;
WHERETRACE(0x002,
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
@@ -164359,7 +172884,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( nFrom==0 ){
sqlcipher_sqlite3ErrorMsg(pParse, "no query solution");
- sqlcipher_sqlite3DbFreeNN(db, pSpace);
+ sqlcipher_sqlite3StackFreeNN(pParse->db, pSpace);
return SQLITE_ERROR;
}
@@ -164395,6 +172920,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
+ /* vvv--- See check-in [12ad822d9b827777] on 2023-03-16 ---vvv */
+ assert( pWInfo->pSelect->pOrderBy==0
+ || pWInfo->nOBSat <= pWInfo->pSelect->pOrderBy->nExpr );
}else{
pWInfo->revMask = pFrom->revLoop;
if( pWInfo->nOBSat<=0 ){
@@ -164437,15 +172965,91 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
}
}
-
pWInfo->nRowOut = pFrom->nRow;
/* Free temporary memory and return success */
- sqlcipher_sqlite3DbFreeNN(db, pSpace);
+ sqlcipher_sqlite3StackFreeNN(pParse->db, pSpace);
return SQLITE_OK;
}
/*
+** This routine implements a heuristic designed to improve query planning.
+** This routine is called in between the first and second call to
+** wherePathSolver(). Hence the name "Interstage" "Heuristic".
+**
+** The first call to wherePathSolver() (hereafter just "solver()") computes
+** the best path without regard to the order of the outputs. The second call
+** to the solver() builds upon the first call to try to find an alternative
+** path that satisfies the ORDER BY clause.
+**
+** This routine looks at the results of the first solver() run, and for
+** every FROM clause term in the resulting query plan that uses an equality
+** constraint against an index, disable other WhereLoops for that same
+** FROM clause term that would try to do a full-table scan. This prevents
+** an index search from being converted into a full-table scan in order to
+** satisfy an ORDER BY clause, since even though we might get slightly better
+** performance using the full-scan without sorting if the output size
+** estimates are very precise, we might also get severe performance
+** degradation using the full-scan if the output size estimate is too large.
+** It is better to err on the side of caution.
+**
+** Except, if the first solver() call generated a full-table scan in an outer
+** loop then stop this analysis at the first full-scan, since the second
+** solver() run might try to swap that full-scan for another in order to
+** get the output into the correct order. In other words, we allow a
+** rewrite like this:
+**
+** First Solver() Second Solver()
+** |-- SCAN t1 |-- SCAN t2
+** |-- SEARCH t2 `-- SEARCH t1
+** `-- SORT USING B-TREE
+**
+** The purpose of this routine is to disallow rewrites such as:
+**
+** First Solver() Second Solver()
+** |-- SEARCH t1 |-- SCAN t2 <--- bad!
+** |-- SEARCH t2 `-- SEARCH t1
+** `-- SORT USING B-TREE
+**
+** See test cases in test/whereN.test for the real-world query that
+** originally provoked this heuristic.
+*/
+static SQLITE_NOINLINE void whereInterstageHeuristic(WhereInfo *pWInfo){
+ int i;
+#ifdef WHERETRACE_ENABLED
+ int once = 0;
+#endif
+ for(i=0; i<pWInfo->nLevel; i++){
+ WhereLoop *p = pWInfo->a[i].pWLoop;
+ if( p==0 ) break;
+ if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ) continue;
+ if( (p->wsFlags & (WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_IN))!=0 ){
+ u8 iTab = p->iTab;
+ WhereLoop *pLoop;
+ for(pLoop=pWInfo->pLoops; pLoop; pLoop=pLoop->pNextLoop){
+ if( pLoop->iTab!=iTab ) continue;
+ if( (pLoop->wsFlags & (WHERE_CONSTRAINT|WHERE_AUTO_INDEX))!=0 ){
+ /* Auto-index and index-constrained loops allowed to remain */
+ continue;
+ }
+#ifdef WHERETRACE_ENABLED
+ if( sqlcipher_sqlite3WhereTrace & 0x80 ){
+ if( once==0 ){
+ sqlcipher_sqlite3DebugPrintf("Loops disabled by interstage heuristic:\n");
+ once = 1;
+ }
+ sqlcipher_sqlite3WhereLoopPrint(pLoop, &pWInfo->sWC);
+ }
+#endif /* WHERETRACE_ENABLED */
+ pLoop->prereq = ALLBITS; /* Prevent 2nd solver() from using this one */
+ }
+ }else{
+ break;
+ }
+ }
+}
+
+/*
** Most queries use only a single table (they are not joins) and have
** simple == constraints against indexed fields. This routine attempts
** to plan those simple cases using much less ceremony than the
@@ -164539,7 +173143,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pLoop->cId = '0';
#endif
#ifdef WHERETRACE_ENABLED
- if( sqlcipher_sqlite3WhereTrace ){
+ if( sqlcipher_sqlite3WhereTrace & 0x02 ){
sqlcipher_sqlite3DebugPrintf("whereShortCut() used to compute solution\n");
}
#endif
@@ -164606,6 +173210,17 @@ static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){
** at most a single row.
** 4) The table must not be referenced by any part of the query apart
** from its own USING or ON clause.
+** 5) The table must not have an inner-join ON or USING clause if there is
+** a RIGHT JOIN anywhere in the query. Otherwise the ON/USING clause
+** might move from the right side to the left side of the RIGHT JOIN.
+** Note: Due to (2), this condition can only arise if the table is
+** the right-most table of a subquery that was flattened into the
+** main query and that subquery was the right-hand operand of an
+** inner join that held an ON or USING clause.
+** 6) The ORDER BY clause has 63 or fewer terms
+** 7) The omit-noop-join optimization is enabled.
+**
+** Items (1), (6), and (7) are checked by the caller.
**
** For example, given:
**
@@ -164631,6 +173246,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
){
int i;
Bitmask tabUsed;
+ int hasRightJoin;
/* Preconditions checked by the caller */
assert( pWInfo->nLevel>=2 );
@@ -164645,6 +173261,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
if( pWInfo->pOrderBy ){
tabUsed |= sqlcipher_sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pOrderBy);
}
+ hasRightJoin = (pWInfo->pTabList->a[0].fg.jointype & JT_LTORJ)!=0;
for(i=pWInfo->nLevel-1; i>=1; i--){
WhereTerm *pTerm, *pEnd;
SrcItem *pItem;
@@ -164667,9 +173284,15 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
break;
}
}
+ if( hasRightJoin
+ && ExprHasProperty(pTerm->pExpr, EP_InnerON)
+ && pTerm->pExpr->w.iJoin==pItem->iCursor
+ ){
+ break; /* restriction (5) */
+ }
}
if( pTerm<pEnd ) continue;
- WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId));
+ WHERETRACE(0xffffffff, ("-> drop loop %c not used\n", pLoop->cId));
notReady &= ~pLoop->maskSelf;
for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
@@ -164708,28 +173331,27 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
const WhereInfo *pWInfo
){
int i;
- LogEst nSearch;
+ LogEst nSearch = 0;
assert( pWInfo->nLevel>=2 );
assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) );
- nSearch = pWInfo->a[0].pWLoop->nOut;
- for(i=1; i<pWInfo->nLevel; i++){
+ for(i=0; i<pWInfo->nLevel; i++){
WhereLoop *pLoop = pWInfo->a[i].pWLoop;
const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
- if( (pLoop->wsFlags & reqFlags)==reqFlags
+ SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
+ Table *pTab = pItem->pTab;
+ if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
+ pTab->tabFlags |= TF_MaybeReanalyze;
+ if( i>=1
+ && (pLoop->wsFlags & reqFlags)==reqFlags
/* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */
&& ALWAYS((pLoop->wsFlags & (WHERE_IPK|WHERE_INDEXED))!=0)
){
- SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
- Table *pTab = pItem->pTab;
- pTab->tabFlags |= TF_StatsUsed;
- if( nSearch > pTab->nRowLogEst
- && (pTab->tabFlags & TF_HasStat1)!=0
- ){
+ if( nSearch > pTab->nRowLogEst ){
testcase( pItem->fg.jointype & JT_LEFT );
pLoop->wsFlags |= WHERE_BLOOMFILTER;
pLoop->wsFlags &= ~WHERE_IDX_ONLY;
- WHERETRACE(0xffff, (
+ WHERETRACE(0xffffffff, (
"-> use Bloom-filter on loop %c because there are ~%.1e "
"lookups into %s which has only ~%.1e rows\n",
pLoop->cId, (double)sqlcipher_sqlite3LogEstToInt(nSearch), pTab->zName,
@@ -164741,6 +173363,147 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
}
/*
+** Expression Node callback for sqlcipher_sqlite3ExprCanReturnSubtype().
+**
+** Only a function call is able to return a subtype. So if the node
+** is not a function call, return WRC_Prune immediately.
+**
+** A function call is able to return a subtype if it has the
+** SQLITE_RESULT_SUBTYPE property.
+**
+** Assume that every function is able to pass-through a subtype from
+** one of its argument (using sqlcipher_sqlite3_result_value()). Most functions
+** are not this way, but we don't have a mechanism to distinguish those
+** that are from those that are not, so assume they all work this way.
+** That means that if one of its arguments is another function and that
+** other function is able to return a subtype, then this function is
+** able to return a subtype.
+*/
+static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
+ int n;
+ FuncDef *pDef;
+ sqlcipher_sqlite3 *db;
+ if( pExpr->op!=TK_FUNCTION ){
+ return WRC_Prune;
+ }
+ assert( ExprUseXList(pExpr) );
+ db = pWalker->pParse->db;
+ n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
+ pDef = sqlcipher_sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
+ if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
+ pWalker->eCode = 1;
+ return WRC_Prune;
+ }
+ return WRC_Continue;
+}
+
+/*
+** Return TRUE if expression pExpr is able to return a subtype.
+**
+** A TRUE return does not guarantee that a subtype will be returned.
+** It only indicates that a subtype return is possible. False positives
+** are acceptable as they only disable an optimization. False negatives,
+** on the other hand, can lead to incorrect answers.
+*/
+static int sqlcipher_sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.pParse = pParse;
+ w.xExprCallback = exprNodeCanReturnSubtype;
+ sqlcipher_sqlite3WalkExpr(&w, pExpr);
+ return w.eCode;
+}
+
+/*
+** The index pIdx is used by a query and contains one or more expressions.
+** In other words pIdx is an index on an expression. iIdxCur is the cursor
+** number for the index and iDataCur is the cursor number for the corresponding
+** table.
+**
+** This routine adds IndexedExpr entries to the Parse->pIdxEpr field for
+** each of the expressions in the index so that the expression code generator
+** will know to replace occurrences of the indexed expression with
+** references to the corresponding column of the index.
+*/
+static SQLITE_NOINLINE void whereAddIndexedExpr(
+ Parse *pParse, /* Add IndexedExpr entries to pParse->pIdxEpr */
+ Index *pIdx, /* The index-on-expression that contains the expressions */
+ int iIdxCur, /* Cursor number for pIdx */
+ SrcItem *pTabItem /* The FROM clause entry for the table */
+){
+ int i;
+ IndexedExpr *p;
+ Table *pTab;
+ assert( pIdx->bHasExpr );
+ pTab = pIdx->pTable;
+ for(i=0; i<pIdx->nColumn; i++){
+ Expr *pExpr;
+ int j = pIdx->aiColumn[i];
+ if( j==XN_EXPR ){
+ pExpr = pIdx->aColExpr->a[i].pExpr;
+ }else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){
+ pExpr = sqlcipher_sqlite3ColumnExpr(pTab, &pTab->aCol[j]);
+ }else{
+ continue;
+ }
+ if( sqlcipher_sqlite3ExprIsConstant(0,pExpr) ) continue;
+ if( pExpr->op==TK_FUNCTION && sqlcipher_sqlite3ExprCanReturnSubtype(pParse,pExpr) ){
+ /* Functions that might set a subtype should not be replaced by the
+ ** value taken from an expression index since the index omits the
+ ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */
+ continue;
+ }
+ p = sqlcipher_sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
+ if( p==0 ) break;
+ p->pIENext = pParse->pIdxEpr;
+#ifdef WHERETRACE_ENABLED
+ if( sqlcipher_sqlite3WhereTrace & 0x200 ){
+ sqlcipher_sqlite3DebugPrintf("New pParse->pIdxEpr term {%d,%d}\n", iIdxCur, i);
+ if( sqlcipher_sqlite3WhereTrace & 0x5000 ) sqlcipher_sqlite3ShowExpr(pExpr);
+ }
+#endif
+ p->pExpr = sqlcipher_sqlite3ExprDup(pParse->db, pExpr, 0);
+ p->iDataCur = pTabItem->iCursor;
+ p->iIdxCur = iIdxCur;
+ p->iIdxCol = i;
+ p->bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0;
+ if( sqlcipher_sqlite3IndexAffinityStr(pParse->db, pIdx) ){
+ p->aff = pIdx->zColAff[i];
+ }
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ p->zIdxName = pIdx->zName;
+#endif
+ pParse->pIdxEpr = p;
+ if( p->pIENext==0 ){
+ void *pArg = (void*)&pParse->pIdxEpr;
+ sqlcipher_sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg);
+ }
+ }
+}
+
+/*
+** Set the reverse-scan order mask to one for all tables in the query
+** with the exception of MATERIALIZED common table expressions that have
+** their own internal ORDER BY clauses.
+**
+** This implements the PRAGMA reverse_unordered_selects=ON setting.
+** (Also SQLITE_DBCONFIG_REVERSE_SCANORDER).
+*/
+static SQLITE_NOINLINE void whereReverseScanOrder(WhereInfo *pWInfo){
+ int ii;
+ for(ii=0; ii<pWInfo->pTabList->nSrc; ii++){
+ SrcItem *pItem = &pWInfo->pTabList->a[ii];
+ if( !pItem->fg.isCte
+ || pItem->u2.pCteUse->eM10d!=M10d_Yes
+ || NEVER(pItem->pSelect==0)
+ || pItem->pSelect->pOrderBy==0
+ ){
+ pWInfo->revMask |= MASKBIT(ii);
+ }
+ }
+}
+
+/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
** information needed to terminate the loop. Later, the calling routine
@@ -164798,7 +173561,7 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
**
** OUTER JOINS
**
-** An outer join of tables t1 and t2 is conceptally coded as follows:
+** An outer join of tables t1 and t2 is conceptually coded as follows:
**
** foreach row1 in t1 do
** flag = 0
@@ -164834,7 +173597,7 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
Expr *pWhere, /* The WHERE clause */
ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */
- Select *pLimit, /* Use this LIMIT/OFFSET clause, if any */
+ Select *pSelect, /* The entire SELECT statement */
u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */
int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number
** If WHERE_USE_LIMIT, then the limit amount */
@@ -164868,7 +173631,11 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
/* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */
testcase( pOrderBy && pOrderBy->nExpr==BMS-1 );
- if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
+ if( pOrderBy && pOrderBy->nExpr>=BMS ){
+ pOrderBy = 0;
+ wctrlFlags &= ~WHERE_WANT_DISTINCT;
+ wctrlFlags |= WHERE_KEEP_ALL_JOINS; /* Disable omit-noop-join opt */
+ }
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
@@ -164893,7 +173660,10 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
** field (type Bitmask) it must be aligned on an 8-byte boundary on
** some architectures. Hence the ROUND8() below.
*/
- nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
+ nByteWInfo = ROUND8P(sizeof(WhereInfo));
+ if( nTabList>1 ){
+ nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel));
+ }
pWInfo = sqlcipher_sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
if( db->mallocFailed ){
sqlcipher_sqlite3DbFree(db, pWInfo);
@@ -164903,7 +173673,9 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->pOrderBy = pOrderBy;
+#if WHERETRACE_ENABLED
pWInfo->pWhere = pWhere;
+#endif
pWInfo->pResultSet = pResultSet;
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
pWInfo->nLevel = nTabList;
@@ -164911,9 +173683,7 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
pWInfo->wctrlFlags = wctrlFlags;
pWInfo->iLimit = iAuxArg;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- pWInfo->pLimit = pLimit;
-#endif
+ pWInfo->pSelect = pSelect;
memset(&pWInfo->nOBSat, 0,
offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat));
memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
@@ -164947,13 +173717,17 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
- ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
+ if( ALWAYS(pWInfo->pSelect)
+ && (pWInfo->pSelect->selFlags & SF_MultiValue)==0
+ ){
+ ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
+ }
}else{
/* Assign a bit from the bitmask to every term in the FROM clause.
**
** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
**
- ** The rule of the previous sentence ensures thta if X is the bitmask for
+ ** The rule of the previous sentence ensures that if X is the bitmask for
** a table T, then X-1 is the bitmask for all other tables to the left of T.
** Knowing the bitmask for all tables to the left of a left join is
** important. Ticket #3015.
@@ -164982,25 +173756,50 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
/* Analyze all of the subexpressions. */
sqlcipher_sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
- sqlcipher_sqlite3WhereAddLimit(&pWInfo->sWC, pLimit);
+ if( pSelect && pSelect->pLimit ){
+ sqlcipher_sqlite3WhereAddLimit(&pWInfo->sWC, pSelect);
+ }
if( pParse->nErr ) goto whereBeginError;
- /* Special case: WHERE terms that do not refer to any tables in the join
- ** (constant expressions). Evaluate each such term, and jump over all the
- ** generated code if the result is not true.
+ /* The False-WHERE-Term-Bypass optimization:
+ **
+ ** If there are WHERE terms that are false, then no rows will be output,
+ ** so skip over all of the code generated here.
+ **
+ ** Conditions:
+ **
+ ** (1) The WHERE term must not refer to any tables in the join.
+ ** (2) The term must not come from an ON clause on the
+ ** right-hand side of a LEFT or FULL JOIN.
+ ** (3) The term must not come from an ON clause, or there must be
+ ** no RIGHT or FULL OUTER joins in pTabList.
+ ** (4) If the expression contains non-deterministic functions
+ ** that are not within a sub-select. This is not required
+ ** for correctness but rather to preserves SQLite's legacy
+ ** behaviour in the following two cases:
**
- ** Do not do this if the expression contains non-deterministic functions
- ** that are not within a sub-select. This is not strictly required, but
- ** preserves SQLite's legacy behaviour in the following two cases:
+ ** WHERE random()>0; -- eval random() once per row
+ ** WHERE (SELECT random())>0; -- eval random() just once overall
**
- ** FROM ... WHERE random()>0; -- eval random() once per row
- ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
+ ** Note that the Where term need not be a constant in order for this
+ ** optimization to apply, though it does need to be constant relative to
+ ** the current subquery (condition 1). The term might include variables
+ ** from outer queries so that the value of the term changes from one
+ ** invocation of the current subquery to the next.
*/
for(ii=0; ii<sWLB.pWC->nBase; ii++){
- WhereTerm *pT = &sWLB.pWC->a[ii];
+ WhereTerm *pT = &sWLB.pWC->a[ii]; /* A term of the WHERE clause */
+ Expr *pX; /* The expression of pT */
if( pT->wtFlags & TERM_VIRTUAL ) continue;
- if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
- sqlcipher_sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
+ pX = pT->pExpr;
+ assert( pX!=0 );
+ assert( pT->prereqAll!=0 || !ExprHasProperty(pX, EP_OuterON) );
+ if( pT->prereqAll==0 /* Conditions (1) and (2) */
+ && (nTabList==0 || exprIsDeterministic(pX)) /* Condition (4) */
+ && !(ExprHasProperty(pX, EP_InnerON) /* Condition (3) */
+ && (pTabList->a[0].fg.jointype & JT_LTORJ)!=0 )
+ ){
+ sqlcipher_sqlite3ExprIfFalse(pParse, pX, pWInfo->iBreak, SQLITE_JUMPIFNULL);
pT->wtFlags |= TERM_CODED;
}
}
@@ -165023,13 +173822,13 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
/* Construct the WhereLoop objects */
#if defined(WHERETRACE_ENABLED)
- if( sqlcipher_sqlite3WhereTrace & 0xffff ){
+ if( sqlcipher_sqlite3WhereTrace & 0xffffffff ){
sqlcipher_sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags);
if( wctrlFlags & WHERE_USE_LIMIT ){
sqlcipher_sqlite3DebugPrintf(", limit: %d", iAuxArg);
}
sqlcipher_sqlite3DebugPrintf(")\n");
- if( sqlcipher_sqlite3WhereTrace & 0x100 ){
+ if( sqlcipher_sqlite3WhereTrace & 0x8000 ){
Select sSelect;
memset(&sSelect, 0, sizeof(sSelect));
sSelect.selFlags = SF_WhereBegin;
@@ -165039,10 +173838,10 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
sSelect.pEList = pResultSet;
sqlcipher_sqlite3TreeViewSelect(0, &sSelect, 0);
}
- }
- if( sqlcipher_sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
- sqlcipher_sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n");
- sqlcipher_sqlite3WhereClausePrint(sWLB.pWC);
+ if( sqlcipher_sqlite3WhereTrace & 0x4000 ){ /* Display all WHERE clause terms */
+ sqlcipher_sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n");
+ sqlcipher_sqlite3WhereClausePrint(sWLB.pWC);
+ }
}
#endif
@@ -165058,7 +173857,7 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
** loops will be built using the revised truthProb values. */
if( sWLB.bldFlags2 & SQLITE_BLDF2_2NDPASS ){
WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC);
- WHERETRACE(0xffff,
+ WHERETRACE(0xffffffff,
("**** Redo all loop computations due to"
" TERM_HIGHTRUTH changes ****\n"));
while( pWInfo->pLoops ){
@@ -165075,12 +173874,24 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
wherePathSolver(pWInfo, 0);
if( db->mallocFailed ) goto whereBeginError;
if( pWInfo->pOrderBy ){
+ whereInterstageHeuristic(pWInfo);
wherePathSolver(pWInfo, pWInfo->nRowOut+1);
if( db->mallocFailed ) goto whereBeginError;
}
+
+ /* TUNING: Assume that a DISTINCT clause on a subquery reduces
+ ** the output size by a factor of 8 (LogEst -30).
+ */
+ if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){
+ WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n",
+ pWInfo->nRowOut, pWInfo->nRowOut-30));
+ pWInfo->nRowOut -= 30;
+ }
+
}
+ assert( pWInfo->pTabList!=0 );
if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
- pWInfo->revMask = ALLBITS;
+ whereReverseScanOrder(pWInfo);
}
if( pParse->nErr ){
goto whereBeginError;
@@ -165124,10 +173935,10 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
** in-line sqlcipher_sqlite3WhereCodeOneLoopStart() for performance reasons.
*/
notReady = ~(Bitmask)0;
- if( pWInfo->nLevel>=2
- && pResultSet!=0 /* these two combine to guarantee */
- && 0==(wctrlFlags & WHERE_AGG_DISTINCT) /* condition (1) above */
- && OptimizationEnabled(db, SQLITE_OmitNoopJoin)
+ if( pWInfo->nLevel>=2 /* Must be a join, or this opt8n is pointless */
+ && pResultSet!=0 /* Condition (1) */
+ && 0==(wctrlFlags & (WHERE_AGG_DISTINCT|WHERE_KEEP_ALL_JOINS)) /* (1),(6) */
+ && OptimizationEnabled(db, SQLITE_OmitNoopJoin) /* (7) */
){
notReady = whereOmitNoopJoin(pWInfo, notReady);
nTabList = pWInfo->nLevel;
@@ -165144,11 +173955,11 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
}
#if defined(WHERETRACE_ENABLED)
- if( sqlcipher_sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
+ if( sqlcipher_sqlite3WhereTrace & 0x4000 ){ /* Display all terms of the WHERE clause */
sqlcipher_sqlite3DebugPrintf("---- WHERE clause at end of analysis:\n");
sqlcipher_sqlite3WhereClausePrint(sWLB.pWC);
}
- WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));
+ WHERETRACE(0xffffffff,("*** Optimizer Finished ***\n"));
#endif
pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;
@@ -165180,6 +173991,7 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
&& !IsVirtual(pTabList->a[0].pTab)
&& (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
+ && OptimizationEnabled(db, SQLITE_OnePass)
)){
pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
@@ -165243,7 +174055,7 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
assert( n<=pTab->nCol );
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
- if( pLoop->u.btree.pIndex!=0 ){
+ if( pLoop->u.btree.pIndex!=0 && (pTab->tabFlags & TF_WithoutRowid)==0 ){
sqlcipher_sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete);
}else
#endif
@@ -165285,6 +174097,14 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
op = OP_ReopenIdx;
}else{
iIndexCur = pParse->nTab++;
+ if( pIx->bHasExpr && OptimizationEnabled(db, SQLITE_IndexedExpr) ){
+ whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem);
+ }
+ if( pIx->pPartIdxWhere && (pTabItem->fg.jointype & JT_RIGHT)==0 ){
+ wherePartIdxExpr(
+ pParse, pIx, pIx->pPartIdxWhere, 0, iIndexCur, pTabItem
+ );
+ }
}
pLevel->iIdxCur = iIndexCur;
assert( pIx!=0 );
@@ -165377,11 +174197,11 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
sqlcipher_sqlite3VdbeJumpHere(v, iOnce);
}
}
+ assert( pTabList == pWInfo->pTabList );
if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
- constructAutomaticIndex(pParse, &pWInfo->sWC,
- &pTabList->a[pLevel->iFrom], notReady, pLevel);
+ constructAutomaticIndex(pParse, &pWInfo->sWC, notReady, pLevel);
#endif
}else{
sqlcipher_sqlite3ConstructBloomFilter(pWInfo, ii, pLevel, notReady);
@@ -165407,11 +174227,14 @@ SQLITE_PRIVATE WhereInfo *sqlcipher_sqlite3WhereBegin(
/* Jump here if malloc fails */
whereBeginError:
if( pWInfo ){
- testcase( pWInfo->pExprMods!=0 );
- whereUndoExprMods(pWInfo);
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
whereInfoFree(db, pWInfo);
}
+#ifdef WHERETRACE_ENABLED
+ /* Prevent harmless compiler warnings about debugging routines
+ ** being declared but never used */
+ sqlcipher_sqlite3ShowWhereLoopList(0);
+#endif /* WHERETRACE_ENABLED */
return 0;
}
@@ -165435,26 +174258,6 @@ whereBeginError:
}
#endif
-#ifdef SQLITE_DEBUG
-/*
-** Return true if cursor iCur is opened by instruction k of the
-** bytecode. Used inside of assert() only.
-*/
-static int cursorIsOpen(Vdbe *v, int iCur, int k){
- while( k>=0 ){
- VdbeOp *pOp = sqlcipher_sqlite3VdbeGetOp(v,k--);
- if( pOp->p1!=iCur ) continue;
- if( pOp->opcode==OP_Close ) return 0;
- if( pOp->opcode==OP_OpenRead ) return 1;
- if( pOp->opcode==OP_OpenWrite ) return 1;
- if( pOp->opcode==OP_OpenDup ) return 1;
- if( pOp->opcode==OP_OpenAutoindex ) return 1;
- if( pOp->opcode==OP_OpenEphemeral ) return 1;
- }
- return 0;
-}
-#endif /* SQLITE_DEBUG */
-
/*
** Generate the end of the WHERE loop. See comments on
** sqlcipher_sqlite3WhereBegin() for additional information.
@@ -165601,7 +174404,15 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereEnd(WhereInfo *pWInfo){
addr = sqlcipher_sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 );
if( (ws & WHERE_IDX_ONLY)==0 ){
- assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor );
+ SrcItem *pSrc = &pTabList->a[pLevel->iFrom];
+ assert( pLevel->iTabCur==pSrc->iCursor );
+ if( pSrc->fg.viaCoroutine ){
+ int m, n;
+ n = pSrc->regResult;
+ assert( pSrc->pTab!=0 );
+ m = pSrc->pTab->nCol;
+ sqlcipher_sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1);
+ }
sqlcipher_sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
}
if( (ws & WHERE_INDEXED)
@@ -165627,7 +174438,6 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereEnd(WhereInfo *pWInfo){
}
assert( pWInfo->nLevel<=pTabList->nSrc );
- if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo);
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
int k, last;
VdbeOp *pOp, *pLastOp;
@@ -165652,6 +174462,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereEnd(WhereInfo *pWInfo){
*/
if( pTabItem->fg.viaCoroutine ){
testcase( pParse->db->mallocFailed );
+ assert( pTabItem->regResult>=0 );
translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
pTabItem->regResult, 0);
continue;
@@ -165681,10 +174492,28 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereEnd(WhereInfo *pWInfo){
}else{
last = pWInfo->iEndWhere;
}
+ if( pIdx->bHasExpr ){
+ IndexedExpr *p = pParse->pIdxEpr;
+ while( p ){
+ if( p->iIdxCur==pLevel->iIdxCur ){
+#ifdef WHERETRACE_ENABLED
+ if( sqlcipher_sqlite3WhereTrace & 0x200 ){
+ sqlcipher_sqlite3DebugPrintf("Disable pParse->pIdxEpr term {%d,%d}\n",
+ p->iIdxCur, p->iIdxCol);
+ if( sqlcipher_sqlite3WhereTrace & 0x5000 ) sqlcipher_sqlite3ShowExpr(p->pExpr);
+ }
+#endif
+ p->iDataCur = -1;
+ p->iIdxCur = -1;
+ }
+ p = p->pIENext;
+ }
+ }
k = pLevel->addrBody + 1;
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeAddopTrace ){
- printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
+ printf("TRANSLATE cursor %d->%d in opcode range %d..%d\n",
+ pLevel->iTabCur, pLevel->iIdxCur, k, last-1);
}
/* Proof that the "+1" on the k value above is safe */
pOp = sqlcipher_sqlite3VdbeGetOp(v, k - 1);
@@ -165728,16 +174557,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereEnd(WhereInfo *pWInfo){
** reference. Verify that this is harmless - that the
** table being referenced really is open.
*/
-#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
- assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
- || cursorIsOpen(v,pOp->p1,k)
- || pOp->opcode==OP_Offset
- );
-#else
- assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
- || cursorIsOpen(v,pOp->p1,k)
- );
-#endif
+ if( pLoop->wsFlags & WHERE_IDX_ONLY ){
+ sqlcipher_sqlite3ErrorMsg(pParse, "internal query planner error");
+ pParse->rc = SQLITE_INTERNAL;
+ }
}
}else if( pOp->opcode==OP_Rowid ){
pOp->p1 = pLevel->iIdxCur;
@@ -165891,7 +174714,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WhereEnd(WhereInfo *pWInfo){
**
** These are the same built-in window functions supported by Postgres.
** Although the behaviour of aggregate window functions (functions that
-** can be used as either aggregates or window funtions) allows them to
+** can be used as either aggregates or window functions) allows them to
** be implemented using an API, built-in window functions are much more
** esoteric. Additionally, some window functions (e.g. nth_value())
** may only be implemented by caching the entire partition in memory.
@@ -166421,7 +175244,7 @@ static Window *windowFind(Parse *pParse, Window *pList, const char *zName){
** is the Window object representing the associated OVER clause. This
** function updates the contents of pWin as follows:
**
-** * If the OVER clause refered to a named window (as in "max(x) OVER win"),
+** * If the OVER clause referred to a named window (as in "max(x) OVER win"),
** search list pList for a matching WINDOW definition, and update pWin
** accordingly. If no such WINDOW clause can be found, leave an error
** in pParse.
@@ -166559,6 +175382,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
}
/* no break */ deliberate_fall_through
+ case TK_IF_NULL_ROW:
case TK_AGG_FUNCTION:
case TK_COLUMN: {
int iCol = -1;
@@ -166674,7 +175498,6 @@ static ExprList *exprListAppendList(
for(i=0; i<pAppend->nExpr; i++){
sqlcipher_sqlite3 *db = pParse->db;
Expr *pDup = sqlcipher_sqlite3ExprDup(db, pAppend->a[i].pExpr, 0);
- assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) );
if( db->mallocFailed ){
sqlcipher_sqlite3ExprDelete(db, pDup);
break;
@@ -166812,7 +175635,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WindowRewrite(Parse *pParse, Select *p){
assert( ExprUseXList(pWin->pOwner) );
assert( pWin->pWFunc!=0 );
pArgs = pWin->pOwner->x.pList;
- if( pWin->pWFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){
+ if( pWin->pWFunc->funcFlags & SQLITE_SUBTYPE ){
selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist);
pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
pWin->bExprArgs = 1;
@@ -166844,7 +175667,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WindowRewrite(Parse *pParse, Select *p){
pSub = sqlcipher_sqlite3SelectNew(
pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
);
- SELECTTRACE(1,pParse,pSub,
+ TREETRACE(0x40,pParse,pSub,
("New window-function subquery in FROM clause of (%u/%p)\n",
p->selId, p));
p->pSrc = sqlcipher_sqlite3SrcListAppend(pParse, 0, 0, 0);
@@ -166854,6 +175677,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3WindowRewrite(Parse *pParse, Select *p){
if( p->pSrc ){
Table *pTab2;
p->pSrc->a[0].pSelect = pSub;
+ p->pSrc->a[0].fg.isCorrelated = 1;
sqlcipher_sqlite3SrcListAssignCursors(pParse, p->pSrc);
pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
pTab2 = sqlcipher_sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
@@ -166937,7 +175761,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WindowListDelete(sqlcipher_sqlite3 *db, Win
** variable values in the expression tree.
*/
static Expr *sqlcipher_sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){
- if( 0==sqlcipher_sqlite3ExprIsConstant(pExpr) ){
+ if( 0==sqlcipher_sqlite3ExprIsConstant(0,pExpr) ){
if( IN_RENAME_OBJECT ) sqlcipher_sqlite3RenameExprUnmap(pParse, pExpr);
sqlcipher_sqlite3ExprDelete(pParse->db, pExpr);
pExpr = sqlcipher_sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0);
@@ -167041,7 +175865,7 @@ SQLITE_PRIVATE Window *sqlcipher_sqlite3WindowAssemble(
}
/*
-** Window *pWin has just been created from a WINDOW clause. Tokne pBase
+** Window *pWin has just been created from a WINDOW clause. Token pBase
** is the base window. Earlier windows from the same WINDOW clause are
** stored in the linked list starting at pWin->pNextWin. This function
** either updates *pWin according to the base specification, or else
@@ -167085,8 +175909,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WindowAttach(Parse *pParse, Expr *p, Window
if( p ){
assert( p->op==TK_FUNCTION );
assert( pWin );
+ assert( ExprIsFullSize(p) );
p->y.pWin = pWin;
- ExprSetProperty(p, EP_WinFunc);
+ ExprSetProperty(p, EP_WinFunc|EP_FullSize);
pWin->pOwner = p;
if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){
sqlcipher_sqlite3ErrorMsg(pParse,
@@ -167347,7 +176172,7 @@ struct WindowCsrAndReg {
**
** (ORDER BY a, b GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING)
**
-** The windows functions implmentation caches the input rows in a temp
+** The windows functions implementation caches the input rows in a temp
** table, sorted by "a, b" (it actually populates the cache lazily, and
** aggressively removes rows once they are no longer required, but that's
** a mere detail). It keeps three cursors open on the temp table. One
@@ -167945,10 +176770,9 @@ static void windowCodeRangeTest(
/* This block runs if reg1 is not NULL, but reg2 is. */
sqlcipher_sqlite3VdbeJumpHere(v, addr);
- sqlcipher_sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v);
- if( op==OP_Gt || op==OP_Ge ){
- sqlcipher_sqlite3VdbeChangeP2(v, -1, addrDone);
- }
+ sqlcipher_sqlite3VdbeAddOp2(v, OP_IsNull, reg2,
+ (op==OP_Gt || op==OP_Ge) ? addrDone : lbl);
+ VdbeCoverage(v);
}
/* Register reg1 currently contains csr1.peerVal (the peer-value from csr1).
@@ -168357,7 +177181,7 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
**
** For the most part, the patterns above are adapted to support UNBOUNDED by
** assuming that it is equivalent to "infinity PRECEDING/FOLLOWING" and
-** CURRENT ROW by assuming that it is equivilent to "0 PRECEDING/FOLLOWING".
+** CURRENT ROW by assuming that it is equivalent to "0 PRECEDING/FOLLOWING".
** This is optimized of course - branches that will never be taken and
** conditions that are always true are omitted from the VM code. The only
** exceptional case is:
@@ -168636,7 +177460,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WindowCodeStep(
}
/* Allocate registers for the array of values from the sub-query, the
- ** samve values in record form, and the rowid used to insert said record
+ ** same values in record form, and the rowid used to insert said record
** into the ephemeral table. */
regNew = pParse->nMem+1;
pParse->nMem += nInput;
@@ -168720,8 +177544,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WindowCodeStep(
VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound <expr> */
VdbeCoverageNeverNullIf(v, op==OP_Le); /* values previously checked */
windowAggFinal(&s, 0);
- sqlcipher_sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1);
- VdbeCoverageNeverTaken(v);
+ sqlcipher_sqlite3VdbeAddOp1(v, OP_Rewind, s.current.csr);
windowReturnOneRow(&s);
sqlcipher_sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr);
sqlcipher_sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd);
@@ -168733,13 +177556,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WindowCodeStep(
}
if( pMWin->eStart!=TK_UNBOUNDED ){
- sqlcipher_sqlite3VdbeAddOp2(v, OP_Rewind, s.start.csr, 1);
- VdbeCoverageNeverTaken(v);
+ sqlcipher_sqlite3VdbeAddOp1(v, OP_Rewind, s.start.csr);
}
- sqlcipher_sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1);
- VdbeCoverageNeverTaken(v);
- sqlcipher_sqlite3VdbeAddOp2(v, OP_Rewind, s.end.csr, 1);
- VdbeCoverageNeverTaken(v);
+ sqlcipher_sqlite3VdbeAddOp1(v, OP_Rewind, s.current.csr);
+ sqlcipher_sqlite3VdbeAddOp1(v, OP_Rewind, s.end.csr);
if( regPeer && pOrderBy ){
sqlcipher_sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, pOrderBy->nExpr-1);
sqlcipher_sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.start.reg, pOrderBy->nExpr-1);
@@ -168881,7 +177701,10 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WindowCodeStep(
/************** End of window.c **********************************************/
/************** Begin file parse.c *******************************************/
/* This file is automatically generated by Lemon from input grammar
-** source file "parse.y". */
+** source file "parse.y" with these options:
+**
+** -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT
+*/
/*
** 2001-09-15
**
@@ -168898,7 +177721,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3WindowCodeStep(
** The canonical source code to this file ("parse.y") is a Lemon grammar
** file that specifies the input grammar and actions to take while parsing.
** That input file is processed by Lemon to generate a C-language
-** implementation of a parser for the given grammer. You might be reading
+** implementation of a parser for the given grammar. You might be reading
** this comment as part of the translated C-code. Edits should be made
** to the original parse.y sources.
*/
@@ -169010,9 +177833,9 @@ static void updateDeleteLimitError(
break;
}
}
- if( (p->selFlags & SF_MultiValue)==0 &&
- (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 &&
- cnt>mxSelect
+ if( (p->selFlags & (SF_MultiValue|SF_Values))==0
+ && (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0
+ && cnt>mxSelect
){
sqlcipher_sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
}
@@ -169032,6 +177855,14 @@ static void updateDeleteLimitError(
return pSelect;
}
+ /* Memory allocator for parser stack resizing. This is a thin wrapper around
+ ** sqlcipher_sqlite3_realloc() that includes a call to sqlcipher_sqlite3FaultSim() to facilitate
+ ** testing.
+ */
+ static void *parserStackRealloc(void *pOld, sqlcipher_sqlite3_uint64 newSize){
+ return sqlcipher_sqlite3FaultSim(700) ? 0 : sqlcipher_sqlite3_realloc(pOld, newSize);
+ }
+
/* Construct a new Expr object from a single token */
static Expr *tokenExpr(Parse *pParse, int op, Token t){
@@ -169281,8 +178112,8 @@ static void updateDeleteLimitError(
#define TK_TRUEFALSE 170
#define TK_ISNOT 171
#define TK_FUNCTION 172
-#define TK_UMINUS 173
-#define TK_UPLUS 174
+#define TK_UPLUS 173
+#define TK_UMINUS 174
#define TK_TRUTH 175
#define TK_REGISTER 176
#define TK_VECTOR 177
@@ -169291,8 +178122,9 @@ static void updateDeleteLimitError(
#define TK_ASTERISK 180
#define TK_SPAN 181
#define TK_ERROR 182
-#define TK_SPACE 183
-#define TK_ILLEGAL 184
+#define TK_QNUMBER 183
+#define TK_SPACE 184
+#define TK_ILLEGAL 185
#endif
/**************** End token definitions ***************************************/
@@ -169333,6 +178165,9 @@ static void updateDeleteLimitError(
** sqlcipher_sqlite3ParserARG_STORE Code to store %extra_argument into yypParser
** sqlcipher_sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser
** sqlcipher_sqlite3ParserCTX_* As sqlcipher_sqlite3ParserARG_ except for %extra_context
+** YYREALLOC Name of the realloc() function to use
+** YYFREE Name of the free() function to use
+** YYDYNSTACK True if stack space should be extended on heap
** YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing.
** YYNSTATE the combined number of states.
@@ -169346,37 +178181,39 @@ static void updateDeleteLimitError(
** YY_NO_ACTION The yy_action[] code for no-op
** YY_MIN_REDUCE Minimum value for reduce actions
** YY_MAX_REDUCE Maximum value for reduce actions
+** YY_MIN_DSTRCTR Minimum symbol value that has a destructor
+** YY_MAX_DSTRCTR Maximum symbol value that has a destructor
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned short int
-#define YYNOCODE 319
+#define YYNOCODE 322
#define YYACTIONTYPE unsigned short int
#define YYWILDCARD 101
#define sqlcipher_sqlite3ParserTOKENTYPE Token
typedef union {
int yyinit;
sqlcipher_sqlite3ParserTOKENTYPE yy0;
- TriggerStep* yy33;
- Window* yy41;
- Select* yy47;
- SrcList* yy131;
- struct TrigEvent yy180;
- struct {int value; int mask;} yy231;
- IdList* yy254;
- u32 yy285;
- ExprList* yy322;
- Cte* yy385;
- int yy394;
- Upsert* yy444;
- u8 yy516;
- With* yy521;
- const char* yy522;
- Expr* yy528;
- OnOrUsing yy561;
- struct FrameBound yy595;
+ ExprList* yy14;
+ With* yy59;
+ Cte* yy67;
+ Upsert* yy122;
+ IdList* yy132;
+ int yy144;
+ const char* yy168;
+ SrcList* yy203;
+ Window* yy211;
+ OnOrUsing yy269;
+ struct TrigEvent yy286;
+ struct {int value; int mask;} yy383;
+ u32 yy391;
+ TriggerStep* yy427;
+ Expr* yy454;
+ u8 yy462;
+ struct FrameBound yy509;
+ Select* yy555;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
@@ -169386,24 +178223,29 @@ typedef union {
#define sqlcipher_sqlite3ParserARG_PARAM
#define sqlcipher_sqlite3ParserARG_FETCH
#define sqlcipher_sqlite3ParserARG_STORE
+#define YYREALLOC parserStackRealloc
+#define YYFREE sqlcipher_sqlite3_free
+#define YYDYNSTACK 1
#define sqlcipher_sqlite3ParserCTX_SDECL Parse *pParse;
#define sqlcipher_sqlite3ParserCTX_PDECL ,Parse *pParse
#define sqlcipher_sqlite3ParserCTX_PARAM ,pParse
#define sqlcipher_sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
#define sqlcipher_sqlite3ParserCTX_STORE yypParser->pParse=pParse;
#define YYFALLBACK 1
-#define YYNSTATE 580
-#define YYNRULE 405
-#define YYNRULE_WITH_ACTION 342
-#define YYNTOKEN 185
-#define YY_MAX_SHIFT 579
-#define YY_MIN_SHIFTREDUCE 839
-#define YY_MAX_SHIFTREDUCE 1243
-#define YY_ERROR_ACTION 1244
-#define YY_ACCEPT_ACTION 1245
-#define YY_NO_ACTION 1246
-#define YY_MIN_REDUCE 1247
-#define YY_MAX_REDUCE 1651
+#define YYNSTATE 587
+#define YYNRULE 409
+#define YYNRULE_WITH_ACTION 344
+#define YYNTOKEN 186
+#define YY_MAX_SHIFT 586
+#define YY_MIN_SHIFTREDUCE 849
+#define YY_MAX_SHIFTREDUCE 1257
+#define YY_ERROR_ACTION 1258
+#define YY_ACCEPT_ACTION 1259
+#define YY_NO_ACTION 1260
+#define YY_MIN_REDUCE 1261
+#define YY_MAX_REDUCE 1669
+#define YY_MIN_DSTRCTR 205
+#define YY_MAX_DSTRCTR 319
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
@@ -169419,6 +178261,22 @@ typedef union {
# define yytestcase(X)
#endif
+/* Macro to determine if stack space has the ability to grow using
+** heap memory.
+*/
+#if YYSTACKDEPTH<=0 || YYDYNSTACK
+# define YYGROWABLESTACK 1
+#else
+# define YYGROWABLESTACK 0
+#endif
+
+/* Guarantee a minimum number of initial stack slots.
+*/
+#if YYSTACKDEPTH<=0
+# undef YYSTACKDEPTH
+# define YYSTACKDEPTH 2 /* Need a minimum stack size */
+#endif
+
/* Next are the tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
@@ -169470,620 +178328,629 @@ typedef union {
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (2101)
+#define YY_ACTTAB_COUNT (2138)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 572, 208, 572, 118, 115, 229, 572, 118, 115, 229,
- /* 10 */ 572, 1318, 381, 1297, 412, 566, 566, 566, 572, 413,
- /* 20 */ 382, 1318, 1280, 41, 41, 41, 41, 208, 1530, 71,
- /* 30 */ 71, 975, 423, 41, 41, 495, 303, 279, 303, 976,
- /* 40 */ 401, 71, 71, 125, 126, 80, 1221, 1221, 1054, 1057,
- /* 50 */ 1044, 1044, 123, 123, 124, 124, 124, 124, 480, 413,
- /* 60 */ 1245, 1, 1, 579, 2, 1249, 554, 118, 115, 229,
- /* 70 */ 317, 484, 146, 484, 528, 118, 115, 229, 533, 1331,
- /* 80 */ 421, 527, 142, 125, 126, 80, 1221, 1221, 1054, 1057,
- /* 90 */ 1044, 1044, 123, 123, 124, 124, 124, 124, 118, 115,
- /* 100 */ 229, 327, 122, 122, 122, 122, 121, 121, 120, 120,
- /* 110 */ 120, 119, 116, 448, 284, 284, 284, 284, 446, 446,
- /* 120 */ 446, 1571, 380, 1573, 1196, 379, 1167, 569, 1167, 569,
- /* 130 */ 413, 1571, 541, 259, 226, 448, 101, 145, 453, 316,
- /* 140 */ 563, 240, 122, 122, 122, 122, 121, 121, 120, 120,
- /* 150 */ 120, 119, 116, 448, 125, 126, 80, 1221, 1221, 1054,
- /* 160 */ 1057, 1044, 1044, 123, 123, 124, 124, 124, 124, 142,
- /* 170 */ 294, 1196, 343, 452, 120, 120, 120, 119, 116, 448,
- /* 180 */ 127, 1196, 1197, 1198, 148, 445, 444, 572, 119, 116,
- /* 190 */ 448, 124, 124, 124, 124, 117, 122, 122, 122, 122,
- /* 200 */ 121, 121, 120, 120, 120, 119, 116, 448, 458, 113,
- /* 210 */ 13, 13, 550, 122, 122, 122, 122, 121, 121, 120,
- /* 220 */ 120, 120, 119, 116, 448, 426, 316, 563, 1196, 1197,
- /* 230 */ 1198, 149, 1228, 413, 1228, 124, 124, 124, 124, 122,
- /* 240 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116,
- /* 250 */ 448, 469, 346, 1041, 1041, 1055, 1058, 125, 126, 80,
- /* 260 */ 1221, 1221, 1054, 1057, 1044, 1044, 123, 123, 124, 124,
- /* 270 */ 124, 124, 1283, 526, 222, 1196, 572, 413, 224, 518,
- /* 280 */ 175, 82, 83, 122, 122, 122, 122, 121, 121, 120,
- /* 290 */ 120, 120, 119, 116, 448, 1011, 16, 16, 1196, 133,
- /* 300 */ 133, 125, 126, 80, 1221, 1221, 1054, 1057, 1044, 1044,
- /* 310 */ 123, 123, 124, 124, 124, 124, 122, 122, 122, 122,
- /* 320 */ 121, 121, 120, 120, 120, 119, 116, 448, 1045, 550,
- /* 330 */ 1196, 377, 1196, 1197, 1198, 252, 1438, 403, 508, 505,
- /* 340 */ 504, 111, 564, 570, 4, 930, 930, 437, 503, 344,
- /* 350 */ 464, 330, 364, 398, 1241, 1196, 1197, 1198, 567, 572,
- /* 360 */ 122, 122, 122, 122, 121, 121, 120, 120, 120, 119,
- /* 370 */ 116, 448, 284, 284, 373, 1584, 1611, 445, 444, 154,
- /* 380 */ 413, 449, 71, 71, 1290, 569, 1225, 1196, 1197, 1198,
- /* 390 */ 85, 1227, 271, 561, 547, 519, 1565, 572, 98, 1226,
- /* 400 */ 6, 1282, 476, 142, 125, 126, 80, 1221, 1221, 1054,
- /* 410 */ 1057, 1044, 1044, 123, 123, 124, 124, 124, 124, 554,
- /* 420 */ 13, 13, 1031, 511, 1228, 1196, 1228, 553, 109, 109,
- /* 430 */ 222, 572, 1242, 175, 572, 431, 110, 197, 449, 574,
- /* 440 */ 573, 434, 1556, 1021, 325, 555, 1196, 270, 287, 372,
- /* 450 */ 514, 367, 513, 257, 71, 71, 547, 71, 71, 363,
- /* 460 */ 316, 563, 1617, 122, 122, 122, 122, 121, 121, 120,
- /* 470 */ 120, 120, 119, 116, 448, 1021, 1021, 1023, 1024, 27,
- /* 480 */ 284, 284, 1196, 1197, 1198, 1162, 572, 1616, 413, 905,
- /* 490 */ 190, 554, 360, 569, 554, 941, 537, 521, 1162, 520,
- /* 500 */ 417, 1162, 556, 1196, 1197, 1198, 572, 548, 1558, 51,
- /* 510 */ 51, 214, 125, 126, 80, 1221, 1221, 1054, 1057, 1044,
- /* 520 */ 1044, 123, 123, 124, 124, 124, 124, 1196, 478, 135,
- /* 530 */ 135, 413, 284, 284, 1494, 509, 121, 121, 120, 120,
- /* 540 */ 120, 119, 116, 448, 1011, 569, 522, 217, 545, 1565,
- /* 550 */ 316, 563, 142, 6, 536, 125, 126, 80, 1221, 1221,
- /* 560 */ 1054, 1057, 1044, 1044, 123, 123, 124, 124, 124, 124,
- /* 570 */ 1559, 122, 122, 122, 122, 121, 121, 120, 120, 120,
- /* 580 */ 119, 116, 448, 489, 1196, 1197, 1198, 486, 281, 1271,
- /* 590 */ 961, 252, 1196, 377, 508, 505, 504, 1196, 344, 575,
- /* 600 */ 1196, 575, 413, 292, 503, 961, 880, 191, 484, 316,
- /* 610 */ 563, 388, 290, 384, 122, 122, 122, 122, 121, 121,
- /* 620 */ 120, 120, 120, 119, 116, 448, 125, 126, 80, 1221,
- /* 630 */ 1221, 1054, 1057, 1044, 1044, 123, 123, 124, 124, 124,
- /* 640 */ 124, 413, 398, 1140, 1196, 873, 100, 284, 284, 1196,
- /* 650 */ 1197, 1198, 377, 1097, 1196, 1197, 1198, 1196, 1197, 1198,
- /* 660 */ 569, 459, 32, 377, 233, 125, 126, 80, 1221, 1221,
- /* 670 */ 1054, 1057, 1044, 1044, 123, 123, 124, 124, 124, 124,
- /* 680 */ 1437, 963, 572, 228, 962, 122, 122, 122, 122, 121,
- /* 690 */ 121, 120, 120, 120, 119, 116, 448, 1162, 228, 1196,
- /* 700 */ 157, 1196, 1197, 1198, 1557, 13, 13, 301, 961, 1236,
- /* 710 */ 1162, 153, 413, 1162, 377, 1587, 1180, 5, 373, 1584,
- /* 720 */ 433, 1242, 3, 961, 122, 122, 122, 122, 121, 121,
- /* 730 */ 120, 120, 120, 119, 116, 448, 125, 126, 80, 1221,
- /* 740 */ 1221, 1054, 1057, 1044, 1044, 123, 123, 124, 124, 124,
- /* 750 */ 124, 413, 208, 571, 1196, 1032, 1196, 1197, 1198, 1196,
- /* 760 */ 392, 856, 155, 1556, 286, 406, 1102, 1102, 492, 572,
- /* 770 */ 469, 346, 1323, 1323, 1556, 125, 126, 80, 1221, 1221,
- /* 780 */ 1054, 1057, 1044, 1044, 123, 123, 124, 124, 124, 124,
- /* 790 */ 129, 572, 13, 13, 378, 122, 122, 122, 122, 121,
- /* 800 */ 121, 120, 120, 120, 119, 116, 448, 302, 572, 457,
- /* 810 */ 532, 1196, 1197, 1198, 13, 13, 1196, 1197, 1198, 1301,
- /* 820 */ 467, 1271, 413, 1321, 1321, 1556, 1016, 457, 456, 200,
- /* 830 */ 299, 71, 71, 1269, 122, 122, 122, 122, 121, 121,
- /* 840 */ 120, 120, 120, 119, 116, 448, 125, 126, 80, 1221,
- /* 850 */ 1221, 1054, 1057, 1044, 1044, 123, 123, 124, 124, 124,
- /* 860 */ 124, 413, 227, 1077, 1162, 284, 284, 423, 312, 278,
- /* 870 */ 278, 285, 285, 1423, 410, 409, 386, 1162, 569, 572,
- /* 880 */ 1162, 1200, 569, 1604, 569, 125, 126, 80, 1221, 1221,
- /* 890 */ 1054, 1057, 1044, 1044, 123, 123, 124, 124, 124, 124,
- /* 900 */ 457, 1486, 13, 13, 1540, 122, 122, 122, 122, 121,
- /* 910 */ 121, 120, 120, 120, 119, 116, 448, 201, 572, 358,
- /* 920 */ 1590, 579, 2, 1249, 844, 845, 846, 1566, 317, 1216,
- /* 930 */ 146, 6, 413, 255, 254, 253, 206, 1331, 9, 1200,
- /* 940 */ 262, 71, 71, 428, 122, 122, 122, 122, 121, 121,
- /* 950 */ 120, 120, 120, 119, 116, 448, 125, 126, 80, 1221,
- /* 960 */ 1221, 1054, 1057, 1044, 1044, 123, 123, 124, 124, 124,
- /* 970 */ 124, 572, 284, 284, 572, 1217, 413, 578, 313, 1249,
- /* 980 */ 353, 1300, 356, 423, 317, 569, 146, 495, 529, 1647,
- /* 990 */ 399, 375, 495, 1331, 70, 70, 1299, 71, 71, 240,
- /* 1000 */ 1329, 104, 80, 1221, 1221, 1054, 1057, 1044, 1044, 123,
- /* 1010 */ 123, 124, 124, 124, 124, 122, 122, 122, 122, 121,
- /* 1020 */ 121, 120, 120, 120, 119, 116, 448, 1118, 284, 284,
- /* 1030 */ 432, 452, 1529, 1217, 443, 284, 284, 1493, 1356, 311,
- /* 1040 */ 478, 569, 1119, 975, 495, 495, 217, 1267, 569, 1542,
- /* 1050 */ 572, 976, 207, 572, 1031, 240, 387, 1120, 523, 122,
- /* 1060 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116,
- /* 1070 */ 448, 1022, 107, 71, 71, 1021, 13, 13, 916, 572,
- /* 1080 */ 1499, 572, 284, 284, 97, 530, 495, 452, 917, 1330,
- /* 1090 */ 1326, 549, 413, 284, 284, 569, 151, 209, 1499, 1501,
- /* 1100 */ 262, 454, 55, 55, 56, 56, 569, 1021, 1021, 1023,
- /* 1110 */ 447, 336, 413, 531, 12, 295, 125, 126, 80, 1221,
- /* 1120 */ 1221, 1054, 1057, 1044, 1044, 123, 123, 124, 124, 124,
- /* 1130 */ 124, 351, 413, 868, 1538, 1217, 125, 126, 80, 1221,
- /* 1140 */ 1221, 1054, 1057, 1044, 1044, 123, 123, 124, 124, 124,
- /* 1150 */ 124, 1141, 1645, 478, 1645, 375, 125, 114, 80, 1221,
- /* 1160 */ 1221, 1054, 1057, 1044, 1044, 123, 123, 124, 124, 124,
- /* 1170 */ 124, 1499, 333, 478, 335, 122, 122, 122, 122, 121,
- /* 1180 */ 121, 120, 120, 120, 119, 116, 448, 203, 1423, 572,
- /* 1190 */ 1298, 868, 468, 1217, 440, 122, 122, 122, 122, 121,
- /* 1200 */ 121, 120, 120, 120, 119, 116, 448, 557, 1141, 1646,
- /* 1210 */ 543, 1646, 15, 15, 896, 122, 122, 122, 122, 121,
- /* 1220 */ 121, 120, 120, 120, 119, 116, 448, 572, 298, 542,
- /* 1230 */ 1139, 1423, 1563, 1564, 1335, 413, 6, 6, 1173, 1272,
- /* 1240 */ 419, 320, 284, 284, 1423, 512, 569, 529, 300, 461,
- /* 1250 */ 43, 43, 572, 897, 12, 569, 334, 482, 429, 411,
- /* 1260 */ 126, 80, 1221, 1221, 1054, 1057, 1044, 1044, 123, 123,
- /* 1270 */ 124, 124, 124, 124, 572, 57, 57, 288, 1196, 1423,
- /* 1280 */ 500, 462, 396, 396, 395, 273, 393, 1139, 1562, 853,
- /* 1290 */ 1173, 411, 6, 572, 321, 1162, 474, 44, 44, 1561,
- /* 1300 */ 1118, 430, 234, 6, 323, 256, 544, 256, 1162, 435,
- /* 1310 */ 572, 1162, 322, 17, 491, 1119, 58, 58, 122, 122,
- /* 1320 */ 122, 122, 121, 121, 120, 120, 120, 119, 116, 448,
- /* 1330 */ 1120, 216, 485, 59, 59, 1196, 1197, 1198, 111, 564,
- /* 1340 */ 324, 4, 236, 460, 530, 572, 237, 460, 572, 441,
- /* 1350 */ 168, 560, 424, 141, 483, 567, 572, 293, 572, 1099,
- /* 1360 */ 572, 293, 572, 1099, 535, 572, 876, 8, 60, 60,
- /* 1370 */ 235, 61, 61, 572, 418, 572, 418, 572, 449, 62,
- /* 1380 */ 62, 45, 45, 46, 46, 47, 47, 199, 49, 49,
- /* 1390 */ 561, 572, 363, 572, 100, 490, 50, 50, 63, 63,
- /* 1400 */ 64, 64, 565, 419, 539, 414, 572, 1031, 572, 538,
- /* 1410 */ 316, 563, 316, 563, 65, 65, 14, 14, 572, 1031,
- /* 1420 */ 572, 516, 936, 876, 1022, 109, 109, 935, 1021, 66,
- /* 1430 */ 66, 131, 131, 110, 455, 449, 574, 573, 420, 177,
- /* 1440 */ 1021, 132, 132, 67, 67, 572, 471, 572, 936, 475,
- /* 1450 */ 1368, 283, 226, 935, 315, 1367, 411, 572, 463, 411,
- /* 1460 */ 1021, 1021, 1023, 239, 411, 86, 213, 1354, 52, 52,
- /* 1470 */ 68, 68, 1021, 1021, 1023, 1024, 27, 1589, 1184, 451,
- /* 1480 */ 69, 69, 288, 97, 108, 1545, 106, 396, 396, 395,
- /* 1490 */ 273, 393, 572, 883, 853, 887, 572, 111, 564, 470,
- /* 1500 */ 4, 572, 152, 30, 38, 572, 1136, 234, 400, 323,
- /* 1510 */ 111, 564, 531, 4, 567, 53, 53, 322, 572, 163,
- /* 1520 */ 163, 572, 341, 472, 164, 164, 337, 567, 76, 76,
- /* 1530 */ 572, 289, 1518, 572, 31, 1517, 572, 449, 342, 487,
- /* 1540 */ 100, 54, 54, 348, 72, 72, 296, 236, 1084, 561,
- /* 1550 */ 449, 883, 1364, 134, 134, 168, 73, 73, 141, 161,
- /* 1560 */ 161, 1578, 561, 539, 572, 319, 572, 352, 540, 1013,
- /* 1570 */ 477, 261, 261, 895, 894, 235, 539, 572, 1031, 572,
- /* 1580 */ 479, 538, 261, 371, 109, 109, 525, 136, 136, 130,
- /* 1590 */ 130, 1031, 110, 370, 449, 574, 573, 109, 109, 1021,
- /* 1600 */ 162, 162, 156, 156, 572, 110, 1084, 449, 574, 573,
- /* 1610 */ 414, 355, 1021, 572, 357, 316, 563, 572, 347, 572,
- /* 1620 */ 100, 501, 361, 258, 100, 902, 903, 140, 140, 359,
- /* 1630 */ 1314, 1021, 1021, 1023, 1024, 27, 139, 139, 366, 455,
- /* 1640 */ 137, 137, 138, 138, 1021, 1021, 1023, 1024, 27, 1184,
- /* 1650 */ 451, 572, 376, 288, 111, 564, 1025, 4, 396, 396,
- /* 1660 */ 395, 273, 393, 572, 1145, 853, 572, 1080, 572, 258,
- /* 1670 */ 496, 567, 572, 211, 75, 75, 559, 966, 234, 261,
- /* 1680 */ 323, 111, 564, 933, 4, 113, 77, 77, 322, 74,
- /* 1690 */ 74, 42, 42, 1377, 449, 48, 48, 1422, 567, 978,
- /* 1700 */ 979, 1096, 1095, 1096, 1095, 866, 561, 150, 934, 1350,
- /* 1710 */ 113, 1362, 558, 1428, 1025, 1279, 1270, 1258, 236, 1257,
- /* 1720 */ 1259, 449, 1597, 1347, 308, 276, 168, 309, 11, 141,
- /* 1730 */ 397, 310, 232, 561, 1409, 1031, 339, 291, 329, 219,
- /* 1740 */ 340, 109, 109, 940, 297, 1414, 235, 345, 481, 110,
- /* 1750 */ 506, 449, 574, 573, 332, 1413, 1021, 404, 1297, 369,
- /* 1760 */ 223, 1490, 1031, 1489, 1359, 1360, 1358, 1357, 109, 109,
- /* 1770 */ 204, 1600, 1236, 562, 265, 218, 110, 205, 449, 574,
- /* 1780 */ 573, 414, 391, 1021, 1537, 179, 316, 563, 1021, 1021,
- /* 1790 */ 1023, 1024, 27, 230, 1535, 1233, 79, 564, 85, 4,
- /* 1800 */ 422, 215, 552, 81, 84, 188, 1410, 128, 1404, 550,
- /* 1810 */ 455, 35, 328, 567, 173, 1021, 1021, 1023, 1024, 27,
- /* 1820 */ 181, 1495, 1397, 331, 465, 183, 184, 185, 186, 466,
- /* 1830 */ 499, 242, 98, 402, 1416, 1418, 449, 1415, 473, 36,
- /* 1840 */ 192, 488, 405, 1506, 246, 91, 494, 196, 561, 1484,
- /* 1850 */ 350, 497, 277, 354, 248, 249, 111, 564, 1260, 4,
- /* 1860 */ 250, 407, 515, 436, 1317, 1308, 93, 1316, 1315, 887,
- /* 1870 */ 1307, 224, 1583, 567, 438, 524, 439, 1031, 263, 264,
- /* 1880 */ 442, 1615, 10, 109, 109, 1287, 408, 1614, 1286, 368,
- /* 1890 */ 1285, 110, 1613, 449, 574, 573, 449, 306, 1021, 307,
- /* 1900 */ 374, 1382, 1569, 1470, 1381, 385, 105, 314, 561, 99,
- /* 1910 */ 1568, 534, 34, 576, 1190, 272, 1340, 551, 383, 274,
- /* 1920 */ 1339, 210, 389, 390, 275, 577, 1255, 1250, 415, 165,
- /* 1930 */ 1021, 1021, 1023, 1024, 27, 147, 1522, 1031, 166, 1523,
- /* 1940 */ 416, 1521, 178, 109, 109, 1520, 304, 167, 840, 450,
- /* 1950 */ 220, 110, 221, 449, 574, 573, 212, 78, 1021, 318,
- /* 1960 */ 231, 1094, 1092, 144, 180, 326, 169, 1216, 241, 182,
- /* 1970 */ 919, 338, 238, 1108, 187, 170, 171, 425, 427, 189,
- /* 1980 */ 87, 88, 89, 90, 172, 1111, 243, 1107, 244, 158,
- /* 1990 */ 1021, 1021, 1023, 1024, 27, 18, 245, 1230, 493, 349,
- /* 2000 */ 1100, 261, 247, 193, 194, 37, 370, 855, 498, 251,
- /* 2010 */ 195, 510, 92, 19, 174, 362, 502, 20, 507, 885,
- /* 2020 */ 365, 898, 94, 305, 159, 95, 517, 96, 1178, 160,
- /* 2030 */ 1060, 1147, 39, 1146, 225, 280, 282, 970, 198, 964,
- /* 2040 */ 113, 1164, 1168, 260, 1166, 21, 1172, 7, 22, 1152,
- /* 2050 */ 33, 23, 24, 25, 1171, 546, 26, 202, 100, 102,
- /* 2060 */ 1075, 103, 1061, 1059, 1063, 1117, 1064, 1116, 266, 267,
- /* 2070 */ 28, 40, 929, 1026, 867, 112, 29, 568, 394, 143,
- /* 2080 */ 1186, 268, 176, 1185, 269, 1246, 1246, 1246, 1246, 1246,
- /* 2090 */ 1246, 1246, 1246, 1246, 1246, 1606, 1246, 1246, 1246, 1246,
- /* 2100 */ 1605,
+ /* 0 */ 580, 128, 125, 232, 1626, 553, 580, 1294, 1285, 580,
+ /* 10 */ 328, 580, 1304, 212, 580, 128, 125, 232, 582, 416,
+ /* 20 */ 582, 395, 1546, 51, 51, 527, 409, 1297, 533, 51,
+ /* 30 */ 51, 987, 51, 51, 81, 81, 1111, 61, 61, 988,
+ /* 40 */ 1111, 1296, 384, 135, 136, 90, 1232, 1232, 1067, 1070,
+ /* 50 */ 1057, 1057, 133, 133, 134, 134, 134, 134, 1581, 416,
+ /* 60 */ 287, 287, 7, 287, 287, 426, 1054, 1054, 1068, 1071,
+ /* 70 */ 289, 560, 496, 577, 528, 565, 577, 501, 565, 486,
+ /* 80 */ 534, 262, 229, 135, 136, 90, 1232, 1232, 1067, 1070,
+ /* 90 */ 1057, 1057, 133, 133, 134, 134, 134, 134, 128, 125,
+ /* 100 */ 232, 1510, 132, 132, 132, 132, 131, 131, 130, 130,
+ /* 110 */ 130, 129, 126, 454, 1208, 1259, 1, 1, 586, 2,
+ /* 120 */ 1263, 1575, 424, 1586, 383, 320, 1178, 153, 1178, 1588,
+ /* 130 */ 416, 382, 1586, 547, 1345, 330, 111, 574, 574, 574,
+ /* 140 */ 293, 1058, 132, 132, 132, 132, 131, 131, 130, 130,
+ /* 150 */ 130, 129, 126, 454, 135, 136, 90, 1232, 1232, 1067,
+ /* 160 */ 1070, 1057, 1057, 133, 133, 134, 134, 134, 134, 287,
+ /* 170 */ 287, 1208, 1209, 1208, 255, 287, 287, 514, 511, 510,
+ /* 180 */ 137, 459, 577, 212, 565, 451, 450, 509, 577, 1620,
+ /* 190 */ 565, 134, 134, 134, 134, 127, 404, 243, 132, 132,
+ /* 200 */ 132, 132, 131, 131, 130, 130, 130, 129, 126, 454,
+ /* 210 */ 282, 475, 349, 132, 132, 132, 132, 131, 131, 130,
+ /* 220 */ 130, 130, 129, 126, 454, 578, 155, 940, 940, 458,
+ /* 230 */ 227, 525, 1240, 416, 1240, 134, 134, 134, 134, 132,
+ /* 240 */ 132, 132, 132, 131, 131, 130, 130, 130, 129, 126,
+ /* 250 */ 454, 130, 130, 130, 129, 126, 454, 135, 136, 90,
+ /* 260 */ 1232, 1232, 1067, 1070, 1057, 1057, 133, 133, 134, 134,
+ /* 270 */ 134, 134, 128, 125, 232, 454, 580, 416, 401, 1253,
+ /* 280 */ 180, 92, 93, 132, 132, 132, 132, 131, 131, 130,
+ /* 290 */ 130, 130, 129, 126, 454, 385, 391, 1208, 387, 81,
+ /* 300 */ 81, 135, 136, 90, 1232, 1232, 1067, 1070, 1057, 1057,
+ /* 310 */ 133, 133, 134, 134, 134, 134, 132, 132, 132, 132,
+ /* 320 */ 131, 131, 130, 130, 130, 129, 126, 454, 131, 131,
+ /* 330 */ 130, 130, 130, 129, 126, 454, 560, 1208, 302, 319,
+ /* 340 */ 571, 121, 572, 484, 4, 559, 1153, 1661, 1632, 1661,
+ /* 350 */ 45, 128, 125, 232, 1208, 1209, 1208, 1254, 575, 1173,
+ /* 360 */ 132, 132, 132, 132, 131, 131, 130, 130, 130, 129,
+ /* 370 */ 126, 454, 1173, 287, 287, 1173, 1023, 580, 426, 1023,
+ /* 380 */ 416, 455, 1606, 586, 2, 1263, 577, 44, 565, 95,
+ /* 390 */ 320, 110, 153, 569, 1208, 1209, 1208, 526, 526, 1345,
+ /* 400 */ 81, 81, 7, 44, 135, 136, 90, 1232, 1232, 1067,
+ /* 410 */ 1070, 1057, 1057, 133, 133, 134, 134, 134, 134, 295,
+ /* 420 */ 1153, 1662, 1044, 1662, 1208, 1151, 319, 571, 119, 119,
+ /* 430 */ 347, 470, 333, 347, 287, 287, 120, 560, 455, 581,
+ /* 440 */ 455, 1173, 1173, 1032, 319, 571, 442, 577, 210, 565,
+ /* 450 */ 1343, 1455, 550, 535, 1173, 1173, 1602, 1173, 1173, 420,
+ /* 460 */ 319, 571, 243, 132, 132, 132, 132, 131, 131, 130,
+ /* 470 */ 130, 130, 129, 126, 454, 1032, 1032, 1034, 1035, 35,
+ /* 480 */ 44, 1208, 1209, 1208, 476, 287, 287, 1332, 416, 1311,
+ /* 490 */ 376, 1599, 363, 225, 458, 1208, 195, 1332, 577, 1151,
+ /* 500 */ 565, 1337, 1337, 274, 580, 1192, 580, 344, 46, 196,
+ /* 510 */ 541, 217, 135, 136, 90, 1232, 1232, 1067, 1070, 1057,
+ /* 520 */ 1057, 133, 133, 134, 134, 134, 134, 19, 19, 19,
+ /* 530 */ 19, 416, 585, 1208, 1263, 515, 1208, 319, 571, 320,
+ /* 540 */ 948, 153, 429, 495, 434, 947, 1208, 492, 1345, 1454,
+ /* 550 */ 536, 1281, 1208, 1209, 1208, 135, 136, 90, 1232, 1232,
+ /* 560 */ 1067, 1070, 1057, 1057, 133, 133, 134, 134, 134, 134,
+ /* 570 */ 579, 132, 132, 132, 132, 131, 131, 130, 130, 130,
+ /* 580 */ 129, 126, 454, 287, 287, 532, 287, 287, 376, 1599,
+ /* 590 */ 1208, 1209, 1208, 1208, 1209, 1208, 577, 490, 565, 577,
+ /* 600 */ 893, 565, 416, 1208, 1209, 1208, 890, 40, 22, 22,
+ /* 610 */ 220, 243, 529, 1453, 132, 132, 132, 132, 131, 131,
+ /* 620 */ 130, 130, 130, 129, 126, 454, 135, 136, 90, 1232,
+ /* 630 */ 1232, 1067, 1070, 1057, 1057, 133, 133, 134, 134, 134,
+ /* 640 */ 134, 416, 180, 458, 1208, 883, 255, 287, 287, 514,
+ /* 650 */ 511, 510, 376, 1599, 1572, 1335, 1335, 580, 893, 509,
+ /* 660 */ 577, 44, 565, 563, 1211, 135, 136, 90, 1232, 1232,
+ /* 670 */ 1067, 1070, 1057, 1057, 133, 133, 134, 134, 134, 134,
+ /* 680 */ 81, 81, 426, 580, 381, 132, 132, 132, 132, 131,
+ /* 690 */ 131, 130, 130, 130, 129, 126, 454, 297, 287, 287,
+ /* 700 */ 464, 1208, 1209, 1208, 1208, 538, 19, 19, 452, 452,
+ /* 710 */ 452, 577, 416, 565, 230, 440, 1191, 539, 319, 571,
+ /* 720 */ 367, 436, 1211, 1439, 132, 132, 132, 132, 131, 131,
+ /* 730 */ 130, 130, 130, 129, 126, 454, 135, 136, 90, 1232,
+ /* 740 */ 1232, 1067, 1070, 1057, 1057, 133, 133, 134, 134, 134,
+ /* 750 */ 134, 416, 211, 953, 1173, 1045, 1114, 1114, 498, 551,
+ /* 760 */ 551, 1208, 1209, 1208, 7, 543, 1574, 1173, 380, 580,
+ /* 770 */ 1173, 5, 1208, 490, 3, 135, 136, 90, 1232, 1232,
+ /* 780 */ 1067, 1070, 1057, 1057, 133, 133, 134, 134, 134, 134,
+ /* 790 */ 580, 517, 19, 19, 431, 132, 132, 132, 132, 131,
+ /* 800 */ 131, 130, 130, 130, 129, 126, 454, 305, 1208, 437,
+ /* 810 */ 225, 1208, 389, 19, 19, 273, 290, 375, 520, 370,
+ /* 820 */ 519, 260, 416, 542, 1572, 553, 1028, 366, 441, 1208,
+ /* 830 */ 1209, 1208, 906, 1556, 132, 132, 132, 132, 131, 131,
+ /* 840 */ 130, 130, 130, 129, 126, 454, 135, 136, 90, 1232,
+ /* 850 */ 1232, 1067, 1070, 1057, 1057, 133, 133, 134, 134, 134,
+ /* 860 */ 134, 416, 1439, 518, 1285, 1208, 1209, 1208, 1208, 1209,
+ /* 870 */ 1208, 907, 48, 346, 1572, 1572, 1283, 1631, 1572, 915,
+ /* 880 */ 580, 129, 126, 454, 110, 135, 136, 90, 1232, 1232,
+ /* 890 */ 1067, 1070, 1057, 1057, 133, 133, 134, 134, 134, 134,
+ /* 900 */ 265, 580, 463, 19, 19, 132, 132, 132, 132, 131,
+ /* 910 */ 131, 130, 130, 130, 129, 126, 454, 1349, 204, 580,
+ /* 920 */ 463, 462, 50, 47, 19, 19, 49, 438, 1109, 577,
+ /* 930 */ 501, 565, 416, 432, 108, 1228, 1573, 1558, 380, 205,
+ /* 940 */ 554, 554, 81, 81, 132, 132, 132, 132, 131, 131,
+ /* 950 */ 130, 130, 130, 129, 126, 454, 135, 136, 90, 1232,
+ /* 960 */ 1232, 1067, 1070, 1057, 1057, 133, 133, 134, 134, 134,
+ /* 970 */ 134, 484, 580, 1208, 580, 1545, 416, 1439, 973, 315,
+ /* 980 */ 1663, 402, 284, 501, 973, 897, 1573, 1573, 380, 380,
+ /* 990 */ 1573, 465, 380, 1228, 463, 80, 80, 81, 81, 501,
+ /* 1000 */ 378, 114, 90, 1232, 1232, 1067, 1070, 1057, 1057, 133,
+ /* 1010 */ 133, 134, 134, 134, 134, 132, 132, 132, 132, 131,
+ /* 1020 */ 131, 130, 130, 130, 129, 126, 454, 1208, 1509, 580,
+ /* 1030 */ 1208, 1209, 1208, 1370, 316, 490, 281, 281, 501, 435,
+ /* 1040 */ 561, 288, 288, 406, 1344, 475, 349, 298, 433, 577,
+ /* 1050 */ 580, 565, 81, 81, 577, 378, 565, 975, 390, 132,
+ /* 1060 */ 132, 132, 132, 131, 131, 130, 130, 130, 129, 126,
+ /* 1070 */ 454, 231, 117, 81, 81, 287, 287, 231, 287, 287,
+ /* 1080 */ 580, 1515, 580, 1340, 1208, 1209, 1208, 139, 577, 560,
+ /* 1090 */ 565, 577, 416, 565, 445, 460, 973, 213, 562, 1515,
+ /* 1100 */ 1517, 1554, 973, 143, 143, 145, 145, 1372, 314, 482,
+ /* 1110 */ 448, 974, 416, 854, 855, 856, 135, 136, 90, 1232,
+ /* 1120 */ 1232, 1067, 1070, 1057, 1057, 133, 133, 134, 134, 134,
+ /* 1130 */ 134, 361, 416, 401, 1152, 304, 135, 136, 90, 1232,
+ /* 1140 */ 1232, 1067, 1070, 1057, 1057, 133, 133, 134, 134, 134,
+ /* 1150 */ 134, 1579, 323, 6, 866, 7, 135, 124, 90, 1232,
+ /* 1160 */ 1232, 1067, 1070, 1057, 1057, 133, 133, 134, 134, 134,
+ /* 1170 */ 134, 413, 412, 1515, 212, 132, 132, 132, 132, 131,
+ /* 1180 */ 131, 130, 130, 130, 129, 126, 454, 415, 118, 1208,
+ /* 1190 */ 116, 10, 356, 265, 359, 132, 132, 132, 132, 131,
+ /* 1200 */ 131, 130, 130, 130, 129, 126, 454, 580, 324, 306,
+ /* 1210 */ 580, 306, 1254, 473, 158, 132, 132, 132, 132, 131,
+ /* 1220 */ 131, 130, 130, 130, 129, 126, 454, 207, 1228, 1130,
+ /* 1230 */ 65, 65, 474, 66, 66, 416, 451, 450, 886, 535,
+ /* 1240 */ 339, 258, 257, 256, 1131, 1237, 1208, 1209, 1208, 327,
+ /* 1250 */ 1239, 878, 159, 580, 16, 484, 1089, 1044, 1238, 1132,
+ /* 1260 */ 136, 90, 1232, 1232, 1067, 1070, 1057, 1057, 133, 133,
+ /* 1270 */ 134, 134, 134, 134, 1033, 580, 81, 81, 1032, 1044,
+ /* 1280 */ 926, 580, 467, 1240, 580, 1240, 1228, 506, 107, 1439,
+ /* 1290 */ 927, 6, 580, 414, 1502, 886, 1033, 484, 21, 21,
+ /* 1300 */ 1032, 336, 1384, 338, 53, 53, 501, 81, 81, 878,
+ /* 1310 */ 1032, 1032, 1034, 449, 259, 19, 19, 537, 132, 132,
+ /* 1320 */ 132, 132, 131, 131, 130, 130, 130, 129, 126, 454,
+ /* 1330 */ 555, 301, 1032, 1032, 1034, 107, 536, 549, 121, 572,
+ /* 1340 */ 1192, 4, 1130, 1580, 453, 580, 466, 7, 1286, 422,
+ /* 1350 */ 466, 354, 1439, 580, 522, 575, 548, 1131, 121, 572,
+ /* 1360 */ 446, 4, 1192, 468, 537, 1184, 1227, 9, 67, 67,
+ /* 1370 */ 491, 580, 1132, 303, 414, 575, 54, 54, 455, 580,
+ /* 1380 */ 123, 948, 580, 421, 580, 337, 947, 1383, 580, 236,
+ /* 1390 */ 569, 580, 1578, 568, 68, 68, 7, 580, 455, 366,
+ /* 1400 */ 423, 182, 69, 69, 545, 70, 70, 71, 71, 544,
+ /* 1410 */ 569, 72, 72, 488, 55, 55, 477, 1184, 296, 1044,
+ /* 1420 */ 56, 56, 296, 497, 545, 119, 119, 414, 1577, 546,
+ /* 1430 */ 573, 422, 7, 120, 1248, 455, 581, 455, 469, 1044,
+ /* 1440 */ 1032, 580, 1561, 556, 480, 119, 119, 531, 259, 121,
+ /* 1450 */ 572, 240, 4, 120, 580, 455, 581, 455, 580, 481,
+ /* 1460 */ 1032, 580, 156, 580, 57, 57, 575, 580, 286, 229,
+ /* 1470 */ 414, 340, 1032, 1032, 1034, 1035, 35, 59, 59, 219,
+ /* 1480 */ 987, 60, 60, 220, 73, 73, 74, 74, 988, 455,
+ /* 1490 */ 75, 75, 1032, 1032, 1034, 1035, 35, 96, 216, 291,
+ /* 1500 */ 556, 569, 1192, 318, 399, 399, 398, 276, 396, 580,
+ /* 1510 */ 489, 863, 478, 1315, 414, 545, 580, 421, 1534, 1148,
+ /* 1520 */ 544, 403, 1192, 292, 237, 1157, 326, 38, 23, 580,
+ /* 1530 */ 1044, 580, 20, 20, 325, 299, 119, 119, 164, 76,
+ /* 1540 */ 76, 1533, 121, 572, 120, 4, 455, 581, 455, 203,
+ /* 1550 */ 580, 1032, 141, 141, 142, 142, 580, 322, 39, 575,
+ /* 1560 */ 345, 1025, 110, 264, 239, 905, 904, 427, 242, 912,
+ /* 1570 */ 913, 374, 173, 77, 77, 43, 483, 1314, 264, 62,
+ /* 1580 */ 62, 373, 455, 1032, 1032, 1034, 1035, 35, 1605, 1196,
+ /* 1590 */ 457, 1096, 238, 291, 569, 163, 1313, 110, 399, 399,
+ /* 1600 */ 398, 276, 396, 990, 991, 863, 485, 350, 264, 110,
+ /* 1610 */ 1036, 493, 580, 1192, 507, 1092, 261, 261, 237, 580,
+ /* 1620 */ 326, 121, 572, 1044, 4, 351, 1380, 417, 325, 119,
+ /* 1630 */ 119, 952, 319, 571, 355, 78, 78, 120, 575, 455,
+ /* 1640 */ 581, 455, 79, 79, 1032, 358, 360, 580, 364, 1096,
+ /* 1650 */ 110, 580, 978, 946, 264, 123, 461, 362, 239, 580,
+ /* 1660 */ 523, 455, 943, 1108, 123, 1108, 173, 580, 1036, 43,
+ /* 1670 */ 63, 63, 1328, 569, 168, 168, 1032, 1032, 1034, 1035,
+ /* 1680 */ 35, 580, 169, 169, 1312, 876, 238, 157, 1593, 580,
+ /* 1690 */ 86, 86, 369, 89, 572, 379, 4, 1107, 945, 1107,
+ /* 1700 */ 123, 580, 1044, 1393, 64, 64, 1192, 1438, 119, 119,
+ /* 1710 */ 575, 580, 82, 82, 567, 580, 120, 165, 455, 581,
+ /* 1720 */ 455, 417, 1366, 1032, 144, 144, 319, 571, 580, 1378,
+ /* 1730 */ 566, 502, 279, 455, 83, 83, 1443, 580, 166, 166,
+ /* 1740 */ 580, 1293, 558, 580, 1284, 569, 580, 12, 580, 1272,
+ /* 1750 */ 461, 146, 146, 1271, 580, 1032, 1032, 1034, 1035, 35,
+ /* 1760 */ 140, 140, 1273, 167, 167, 1613, 160, 160, 1363, 150,
+ /* 1770 */ 150, 149, 149, 311, 1044, 580, 312, 147, 147, 313,
+ /* 1780 */ 119, 119, 222, 235, 580, 1192, 400, 580, 120, 580,
+ /* 1790 */ 455, 581, 455, 1196, 457, 1032, 512, 291, 148, 148,
+ /* 1800 */ 1425, 1616, 399, 399, 398, 276, 396, 85, 85, 863,
+ /* 1810 */ 87, 87, 84, 84, 557, 580, 294, 580, 1430, 342,
+ /* 1820 */ 343, 1429, 237, 300, 326, 332, 335, 1032, 1032, 1034,
+ /* 1830 */ 1035, 35, 325, 348, 407, 487, 226, 1311, 52, 52,
+ /* 1840 */ 58, 58, 372, 1375, 1506, 570, 1505, 121, 572, 221,
+ /* 1850 */ 4, 208, 268, 209, 394, 1248, 1553, 1192, 1376, 1374,
+ /* 1860 */ 1373, 1551, 239, 184, 575, 233, 425, 1245, 95, 218,
+ /* 1870 */ 173, 1511, 193, 43, 91, 94, 138, 556, 1420, 178,
+ /* 1880 */ 186, 1426, 13, 331, 471, 1413, 334, 455, 188, 189,
+ /* 1890 */ 238, 190, 191, 472, 505, 245, 108, 494, 1434, 569,
+ /* 1900 */ 249, 197, 1432, 405, 479, 1431, 408, 14, 1500, 101,
+ /* 1910 */ 1522, 500, 201, 280, 251, 503, 357, 1274, 252, 410,
+ /* 1920 */ 253, 521, 1331, 353, 1330, 417, 1329, 439, 1044, 1322,
+ /* 1930 */ 319, 571, 103, 1630, 119, 119, 897, 1321, 1629, 227,
+ /* 1940 */ 443, 1301, 120, 411, 455, 581, 455, 1300, 371, 1032,
+ /* 1950 */ 1299, 530, 1628, 1598, 461, 444, 309, 310, 377, 266,
+ /* 1960 */ 267, 1584, 1583, 447, 11, 1398, 1397, 1487, 388, 115,
+ /* 1970 */ 317, 109, 540, 214, 1354, 386, 42, 393, 1353, 583,
+ /* 1980 */ 1202, 1032, 1032, 1034, 1035, 35, 392, 278, 275, 277,
+ /* 1990 */ 584, 1269, 1264, 170, 1538, 418, 419, 1539, 1537, 171,
+ /* 2000 */ 1536, 154, 307, 223, 183, 224, 850, 456, 172, 215,
+ /* 2010 */ 88, 1192, 234, 1106, 321, 152, 1104, 329, 185, 174,
+ /* 2020 */ 1227, 187, 241, 929, 244, 341, 1120, 192, 175, 176,
+ /* 2030 */ 428, 430, 97, 194, 177, 98, 99, 100, 1123, 246,
+ /* 2040 */ 1119, 247, 161, 24, 248, 352, 1112, 264, 198, 1242,
+ /* 2050 */ 250, 499, 199, 15, 865, 504, 373, 254, 508, 513,
+ /* 2060 */ 200, 516, 102, 25, 179, 365, 26, 895, 104, 368,
+ /* 2070 */ 162, 908, 105, 308, 524, 106, 1189, 1073, 1159, 17,
+ /* 2080 */ 228, 283, 27, 1158, 285, 263, 982, 202, 976, 123,
+ /* 2090 */ 28, 1179, 1183, 29, 30, 1175, 31, 1177, 1164, 41,
+ /* 2100 */ 32, 206, 552, 33, 110, 1182, 112, 8, 113, 1087,
+ /* 2110 */ 1074, 1072, 1076, 34, 1077, 564, 1129, 269, 1128, 270,
+ /* 2120 */ 36, 18, 1198, 1037, 877, 151, 122, 37, 397, 271,
+ /* 2130 */ 272, 576, 181, 1197, 1260, 939, 1260, 1621,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 193, 193, 193, 274, 275, 276, 193, 274, 275, 276,
- /* 10 */ 193, 223, 219, 225, 206, 210, 211, 212, 193, 19,
- /* 20 */ 219, 233, 216, 216, 217, 216, 217, 193, 295, 216,
- /* 30 */ 217, 31, 193, 216, 217, 193, 228, 213, 230, 39,
- /* 40 */ 206, 216, 217, 43, 44, 45, 46, 47, 48, 49,
- /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 193, 19,
- /* 60 */ 185, 186, 187, 188, 189, 190, 253, 274, 275, 276,
- /* 70 */ 195, 193, 197, 193, 261, 274, 275, 276, 253, 204,
- /* 80 */ 238, 204, 81, 43, 44, 45, 46, 47, 48, 49,
- /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 274, 275,
- /* 100 */ 276, 262, 102, 103, 104, 105, 106, 107, 108, 109,
- /* 110 */ 110, 111, 112, 113, 239, 240, 239, 240, 210, 211,
- /* 120 */ 212, 314, 315, 314, 59, 316, 86, 252, 88, 252,
- /* 130 */ 19, 314, 315, 256, 257, 113, 25, 72, 296, 138,
- /* 140 */ 139, 266, 102, 103, 104, 105, 106, 107, 108, 109,
+ /* 0 */ 194, 276, 277, 278, 216, 194, 194, 217, 194, 194,
+ /* 10 */ 194, 194, 224, 194, 194, 276, 277, 278, 204, 19,
+ /* 20 */ 206, 202, 297, 217, 218, 205, 207, 217, 205, 217,
+ /* 30 */ 218, 31, 217, 218, 217, 218, 29, 217, 218, 39,
+ /* 40 */ 33, 217, 220, 43, 44, 45, 46, 47, 48, 49,
+ /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 312, 19,
+ /* 60 */ 240, 241, 316, 240, 241, 194, 46, 47, 48, 49,
+ /* 70 */ 22, 254, 65, 253, 254, 255, 253, 194, 255, 194,
+ /* 80 */ 263, 258, 259, 43, 44, 45, 46, 47, 48, 49,
+ /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 276, 277,
+ /* 100 */ 278, 285, 102, 103, 104, 105, 106, 107, 108, 109,
+ /* 110 */ 110, 111, 112, 113, 59, 186, 187, 188, 189, 190,
+ /* 120 */ 191, 310, 239, 317, 318, 196, 86, 198, 88, 317,
+ /* 130 */ 19, 319, 317, 318, 205, 264, 25, 211, 212, 213,
+ /* 140 */ 205, 121, 102, 103, 104, 105, 106, 107, 108, 109,
/* 150 */ 110, 111, 112, 113, 43, 44, 45, 46, 47, 48,
- /* 160 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 81,
- /* 170 */ 292, 59, 292, 298, 108, 109, 110, 111, 112, 113,
- /* 180 */ 69, 116, 117, 118, 72, 106, 107, 193, 111, 112,
- /* 190 */ 113, 54, 55, 56, 57, 58, 102, 103, 104, 105,
- /* 200 */ 106, 107, 108, 109, 110, 111, 112, 113, 120, 25,
- /* 210 */ 216, 217, 145, 102, 103, 104, 105, 106, 107, 108,
- /* 220 */ 109, 110, 111, 112, 113, 231, 138, 139, 116, 117,
- /* 230 */ 118, 164, 153, 19, 155, 54, 55, 56, 57, 102,
+ /* 160 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 240,
+ /* 170 */ 241, 116, 117, 118, 119, 240, 241, 122, 123, 124,
+ /* 180 */ 69, 298, 253, 194, 255, 106, 107, 132, 253, 141,
+ /* 190 */ 255, 54, 55, 56, 57, 58, 207, 268, 102, 103,
+ /* 200 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
+ /* 210 */ 214, 128, 129, 102, 103, 104, 105, 106, 107, 108,
+ /* 220 */ 109, 110, 111, 112, 113, 134, 25, 136, 137, 300,
+ /* 230 */ 165, 166, 153, 19, 155, 54, 55, 56, 57, 102,
/* 240 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
- /* 250 */ 113, 128, 129, 46, 47, 48, 49, 43, 44, 45,
+ /* 250 */ 113, 108, 109, 110, 111, 112, 113, 43, 44, 45,
/* 260 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
- /* 270 */ 56, 57, 216, 193, 25, 59, 193, 19, 165, 166,
- /* 280 */ 193, 67, 24, 102, 103, 104, 105, 106, 107, 108,
- /* 290 */ 109, 110, 111, 112, 113, 73, 216, 217, 59, 216,
- /* 300 */ 217, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ /* 270 */ 56, 57, 276, 277, 278, 113, 194, 19, 22, 23,
+ /* 280 */ 194, 67, 24, 102, 103, 104, 105, 106, 107, 108,
+ /* 290 */ 109, 110, 111, 112, 113, 220, 250, 59, 252, 217,
+ /* 300 */ 218, 43, 44, 45, 46, 47, 48, 49, 50, 51,
/* 310 */ 52, 53, 54, 55, 56, 57, 102, 103, 104, 105,
- /* 320 */ 106, 107, 108, 109, 110, 111, 112, 113, 121, 145,
- /* 330 */ 59, 193, 116, 117, 118, 119, 273, 204, 122, 123,
- /* 340 */ 124, 19, 20, 134, 22, 136, 137, 19, 132, 127,
- /* 350 */ 128, 129, 24, 22, 23, 116, 117, 118, 36, 193,
+ /* 320 */ 106, 107, 108, 109, 110, 111, 112, 113, 106, 107,
+ /* 330 */ 108, 109, 110, 111, 112, 113, 254, 59, 205, 138,
+ /* 340 */ 139, 19, 20, 194, 22, 263, 22, 23, 231, 25,
+ /* 350 */ 72, 276, 277, 278, 116, 117, 118, 101, 36, 76,
/* 360 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
- /* 370 */ 112, 113, 239, 240, 311, 312, 215, 106, 107, 241,
- /* 380 */ 19, 59, 216, 217, 223, 252, 115, 116, 117, 118,
- /* 390 */ 151, 120, 26, 71, 193, 308, 309, 193, 149, 128,
- /* 400 */ 313, 216, 269, 81, 43, 44, 45, 46, 47, 48,
- /* 410 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 253,
- /* 420 */ 216, 217, 100, 95, 153, 59, 155, 261, 106, 107,
- /* 430 */ 25, 193, 101, 193, 193, 231, 114, 25, 116, 117,
- /* 440 */ 118, 113, 304, 121, 193, 204, 59, 119, 120, 121,
- /* 450 */ 122, 123, 124, 125, 216, 217, 193, 216, 217, 131,
- /* 460 */ 138, 139, 230, 102, 103, 104, 105, 106, 107, 108,
+ /* 370 */ 112, 113, 89, 240, 241, 92, 73, 194, 194, 73,
+ /* 380 */ 19, 59, 188, 189, 190, 191, 253, 81, 255, 151,
+ /* 390 */ 196, 25, 198, 71, 116, 117, 118, 311, 312, 205,
+ /* 400 */ 217, 218, 316, 81, 43, 44, 45, 46, 47, 48,
+ /* 410 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 270,
+ /* 420 */ 22, 23, 100, 25, 59, 101, 138, 139, 106, 107,
+ /* 430 */ 127, 128, 129, 127, 240, 241, 114, 254, 116, 117,
+ /* 440 */ 118, 76, 76, 121, 138, 139, 263, 253, 264, 255,
+ /* 450 */ 205, 275, 87, 19, 89, 89, 194, 92, 92, 199,
+ /* 460 */ 138, 139, 268, 102, 103, 104, 105, 106, 107, 108,
/* 470 */ 109, 110, 111, 112, 113, 153, 154, 155, 156, 157,
- /* 480 */ 239, 240, 116, 117, 118, 76, 193, 23, 19, 25,
- /* 490 */ 22, 253, 23, 252, 253, 108, 87, 204, 89, 261,
- /* 500 */ 198, 92, 261, 116, 117, 118, 193, 306, 307, 216,
- /* 510 */ 217, 150, 43, 44, 45, 46, 47, 48, 49, 50,
- /* 520 */ 51, 52, 53, 54, 55, 56, 57, 59, 193, 216,
- /* 530 */ 217, 19, 239, 240, 283, 23, 106, 107, 108, 109,
- /* 540 */ 110, 111, 112, 113, 73, 252, 253, 142, 308, 309,
- /* 550 */ 138, 139, 81, 313, 145, 43, 44, 45, 46, 47,
+ /* 480 */ 81, 116, 117, 118, 129, 240, 241, 224, 19, 226,
+ /* 490 */ 314, 315, 23, 25, 300, 59, 22, 234, 253, 101,
+ /* 500 */ 255, 236, 237, 26, 194, 183, 194, 152, 72, 22,
+ /* 510 */ 145, 150, 43, 44, 45, 46, 47, 48, 49, 50,
+ /* 520 */ 51, 52, 53, 54, 55, 56, 57, 217, 218, 217,
+ /* 530 */ 218, 19, 189, 59, 191, 23, 59, 138, 139, 196,
+ /* 540 */ 135, 198, 232, 283, 232, 140, 59, 287, 205, 275,
+ /* 550 */ 116, 205, 116, 117, 118, 43, 44, 45, 46, 47,
/* 560 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 570 */ 307, 102, 103, 104, 105, 106, 107, 108, 109, 110,
- /* 580 */ 111, 112, 113, 281, 116, 117, 118, 285, 23, 193,
- /* 590 */ 25, 119, 59, 193, 122, 123, 124, 59, 127, 203,
- /* 600 */ 59, 205, 19, 268, 132, 25, 23, 22, 193, 138,
- /* 610 */ 139, 249, 204, 251, 102, 103, 104, 105, 106, 107,
+ /* 570 */ 194, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+ /* 580 */ 111, 112, 113, 240, 241, 194, 240, 241, 314, 315,
+ /* 590 */ 116, 117, 118, 116, 117, 118, 253, 194, 255, 253,
+ /* 600 */ 59, 255, 19, 116, 117, 118, 23, 22, 217, 218,
+ /* 610 */ 142, 268, 205, 275, 102, 103, 104, 105, 106, 107,
/* 620 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
/* 630 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 640 */ 57, 19, 22, 23, 59, 23, 25, 239, 240, 116,
- /* 650 */ 117, 118, 193, 11, 116, 117, 118, 116, 117, 118,
- /* 660 */ 252, 269, 22, 193, 15, 43, 44, 45, 46, 47,
+ /* 640 */ 57, 19, 194, 300, 59, 23, 119, 240, 241, 122,
+ /* 650 */ 123, 124, 314, 315, 194, 236, 237, 194, 117, 132,
+ /* 660 */ 253, 81, 255, 205, 59, 43, 44, 45, 46, 47,
/* 670 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 680 */ 273, 143, 193, 118, 143, 102, 103, 104, 105, 106,
- /* 690 */ 107, 108, 109, 110, 111, 112, 113, 76, 118, 59,
- /* 700 */ 241, 116, 117, 118, 304, 216, 217, 292, 143, 60,
- /* 710 */ 89, 241, 19, 92, 193, 193, 23, 22, 311, 312,
- /* 720 */ 231, 101, 22, 143, 102, 103, 104, 105, 106, 107,
+ /* 680 */ 217, 218, 194, 194, 194, 102, 103, 104, 105, 106,
+ /* 690 */ 107, 108, 109, 110, 111, 112, 113, 294, 240, 241,
+ /* 700 */ 120, 116, 117, 118, 59, 194, 217, 218, 211, 212,
+ /* 710 */ 213, 253, 19, 255, 194, 19, 23, 254, 138, 139,
+ /* 720 */ 24, 232, 117, 194, 102, 103, 104, 105, 106, 107,
/* 730 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
/* 740 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 750 */ 57, 19, 193, 193, 59, 23, 116, 117, 118, 59,
- /* 760 */ 201, 21, 241, 304, 22, 206, 127, 128, 129, 193,
- /* 770 */ 128, 129, 235, 236, 304, 43, 44, 45, 46, 47,
+ /* 750 */ 57, 19, 264, 108, 76, 23, 127, 128, 129, 311,
+ /* 760 */ 312, 116, 117, 118, 316, 87, 306, 89, 308, 194,
+ /* 770 */ 92, 22, 59, 194, 22, 43, 44, 45, 46, 47,
/* 780 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 790 */ 22, 193, 216, 217, 193, 102, 103, 104, 105, 106,
- /* 800 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 193,
- /* 810 */ 193, 116, 117, 118, 216, 217, 116, 117, 118, 226,
- /* 820 */ 80, 193, 19, 235, 236, 304, 23, 211, 212, 231,
- /* 830 */ 204, 216, 217, 205, 102, 103, 104, 105, 106, 107,
+ /* 790 */ 194, 95, 217, 218, 265, 102, 103, 104, 105, 106,
+ /* 800 */ 107, 108, 109, 110, 111, 112, 113, 232, 59, 113,
+ /* 810 */ 25, 59, 194, 217, 218, 119, 120, 121, 122, 123,
+ /* 820 */ 124, 125, 19, 145, 194, 194, 23, 131, 232, 116,
+ /* 830 */ 117, 118, 35, 194, 102, 103, 104, 105, 106, 107,
/* 840 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
/* 850 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 860 */ 57, 19, 193, 123, 76, 239, 240, 193, 253, 239,
- /* 870 */ 240, 239, 240, 193, 106, 107, 193, 89, 252, 193,
- /* 880 */ 92, 59, 252, 141, 252, 43, 44, 45, 46, 47,
+ /* 860 */ 57, 19, 194, 66, 194, 116, 117, 118, 116, 117,
+ /* 870 */ 118, 74, 242, 294, 194, 194, 206, 23, 194, 25,
+ /* 880 */ 194, 111, 112, 113, 25, 43, 44, 45, 46, 47,
/* 890 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 900 */ 284, 161, 216, 217, 193, 102, 103, 104, 105, 106,
- /* 910 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 16,
- /* 920 */ 187, 188, 189, 190, 7, 8, 9, 309, 195, 25,
- /* 930 */ 197, 313, 19, 127, 128, 129, 262, 204, 22, 117,
- /* 940 */ 24, 216, 217, 263, 102, 103, 104, 105, 106, 107,
+ /* 900 */ 24, 194, 194, 217, 218, 102, 103, 104, 105, 106,
+ /* 910 */ 107, 108, 109, 110, 111, 112, 113, 241, 232, 194,
+ /* 920 */ 212, 213, 242, 242, 217, 218, 242, 130, 11, 253,
+ /* 930 */ 194, 255, 19, 265, 149, 59, 306, 194, 308, 232,
+ /* 940 */ 309, 310, 217, 218, 102, 103, 104, 105, 106, 107,
/* 950 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
/* 960 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 970 */ 57, 193, 239, 240, 193, 59, 19, 188, 253, 190,
- /* 980 */ 77, 226, 79, 193, 195, 252, 197, 193, 19, 301,
- /* 990 */ 302, 193, 193, 204, 216, 217, 226, 216, 217, 266,
- /* 1000 */ 204, 159, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 970 */ 57, 194, 194, 59, 194, 239, 19, 194, 25, 254,
+ /* 980 */ 303, 304, 23, 194, 25, 126, 306, 306, 308, 308,
+ /* 990 */ 306, 271, 308, 117, 286, 217, 218, 217, 218, 194,
+ /* 1000 */ 194, 159, 45, 46, 47, 48, 49, 50, 51, 52,
/* 1010 */ 53, 54, 55, 56, 57, 102, 103, 104, 105, 106,
- /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 12, 239, 240,
- /* 1030 */ 232, 298, 238, 117, 253, 239, 240, 238, 259, 260,
- /* 1040 */ 193, 252, 27, 31, 193, 193, 142, 204, 252, 193,
- /* 1050 */ 193, 39, 262, 193, 100, 266, 278, 42, 204, 102,
+ /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 59, 239, 194,
+ /* 1030 */ 116, 117, 118, 260, 254, 194, 240, 241, 194, 233,
+ /* 1040 */ 205, 240, 241, 205, 239, 128, 129, 270, 265, 253,
+ /* 1050 */ 194, 255, 217, 218, 253, 194, 255, 143, 280, 102,
/* 1060 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
- /* 1070 */ 113, 117, 159, 216, 217, 121, 216, 217, 63, 193,
- /* 1080 */ 193, 193, 239, 240, 115, 116, 193, 298, 73, 238,
- /* 1090 */ 238, 231, 19, 239, 240, 252, 22, 24, 211, 212,
- /* 1100 */ 24, 193, 216, 217, 216, 217, 252, 153, 154, 155,
- /* 1110 */ 253, 16, 19, 144, 213, 268, 43, 44, 45, 46,
+ /* 1070 */ 113, 118, 159, 217, 218, 240, 241, 118, 240, 241,
+ /* 1080 */ 194, 194, 194, 239, 116, 117, 118, 22, 253, 254,
+ /* 1090 */ 255, 253, 19, 255, 233, 194, 143, 24, 263, 212,
+ /* 1100 */ 213, 194, 143, 217, 218, 217, 218, 261, 262, 271,
+ /* 1110 */ 254, 143, 19, 7, 8, 9, 43, 44, 45, 46,
/* 1120 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1130 */ 57, 238, 19, 59, 193, 59, 43, 44, 45, 46,
+ /* 1130 */ 57, 16, 19, 22, 23, 294, 43, 44, 45, 46,
/* 1140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1150 */ 57, 22, 23, 193, 25, 193, 43, 44, 45, 46,
+ /* 1150 */ 57, 312, 194, 214, 21, 316, 43, 44, 45, 46,
/* 1160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1170 */ 57, 284, 77, 193, 79, 102, 103, 104, 105, 106,
- /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 286, 193, 193,
- /* 1190 */ 193, 117, 291, 117, 232, 102, 103, 104, 105, 106,
- /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 204, 22, 23,
- /* 1210 */ 66, 25, 216, 217, 35, 102, 103, 104, 105, 106,
- /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 193, 268, 85,
- /* 1230 */ 101, 193, 309, 309, 240, 19, 313, 313, 94, 208,
- /* 1240 */ 209, 193, 239, 240, 193, 66, 252, 19, 268, 244,
- /* 1250 */ 216, 217, 193, 74, 213, 252, 161, 19, 263, 254,
+ /* 1170 */ 57, 106, 107, 286, 194, 102, 103, 104, 105, 106,
+ /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 207, 158, 59,
+ /* 1190 */ 160, 22, 77, 24, 79, 102, 103, 104, 105, 106,
+ /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 194, 194, 229,
+ /* 1210 */ 194, 231, 101, 80, 22, 102, 103, 104, 105, 106,
+ /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 288, 59, 12,
+ /* 1230 */ 217, 218, 293, 217, 218, 19, 106, 107, 59, 19,
+ /* 1240 */ 16, 127, 128, 129, 27, 115, 116, 117, 118, 194,
+ /* 1250 */ 120, 59, 22, 194, 24, 194, 123, 100, 128, 42,
/* 1260 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 1270 */ 54, 55, 56, 57, 193, 216, 217, 5, 59, 193,
- /* 1280 */ 19, 244, 10, 11, 12, 13, 14, 101, 309, 17,
- /* 1290 */ 146, 254, 313, 193, 193, 76, 115, 216, 217, 309,
- /* 1300 */ 12, 263, 30, 313, 32, 46, 87, 46, 89, 130,
- /* 1310 */ 193, 92, 40, 22, 263, 27, 216, 217, 102, 103,
+ /* 1270 */ 54, 55, 56, 57, 117, 194, 217, 218, 121, 100,
+ /* 1280 */ 63, 194, 245, 153, 194, 155, 117, 19, 115, 194,
+ /* 1290 */ 73, 214, 194, 256, 161, 116, 117, 194, 217, 218,
+ /* 1300 */ 121, 77, 194, 79, 217, 218, 194, 217, 218, 117,
+ /* 1310 */ 153, 154, 155, 254, 46, 217, 218, 144, 102, 103,
/* 1320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
- /* 1330 */ 42, 150, 291, 216, 217, 116, 117, 118, 19, 20,
- /* 1340 */ 193, 22, 70, 260, 116, 193, 24, 264, 193, 263,
- /* 1350 */ 78, 63, 61, 81, 116, 36, 193, 260, 193, 29,
- /* 1360 */ 193, 264, 193, 33, 145, 193, 59, 48, 216, 217,
- /* 1370 */ 98, 216, 217, 193, 115, 193, 115, 193, 59, 216,
- /* 1380 */ 217, 216, 217, 216, 217, 216, 217, 255, 216, 217,
- /* 1390 */ 71, 193, 131, 193, 25, 65, 216, 217, 216, 217,
- /* 1400 */ 216, 217, 208, 209, 85, 133, 193, 100, 193, 90,
- /* 1410 */ 138, 139, 138, 139, 216, 217, 216, 217, 193, 100,
- /* 1420 */ 193, 108, 135, 116, 117, 106, 107, 140, 121, 216,
- /* 1430 */ 217, 216, 217, 114, 162, 116, 117, 118, 299, 300,
- /* 1440 */ 121, 216, 217, 216, 217, 193, 244, 193, 135, 244,
- /* 1450 */ 193, 256, 257, 140, 244, 193, 254, 193, 193, 254,
- /* 1460 */ 153, 154, 155, 141, 254, 149, 150, 258, 216, 217,
- /* 1470 */ 216, 217, 153, 154, 155, 156, 157, 0, 1, 2,
- /* 1480 */ 216, 217, 5, 115, 158, 193, 160, 10, 11, 12,
- /* 1490 */ 13, 14, 193, 59, 17, 126, 193, 19, 20, 129,
- /* 1500 */ 22, 193, 22, 22, 24, 193, 23, 30, 25, 32,
- /* 1510 */ 19, 20, 144, 22, 36, 216, 217, 40, 193, 216,
- /* 1520 */ 217, 193, 152, 129, 216, 217, 193, 36, 216, 217,
- /* 1530 */ 193, 99, 193, 193, 53, 193, 193, 59, 23, 193,
- /* 1540 */ 25, 216, 217, 193, 216, 217, 152, 70, 59, 71,
- /* 1550 */ 59, 117, 193, 216, 217, 78, 216, 217, 81, 216,
- /* 1560 */ 217, 318, 71, 85, 193, 133, 193, 193, 90, 23,
- /* 1570 */ 23, 25, 25, 120, 121, 98, 85, 193, 100, 193,
- /* 1580 */ 23, 90, 25, 121, 106, 107, 19, 216, 217, 216,
- /* 1590 */ 217, 100, 114, 131, 116, 117, 118, 106, 107, 121,
- /* 1600 */ 216, 217, 216, 217, 193, 114, 117, 116, 117, 118,
- /* 1610 */ 133, 193, 121, 193, 193, 138, 139, 193, 23, 193,
- /* 1620 */ 25, 23, 23, 25, 25, 7, 8, 216, 217, 193,
- /* 1630 */ 193, 153, 154, 155, 156, 157, 216, 217, 193, 162,
- /* 1640 */ 216, 217, 216, 217, 153, 154, 155, 156, 157, 1,
- /* 1650 */ 2, 193, 193, 5, 19, 20, 59, 22, 10, 11,
- /* 1660 */ 12, 13, 14, 193, 97, 17, 193, 23, 193, 25,
- /* 1670 */ 288, 36, 193, 242, 216, 217, 236, 23, 30, 25,
- /* 1680 */ 32, 19, 20, 23, 22, 25, 216, 217, 40, 216,
- /* 1690 */ 217, 216, 217, 193, 59, 216, 217, 193, 36, 83,
- /* 1700 */ 84, 153, 153, 155, 155, 23, 71, 25, 23, 193,
- /* 1710 */ 25, 193, 193, 193, 117, 193, 193, 193, 70, 193,
- /* 1720 */ 193, 59, 193, 255, 255, 287, 78, 255, 243, 81,
- /* 1730 */ 191, 255, 297, 71, 271, 100, 293, 245, 267, 214,
- /* 1740 */ 246, 106, 107, 108, 246, 271, 98, 245, 293, 114,
- /* 1750 */ 220, 116, 117, 118, 267, 271, 121, 271, 225, 219,
- /* 1760 */ 229, 219, 100, 219, 259, 259, 259, 259, 106, 107,
- /* 1770 */ 249, 196, 60, 280, 141, 243, 114, 249, 116, 117,
- /* 1780 */ 118, 133, 245, 121, 200, 297, 138, 139, 153, 154,
- /* 1790 */ 155, 156, 157, 297, 200, 38, 19, 20, 151, 22,
- /* 1800 */ 200, 150, 140, 294, 294, 22, 272, 148, 250, 145,
- /* 1810 */ 162, 270, 249, 36, 43, 153, 154, 155, 156, 157,
- /* 1820 */ 234, 283, 250, 249, 18, 237, 237, 237, 237, 200,
- /* 1830 */ 18, 199, 149, 246, 272, 234, 59, 272, 246, 270,
- /* 1840 */ 234, 200, 246, 290, 199, 158, 62, 22, 71, 246,
- /* 1850 */ 289, 221, 200, 200, 199, 199, 19, 20, 200, 22,
- /* 1860 */ 199, 221, 115, 64, 218, 227, 22, 218, 218, 126,
- /* 1870 */ 227, 165, 312, 36, 24, 305, 113, 100, 200, 91,
- /* 1880 */ 82, 224, 22, 106, 107, 218, 221, 224, 220, 218,
- /* 1890 */ 218, 114, 218, 116, 117, 118, 59, 282, 121, 282,
- /* 1900 */ 221, 265, 317, 277, 265, 200, 158, 279, 71, 147,
- /* 1910 */ 317, 146, 25, 202, 13, 194, 250, 140, 249, 194,
- /* 1920 */ 250, 248, 247, 246, 6, 192, 192, 192, 303, 207,
- /* 1930 */ 153, 154, 155, 156, 157, 222, 213, 100, 207, 213,
- /* 1940 */ 303, 213, 300, 106, 107, 213, 222, 207, 4, 3,
- /* 1950 */ 214, 114, 214, 116, 117, 118, 22, 213, 121, 163,
- /* 1960 */ 15, 23, 23, 16, 151, 139, 130, 25, 144, 142,
- /* 1970 */ 20, 16, 24, 1, 142, 130, 130, 61, 37, 151,
- /* 1980 */ 53, 53, 53, 53, 130, 116, 34, 1, 141, 5,
- /* 1990 */ 153, 154, 155, 156, 157, 22, 115, 75, 41, 161,
- /* 2000 */ 68, 25, 141, 68, 115, 24, 131, 20, 19, 125,
- /* 2010 */ 22, 96, 22, 22, 37, 23, 67, 22, 67, 59,
- /* 2020 */ 24, 28, 22, 67, 23, 149, 22, 25, 23, 23,
- /* 2030 */ 23, 23, 22, 97, 141, 23, 23, 116, 22, 143,
- /* 2040 */ 25, 88, 75, 34, 86, 34, 75, 44, 34, 23,
- /* 2050 */ 22, 34, 34, 34, 93, 24, 34, 25, 25, 142,
- /* 2060 */ 23, 142, 23, 23, 23, 23, 11, 23, 25, 22,
- /* 2070 */ 22, 22, 135, 23, 23, 22, 22, 25, 15, 23,
- /* 2080 */ 1, 141, 25, 1, 141, 319, 319, 319, 319, 319,
- /* 2090 */ 319, 319, 319, 319, 319, 141, 319, 319, 319, 319,
- /* 2100 */ 141, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2110 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2120 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2130 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2140 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2150 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2160 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2170 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2180 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2190 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2200 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2210 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2220 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2230 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2240 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2250 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2260 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2270 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2280 */ 319, 319, 319, 319, 319, 319,
+ /* 1330 */ 232, 270, 153, 154, 155, 115, 116, 66, 19, 20,
+ /* 1340 */ 183, 22, 12, 312, 254, 194, 262, 316, 209, 210,
+ /* 1350 */ 266, 239, 194, 194, 108, 36, 85, 27, 19, 20,
+ /* 1360 */ 265, 22, 183, 245, 144, 94, 25, 48, 217, 218,
+ /* 1370 */ 293, 194, 42, 270, 256, 36, 217, 218, 59, 194,
+ /* 1380 */ 25, 135, 194, 115, 194, 161, 140, 194, 194, 15,
+ /* 1390 */ 71, 194, 312, 63, 217, 218, 316, 194, 59, 131,
+ /* 1400 */ 301, 302, 217, 218, 85, 217, 218, 217, 218, 90,
+ /* 1410 */ 71, 217, 218, 19, 217, 218, 245, 146, 262, 100,
+ /* 1420 */ 217, 218, 266, 265, 85, 106, 107, 256, 312, 90,
+ /* 1430 */ 209, 210, 316, 114, 60, 116, 117, 118, 194, 100,
+ /* 1440 */ 121, 194, 194, 145, 115, 106, 107, 19, 46, 19,
+ /* 1450 */ 20, 24, 22, 114, 194, 116, 117, 118, 194, 245,
+ /* 1460 */ 121, 194, 164, 194, 217, 218, 36, 194, 258, 259,
+ /* 1470 */ 256, 194, 153, 154, 155, 156, 157, 217, 218, 150,
+ /* 1480 */ 31, 217, 218, 142, 217, 218, 217, 218, 39, 59,
+ /* 1490 */ 217, 218, 153, 154, 155, 156, 157, 149, 150, 5,
+ /* 1500 */ 145, 71, 183, 245, 10, 11, 12, 13, 14, 194,
+ /* 1510 */ 116, 17, 129, 227, 256, 85, 194, 115, 194, 23,
+ /* 1520 */ 90, 25, 183, 99, 30, 97, 32, 22, 22, 194,
+ /* 1530 */ 100, 194, 217, 218, 40, 152, 106, 107, 23, 217,
+ /* 1540 */ 218, 194, 19, 20, 114, 22, 116, 117, 118, 257,
+ /* 1550 */ 194, 121, 217, 218, 217, 218, 194, 133, 53, 36,
+ /* 1560 */ 23, 23, 25, 25, 70, 120, 121, 61, 141, 7,
+ /* 1570 */ 8, 121, 78, 217, 218, 81, 23, 227, 25, 217,
+ /* 1580 */ 218, 131, 59, 153, 154, 155, 156, 157, 0, 1,
+ /* 1590 */ 2, 59, 98, 5, 71, 23, 227, 25, 10, 11,
+ /* 1600 */ 12, 13, 14, 83, 84, 17, 23, 23, 25, 25,
+ /* 1610 */ 59, 194, 194, 183, 23, 23, 25, 25, 30, 194,
+ /* 1620 */ 32, 19, 20, 100, 22, 194, 194, 133, 40, 106,
+ /* 1630 */ 107, 108, 138, 139, 194, 217, 218, 114, 36, 116,
+ /* 1640 */ 117, 118, 217, 218, 121, 194, 194, 194, 23, 117,
+ /* 1650 */ 25, 194, 23, 23, 25, 25, 162, 194, 70, 194,
+ /* 1660 */ 145, 59, 23, 153, 25, 155, 78, 194, 117, 81,
+ /* 1670 */ 217, 218, 194, 71, 217, 218, 153, 154, 155, 156,
+ /* 1680 */ 157, 194, 217, 218, 194, 23, 98, 25, 321, 194,
+ /* 1690 */ 217, 218, 194, 19, 20, 194, 22, 153, 23, 155,
+ /* 1700 */ 25, 194, 100, 194, 217, 218, 183, 194, 106, 107,
+ /* 1710 */ 36, 194, 217, 218, 237, 194, 114, 243, 116, 117,
+ /* 1720 */ 118, 133, 194, 121, 217, 218, 138, 139, 194, 194,
+ /* 1730 */ 194, 290, 289, 59, 217, 218, 194, 194, 217, 218,
+ /* 1740 */ 194, 194, 140, 194, 194, 71, 194, 244, 194, 194,
+ /* 1750 */ 162, 217, 218, 194, 194, 153, 154, 155, 156, 157,
+ /* 1760 */ 217, 218, 194, 217, 218, 194, 217, 218, 257, 217,
+ /* 1770 */ 218, 217, 218, 257, 100, 194, 257, 217, 218, 257,
+ /* 1780 */ 106, 107, 215, 299, 194, 183, 192, 194, 114, 194,
+ /* 1790 */ 116, 117, 118, 1, 2, 121, 221, 5, 217, 218,
+ /* 1800 */ 273, 197, 10, 11, 12, 13, 14, 217, 218, 17,
+ /* 1810 */ 217, 218, 217, 218, 140, 194, 246, 194, 273, 295,
+ /* 1820 */ 247, 273, 30, 247, 32, 269, 269, 153, 154, 155,
+ /* 1830 */ 156, 157, 40, 246, 273, 295, 230, 226, 217, 218,
+ /* 1840 */ 217, 218, 220, 261, 220, 282, 220, 19, 20, 244,
+ /* 1850 */ 22, 250, 141, 250, 246, 60, 201, 183, 261, 261,
+ /* 1860 */ 261, 201, 70, 299, 36, 299, 201, 38, 151, 150,
+ /* 1870 */ 78, 285, 22, 81, 296, 296, 148, 145, 251, 43,
+ /* 1880 */ 235, 274, 272, 250, 18, 251, 250, 59, 238, 238,
+ /* 1890 */ 98, 238, 238, 201, 18, 200, 149, 201, 235, 71,
+ /* 1900 */ 200, 235, 274, 247, 247, 274, 247, 272, 247, 158,
+ /* 1910 */ 292, 62, 22, 201, 200, 222, 201, 201, 200, 222,
+ /* 1920 */ 200, 115, 219, 291, 219, 133, 219, 64, 100, 228,
+ /* 1930 */ 138, 139, 22, 225, 106, 107, 126, 228, 225, 165,
+ /* 1940 */ 24, 219, 114, 222, 116, 117, 118, 221, 219, 121,
+ /* 1950 */ 219, 307, 219, 315, 162, 113, 284, 284, 222, 201,
+ /* 1960 */ 91, 320, 320, 82, 22, 267, 267, 279, 201, 158,
+ /* 1970 */ 281, 147, 146, 249, 251, 250, 25, 247, 251, 203,
+ /* 1980 */ 13, 153, 154, 155, 156, 157, 248, 6, 195, 195,
+ /* 1990 */ 193, 193, 193, 208, 214, 305, 305, 214, 214, 208,
+ /* 2000 */ 214, 223, 223, 215, 302, 215, 4, 3, 208, 22,
+ /* 2010 */ 214, 183, 15, 23, 163, 16, 23, 139, 151, 130,
+ /* 2020 */ 25, 142, 24, 20, 144, 16, 1, 142, 130, 130,
+ /* 2030 */ 61, 37, 53, 151, 130, 53, 53, 53, 116, 34,
+ /* 2040 */ 1, 141, 5, 22, 115, 161, 68, 25, 68, 75,
+ /* 2050 */ 141, 41, 115, 24, 20, 19, 131, 125, 67, 67,
+ /* 2060 */ 22, 96, 22, 22, 37, 23, 22, 59, 22, 24,
+ /* 2070 */ 23, 28, 149, 67, 22, 25, 23, 23, 23, 22,
+ /* 2080 */ 141, 23, 34, 97, 23, 34, 116, 22, 143, 25,
+ /* 2090 */ 34, 75, 75, 34, 34, 88, 34, 86, 23, 22,
+ /* 2100 */ 34, 25, 24, 34, 25, 93, 142, 44, 142, 23,
+ /* 2110 */ 23, 23, 23, 22, 11, 25, 23, 25, 23, 22,
+ /* 2120 */ 22, 22, 1, 23, 23, 23, 22, 22, 15, 141,
+ /* 2130 */ 141, 25, 25, 1, 322, 135, 322, 141, 322, 322,
+ /* 2140 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2150 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2160 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2170 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2180 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2190 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2200 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2210 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2220 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2230 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2240 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2250 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2260 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2270 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2280 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2290 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2300 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2310 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2320 */ 322, 322, 322, 322,
};
-#define YY_SHIFT_COUNT (579)
+#define YY_SHIFT_COUNT (586)
#define YY_SHIFT_MIN (0)
-#define YY_SHIFT_MAX (2082)
+#define YY_SHIFT_MAX (2132)
static const unsigned short int yy_shift_ofst[] = {
- /* 0 */ 1648, 1477, 1272, 322, 322, 1, 1319, 1478, 1491, 1837,
- /* 10 */ 1837, 1837, 471, 0, 0, 214, 1093, 1837, 1837, 1837,
- /* 20 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 30 */ 271, 271, 1219, 1219, 216, 88, 1, 1, 1, 1,
- /* 40 */ 1, 40, 111, 258, 361, 469, 512, 583, 622, 693,
- /* 50 */ 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, 1093,
- /* 60 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093,
- /* 70 */ 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1635, 1662,
- /* 80 */ 1777, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 90 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 100 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 110 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 120 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 130 */ 137, 181, 181, 181, 181, 181, 181, 181, 94, 430,
- /* 140 */ 66, 65, 112, 366, 533, 533, 740, 1261, 533, 533,
- /* 150 */ 79, 79, 533, 412, 412, 412, 77, 412, 123, 113,
- /* 160 */ 113, 22, 22, 2101, 2101, 328, 328, 328, 239, 468,
- /* 170 */ 468, 468, 468, 1015, 1015, 409, 366, 1129, 1186, 533,
- /* 180 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533,
- /* 190 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 969,
- /* 200 */ 621, 621, 533, 642, 788, 788, 1228, 1228, 822, 822,
- /* 210 */ 67, 1274, 2101, 2101, 2101, 2101, 2101, 2101, 2101, 1307,
- /* 220 */ 954, 954, 585, 472, 640, 387, 695, 538, 541, 700,
- /* 230 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533,
- /* 240 */ 222, 533, 533, 533, 533, 533, 533, 533, 533, 533,
- /* 250 */ 533, 533, 533, 1179, 1179, 1179, 533, 533, 533, 565,
- /* 260 */ 533, 533, 533, 916, 1144, 533, 533, 1288, 533, 533,
- /* 270 */ 533, 533, 533, 533, 533, 533, 639, 1330, 209, 1076,
- /* 280 */ 1076, 1076, 1076, 580, 209, 209, 1313, 768, 917, 649,
- /* 290 */ 1181, 1316, 405, 1316, 1238, 249, 1181, 1181, 249, 1181,
- /* 300 */ 405, 1238, 1369, 464, 1259, 1012, 1012, 1012, 1368, 1368,
- /* 310 */ 1368, 1368, 184, 184, 1326, 904, 1287, 1480, 1712, 1712,
- /* 320 */ 1633, 1633, 1757, 1757, 1633, 1647, 1651, 1783, 1659, 1664,
- /* 330 */ 1771, 1659, 1664, 1806, 1806, 1806, 1806, 1633, 1812, 1683,
- /* 340 */ 1651, 1651, 1683, 1783, 1771, 1683, 1771, 1683, 1633, 1812,
- /* 350 */ 1687, 1784, 1633, 1812, 1825, 1633, 1812, 1633, 1812, 1825,
- /* 360 */ 1747, 1747, 1747, 1799, 1844, 1844, 1825, 1747, 1743, 1747,
- /* 370 */ 1799, 1747, 1747, 1706, 1850, 1763, 1763, 1825, 1633, 1788,
- /* 380 */ 1788, 1798, 1798, 1659, 1664, 1860, 1633, 1748, 1659, 1762,
- /* 390 */ 1765, 1683, 1887, 1901, 1901, 1918, 1918, 1918, 2101, 2101,
- /* 400 */ 2101, 2101, 2101, 2101, 2101, 2101, 2101, 2101, 2101, 2101,
- /* 410 */ 2101, 2101, 2101, 207, 1095, 331, 620, 903, 806, 1074,
- /* 420 */ 1483, 1432, 1481, 1322, 1370, 1394, 1515, 1291, 1546, 1547,
- /* 430 */ 1557, 1595, 1598, 1599, 1434, 1453, 1618, 1462, 1567, 1489,
- /* 440 */ 1644, 1654, 1616, 1660, 1548, 1549, 1682, 1685, 1597, 742,
- /* 450 */ 1944, 1946, 1934, 1796, 1945, 1947, 1938, 1939, 1826, 1813,
- /* 460 */ 1836, 1942, 1942, 1948, 1827, 1950, 1824, 1955, 1972, 1832,
- /* 470 */ 1845, 1942, 1846, 1916, 1941, 1942, 1828, 1927, 1928, 1929,
- /* 480 */ 1930, 1854, 1869, 1952, 1847, 1986, 1984, 1973, 1881, 1838,
- /* 490 */ 1932, 1976, 1935, 1922, 1957, 1861, 1889, 1981, 1987, 1989,
- /* 500 */ 1875, 1884, 1988, 1949, 1990, 1991, 1992, 1995, 1951, 1960,
- /* 510 */ 1996, 1915, 1993, 2000, 1956, 1977, 2001, 1876, 2004, 2005,
- /* 520 */ 2006, 2007, 2002, 2008, 2010, 1936, 1893, 2012, 2013, 1921,
- /* 530 */ 2009, 2016, 1896, 2015, 2011, 2014, 2017, 2018, 1953, 1967,
- /* 540 */ 1958, 2003, 1971, 1961, 2019, 2026, 2028, 2031, 2032, 2033,
- /* 550 */ 2022, 1917, 1919, 2037, 2015, 2039, 2040, 2041, 2042, 2043,
- /* 560 */ 2044, 2047, 2055, 2048, 2049, 2050, 2051, 2053, 2054, 2052,
- /* 570 */ 1937, 1940, 1943, 1954, 1959, 2057, 2056, 2063, 2079, 2082,
+ /* 0 */ 1792, 1588, 1494, 322, 322, 399, 306, 1319, 1339, 1430,
+ /* 10 */ 1828, 1828, 1828, 580, 399, 399, 399, 399, 399, 0,
+ /* 20 */ 0, 214, 1093, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
+ /* 30 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1130, 1130,
+ /* 40 */ 365, 365, 55, 278, 436, 713, 713, 201, 201, 201,
+ /* 50 */ 201, 40, 111, 258, 361, 469, 512, 583, 622, 693,
+ /* 60 */ 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, 1093,
+ /* 70 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093,
+ /* 80 */ 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1523, 1602,
+ /* 90 */ 1674, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
+ /* 100 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
+ /* 110 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
+ /* 120 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
+ /* 130 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
+ /* 140 */ 137, 181, 181, 181, 181, 181, 181, 181, 96, 222,
+ /* 150 */ 143, 477, 713, 1133, 1268, 713, 713, 79, 79, 713,
+ /* 160 */ 770, 83, 65, 65, 65, 288, 162, 162, 2138, 2138,
+ /* 170 */ 696, 696, 696, 238, 474, 474, 474, 474, 1217, 1217,
+ /* 180 */ 678, 477, 324, 398, 713, 713, 713, 713, 713, 713,
+ /* 190 */ 713, 713, 713, 713, 713, 713, 713, 713, 713, 713,
+ /* 200 */ 713, 713, 713, 1220, 366, 366, 713, 917, 283, 283,
+ /* 210 */ 434, 434, 605, 605, 1298, 2138, 2138, 2138, 2138, 2138,
+ /* 220 */ 2138, 2138, 1179, 1157, 1157, 487, 527, 585, 645, 749,
+ /* 230 */ 914, 968, 752, 713, 713, 713, 713, 713, 713, 713,
+ /* 240 */ 713, 713, 713, 303, 713, 713, 713, 713, 713, 713,
+ /* 250 */ 713, 713, 713, 713, 713, 713, 797, 797, 797, 713,
+ /* 260 */ 713, 713, 959, 713, 713, 713, 1169, 1271, 713, 713,
+ /* 270 */ 1330, 713, 713, 713, 713, 713, 713, 713, 713, 629,
+ /* 280 */ 7, 91, 876, 876, 876, 876, 953, 91, 91, 1246,
+ /* 290 */ 1065, 1106, 1374, 1329, 1348, 468, 1348, 1394, 785, 1329,
+ /* 300 */ 1329, 785, 1329, 468, 1394, 859, 854, 1402, 1449, 1449,
+ /* 310 */ 1449, 1173, 1173, 1173, 1173, 1355, 1355, 1030, 1341, 405,
+ /* 320 */ 1230, 1795, 1795, 1711, 1711, 1829, 1829, 1711, 1717, 1719,
+ /* 330 */ 1850, 1728, 1732, 1836, 1728, 1732, 1866, 1866, 1866, 1866,
+ /* 340 */ 1711, 1876, 1747, 1719, 1719, 1747, 1850, 1836, 1747, 1836,
+ /* 350 */ 1747, 1711, 1876, 1751, 1849, 1711, 1876, 1890, 1711, 1876,
+ /* 360 */ 1711, 1876, 1890, 1806, 1806, 1806, 1863, 1910, 1910, 1890,
+ /* 370 */ 1806, 1810, 1806, 1863, 1806, 1806, 1774, 1916, 1842, 1842,
+ /* 380 */ 1890, 1711, 1869, 1869, 1881, 1881, 1728, 1732, 1942, 1711,
+ /* 390 */ 1811, 1728, 1824, 1826, 1747, 1951, 1967, 1967, 1981, 1981,
+ /* 400 */ 1981, 2138, 2138, 2138, 2138, 2138, 2138, 2138, 2138, 2138,
+ /* 410 */ 2138, 2138, 2138, 2138, 2138, 2138, 20, 1224, 256, 1111,
+ /* 420 */ 1115, 1114, 1192, 1496, 1424, 1505, 1427, 355, 1383, 1537,
+ /* 430 */ 1506, 1538, 1553, 1583, 1584, 1591, 1625, 541, 1445, 1562,
+ /* 440 */ 1450, 1572, 1515, 1428, 1532, 1592, 1629, 1520, 1630, 1639,
+ /* 450 */ 1510, 1544, 1662, 1675, 1551, 48, 2002, 2004, 1987, 1851,
+ /* 460 */ 1997, 1999, 1990, 1993, 1878, 1867, 1889, 1995, 1995, 1998,
+ /* 470 */ 1879, 2003, 1880, 2009, 2025, 1885, 1898, 1995, 1899, 1969,
+ /* 480 */ 1994, 1995, 1882, 1979, 1982, 1983, 1984, 1904, 1922, 2005,
+ /* 490 */ 1900, 2039, 2037, 2021, 1929, 1884, 1978, 2022, 1980, 1974,
+ /* 500 */ 2010, 1909, 1937, 2029, 2034, 2036, 1925, 1932, 2038, 1991,
+ /* 510 */ 2040, 2041, 2042, 2044, 1992, 2008, 2045, 1965, 2043, 2046,
+ /* 520 */ 2006, 2027, 2047, 2048, 1923, 2052, 2053, 2054, 2050, 2055,
+ /* 530 */ 2057, 1986, 1939, 2058, 2061, 1970, 2051, 2065, 1945, 2064,
+ /* 540 */ 2056, 2059, 2060, 2062, 2007, 2016, 2011, 2063, 2017, 2012,
+ /* 550 */ 2066, 2075, 2077, 2078, 2076, 2079, 2069, 1964, 1966, 2086,
+ /* 560 */ 2064, 2087, 2088, 2089, 2091, 2090, 2093, 2092, 2095, 2097,
+ /* 570 */ 2103, 2098, 2099, 2100, 2101, 2104, 2105, 2106, 2000, 1988,
+ /* 580 */ 1989, 1996, 2107, 2102, 2113, 2121, 2132,
};
-#define YY_REDUCE_COUNT (412)
-#define YY_REDUCE_MIN (-271)
-#define YY_REDUCE_MAX (1744)
+#define YY_REDUCE_COUNT (415)
+#define YY_REDUCE_MIN (-275)
+#define YY_REDUCE_MAX (1800)
static const short yy_reduce_ofst[] = {
- /* 0 */ -125, 733, 789, 241, 293, -123, -193, -191, -183, -187,
- /* 10 */ 166, 238, 133, -207, -199, -267, -176, -6, 204, 489,
- /* 20 */ 576, -175, 598, 686, 615, 725, 860, 778, 781, 857,
- /* 30 */ 616, 887, 87, 240, -192, 408, 626, 796, 843, 854,
- /* 40 */ 1003, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 50 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 60 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 70 */ -271, -271, -271, -271, -271, -271, -271, -271, 80, 83,
- /* 80 */ 313, 886, 888, 996, 1034, 1059, 1081, 1100, 1117, 1152,
- /* 90 */ 1155, 1163, 1165, 1167, 1169, 1172, 1180, 1182, 1184, 1198,
- /* 100 */ 1200, 1213, 1215, 1225, 1227, 1252, 1254, 1264, 1299, 1303,
- /* 110 */ 1308, 1312, 1325, 1328, 1337, 1340, 1343, 1371, 1373, 1384,
- /* 120 */ 1386, 1411, 1420, 1424, 1426, 1458, 1470, 1473, 1475, 1479,
- /* 130 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 140 */ -271, 138, 459, 396, -158, 470, 302, -212, 521, 201,
- /* 150 */ -195, -92, 559, 630, 632, 630, -271, 632, 901, 63,
- /* 160 */ 407, -271, -271, -271, -271, 161, 161, 161, 251, 335,
- /* 170 */ 847, 960, 980, 537, 588, 618, 628, 688, 688, -166,
- /* 180 */ -161, 674, 790, 794, 799, 851, 852, -122, 680, -120,
- /* 190 */ 995, 1038, 415, 1051, 893, 798, 962, 400, 1086, 779,
- /* 200 */ 923, 924, 263, 1041, 979, 990, 1083, 1097, 1031, 1194,
- /* 210 */ 362, 994, 1139, 1005, 1037, 1202, 1205, 1195, 1210, -194,
- /* 220 */ 56, 185, -135, 232, 522, 560, 601, 617, 669, 683,
- /* 230 */ 711, 856, 908, 941, 1048, 1101, 1147, 1257, 1262, 1265,
- /* 240 */ 392, 1292, 1333, 1339, 1342, 1346, 1350, 1359, 1374, 1418,
- /* 250 */ 1421, 1436, 1437, 593, 755, 770, 997, 1445, 1459, 1209,
- /* 260 */ 1500, 1504, 1516, 1132, 1243, 1518, 1519, 1440, 1520, 560,
- /* 270 */ 1522, 1523, 1524, 1526, 1527, 1529, 1382, 1438, 1431, 1468,
- /* 280 */ 1469, 1472, 1476, 1209, 1431, 1431, 1485, 1525, 1539, 1435,
- /* 290 */ 1463, 1471, 1492, 1487, 1443, 1494, 1474, 1484, 1498, 1486,
- /* 300 */ 1502, 1455, 1530, 1531, 1533, 1540, 1542, 1544, 1505, 1506,
- /* 310 */ 1507, 1508, 1521, 1528, 1493, 1537, 1532, 1575, 1488, 1496,
- /* 320 */ 1584, 1594, 1509, 1510, 1600, 1538, 1534, 1541, 1558, 1563,
- /* 330 */ 1586, 1572, 1574, 1588, 1589, 1590, 1591, 1629, 1632, 1587,
- /* 340 */ 1562, 1565, 1592, 1569, 1601, 1596, 1606, 1603, 1641, 1645,
- /* 350 */ 1553, 1561, 1652, 1655, 1630, 1653, 1656, 1658, 1661, 1640,
- /* 360 */ 1646, 1649, 1650, 1638, 1657, 1663, 1665, 1667, 1668, 1671,
- /* 370 */ 1643, 1672, 1674, 1560, 1570, 1615, 1617, 1679, 1678, 1585,
- /* 380 */ 1593, 1636, 1639, 1666, 1669, 1626, 1705, 1628, 1670, 1673,
- /* 390 */ 1675, 1677, 1711, 1721, 1725, 1733, 1734, 1735, 1625, 1637,
- /* 400 */ 1642, 1722, 1723, 1726, 1728, 1732, 1731, 1713, 1724, 1736,
- /* 410 */ 1738, 1744, 1740,
+ /* 0 */ -71, 194, 343, 835, -180, -177, 838, -194, -188, -185,
+ /* 10 */ -183, 82, 183, -65, 133, 245, 346, 407, 458, -178,
+ /* 20 */ 75, -275, -4, 310, 312, 489, 575, 596, 463, 686,
+ /* 30 */ 707, 725, 780, 1098, 856, 778, 1059, 1090, 708, 887,
+ /* 40 */ 86, 448, 980, 630, 680, 681, 684, 796, 801, 796,
+ /* 50 */ 801, -261, -261, -261, -261, -261, -261, -261, -261, -261,
+ /* 60 */ -261, -261, -261, -261, -261, -261, -261, -261, -261, -261,
+ /* 70 */ -261, -261, -261, -261, -261, -261, -261, -261, -261, -261,
+ /* 80 */ -261, -261, -261, -261, -261, -261, -261, -261, 391, 886,
+ /* 90 */ 888, 1013, 1016, 1081, 1087, 1151, 1159, 1177, 1185, 1188,
+ /* 100 */ 1190, 1194, 1197, 1203, 1247, 1260, 1264, 1267, 1269, 1273,
+ /* 110 */ 1315, 1322, 1335, 1337, 1356, 1362, 1418, 1425, 1453, 1457,
+ /* 120 */ 1465, 1473, 1487, 1495, 1507, 1517, 1521, 1534, 1543, 1546,
+ /* 130 */ 1549, 1552, 1554, 1560, 1581, 1590, 1593, 1595, 1621, 1623,
+ /* 140 */ -261, -261, -261, -261, -261, -261, -261, -261, -261, -261,
+ /* 150 */ -261, -186, -117, 260, 263, 460, 631, -74, 497, -181,
+ /* 160 */ -261, 939, 176, 274, 338, 676, -261, -261, -261, -261,
+ /* 170 */ -212, -212, -212, -184, 149, 777, 1061, 1103, 265, 419,
+ /* 180 */ -254, 670, 677, 677, -11, -129, 184, 488, 736, 789,
+ /* 190 */ 805, 844, 403, 529, 579, 668, 783, 841, 1158, 1112,
+ /* 200 */ 806, 861, 1095, 846, 839, 1031, -189, 1077, 1080, 1116,
+ /* 210 */ 1084, 1156, 1139, 1221, 46, 1099, 1037, 1118, 1171, 1214,
+ /* 220 */ 1210, 1258, -210, -190, -176, -115, 117, 262, 376, 490,
+ /* 230 */ 511, 520, 618, 639, 743, 901, 907, 958, 1014, 1055,
+ /* 240 */ 1108, 1193, 1244, 720, 1248, 1277, 1324, 1347, 1417, 1431,
+ /* 250 */ 1432, 1440, 1451, 1452, 1463, 1478, 1286, 1350, 1369, 1490,
+ /* 260 */ 1498, 1501, 773, 1509, 1513, 1528, 1292, 1367, 1535, 1536,
+ /* 270 */ 1477, 1542, 376, 1547, 1550, 1555, 1559, 1568, 1571, 1441,
+ /* 280 */ 1443, 1474, 1511, 1516, 1519, 1522, 773, 1474, 1474, 1503,
+ /* 290 */ 1567, 1594, 1484, 1527, 1556, 1570, 1557, 1524, 1573, 1545,
+ /* 300 */ 1548, 1576, 1561, 1587, 1540, 1575, 1606, 1611, 1622, 1624,
+ /* 310 */ 1626, 1582, 1597, 1598, 1599, 1601, 1603, 1563, 1608, 1605,
+ /* 320 */ 1604, 1564, 1566, 1655, 1660, 1578, 1579, 1665, 1586, 1607,
+ /* 330 */ 1610, 1627, 1633, 1645, 1634, 1636, 1650, 1651, 1653, 1654,
+ /* 340 */ 1692, 1695, 1656, 1628, 1631, 1657, 1635, 1663, 1659, 1666,
+ /* 350 */ 1661, 1696, 1700, 1618, 1632, 1712, 1714, 1693, 1715, 1718,
+ /* 360 */ 1716, 1720, 1697, 1703, 1705, 1707, 1701, 1708, 1713, 1721,
+ /* 370 */ 1722, 1726, 1729, 1709, 1731, 1733, 1638, 1644, 1672, 1673,
+ /* 380 */ 1736, 1758, 1641, 1642, 1698, 1699, 1723, 1725, 1688, 1767,
+ /* 390 */ 1689, 1727, 1724, 1738, 1730, 1776, 1793, 1794, 1797, 1798,
+ /* 400 */ 1799, 1690, 1691, 1702, 1785, 1780, 1783, 1784, 1786, 1791,
+ /* 410 */ 1778, 1779, 1788, 1790, 1796, 1800,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 1651, 1651, 1651, 1479, 1244, 1355, 1244, 1244, 1244, 1479,
- /* 10 */ 1479, 1479, 1244, 1385, 1385, 1532, 1277, 1244, 1244, 1244,
- /* 20 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1478, 1244, 1244,
- /* 30 */ 1244, 1244, 1567, 1567, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 40 */ 1244, 1244, 1394, 1244, 1401, 1244, 1244, 1244, 1244, 1244,
- /* 50 */ 1480, 1481, 1244, 1244, 1244, 1531, 1533, 1496, 1408, 1407,
- /* 60 */ 1406, 1405, 1514, 1373, 1399, 1392, 1396, 1474, 1475, 1473,
- /* 70 */ 1477, 1481, 1480, 1244, 1395, 1442, 1458, 1441, 1244, 1244,
- /* 80 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 90 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 100 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 110 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 120 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 130 */ 1450, 1457, 1456, 1455, 1464, 1454, 1451, 1444, 1443, 1445,
- /* 140 */ 1446, 1244, 1244, 1268, 1244, 1244, 1265, 1319, 1244, 1244,
- /* 150 */ 1244, 1244, 1244, 1551, 1550, 1244, 1447, 1244, 1277, 1436,
- /* 160 */ 1435, 1461, 1448, 1460, 1459, 1539, 1603, 1602, 1497, 1244,
- /* 170 */ 1244, 1244, 1244, 1244, 1244, 1567, 1244, 1244, 1244, 1244,
- /* 180 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 190 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1375,
- /* 200 */ 1567, 1567, 1244, 1277, 1567, 1567, 1376, 1376, 1273, 1273,
- /* 210 */ 1379, 1244, 1546, 1346, 1346, 1346, 1346, 1355, 1346, 1244,
- /* 220 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 230 */ 1244, 1244, 1244, 1244, 1536, 1534, 1244, 1244, 1244, 1244,
- /* 240 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 250 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 260 */ 1244, 1244, 1244, 1351, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 270 */ 1244, 1244, 1244, 1244, 1244, 1596, 1244, 1509, 1333, 1351,
- /* 280 */ 1351, 1351, 1351, 1353, 1334, 1332, 1345, 1278, 1251, 1643,
- /* 290 */ 1411, 1400, 1352, 1400, 1640, 1398, 1411, 1411, 1398, 1411,
- /* 300 */ 1352, 1640, 1294, 1619, 1289, 1385, 1385, 1385, 1375, 1375,
- /* 310 */ 1375, 1375, 1379, 1379, 1476, 1352, 1345, 1244, 1643, 1643,
- /* 320 */ 1361, 1361, 1642, 1642, 1361, 1497, 1627, 1420, 1393, 1379,
- /* 330 */ 1322, 1393, 1379, 1328, 1328, 1328, 1328, 1361, 1262, 1398,
- /* 340 */ 1627, 1627, 1398, 1420, 1322, 1398, 1322, 1398, 1361, 1262,
- /* 350 */ 1513, 1637, 1361, 1262, 1487, 1361, 1262, 1361, 1262, 1487,
- /* 360 */ 1320, 1320, 1320, 1309, 1244, 1244, 1487, 1320, 1294, 1320,
- /* 370 */ 1309, 1320, 1320, 1585, 1244, 1491, 1491, 1487, 1361, 1577,
- /* 380 */ 1577, 1388, 1388, 1393, 1379, 1482, 1361, 1244, 1393, 1391,
- /* 390 */ 1389, 1398, 1312, 1599, 1599, 1595, 1595, 1595, 1648, 1648,
- /* 400 */ 1546, 1612, 1277, 1277, 1277, 1277, 1612, 1296, 1296, 1278,
- /* 410 */ 1278, 1277, 1612, 1244, 1244, 1244, 1244, 1244, 1244, 1607,
- /* 420 */ 1244, 1541, 1498, 1365, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 430 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1552, 1244,
- /* 440 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1425,
- /* 450 */ 1244, 1247, 1543, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 460 */ 1244, 1402, 1403, 1366, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 470 */ 1244, 1417, 1244, 1244, 1244, 1412, 1244, 1244, 1244, 1244,
- /* 480 */ 1244, 1244, 1244, 1244, 1639, 1244, 1244, 1244, 1244, 1244,
- /* 490 */ 1244, 1512, 1511, 1244, 1244, 1363, 1244, 1244, 1244, 1244,
- /* 500 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1292,
- /* 510 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 520 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 530 */ 1244, 1244, 1244, 1390, 1244, 1244, 1244, 1244, 1244, 1244,
- /* 540 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1582, 1380,
- /* 550 */ 1244, 1244, 1244, 1244, 1630, 1244, 1244, 1244, 1244, 1244,
- /* 560 */ 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1623,
- /* 570 */ 1336, 1427, 1244, 1426, 1430, 1266, 1244, 1256, 1244, 1244,
+ /* 0 */ 1667, 1667, 1667, 1495, 1258, 1371, 1258, 1258, 1258, 1258,
+ /* 10 */ 1495, 1495, 1495, 1258, 1258, 1258, 1258, 1258, 1258, 1401,
+ /* 20 */ 1401, 1548, 1291, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 30 */ 1258, 1258, 1258, 1258, 1258, 1494, 1258, 1258, 1258, 1258,
+ /* 40 */ 1582, 1582, 1258, 1258, 1258, 1258, 1258, 1567, 1566, 1258,
+ /* 50 */ 1258, 1258, 1410, 1258, 1417, 1258, 1258, 1258, 1258, 1258,
+ /* 60 */ 1496, 1497, 1258, 1258, 1258, 1547, 1549, 1512, 1424, 1423,
+ /* 70 */ 1422, 1421, 1530, 1389, 1415, 1408, 1412, 1491, 1492, 1490,
+ /* 80 */ 1645, 1497, 1496, 1258, 1411, 1459, 1475, 1458, 1258, 1258,
+ /* 90 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 100 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 110 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 120 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 130 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 140 */ 1467, 1474, 1473, 1472, 1481, 1471, 1468, 1461, 1460, 1462,
+ /* 150 */ 1463, 1282, 1258, 1279, 1333, 1258, 1258, 1258, 1258, 1258,
+ /* 160 */ 1464, 1291, 1452, 1451, 1450, 1258, 1478, 1465, 1477, 1476,
+ /* 170 */ 1555, 1619, 1618, 1513, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 180 */ 1582, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 190 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 200 */ 1258, 1258, 1258, 1391, 1582, 1582, 1258, 1291, 1582, 1582,
+ /* 210 */ 1392, 1392, 1287, 1287, 1395, 1562, 1362, 1362, 1362, 1362,
+ /* 220 */ 1371, 1362, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 230 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1552, 1550, 1258,
+ /* 240 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 250 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 260 */ 1258, 1258, 1258, 1258, 1258, 1258, 1367, 1258, 1258, 1258,
+ /* 270 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1612, 1258,
+ /* 280 */ 1525, 1347, 1367, 1367, 1367, 1367, 1369, 1348, 1346, 1361,
+ /* 290 */ 1292, 1265, 1659, 1427, 1416, 1368, 1416, 1656, 1414, 1427,
+ /* 300 */ 1427, 1414, 1427, 1368, 1656, 1308, 1634, 1303, 1401, 1401,
+ /* 310 */ 1401, 1391, 1391, 1391, 1391, 1395, 1395, 1493, 1368, 1361,
+ /* 320 */ 1258, 1659, 1659, 1377, 1377, 1658, 1658, 1377, 1513, 1642,
+ /* 330 */ 1436, 1409, 1395, 1336, 1409, 1395, 1342, 1342, 1342, 1342,
+ /* 340 */ 1377, 1276, 1414, 1642, 1642, 1414, 1436, 1336, 1414, 1336,
+ /* 350 */ 1414, 1377, 1276, 1529, 1653, 1377, 1276, 1503, 1377, 1276,
+ /* 360 */ 1377, 1276, 1503, 1334, 1334, 1334, 1323, 1258, 1258, 1503,
+ /* 370 */ 1334, 1308, 1334, 1323, 1334, 1334, 1600, 1258, 1507, 1507,
+ /* 380 */ 1503, 1377, 1592, 1592, 1404, 1404, 1409, 1395, 1498, 1377,
+ /* 390 */ 1258, 1409, 1407, 1405, 1414, 1326, 1615, 1615, 1611, 1611,
+ /* 400 */ 1611, 1664, 1664, 1562, 1627, 1291, 1291, 1291, 1291, 1627,
+ /* 410 */ 1310, 1310, 1292, 1292, 1291, 1627, 1258, 1258, 1258, 1258,
+ /* 420 */ 1258, 1258, 1622, 1258, 1557, 1514, 1381, 1258, 1258, 1258,
+ /* 430 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 440 */ 1258, 1258, 1258, 1568, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 450 */ 1258, 1258, 1258, 1258, 1258, 1441, 1258, 1261, 1559, 1258,
+ /* 460 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1418, 1419, 1382,
+ /* 470 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1433, 1258, 1258,
+ /* 480 */ 1258, 1428, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 490 */ 1655, 1258, 1258, 1258, 1258, 1258, 1258, 1528, 1527, 1258,
+ /* 500 */ 1258, 1379, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 510 */ 1258, 1258, 1258, 1258, 1258, 1306, 1258, 1258, 1258, 1258,
+ /* 520 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 530 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1406,
+ /* 540 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ /* 550 */ 1258, 1258, 1258, 1258, 1597, 1396, 1258, 1258, 1258, 1258,
+ /* 560 */ 1646, 1258, 1258, 1258, 1258, 1356, 1258, 1258, 1258, 1258,
+ /* 570 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1638, 1350, 1442,
+ /* 580 */ 1258, 1445, 1280, 1258, 1270, 1258, 1258,
};
/********** End of lemon-generated parsing tables *****************************/
@@ -170276,8 +179143,8 @@ static const YYCODETYPE yyFallback[] = {
0, /* TRUEFALSE => nothing */
0, /* ISNOT => nothing */
0, /* FUNCTION => nothing */
- 0, /* UMINUS => nothing */
0, /* UPLUS => nothing */
+ 0, /* UMINUS => nothing */
0, /* TRUTH => nothing */
0, /* REGISTER => nothing */
0, /* VECTOR => nothing */
@@ -170286,6 +179153,7 @@ static const YYCODETYPE yyFallback[] = {
0, /* ASTERISK => nothing */
0, /* SPAN => nothing */
0, /* ERROR => nothing */
+ 0, /* QNUMBER => nothing */
0, /* SPACE => nothing */
0, /* ILLEGAL => nothing */
};
@@ -170328,14 +179196,9 @@ struct yyParser {
#endif
sqlcipher_sqlite3ParserARG_SDECL /* A place to hold %extra_argument */
sqlcipher_sqlite3ParserCTX_SDECL /* A place to hold %extra_context */
-#if YYSTACKDEPTH<=0
- int yystksz; /* Current side of the stack */
- yyStackEntry *yystack; /* The parser's stack */
- yyStackEntry yystk0; /* First stack entry */
-#else
- yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
- yyStackEntry *yystackEnd; /* Last entry in the stack */
-#endif
+ yyStackEntry *yystackEnd; /* Last entry in the stack */
+ yyStackEntry *yystack; /* The parser stack */
+ yyStackEntry yystk0[YYSTACKDEPTH]; /* Initial stack space */
};
typedef struct yyParser yyParser;
@@ -170549,8 +179412,8 @@ static const char *const yyTokenName[] = {
/* 170 */ "TRUEFALSE",
/* 171 */ "ISNOT",
/* 172 */ "FUNCTION",
- /* 173 */ "UMINUS",
- /* 174 */ "UPLUS",
+ /* 173 */ "UPLUS",
+ /* 174 */ "UMINUS",
/* 175 */ "TRUTH",
/* 176 */ "REGISTER",
/* 177 */ "VECTOR",
@@ -170559,142 +179422,145 @@ static const char *const yyTokenName[] = {
/* 180 */ "ASTERISK",
/* 181 */ "SPAN",
/* 182 */ "ERROR",
- /* 183 */ "SPACE",
- /* 184 */ "ILLEGAL",
- /* 185 */ "input",
- /* 186 */ "cmdlist",
- /* 187 */ "ecmd",
- /* 188 */ "cmdx",
- /* 189 */ "explain",
- /* 190 */ "cmd",
- /* 191 */ "transtype",
- /* 192 */ "trans_opt",
- /* 193 */ "nm",
- /* 194 */ "savepoint_opt",
- /* 195 */ "create_table",
- /* 196 */ "create_table_args",
- /* 197 */ "createkw",
- /* 198 */ "temp",
- /* 199 */ "ifnotexists",
- /* 200 */ "dbnm",
- /* 201 */ "columnlist",
- /* 202 */ "conslist_opt",
- /* 203 */ "table_option_set",
- /* 204 */ "select",
- /* 205 */ "table_option",
- /* 206 */ "columnname",
- /* 207 */ "carglist",
- /* 208 */ "typetoken",
- /* 209 */ "typename",
- /* 210 */ "signed",
- /* 211 */ "plus_num",
- /* 212 */ "minus_num",
- /* 213 */ "scanpt",
- /* 214 */ "scantok",
- /* 215 */ "ccons",
- /* 216 */ "term",
- /* 217 */ "expr",
- /* 218 */ "onconf",
- /* 219 */ "sortorder",
- /* 220 */ "autoinc",
- /* 221 */ "eidlist_opt",
- /* 222 */ "refargs",
- /* 223 */ "defer_subclause",
- /* 224 */ "generated",
- /* 225 */ "refarg",
- /* 226 */ "refact",
- /* 227 */ "init_deferred_pred_opt",
- /* 228 */ "conslist",
- /* 229 */ "tconscomma",
- /* 230 */ "tcons",
- /* 231 */ "sortlist",
- /* 232 */ "eidlist",
- /* 233 */ "defer_subclause_opt",
- /* 234 */ "orconf",
- /* 235 */ "resolvetype",
- /* 236 */ "raisetype",
- /* 237 */ "ifexists",
- /* 238 */ "fullname",
- /* 239 */ "selectnowith",
- /* 240 */ "oneselect",
- /* 241 */ "wqlist",
- /* 242 */ "multiselect_op",
- /* 243 */ "distinct",
- /* 244 */ "selcollist",
- /* 245 */ "from",
- /* 246 */ "where_opt",
- /* 247 */ "groupby_opt",
- /* 248 */ "having_opt",
- /* 249 */ "orderby_opt",
- /* 250 */ "limit_opt",
- /* 251 */ "window_clause",
- /* 252 */ "values",
- /* 253 */ "nexprlist",
- /* 254 */ "sclp",
- /* 255 */ "as",
- /* 256 */ "seltablist",
- /* 257 */ "stl_prefix",
- /* 258 */ "joinop",
- /* 259 */ "on_using",
- /* 260 */ "indexed_by",
- /* 261 */ "exprlist",
- /* 262 */ "xfullname",
- /* 263 */ "idlist",
- /* 264 */ "indexed_opt",
- /* 265 */ "nulls",
- /* 266 */ "with",
- /* 267 */ "where_opt_ret",
- /* 268 */ "setlist",
- /* 269 */ "insert_cmd",
- /* 270 */ "idlist_opt",
- /* 271 */ "upsert",
- /* 272 */ "returning",
- /* 273 */ "filter_over",
- /* 274 */ "likeop",
- /* 275 */ "between_op",
- /* 276 */ "in_op",
- /* 277 */ "paren_exprlist",
- /* 278 */ "case_operand",
- /* 279 */ "case_exprlist",
- /* 280 */ "case_else",
- /* 281 */ "uniqueflag",
- /* 282 */ "collate",
- /* 283 */ "vinto",
- /* 284 */ "nmnum",
- /* 285 */ "trigger_decl",
- /* 286 */ "trigger_cmd_list",
- /* 287 */ "trigger_time",
- /* 288 */ "trigger_event",
- /* 289 */ "foreach_clause",
- /* 290 */ "when_clause",
- /* 291 */ "trigger_cmd",
- /* 292 */ "trnm",
- /* 293 */ "tridxby",
- /* 294 */ "database_kw_opt",
- /* 295 */ "key_opt",
- /* 296 */ "add_column_fullname",
- /* 297 */ "kwcolumn_opt",
- /* 298 */ "create_vtab",
- /* 299 */ "vtabarglist",
- /* 300 */ "vtabarg",
- /* 301 */ "vtabargtoken",
- /* 302 */ "lp",
- /* 303 */ "anylist",
- /* 304 */ "wqitem",
- /* 305 */ "wqas",
- /* 306 */ "windowdefn_list",
- /* 307 */ "windowdefn",
- /* 308 */ "window",
- /* 309 */ "frame_opt",
- /* 310 */ "part_opt",
- /* 311 */ "filter_clause",
- /* 312 */ "over_clause",
- /* 313 */ "range_or_rows",
- /* 314 */ "frame_bound",
- /* 315 */ "frame_bound_s",
- /* 316 */ "frame_bound_e",
- /* 317 */ "frame_exclude_opt",
- /* 318 */ "frame_exclude",
+ /* 183 */ "QNUMBER",
+ /* 184 */ "SPACE",
+ /* 185 */ "ILLEGAL",
+ /* 186 */ "input",
+ /* 187 */ "cmdlist",
+ /* 188 */ "ecmd",
+ /* 189 */ "cmdx",
+ /* 190 */ "explain",
+ /* 191 */ "cmd",
+ /* 192 */ "transtype",
+ /* 193 */ "trans_opt",
+ /* 194 */ "nm",
+ /* 195 */ "savepoint_opt",
+ /* 196 */ "create_table",
+ /* 197 */ "create_table_args",
+ /* 198 */ "createkw",
+ /* 199 */ "temp",
+ /* 200 */ "ifnotexists",
+ /* 201 */ "dbnm",
+ /* 202 */ "columnlist",
+ /* 203 */ "conslist_opt",
+ /* 204 */ "table_option_set",
+ /* 205 */ "select",
+ /* 206 */ "table_option",
+ /* 207 */ "columnname",
+ /* 208 */ "carglist",
+ /* 209 */ "typetoken",
+ /* 210 */ "typename",
+ /* 211 */ "signed",
+ /* 212 */ "plus_num",
+ /* 213 */ "minus_num",
+ /* 214 */ "scanpt",
+ /* 215 */ "scantok",
+ /* 216 */ "ccons",
+ /* 217 */ "term",
+ /* 218 */ "expr",
+ /* 219 */ "onconf",
+ /* 220 */ "sortorder",
+ /* 221 */ "autoinc",
+ /* 222 */ "eidlist_opt",
+ /* 223 */ "refargs",
+ /* 224 */ "defer_subclause",
+ /* 225 */ "generated",
+ /* 226 */ "refarg",
+ /* 227 */ "refact",
+ /* 228 */ "init_deferred_pred_opt",
+ /* 229 */ "conslist",
+ /* 230 */ "tconscomma",
+ /* 231 */ "tcons",
+ /* 232 */ "sortlist",
+ /* 233 */ "eidlist",
+ /* 234 */ "defer_subclause_opt",
+ /* 235 */ "orconf",
+ /* 236 */ "resolvetype",
+ /* 237 */ "raisetype",
+ /* 238 */ "ifexists",
+ /* 239 */ "fullname",
+ /* 240 */ "selectnowith",
+ /* 241 */ "oneselect",
+ /* 242 */ "wqlist",
+ /* 243 */ "multiselect_op",
+ /* 244 */ "distinct",
+ /* 245 */ "selcollist",
+ /* 246 */ "from",
+ /* 247 */ "where_opt",
+ /* 248 */ "groupby_opt",
+ /* 249 */ "having_opt",
+ /* 250 */ "orderby_opt",
+ /* 251 */ "limit_opt",
+ /* 252 */ "window_clause",
+ /* 253 */ "values",
+ /* 254 */ "nexprlist",
+ /* 255 */ "mvalues",
+ /* 256 */ "sclp",
+ /* 257 */ "as",
+ /* 258 */ "seltablist",
+ /* 259 */ "stl_prefix",
+ /* 260 */ "joinop",
+ /* 261 */ "on_using",
+ /* 262 */ "indexed_by",
+ /* 263 */ "exprlist",
+ /* 264 */ "xfullname",
+ /* 265 */ "idlist",
+ /* 266 */ "indexed_opt",
+ /* 267 */ "nulls",
+ /* 268 */ "with",
+ /* 269 */ "where_opt_ret",
+ /* 270 */ "setlist",
+ /* 271 */ "insert_cmd",
+ /* 272 */ "idlist_opt",
+ /* 273 */ "upsert",
+ /* 274 */ "returning",
+ /* 275 */ "filter_over",
+ /* 276 */ "likeop",
+ /* 277 */ "between_op",
+ /* 278 */ "in_op",
+ /* 279 */ "paren_exprlist",
+ /* 280 */ "case_operand",
+ /* 281 */ "case_exprlist",
+ /* 282 */ "case_else",
+ /* 283 */ "uniqueflag",
+ /* 284 */ "collate",
+ /* 285 */ "vinto",
+ /* 286 */ "nmnum",
+ /* 287 */ "trigger_decl",
+ /* 288 */ "trigger_cmd_list",
+ /* 289 */ "trigger_time",
+ /* 290 */ "trigger_event",
+ /* 291 */ "foreach_clause",
+ /* 292 */ "when_clause",
+ /* 293 */ "trigger_cmd",
+ /* 294 */ "trnm",
+ /* 295 */ "tridxby",
+ /* 296 */ "database_kw_opt",
+ /* 297 */ "key_opt",
+ /* 298 */ "add_column_fullname",
+ /* 299 */ "kwcolumn_opt",
+ /* 300 */ "create_vtab",
+ /* 301 */ "vtabarglist",
+ /* 302 */ "vtabarg",
+ /* 303 */ "vtabargtoken",
+ /* 304 */ "lp",
+ /* 305 */ "anylist",
+ /* 306 */ "wqitem",
+ /* 307 */ "wqas",
+ /* 308 */ "withnm",
+ /* 309 */ "windowdefn_list",
+ /* 310 */ "windowdefn",
+ /* 311 */ "window",
+ /* 312 */ "frame_opt",
+ /* 313 */ "part_opt",
+ /* 314 */ "filter_clause",
+ /* 315 */ "over_clause",
+ /* 316 */ "range_or_rows",
+ /* 317 */ "frame_bound",
+ /* 318 */ "frame_bound_s",
+ /* 319 */ "frame_bound_e",
+ /* 320 */ "frame_exclude_opt",
+ /* 321 */ "frame_exclude",
};
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
@@ -170797,351 +179663,363 @@ static const char *const yyRuleName[] = {
/* 92 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
/* 93 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt",
/* 94 */ "values ::= VALUES LP nexprlist RP",
- /* 95 */ "values ::= values COMMA LP nexprlist RP",
- /* 96 */ "distinct ::= DISTINCT",
- /* 97 */ "distinct ::= ALL",
- /* 98 */ "distinct ::=",
- /* 99 */ "sclp ::=",
- /* 100 */ "selcollist ::= sclp scanpt expr scanpt as",
- /* 101 */ "selcollist ::= sclp scanpt STAR",
- /* 102 */ "selcollist ::= sclp scanpt nm DOT STAR",
- /* 103 */ "as ::= AS nm",
- /* 104 */ "as ::=",
- /* 105 */ "from ::=",
- /* 106 */ "from ::= FROM seltablist",
- /* 107 */ "stl_prefix ::= seltablist joinop",
- /* 108 */ "stl_prefix ::=",
- /* 109 */ "seltablist ::= stl_prefix nm dbnm as on_using",
- /* 110 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using",
- /* 111 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using",
- /* 112 */ "seltablist ::= stl_prefix LP select RP as on_using",
- /* 113 */ "seltablist ::= stl_prefix LP seltablist RP as on_using",
- /* 114 */ "dbnm ::=",
- /* 115 */ "dbnm ::= DOT nm",
- /* 116 */ "fullname ::= nm",
- /* 117 */ "fullname ::= nm DOT nm",
- /* 118 */ "xfullname ::= nm",
- /* 119 */ "xfullname ::= nm DOT nm",
- /* 120 */ "xfullname ::= nm DOT nm AS nm",
- /* 121 */ "xfullname ::= nm AS nm",
- /* 122 */ "joinop ::= COMMA|JOIN",
- /* 123 */ "joinop ::= JOIN_KW JOIN",
- /* 124 */ "joinop ::= JOIN_KW nm JOIN",
- /* 125 */ "joinop ::= JOIN_KW nm nm JOIN",
- /* 126 */ "on_using ::= ON expr",
- /* 127 */ "on_using ::= USING LP idlist RP",
- /* 128 */ "on_using ::=",
- /* 129 */ "indexed_opt ::=",
- /* 130 */ "indexed_by ::= INDEXED BY nm",
- /* 131 */ "indexed_by ::= NOT INDEXED",
- /* 132 */ "orderby_opt ::=",
- /* 133 */ "orderby_opt ::= ORDER BY sortlist",
- /* 134 */ "sortlist ::= sortlist COMMA expr sortorder nulls",
- /* 135 */ "sortlist ::= expr sortorder nulls",
- /* 136 */ "sortorder ::= ASC",
- /* 137 */ "sortorder ::= DESC",
- /* 138 */ "sortorder ::=",
- /* 139 */ "nulls ::= NULLS FIRST",
- /* 140 */ "nulls ::= NULLS LAST",
- /* 141 */ "nulls ::=",
- /* 142 */ "groupby_opt ::=",
- /* 143 */ "groupby_opt ::= GROUP BY nexprlist",
- /* 144 */ "having_opt ::=",
- /* 145 */ "having_opt ::= HAVING expr",
- /* 146 */ "limit_opt ::=",
- /* 147 */ "limit_opt ::= LIMIT expr",
- /* 148 */ "limit_opt ::= LIMIT expr OFFSET expr",
- /* 149 */ "limit_opt ::= LIMIT expr COMMA expr",
- /* 150 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt",
- /* 151 */ "where_opt ::=",
- /* 152 */ "where_opt ::= WHERE expr",
- /* 153 */ "where_opt_ret ::=",
- /* 154 */ "where_opt_ret ::= WHERE expr",
- /* 155 */ "where_opt_ret ::= RETURNING selcollist",
- /* 156 */ "where_opt_ret ::= WHERE expr RETURNING selcollist",
- /* 157 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt",
- /* 158 */ "setlist ::= setlist COMMA nm EQ expr",
- /* 159 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
- /* 160 */ "setlist ::= nm EQ expr",
- /* 161 */ "setlist ::= LP idlist RP EQ expr",
- /* 162 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
- /* 163 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning",
- /* 164 */ "upsert ::=",
- /* 165 */ "upsert ::= RETURNING selcollist",
- /* 166 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert",
- /* 167 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert",
- /* 168 */ "upsert ::= ON CONFLICT DO NOTHING returning",
- /* 169 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning",
- /* 170 */ "returning ::= RETURNING selcollist",
- /* 171 */ "insert_cmd ::= INSERT orconf",
- /* 172 */ "insert_cmd ::= REPLACE",
- /* 173 */ "idlist_opt ::=",
- /* 174 */ "idlist_opt ::= LP idlist RP",
- /* 175 */ "idlist ::= idlist COMMA nm",
- /* 176 */ "idlist ::= nm",
- /* 177 */ "expr ::= LP expr RP",
- /* 178 */ "expr ::= ID|INDEXED",
- /* 179 */ "expr ::= JOIN_KW",
- /* 180 */ "expr ::= nm DOT nm",
- /* 181 */ "expr ::= nm DOT nm DOT nm",
- /* 182 */ "term ::= NULL|FLOAT|BLOB",
- /* 183 */ "term ::= STRING",
- /* 184 */ "term ::= INTEGER",
- /* 185 */ "expr ::= VARIABLE",
- /* 186 */ "expr ::= expr COLLATE ID|STRING",
- /* 187 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 188 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
- /* 189 */ "expr ::= ID|INDEXED LP STAR RP",
- /* 190 */ "expr ::= ID|INDEXED LP distinct exprlist RP filter_over",
- /* 191 */ "expr ::= ID|INDEXED LP STAR RP filter_over",
- /* 192 */ "term ::= CTIME_KW",
- /* 193 */ "expr ::= LP nexprlist COMMA expr RP",
- /* 194 */ "expr ::= expr AND expr",
- /* 195 */ "expr ::= expr OR expr",
- /* 196 */ "expr ::= expr LT|GT|GE|LE expr",
- /* 197 */ "expr ::= expr EQ|NE expr",
- /* 198 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
- /* 199 */ "expr ::= expr PLUS|MINUS expr",
- /* 200 */ "expr ::= expr STAR|SLASH|REM expr",
- /* 201 */ "expr ::= expr CONCAT expr",
- /* 202 */ "likeop ::= NOT LIKE_KW|MATCH",
- /* 203 */ "expr ::= expr likeop expr",
- /* 204 */ "expr ::= expr likeop expr ESCAPE expr",
- /* 205 */ "expr ::= expr ISNULL|NOTNULL",
- /* 206 */ "expr ::= expr NOT NULL",
- /* 207 */ "expr ::= expr IS expr",
- /* 208 */ "expr ::= expr IS NOT expr",
- /* 209 */ "expr ::= expr IS NOT DISTINCT FROM expr",
- /* 210 */ "expr ::= expr IS DISTINCT FROM expr",
- /* 211 */ "expr ::= NOT expr",
- /* 212 */ "expr ::= BITNOT expr",
- /* 213 */ "expr ::= PLUS|MINUS expr",
- /* 214 */ "expr ::= expr PTR expr",
- /* 215 */ "between_op ::= BETWEEN",
- /* 216 */ "between_op ::= NOT BETWEEN",
- /* 217 */ "expr ::= expr between_op expr AND expr",
- /* 218 */ "in_op ::= IN",
- /* 219 */ "in_op ::= NOT IN",
- /* 220 */ "expr ::= expr in_op LP exprlist RP",
- /* 221 */ "expr ::= LP select RP",
- /* 222 */ "expr ::= expr in_op LP select RP",
- /* 223 */ "expr ::= expr in_op nm dbnm paren_exprlist",
- /* 224 */ "expr ::= EXISTS LP select RP",
- /* 225 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 226 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 227 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 228 */ "case_else ::= ELSE expr",
- /* 229 */ "case_else ::=",
- /* 230 */ "case_operand ::= expr",
- /* 231 */ "case_operand ::=",
- /* 232 */ "exprlist ::=",
- /* 233 */ "nexprlist ::= nexprlist COMMA expr",
- /* 234 */ "nexprlist ::= expr",
- /* 235 */ "paren_exprlist ::=",
- /* 236 */ "paren_exprlist ::= LP exprlist RP",
- /* 237 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
- /* 238 */ "uniqueflag ::= UNIQUE",
- /* 239 */ "uniqueflag ::=",
- /* 240 */ "eidlist_opt ::=",
- /* 241 */ "eidlist_opt ::= LP eidlist RP",
- /* 242 */ "eidlist ::= eidlist COMMA nm collate sortorder",
- /* 243 */ "eidlist ::= nm collate sortorder",
- /* 244 */ "collate ::=",
- /* 245 */ "collate ::= COLLATE ID|STRING",
- /* 246 */ "cmd ::= DROP INDEX ifexists fullname",
- /* 247 */ "cmd ::= VACUUM vinto",
- /* 248 */ "cmd ::= VACUUM nm vinto",
- /* 249 */ "vinto ::= INTO expr",
- /* 250 */ "vinto ::=",
- /* 251 */ "cmd ::= PRAGMA nm dbnm",
- /* 252 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
- /* 253 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
- /* 254 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 255 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
- /* 256 */ "plus_num ::= PLUS INTEGER|FLOAT",
- /* 257 */ "minus_num ::= MINUS INTEGER|FLOAT",
- /* 258 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
- /* 259 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 260 */ "trigger_time ::= BEFORE|AFTER",
- /* 261 */ "trigger_time ::= INSTEAD OF",
- /* 262 */ "trigger_time ::=",
- /* 263 */ "trigger_event ::= DELETE|INSERT",
- /* 264 */ "trigger_event ::= UPDATE",
- /* 265 */ "trigger_event ::= UPDATE OF idlist",
- /* 266 */ "when_clause ::=",
- /* 267 */ "when_clause ::= WHEN expr",
- /* 268 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
- /* 269 */ "trigger_cmd_list ::= trigger_cmd SEMI",
- /* 270 */ "trnm ::= nm DOT nm",
- /* 271 */ "tridxby ::= INDEXED BY nm",
- /* 272 */ "tridxby ::= NOT INDEXED",
- /* 273 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
- /* 274 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
- /* 275 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
- /* 276 */ "trigger_cmd ::= scanpt select scanpt",
- /* 277 */ "expr ::= RAISE LP IGNORE RP",
- /* 278 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 279 */ "raisetype ::= ROLLBACK",
- /* 280 */ "raisetype ::= ABORT",
- /* 281 */ "raisetype ::= FAIL",
- /* 282 */ "cmd ::= DROP TRIGGER ifexists fullname",
- /* 283 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
- /* 284 */ "cmd ::= DETACH database_kw_opt expr",
- /* 285 */ "key_opt ::=",
- /* 286 */ "key_opt ::= KEY expr",
- /* 287 */ "cmd ::= REINDEX",
- /* 288 */ "cmd ::= REINDEX nm dbnm",
- /* 289 */ "cmd ::= ANALYZE",
- /* 290 */ "cmd ::= ANALYZE nm dbnm",
- /* 291 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 292 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
- /* 293 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm",
- /* 294 */ "add_column_fullname ::= fullname",
- /* 295 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
- /* 296 */ "cmd ::= create_vtab",
- /* 297 */ "cmd ::= create_vtab LP vtabarglist RP",
- /* 298 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
- /* 299 */ "vtabarg ::=",
- /* 300 */ "vtabargtoken ::= ANY",
- /* 301 */ "vtabargtoken ::= lp anylist RP",
- /* 302 */ "lp ::= LP",
- /* 303 */ "with ::= WITH wqlist",
- /* 304 */ "with ::= WITH RECURSIVE wqlist",
- /* 305 */ "wqas ::= AS",
- /* 306 */ "wqas ::= AS MATERIALIZED",
- /* 307 */ "wqas ::= AS NOT MATERIALIZED",
- /* 308 */ "wqitem ::= nm eidlist_opt wqas LP select RP",
- /* 309 */ "wqlist ::= wqitem",
- /* 310 */ "wqlist ::= wqlist COMMA wqitem",
- /* 311 */ "windowdefn_list ::= windowdefn",
- /* 312 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
- /* 313 */ "windowdefn ::= nm AS LP window RP",
- /* 314 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
- /* 315 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
- /* 316 */ "window ::= ORDER BY sortlist frame_opt",
- /* 317 */ "window ::= nm ORDER BY sortlist frame_opt",
- /* 318 */ "window ::= frame_opt",
- /* 319 */ "window ::= nm frame_opt",
- /* 320 */ "frame_opt ::=",
- /* 321 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
- /* 322 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
- /* 323 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
- /* 324 */ "frame_bound_s ::= frame_bound",
- /* 325 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
- /* 326 */ "frame_bound_e ::= frame_bound",
- /* 327 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
- /* 328 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
- /* 329 */ "frame_bound ::= CURRENT ROW",
- /* 330 */ "frame_exclude_opt ::=",
- /* 331 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
- /* 332 */ "frame_exclude ::= NO OTHERS",
- /* 333 */ "frame_exclude ::= CURRENT ROW",
- /* 334 */ "frame_exclude ::= GROUP|TIES",
- /* 335 */ "window_clause ::= WINDOW windowdefn_list",
- /* 336 */ "filter_over ::= filter_clause over_clause",
- /* 337 */ "filter_over ::= over_clause",
- /* 338 */ "filter_over ::= filter_clause",
- /* 339 */ "over_clause ::= OVER LP window RP",
- /* 340 */ "over_clause ::= OVER nm",
- /* 341 */ "filter_clause ::= FILTER LP WHERE expr RP",
- /* 342 */ "input ::= cmdlist",
- /* 343 */ "cmdlist ::= cmdlist ecmd",
- /* 344 */ "cmdlist ::= ecmd",
- /* 345 */ "ecmd ::= SEMI",
- /* 346 */ "ecmd ::= cmdx SEMI",
- /* 347 */ "ecmd ::= explain cmdx SEMI",
- /* 348 */ "trans_opt ::=",
- /* 349 */ "trans_opt ::= TRANSACTION",
- /* 350 */ "trans_opt ::= TRANSACTION nm",
- /* 351 */ "savepoint_opt ::= SAVEPOINT",
- /* 352 */ "savepoint_opt ::=",
- /* 353 */ "cmd ::= create_table create_table_args",
- /* 354 */ "table_option_set ::= table_option",
- /* 355 */ "columnlist ::= columnlist COMMA columnname carglist",
- /* 356 */ "columnlist ::= columnname carglist",
- /* 357 */ "nm ::= ID|INDEXED",
- /* 358 */ "nm ::= STRING",
- /* 359 */ "nm ::= JOIN_KW",
- /* 360 */ "typetoken ::= typename",
- /* 361 */ "typename ::= ID|STRING",
- /* 362 */ "signed ::= plus_num",
- /* 363 */ "signed ::= minus_num",
- /* 364 */ "carglist ::= carglist ccons",
- /* 365 */ "carglist ::=",
- /* 366 */ "ccons ::= NULL onconf",
- /* 367 */ "ccons ::= GENERATED ALWAYS AS generated",
- /* 368 */ "ccons ::= AS generated",
- /* 369 */ "conslist_opt ::= COMMA conslist",
- /* 370 */ "conslist ::= conslist tconscomma tcons",
- /* 371 */ "conslist ::= tcons",
- /* 372 */ "tconscomma ::=",
- /* 373 */ "defer_subclause_opt ::= defer_subclause",
- /* 374 */ "resolvetype ::= raisetype",
- /* 375 */ "selectnowith ::= oneselect",
- /* 376 */ "oneselect ::= values",
- /* 377 */ "sclp ::= selcollist COMMA",
- /* 378 */ "as ::= ID|STRING",
- /* 379 */ "indexed_opt ::= indexed_by",
- /* 380 */ "returning ::=",
- /* 381 */ "expr ::= term",
- /* 382 */ "likeop ::= LIKE_KW|MATCH",
- /* 383 */ "exprlist ::= nexprlist",
- /* 384 */ "nmnum ::= plus_num",
- /* 385 */ "nmnum ::= nm",
- /* 386 */ "nmnum ::= ON",
- /* 387 */ "nmnum ::= DELETE",
- /* 388 */ "nmnum ::= DEFAULT",
- /* 389 */ "plus_num ::= INTEGER|FLOAT",
- /* 390 */ "foreach_clause ::=",
- /* 391 */ "foreach_clause ::= FOR EACH ROW",
- /* 392 */ "trnm ::= nm",
- /* 393 */ "tridxby ::=",
- /* 394 */ "database_kw_opt ::= DATABASE",
- /* 395 */ "database_kw_opt ::=",
- /* 396 */ "kwcolumn_opt ::=",
- /* 397 */ "kwcolumn_opt ::= COLUMNKW",
- /* 398 */ "vtabarglist ::= vtabarg",
- /* 399 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
- /* 400 */ "vtabarg ::= vtabarg vtabargtoken",
- /* 401 */ "anylist ::=",
- /* 402 */ "anylist ::= anylist LP anylist RP",
- /* 403 */ "anylist ::= anylist ANY",
- /* 404 */ "with ::=",
+ /* 95 */ "oneselect ::= mvalues",
+ /* 96 */ "mvalues ::= values COMMA LP nexprlist RP",
+ /* 97 */ "mvalues ::= mvalues COMMA LP nexprlist RP",
+ /* 98 */ "distinct ::= DISTINCT",
+ /* 99 */ "distinct ::= ALL",
+ /* 100 */ "distinct ::=",
+ /* 101 */ "sclp ::=",
+ /* 102 */ "selcollist ::= sclp scanpt expr scanpt as",
+ /* 103 */ "selcollist ::= sclp scanpt STAR",
+ /* 104 */ "selcollist ::= sclp scanpt nm DOT STAR",
+ /* 105 */ "as ::= AS nm",
+ /* 106 */ "as ::=",
+ /* 107 */ "from ::=",
+ /* 108 */ "from ::= FROM seltablist",
+ /* 109 */ "stl_prefix ::= seltablist joinop",
+ /* 110 */ "stl_prefix ::=",
+ /* 111 */ "seltablist ::= stl_prefix nm dbnm as on_using",
+ /* 112 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using",
+ /* 113 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using",
+ /* 114 */ "seltablist ::= stl_prefix LP select RP as on_using",
+ /* 115 */ "seltablist ::= stl_prefix LP seltablist RP as on_using",
+ /* 116 */ "dbnm ::=",
+ /* 117 */ "dbnm ::= DOT nm",
+ /* 118 */ "fullname ::= nm",
+ /* 119 */ "fullname ::= nm DOT nm",
+ /* 120 */ "xfullname ::= nm",
+ /* 121 */ "xfullname ::= nm DOT nm",
+ /* 122 */ "xfullname ::= nm DOT nm AS nm",
+ /* 123 */ "xfullname ::= nm AS nm",
+ /* 124 */ "joinop ::= COMMA|JOIN",
+ /* 125 */ "joinop ::= JOIN_KW JOIN",
+ /* 126 */ "joinop ::= JOIN_KW nm JOIN",
+ /* 127 */ "joinop ::= JOIN_KW nm nm JOIN",
+ /* 128 */ "on_using ::= ON expr",
+ /* 129 */ "on_using ::= USING LP idlist RP",
+ /* 130 */ "on_using ::=",
+ /* 131 */ "indexed_opt ::=",
+ /* 132 */ "indexed_by ::= INDEXED BY nm",
+ /* 133 */ "indexed_by ::= NOT INDEXED",
+ /* 134 */ "orderby_opt ::=",
+ /* 135 */ "orderby_opt ::= ORDER BY sortlist",
+ /* 136 */ "sortlist ::= sortlist COMMA expr sortorder nulls",
+ /* 137 */ "sortlist ::= expr sortorder nulls",
+ /* 138 */ "sortorder ::= ASC",
+ /* 139 */ "sortorder ::= DESC",
+ /* 140 */ "sortorder ::=",
+ /* 141 */ "nulls ::= NULLS FIRST",
+ /* 142 */ "nulls ::= NULLS LAST",
+ /* 143 */ "nulls ::=",
+ /* 144 */ "groupby_opt ::=",
+ /* 145 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 146 */ "having_opt ::=",
+ /* 147 */ "having_opt ::= HAVING expr",
+ /* 148 */ "limit_opt ::=",
+ /* 149 */ "limit_opt ::= LIMIT expr",
+ /* 150 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 151 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 152 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt",
+ /* 153 */ "where_opt ::=",
+ /* 154 */ "where_opt ::= WHERE expr",
+ /* 155 */ "where_opt_ret ::=",
+ /* 156 */ "where_opt_ret ::= WHERE expr",
+ /* 157 */ "where_opt_ret ::= RETURNING selcollist",
+ /* 158 */ "where_opt_ret ::= WHERE expr RETURNING selcollist",
+ /* 159 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt",
+ /* 160 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 161 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
+ /* 162 */ "setlist ::= nm EQ expr",
+ /* 163 */ "setlist ::= LP idlist RP EQ expr",
+ /* 164 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
+ /* 165 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning",
+ /* 166 */ "upsert ::=",
+ /* 167 */ "upsert ::= RETURNING selcollist",
+ /* 168 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert",
+ /* 169 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert",
+ /* 170 */ "upsert ::= ON CONFLICT DO NOTHING returning",
+ /* 171 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning",
+ /* 172 */ "returning ::= RETURNING selcollist",
+ /* 173 */ "insert_cmd ::= INSERT orconf",
+ /* 174 */ "insert_cmd ::= REPLACE",
+ /* 175 */ "idlist_opt ::=",
+ /* 176 */ "idlist_opt ::= LP idlist RP",
+ /* 177 */ "idlist ::= idlist COMMA nm",
+ /* 178 */ "idlist ::= nm",
+ /* 179 */ "expr ::= LP expr RP",
+ /* 180 */ "expr ::= ID|INDEXED|JOIN_KW",
+ /* 181 */ "expr ::= nm DOT nm",
+ /* 182 */ "expr ::= nm DOT nm DOT nm",
+ /* 183 */ "term ::= NULL|FLOAT|BLOB",
+ /* 184 */ "term ::= STRING",
+ /* 185 */ "term ::= INTEGER",
+ /* 186 */ "expr ::= VARIABLE",
+ /* 187 */ "expr ::= expr COLLATE ID|STRING",
+ /* 188 */ "expr ::= CAST LP expr AS typetoken RP",
+ /* 189 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP",
+ /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP",
+ /* 191 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP",
+ /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over",
+ /* 193 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over",
+ /* 194 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over",
+ /* 195 */ "term ::= CTIME_KW",
+ /* 196 */ "expr ::= LP nexprlist COMMA expr RP",
+ /* 197 */ "expr ::= expr AND expr",
+ /* 198 */ "expr ::= expr OR expr",
+ /* 199 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 200 */ "expr ::= expr EQ|NE expr",
+ /* 201 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 202 */ "expr ::= expr PLUS|MINUS expr",
+ /* 203 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 204 */ "expr ::= expr CONCAT expr",
+ /* 205 */ "likeop ::= NOT LIKE_KW|MATCH",
+ /* 206 */ "expr ::= expr likeop expr",
+ /* 207 */ "expr ::= expr likeop expr ESCAPE expr",
+ /* 208 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 209 */ "expr ::= expr NOT NULL",
+ /* 210 */ "expr ::= expr IS expr",
+ /* 211 */ "expr ::= expr IS NOT expr",
+ /* 212 */ "expr ::= expr IS NOT DISTINCT FROM expr",
+ /* 213 */ "expr ::= expr IS DISTINCT FROM expr",
+ /* 214 */ "expr ::= NOT expr",
+ /* 215 */ "expr ::= BITNOT expr",
+ /* 216 */ "expr ::= PLUS|MINUS expr",
+ /* 217 */ "expr ::= expr PTR expr",
+ /* 218 */ "between_op ::= BETWEEN",
+ /* 219 */ "between_op ::= NOT BETWEEN",
+ /* 220 */ "expr ::= expr between_op expr AND expr",
+ /* 221 */ "in_op ::= IN",
+ /* 222 */ "in_op ::= NOT IN",
+ /* 223 */ "expr ::= expr in_op LP exprlist RP",
+ /* 224 */ "expr ::= LP select RP",
+ /* 225 */ "expr ::= expr in_op LP select RP",
+ /* 226 */ "expr ::= expr in_op nm dbnm paren_exprlist",
+ /* 227 */ "expr ::= EXISTS LP select RP",
+ /* 228 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 229 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 230 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 231 */ "case_else ::= ELSE expr",
+ /* 232 */ "case_else ::=",
+ /* 233 */ "case_operand ::=",
+ /* 234 */ "exprlist ::=",
+ /* 235 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 236 */ "nexprlist ::= expr",
+ /* 237 */ "paren_exprlist ::=",
+ /* 238 */ "paren_exprlist ::= LP exprlist RP",
+ /* 239 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
+ /* 240 */ "uniqueflag ::= UNIQUE",
+ /* 241 */ "uniqueflag ::=",
+ /* 242 */ "eidlist_opt ::=",
+ /* 243 */ "eidlist_opt ::= LP eidlist RP",
+ /* 244 */ "eidlist ::= eidlist COMMA nm collate sortorder",
+ /* 245 */ "eidlist ::= nm collate sortorder",
+ /* 246 */ "collate ::=",
+ /* 247 */ "collate ::= COLLATE ID|STRING",
+ /* 248 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 249 */ "cmd ::= VACUUM vinto",
+ /* 250 */ "cmd ::= VACUUM nm vinto",
+ /* 251 */ "vinto ::= INTO expr",
+ /* 252 */ "vinto ::=",
+ /* 253 */ "cmd ::= PRAGMA nm dbnm",
+ /* 254 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 255 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 256 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 257 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
+ /* 258 */ "plus_num ::= PLUS INTEGER|FLOAT",
+ /* 259 */ "minus_num ::= MINUS INTEGER|FLOAT",
+ /* 260 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
+ /* 261 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 262 */ "trigger_time ::= BEFORE|AFTER",
+ /* 263 */ "trigger_time ::= INSTEAD OF",
+ /* 264 */ "trigger_time ::=",
+ /* 265 */ "trigger_event ::= DELETE|INSERT",
+ /* 266 */ "trigger_event ::= UPDATE",
+ /* 267 */ "trigger_event ::= UPDATE OF idlist",
+ /* 268 */ "when_clause ::=",
+ /* 269 */ "when_clause ::= WHEN expr",
+ /* 270 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 271 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 272 */ "trnm ::= nm DOT nm",
+ /* 273 */ "tridxby ::= INDEXED BY nm",
+ /* 274 */ "tridxby ::= NOT INDEXED",
+ /* 275 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
+ /* 276 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
+ /* 277 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
+ /* 278 */ "trigger_cmd ::= scanpt select scanpt",
+ /* 279 */ "expr ::= RAISE LP IGNORE RP",
+ /* 280 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 281 */ "raisetype ::= ROLLBACK",
+ /* 282 */ "raisetype ::= ABORT",
+ /* 283 */ "raisetype ::= FAIL",
+ /* 284 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 285 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 286 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 287 */ "key_opt ::=",
+ /* 288 */ "key_opt ::= KEY expr",
+ /* 289 */ "cmd ::= REINDEX",
+ /* 290 */ "cmd ::= REINDEX nm dbnm",
+ /* 291 */ "cmd ::= ANALYZE",
+ /* 292 */ "cmd ::= ANALYZE nm dbnm",
+ /* 293 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 294 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
+ /* 295 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm",
+ /* 296 */ "add_column_fullname ::= fullname",
+ /* 297 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
+ /* 298 */ "cmd ::= create_vtab",
+ /* 299 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 300 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
+ /* 301 */ "vtabarg ::=",
+ /* 302 */ "vtabargtoken ::= ANY",
+ /* 303 */ "vtabargtoken ::= lp anylist RP",
+ /* 304 */ "lp ::= LP",
+ /* 305 */ "with ::= WITH wqlist",
+ /* 306 */ "with ::= WITH RECURSIVE wqlist",
+ /* 307 */ "wqas ::= AS",
+ /* 308 */ "wqas ::= AS MATERIALIZED",
+ /* 309 */ "wqas ::= AS NOT MATERIALIZED",
+ /* 310 */ "wqitem ::= withnm eidlist_opt wqas LP select RP",
+ /* 311 */ "withnm ::= nm",
+ /* 312 */ "wqlist ::= wqitem",
+ /* 313 */ "wqlist ::= wqlist COMMA wqitem",
+ /* 314 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
+ /* 315 */ "windowdefn ::= nm AS LP window RP",
+ /* 316 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 317 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 318 */ "window ::= ORDER BY sortlist frame_opt",
+ /* 319 */ "window ::= nm ORDER BY sortlist frame_opt",
+ /* 320 */ "window ::= nm frame_opt",
+ /* 321 */ "frame_opt ::=",
+ /* 322 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
+ /* 323 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
+ /* 324 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
+ /* 325 */ "frame_bound_s ::= frame_bound",
+ /* 326 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
+ /* 327 */ "frame_bound_e ::= frame_bound",
+ /* 328 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
+ /* 329 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
+ /* 330 */ "frame_bound ::= CURRENT ROW",
+ /* 331 */ "frame_exclude_opt ::=",
+ /* 332 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
+ /* 333 */ "frame_exclude ::= NO OTHERS",
+ /* 334 */ "frame_exclude ::= CURRENT ROW",
+ /* 335 */ "frame_exclude ::= GROUP|TIES",
+ /* 336 */ "window_clause ::= WINDOW windowdefn_list",
+ /* 337 */ "filter_over ::= filter_clause over_clause",
+ /* 338 */ "filter_over ::= over_clause",
+ /* 339 */ "filter_over ::= filter_clause",
+ /* 340 */ "over_clause ::= OVER LP window RP",
+ /* 341 */ "over_clause ::= OVER nm",
+ /* 342 */ "filter_clause ::= FILTER LP WHERE expr RP",
+ /* 343 */ "term ::= QNUMBER",
+ /* 344 */ "input ::= cmdlist",
+ /* 345 */ "cmdlist ::= cmdlist ecmd",
+ /* 346 */ "cmdlist ::= ecmd",
+ /* 347 */ "ecmd ::= SEMI",
+ /* 348 */ "ecmd ::= cmdx SEMI",
+ /* 349 */ "ecmd ::= explain cmdx SEMI",
+ /* 350 */ "trans_opt ::=",
+ /* 351 */ "trans_opt ::= TRANSACTION",
+ /* 352 */ "trans_opt ::= TRANSACTION nm",
+ /* 353 */ "savepoint_opt ::= SAVEPOINT",
+ /* 354 */ "savepoint_opt ::=",
+ /* 355 */ "cmd ::= create_table create_table_args",
+ /* 356 */ "table_option_set ::= table_option",
+ /* 357 */ "columnlist ::= columnlist COMMA columnname carglist",
+ /* 358 */ "columnlist ::= columnname carglist",
+ /* 359 */ "nm ::= ID|INDEXED|JOIN_KW",
+ /* 360 */ "nm ::= STRING",
+ /* 361 */ "typetoken ::= typename",
+ /* 362 */ "typename ::= ID|STRING",
+ /* 363 */ "signed ::= plus_num",
+ /* 364 */ "signed ::= minus_num",
+ /* 365 */ "carglist ::= carglist ccons",
+ /* 366 */ "carglist ::=",
+ /* 367 */ "ccons ::= NULL onconf",
+ /* 368 */ "ccons ::= GENERATED ALWAYS AS generated",
+ /* 369 */ "ccons ::= AS generated",
+ /* 370 */ "conslist_opt ::= COMMA conslist",
+ /* 371 */ "conslist ::= conslist tconscomma tcons",
+ /* 372 */ "conslist ::= tcons",
+ /* 373 */ "tconscomma ::=",
+ /* 374 */ "defer_subclause_opt ::= defer_subclause",
+ /* 375 */ "resolvetype ::= raisetype",
+ /* 376 */ "selectnowith ::= oneselect",
+ /* 377 */ "oneselect ::= values",
+ /* 378 */ "sclp ::= selcollist COMMA",
+ /* 379 */ "as ::= ID|STRING",
+ /* 380 */ "indexed_opt ::= indexed_by",
+ /* 381 */ "returning ::=",
+ /* 382 */ "expr ::= term",
+ /* 383 */ "likeop ::= LIKE_KW|MATCH",
+ /* 384 */ "case_operand ::= expr",
+ /* 385 */ "exprlist ::= nexprlist",
+ /* 386 */ "nmnum ::= plus_num",
+ /* 387 */ "nmnum ::= nm",
+ /* 388 */ "nmnum ::= ON",
+ /* 389 */ "nmnum ::= DELETE",
+ /* 390 */ "nmnum ::= DEFAULT",
+ /* 391 */ "plus_num ::= INTEGER|FLOAT",
+ /* 392 */ "foreach_clause ::=",
+ /* 393 */ "foreach_clause ::= FOR EACH ROW",
+ /* 394 */ "trnm ::= nm",
+ /* 395 */ "tridxby ::=",
+ /* 396 */ "database_kw_opt ::= DATABASE",
+ /* 397 */ "database_kw_opt ::=",
+ /* 398 */ "kwcolumn_opt ::=",
+ /* 399 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 400 */ "vtabarglist ::= vtabarg",
+ /* 401 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 402 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 403 */ "anylist ::=",
+ /* 404 */ "anylist ::= anylist LP anylist RP",
+ /* 405 */ "anylist ::= anylist ANY",
+ /* 406 */ "with ::=",
+ /* 407 */ "windowdefn_list ::= windowdefn",
+ /* 408 */ "window ::= frame_opt",
};
#endif /* NDEBUG */
-#if YYSTACKDEPTH<=0
+#if YYGROWABLESTACK
/*
** Try to increase the size of the parser stack. Return the number
** of errors. Return 0 on success.
*/
static int yyGrowStack(yyParser *p){
+ int oldSize = 1 + (int)(p->yystackEnd - p->yystack);
int newSize;
int idx;
yyStackEntry *pNew;
- newSize = p->yystksz*2 + 100;
- idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
- if( p->yystack==&p->yystk0 ){
- pNew = malloc(newSize*sizeof(pNew[0]));
- if( pNew ) pNew[0] = p->yystk0;
+ newSize = oldSize*2 + 100;
+ idx = (int)(p->yytos - p->yystack);
+ if( p->yystack==p->yystk0 ){
+ pNew = YYREALLOC(0, newSize*sizeof(pNew[0]));
+ if( pNew==0 ) return 1;
+ memcpy(pNew, p->yystack, oldSize*sizeof(pNew[0]));
}else{
- pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0]));
+ if( pNew==0 ) return 1;
}
- if( pNew ){
- p->yystack = pNew;
- p->yytos = &p->yystack[idx];
+ p->yystack = pNew;
+ p->yytos = &p->yystack[idx];
#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
- yyTracePrompt, p->yystksz, newSize);
- }
-#endif
- p->yystksz = newSize;
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
+ yyTracePrompt, oldSize, newSize);
}
- return pNew==0;
+#endif
+ p->yystackEnd = &p->yystack[newSize-1];
+ return 0;
}
+#endif /* YYGROWABLESTACK */
+
+#if !YYGROWABLESTACK
+/* For builds that do no have a growable stack, yyGrowStack always
+** returns an error.
+*/
+# define yyGrowStack(X) 1
#endif
/* Datatype of the argument to the memory allocated passed as the
@@ -171161,24 +180039,14 @@ SQLITE_PRIVATE void sqlcipher_sqlite3ParserInit(void *yypRawParser sqlcipher_sql
#ifdef YYTRACKMAXSTACKDEPTH
yypParser->yyhwm = 0;
#endif
-#if YYSTACKDEPTH<=0
- yypParser->yytos = NULL;
- yypParser->yystack = NULL;
- yypParser->yystksz = 0;
- if( yyGrowStack(yypParser) ){
- yypParser->yystack = &yypParser->yystk0;
- yypParser->yystksz = 1;
- }
-#endif
+ yypParser->yystack = yypParser->yystk0;
+ yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt = -1;
#endif
yypParser->yytos = yypParser->yystack;
yypParser->yystack[0].stateno = 0;
yypParser->yystack[0].major = 0;
-#if YYSTACKDEPTH>0
- yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
-#endif
}
#ifndef sqlcipher_sqlite3Parser_ENGINEALWAYSONSTACK
@@ -171232,97 +180100,98 @@ static void yy_destructor(
** inside the C code.
*/
/********* Begin destructor definitions ***************************************/
- case 204: /* select */
- case 239: /* selectnowith */
- case 240: /* oneselect */
- case 252: /* values */
+ case 205: /* select */
+ case 240: /* selectnowith */
+ case 241: /* oneselect */
+ case 253: /* values */
+ case 255: /* mvalues */
{
-sqlcipher_sqlite3SelectDelete(pParse->db, (yypminor->yy47));
-}
- break;
- case 216: /* term */
- case 217: /* expr */
- case 246: /* where_opt */
- case 248: /* having_opt */
- case 267: /* where_opt_ret */
- case 278: /* case_operand */
- case 280: /* case_else */
- case 283: /* vinto */
- case 290: /* when_clause */
- case 295: /* key_opt */
- case 311: /* filter_clause */
+sqlcipher_sqlite3SelectDelete(pParse->db, (yypminor->yy555));
+}
+ break;
+ case 217: /* term */
+ case 218: /* expr */
+ case 247: /* where_opt */
+ case 249: /* having_opt */
+ case 269: /* where_opt_ret */
+ case 280: /* case_operand */
+ case 282: /* case_else */
+ case 285: /* vinto */
+ case 292: /* when_clause */
+ case 297: /* key_opt */
+ case 314: /* filter_clause */
{
-sqlcipher_sqlite3ExprDelete(pParse->db, (yypminor->yy528));
-}
- break;
- case 221: /* eidlist_opt */
- case 231: /* sortlist */
- case 232: /* eidlist */
- case 244: /* selcollist */
- case 247: /* groupby_opt */
- case 249: /* orderby_opt */
- case 253: /* nexprlist */
- case 254: /* sclp */
- case 261: /* exprlist */
- case 268: /* setlist */
- case 277: /* paren_exprlist */
- case 279: /* case_exprlist */
- case 310: /* part_opt */
+sqlcipher_sqlite3ExprDelete(pParse->db, (yypminor->yy454));
+}
+ break;
+ case 222: /* eidlist_opt */
+ case 232: /* sortlist */
+ case 233: /* eidlist */
+ case 245: /* selcollist */
+ case 248: /* groupby_opt */
+ case 250: /* orderby_opt */
+ case 254: /* nexprlist */
+ case 256: /* sclp */
+ case 263: /* exprlist */
+ case 270: /* setlist */
+ case 279: /* paren_exprlist */
+ case 281: /* case_exprlist */
+ case 313: /* part_opt */
{
-sqlcipher_sqlite3ExprListDelete(pParse->db, (yypminor->yy322));
+sqlcipher_sqlite3ExprListDelete(pParse->db, (yypminor->yy14));
}
break;
- case 238: /* fullname */
- case 245: /* from */
- case 256: /* seltablist */
- case 257: /* stl_prefix */
- case 262: /* xfullname */
+ case 239: /* fullname */
+ case 246: /* from */
+ case 258: /* seltablist */
+ case 259: /* stl_prefix */
+ case 264: /* xfullname */
{
-sqlcipher_sqlite3SrcListDelete(pParse->db, (yypminor->yy131));
+sqlcipher_sqlite3SrcListDelete(pParse->db, (yypminor->yy203));
}
break;
- case 241: /* wqlist */
+ case 242: /* wqlist */
{
-sqlcipher_sqlite3WithDelete(pParse->db, (yypminor->yy521));
+sqlcipher_sqlite3WithDelete(pParse->db, (yypminor->yy59));
}
break;
- case 251: /* window_clause */
- case 306: /* windowdefn_list */
+ case 252: /* window_clause */
+ case 309: /* windowdefn_list */
{
-sqlcipher_sqlite3WindowListDelete(pParse->db, (yypminor->yy41));
+sqlcipher_sqlite3WindowListDelete(pParse->db, (yypminor->yy211));
}
break;
- case 263: /* idlist */
- case 270: /* idlist_opt */
+ case 265: /* idlist */
+ case 272: /* idlist_opt */
{
-sqlcipher_sqlite3IdListDelete(pParse->db, (yypminor->yy254));
+sqlcipher_sqlite3IdListDelete(pParse->db, (yypminor->yy132));
}
break;
- case 273: /* filter_over */
- case 307: /* windowdefn */
- case 308: /* window */
- case 309: /* frame_opt */
- case 312: /* over_clause */
+ case 275: /* filter_over */
+ case 310: /* windowdefn */
+ case 311: /* window */
+ case 312: /* frame_opt */
+ case 315: /* over_clause */
{
-sqlcipher_sqlite3WindowDelete(pParse->db, (yypminor->yy41));
+sqlcipher_sqlite3WindowDelete(pParse->db, (yypminor->yy211));
}
break;
- case 286: /* trigger_cmd_list */
- case 291: /* trigger_cmd */
+ case 288: /* trigger_cmd_list */
+ case 293: /* trigger_cmd */
{
-sqlcipher_sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy33));
+sqlcipher_sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy427));
}
break;
- case 288: /* trigger_event */
+ case 290: /* trigger_event */
{
-sqlcipher_sqlite3IdListDelete(pParse->db, (yypminor->yy180).b);
+sqlcipher_sqlite3IdListDelete(pParse->db, (yypminor->yy286).b);
}
break;
- case 314: /* frame_bound */
- case 315: /* frame_bound_s */
- case 316: /* frame_bound_e */
+ case 317: /* frame_bound */
+ case 318: /* frame_bound_s */
+ case 319: /* frame_bound_e */
{
-sqlcipher_sqlite3ExprDelete(pParse->db, (yypminor->yy595).pExpr);
+sqlcipher_sqlite3ExprDelete(pParse->db, (yypminor->yy509).pExpr);
}
break;
/********* End destructor definitions *****************************************/
@@ -171356,9 +180225,26 @@ static void yy_pop_parser_stack(yyParser *pParser){
*/
SQLITE_PRIVATE void sqlcipher_sqlite3ParserFinalize(void *p){
yyParser *pParser = (yyParser*)p;
- while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
-#if YYSTACKDEPTH<=0
- if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
+
+ /* In-lined version of calling yy_pop_parser_stack() for each
+ ** element left in the stack */
+ yyStackEntry *yytos = pParser->yytos;
+ while( yytos>pParser->yystack ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sPopping %s\n",
+ yyTracePrompt,
+ yyTokenName[yytos->major]);
+ }
+#endif
+ if( yytos->major>=YY_MIN_DSTRCTR ){
+ yy_destructor(pParser, yytos->major, &yytos->minor);
+ }
+ yytos--;
+ }
+
+#if YYGROWABLESTACK
+ if( pParser->yystack!=pParser->yystk0 ) YYFREE(pParser->yystack);
#endif
}
@@ -171541,7 +180427,7 @@ static void yyStackOverflow(yyParser *yypParser){
** stack every overflows */
/******** Begin %stack_overflow code ******************************************/
- sqlcipher_sqlite3ErrorMsg(pParse, "parser stack overflow");
+ sqlcipher_sqlite3OomFault(pParse->db);
/******** End %stack_overflow code ********************************************/
sqlcipher_sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument var */
sqlcipher_sqlite3ParserCTX_STORE
@@ -171585,25 +180471,19 @@ static void yy_shift(
assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
}
#endif
-#if YYSTACKDEPTH>0
- if( yypParser->yytos>yypParser->yystackEnd ){
- yypParser->yytos--;
- yyStackOverflow(yypParser);
- return;
- }
-#else
- if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
+ yytos = yypParser->yytos;
+ if( yytos>yypParser->yystackEnd ){
if( yyGrowStack(yypParser) ){
yypParser->yytos--;
yyStackOverflow(yypParser);
return;
}
+ yytos = yypParser->yytos;
+ assert( yytos <= yypParser->yystackEnd );
}
-#endif
if( yyNewState > YY_MAX_SHIFT ){
yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
}
- yytos = yypParser->yytos;
yytos->stateno = yyNewState;
yytos->major = yyMajor;
yytos->minor.yy0 = yyMinor;
@@ -171613,411 +180493,415 @@ static void yy_shift(
/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
** of that rule */
static const YYCODETYPE yyRuleInfoLhs[] = {
- 189, /* (0) explain ::= EXPLAIN */
- 189, /* (1) explain ::= EXPLAIN QUERY PLAN */
- 188, /* (2) cmdx ::= cmd */
- 190, /* (3) cmd ::= BEGIN transtype trans_opt */
- 191, /* (4) transtype ::= */
- 191, /* (5) transtype ::= DEFERRED */
- 191, /* (6) transtype ::= IMMEDIATE */
- 191, /* (7) transtype ::= EXCLUSIVE */
- 190, /* (8) cmd ::= COMMIT|END trans_opt */
- 190, /* (9) cmd ::= ROLLBACK trans_opt */
- 190, /* (10) cmd ::= SAVEPOINT nm */
- 190, /* (11) cmd ::= RELEASE savepoint_opt nm */
- 190, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
- 195, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
- 197, /* (14) createkw ::= CREATE */
- 199, /* (15) ifnotexists ::= */
- 199, /* (16) ifnotexists ::= IF NOT EXISTS */
- 198, /* (17) temp ::= TEMP */
- 198, /* (18) temp ::= */
- 196, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
- 196, /* (20) create_table_args ::= AS select */
- 203, /* (21) table_option_set ::= */
- 203, /* (22) table_option_set ::= table_option_set COMMA table_option */
- 205, /* (23) table_option ::= WITHOUT nm */
- 205, /* (24) table_option ::= nm */
- 206, /* (25) columnname ::= nm typetoken */
- 208, /* (26) typetoken ::= */
- 208, /* (27) typetoken ::= typename LP signed RP */
- 208, /* (28) typetoken ::= typename LP signed COMMA signed RP */
- 209, /* (29) typename ::= typename ID|STRING */
- 213, /* (30) scanpt ::= */
- 214, /* (31) scantok ::= */
- 215, /* (32) ccons ::= CONSTRAINT nm */
- 215, /* (33) ccons ::= DEFAULT scantok term */
- 215, /* (34) ccons ::= DEFAULT LP expr RP */
- 215, /* (35) ccons ::= DEFAULT PLUS scantok term */
- 215, /* (36) ccons ::= DEFAULT MINUS scantok term */
- 215, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */
- 215, /* (38) ccons ::= NOT NULL onconf */
- 215, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */
- 215, /* (40) ccons ::= UNIQUE onconf */
- 215, /* (41) ccons ::= CHECK LP expr RP */
- 215, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */
- 215, /* (43) ccons ::= defer_subclause */
- 215, /* (44) ccons ::= COLLATE ID|STRING */
- 224, /* (45) generated ::= LP expr RP */
- 224, /* (46) generated ::= LP expr RP ID */
- 220, /* (47) autoinc ::= */
- 220, /* (48) autoinc ::= AUTOINCR */
- 222, /* (49) refargs ::= */
- 222, /* (50) refargs ::= refargs refarg */
- 225, /* (51) refarg ::= MATCH nm */
- 225, /* (52) refarg ::= ON INSERT refact */
- 225, /* (53) refarg ::= ON DELETE refact */
- 225, /* (54) refarg ::= ON UPDATE refact */
- 226, /* (55) refact ::= SET NULL */
- 226, /* (56) refact ::= SET DEFAULT */
- 226, /* (57) refact ::= CASCADE */
- 226, /* (58) refact ::= RESTRICT */
- 226, /* (59) refact ::= NO ACTION */
- 223, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
- 223, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
- 227, /* (62) init_deferred_pred_opt ::= */
- 227, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */
- 227, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
- 202, /* (65) conslist_opt ::= */
- 229, /* (66) tconscomma ::= COMMA */
- 230, /* (67) tcons ::= CONSTRAINT nm */
- 230, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
- 230, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */
- 230, /* (70) tcons ::= CHECK LP expr RP onconf */
- 230, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
- 233, /* (72) defer_subclause_opt ::= */
- 218, /* (73) onconf ::= */
- 218, /* (74) onconf ::= ON CONFLICT resolvetype */
- 234, /* (75) orconf ::= */
- 234, /* (76) orconf ::= OR resolvetype */
- 235, /* (77) resolvetype ::= IGNORE */
- 235, /* (78) resolvetype ::= REPLACE */
- 190, /* (79) cmd ::= DROP TABLE ifexists fullname */
- 237, /* (80) ifexists ::= IF EXISTS */
- 237, /* (81) ifexists ::= */
- 190, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
- 190, /* (83) cmd ::= DROP VIEW ifexists fullname */
- 190, /* (84) cmd ::= select */
- 204, /* (85) select ::= WITH wqlist selectnowith */
- 204, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */
- 204, /* (87) select ::= selectnowith */
- 239, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */
- 242, /* (89) multiselect_op ::= UNION */
- 242, /* (90) multiselect_op ::= UNION ALL */
- 242, /* (91) multiselect_op ::= EXCEPT|INTERSECT */
- 240, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
- 240, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
- 252, /* (94) values ::= VALUES LP nexprlist RP */
- 252, /* (95) values ::= values COMMA LP nexprlist RP */
- 243, /* (96) distinct ::= DISTINCT */
- 243, /* (97) distinct ::= ALL */
- 243, /* (98) distinct ::= */
- 254, /* (99) sclp ::= */
- 244, /* (100) selcollist ::= sclp scanpt expr scanpt as */
- 244, /* (101) selcollist ::= sclp scanpt STAR */
- 244, /* (102) selcollist ::= sclp scanpt nm DOT STAR */
- 255, /* (103) as ::= AS nm */
- 255, /* (104) as ::= */
- 245, /* (105) from ::= */
- 245, /* (106) from ::= FROM seltablist */
- 257, /* (107) stl_prefix ::= seltablist joinop */
- 257, /* (108) stl_prefix ::= */
- 256, /* (109) seltablist ::= stl_prefix nm dbnm as on_using */
- 256, /* (110) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
- 256, /* (111) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
- 256, /* (112) seltablist ::= stl_prefix LP select RP as on_using */
- 256, /* (113) seltablist ::= stl_prefix LP seltablist RP as on_using */
- 200, /* (114) dbnm ::= */
- 200, /* (115) dbnm ::= DOT nm */
- 238, /* (116) fullname ::= nm */
- 238, /* (117) fullname ::= nm DOT nm */
- 262, /* (118) xfullname ::= nm */
- 262, /* (119) xfullname ::= nm DOT nm */
- 262, /* (120) xfullname ::= nm DOT nm AS nm */
- 262, /* (121) xfullname ::= nm AS nm */
- 258, /* (122) joinop ::= COMMA|JOIN */
- 258, /* (123) joinop ::= JOIN_KW JOIN */
- 258, /* (124) joinop ::= JOIN_KW nm JOIN */
- 258, /* (125) joinop ::= JOIN_KW nm nm JOIN */
- 259, /* (126) on_using ::= ON expr */
- 259, /* (127) on_using ::= USING LP idlist RP */
- 259, /* (128) on_using ::= */
- 264, /* (129) indexed_opt ::= */
- 260, /* (130) indexed_by ::= INDEXED BY nm */
- 260, /* (131) indexed_by ::= NOT INDEXED */
- 249, /* (132) orderby_opt ::= */
- 249, /* (133) orderby_opt ::= ORDER BY sortlist */
- 231, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */
- 231, /* (135) sortlist ::= expr sortorder nulls */
- 219, /* (136) sortorder ::= ASC */
- 219, /* (137) sortorder ::= DESC */
- 219, /* (138) sortorder ::= */
- 265, /* (139) nulls ::= NULLS FIRST */
- 265, /* (140) nulls ::= NULLS LAST */
- 265, /* (141) nulls ::= */
- 247, /* (142) groupby_opt ::= */
- 247, /* (143) groupby_opt ::= GROUP BY nexprlist */
- 248, /* (144) having_opt ::= */
- 248, /* (145) having_opt ::= HAVING expr */
- 250, /* (146) limit_opt ::= */
- 250, /* (147) limit_opt ::= LIMIT expr */
- 250, /* (148) limit_opt ::= LIMIT expr OFFSET expr */
- 250, /* (149) limit_opt ::= LIMIT expr COMMA expr */
- 190, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */
- 246, /* (151) where_opt ::= */
- 246, /* (152) where_opt ::= WHERE expr */
- 267, /* (153) where_opt_ret ::= */
- 267, /* (154) where_opt_ret ::= WHERE expr */
- 267, /* (155) where_opt_ret ::= RETURNING selcollist */
- 267, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */
- 190, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */
- 268, /* (158) setlist ::= setlist COMMA nm EQ expr */
- 268, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */
- 268, /* (160) setlist ::= nm EQ expr */
- 268, /* (161) setlist ::= LP idlist RP EQ expr */
- 190, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
- 190, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
- 271, /* (164) upsert ::= */
- 271, /* (165) upsert ::= RETURNING selcollist */
- 271, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
- 271, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
- 271, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */
- 271, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
- 272, /* (170) returning ::= RETURNING selcollist */
- 269, /* (171) insert_cmd ::= INSERT orconf */
- 269, /* (172) insert_cmd ::= REPLACE */
- 270, /* (173) idlist_opt ::= */
- 270, /* (174) idlist_opt ::= LP idlist RP */
- 263, /* (175) idlist ::= idlist COMMA nm */
- 263, /* (176) idlist ::= nm */
- 217, /* (177) expr ::= LP expr RP */
- 217, /* (178) expr ::= ID|INDEXED */
- 217, /* (179) expr ::= JOIN_KW */
- 217, /* (180) expr ::= nm DOT nm */
- 217, /* (181) expr ::= nm DOT nm DOT nm */
- 216, /* (182) term ::= NULL|FLOAT|BLOB */
- 216, /* (183) term ::= STRING */
- 216, /* (184) term ::= INTEGER */
- 217, /* (185) expr ::= VARIABLE */
- 217, /* (186) expr ::= expr COLLATE ID|STRING */
- 217, /* (187) expr ::= CAST LP expr AS typetoken RP */
- 217, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
- 217, /* (189) expr ::= ID|INDEXED LP STAR RP */
- 217, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
- 217, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
- 216, /* (192) term ::= CTIME_KW */
- 217, /* (193) expr ::= LP nexprlist COMMA expr RP */
- 217, /* (194) expr ::= expr AND expr */
- 217, /* (195) expr ::= expr OR expr */
- 217, /* (196) expr ::= expr LT|GT|GE|LE expr */
- 217, /* (197) expr ::= expr EQ|NE expr */
- 217, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
- 217, /* (199) expr ::= expr PLUS|MINUS expr */
- 217, /* (200) expr ::= expr STAR|SLASH|REM expr */
- 217, /* (201) expr ::= expr CONCAT expr */
- 274, /* (202) likeop ::= NOT LIKE_KW|MATCH */
- 217, /* (203) expr ::= expr likeop expr */
- 217, /* (204) expr ::= expr likeop expr ESCAPE expr */
- 217, /* (205) expr ::= expr ISNULL|NOTNULL */
- 217, /* (206) expr ::= expr NOT NULL */
- 217, /* (207) expr ::= expr IS expr */
- 217, /* (208) expr ::= expr IS NOT expr */
- 217, /* (209) expr ::= expr IS NOT DISTINCT FROM expr */
- 217, /* (210) expr ::= expr IS DISTINCT FROM expr */
- 217, /* (211) expr ::= NOT expr */
- 217, /* (212) expr ::= BITNOT expr */
- 217, /* (213) expr ::= PLUS|MINUS expr */
- 217, /* (214) expr ::= expr PTR expr */
- 275, /* (215) between_op ::= BETWEEN */
- 275, /* (216) between_op ::= NOT BETWEEN */
- 217, /* (217) expr ::= expr between_op expr AND expr */
- 276, /* (218) in_op ::= IN */
- 276, /* (219) in_op ::= NOT IN */
- 217, /* (220) expr ::= expr in_op LP exprlist RP */
- 217, /* (221) expr ::= LP select RP */
- 217, /* (222) expr ::= expr in_op LP select RP */
- 217, /* (223) expr ::= expr in_op nm dbnm paren_exprlist */
- 217, /* (224) expr ::= EXISTS LP select RP */
- 217, /* (225) expr ::= CASE case_operand case_exprlist case_else END */
- 279, /* (226) case_exprlist ::= case_exprlist WHEN expr THEN expr */
- 279, /* (227) case_exprlist ::= WHEN expr THEN expr */
- 280, /* (228) case_else ::= ELSE expr */
- 280, /* (229) case_else ::= */
- 278, /* (230) case_operand ::= expr */
- 278, /* (231) case_operand ::= */
- 261, /* (232) exprlist ::= */
- 253, /* (233) nexprlist ::= nexprlist COMMA expr */
- 253, /* (234) nexprlist ::= expr */
- 277, /* (235) paren_exprlist ::= */
- 277, /* (236) paren_exprlist ::= LP exprlist RP */
- 190, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
- 281, /* (238) uniqueflag ::= UNIQUE */
- 281, /* (239) uniqueflag ::= */
- 221, /* (240) eidlist_opt ::= */
- 221, /* (241) eidlist_opt ::= LP eidlist RP */
- 232, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */
- 232, /* (243) eidlist ::= nm collate sortorder */
- 282, /* (244) collate ::= */
- 282, /* (245) collate ::= COLLATE ID|STRING */
- 190, /* (246) cmd ::= DROP INDEX ifexists fullname */
- 190, /* (247) cmd ::= VACUUM vinto */
- 190, /* (248) cmd ::= VACUUM nm vinto */
- 283, /* (249) vinto ::= INTO expr */
- 283, /* (250) vinto ::= */
- 190, /* (251) cmd ::= PRAGMA nm dbnm */
- 190, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */
- 190, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */
- 190, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */
- 190, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */
- 211, /* (256) plus_num ::= PLUS INTEGER|FLOAT */
- 212, /* (257) minus_num ::= MINUS INTEGER|FLOAT */
- 190, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
- 285, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
- 287, /* (260) trigger_time ::= BEFORE|AFTER */
- 287, /* (261) trigger_time ::= INSTEAD OF */
- 287, /* (262) trigger_time ::= */
- 288, /* (263) trigger_event ::= DELETE|INSERT */
- 288, /* (264) trigger_event ::= UPDATE */
- 288, /* (265) trigger_event ::= UPDATE OF idlist */
- 290, /* (266) when_clause ::= */
- 290, /* (267) when_clause ::= WHEN expr */
- 286, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
- 286, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */
- 292, /* (270) trnm ::= nm DOT nm */
- 293, /* (271) tridxby ::= INDEXED BY nm */
- 293, /* (272) tridxby ::= NOT INDEXED */
- 291, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
- 291, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
- 291, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
- 291, /* (276) trigger_cmd ::= scanpt select scanpt */
- 217, /* (277) expr ::= RAISE LP IGNORE RP */
- 217, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */
- 236, /* (279) raisetype ::= ROLLBACK */
- 236, /* (280) raisetype ::= ABORT */
- 236, /* (281) raisetype ::= FAIL */
- 190, /* (282) cmd ::= DROP TRIGGER ifexists fullname */
- 190, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
- 190, /* (284) cmd ::= DETACH database_kw_opt expr */
- 295, /* (285) key_opt ::= */
- 295, /* (286) key_opt ::= KEY expr */
- 190, /* (287) cmd ::= REINDEX */
- 190, /* (288) cmd ::= REINDEX nm dbnm */
- 190, /* (289) cmd ::= ANALYZE */
- 190, /* (290) cmd ::= ANALYZE nm dbnm */
- 190, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */
- 190, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
- 190, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
- 296, /* (294) add_column_fullname ::= fullname */
- 190, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
- 190, /* (296) cmd ::= create_vtab */
- 190, /* (297) cmd ::= create_vtab LP vtabarglist RP */
- 298, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
- 300, /* (299) vtabarg ::= */
- 301, /* (300) vtabargtoken ::= ANY */
- 301, /* (301) vtabargtoken ::= lp anylist RP */
- 302, /* (302) lp ::= LP */
- 266, /* (303) with ::= WITH wqlist */
- 266, /* (304) with ::= WITH RECURSIVE wqlist */
- 305, /* (305) wqas ::= AS */
- 305, /* (306) wqas ::= AS MATERIALIZED */
- 305, /* (307) wqas ::= AS NOT MATERIALIZED */
- 304, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */
- 241, /* (309) wqlist ::= wqitem */
- 241, /* (310) wqlist ::= wqlist COMMA wqitem */
- 306, /* (311) windowdefn_list ::= windowdefn */
- 306, /* (312) windowdefn_list ::= windowdefn_list COMMA windowdefn */
- 307, /* (313) windowdefn ::= nm AS LP window RP */
- 308, /* (314) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
- 308, /* (315) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
- 308, /* (316) window ::= ORDER BY sortlist frame_opt */
- 308, /* (317) window ::= nm ORDER BY sortlist frame_opt */
- 308, /* (318) window ::= frame_opt */
- 308, /* (319) window ::= nm frame_opt */
- 309, /* (320) frame_opt ::= */
- 309, /* (321) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
- 309, /* (322) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
- 313, /* (323) range_or_rows ::= RANGE|ROWS|GROUPS */
- 315, /* (324) frame_bound_s ::= frame_bound */
- 315, /* (325) frame_bound_s ::= UNBOUNDED PRECEDING */
- 316, /* (326) frame_bound_e ::= frame_bound */
- 316, /* (327) frame_bound_e ::= UNBOUNDED FOLLOWING */
- 314, /* (328) frame_bound ::= expr PRECEDING|FOLLOWING */
- 314, /* (329) frame_bound ::= CURRENT ROW */
- 317, /* (330) frame_exclude_opt ::= */
- 317, /* (331) frame_exclude_opt ::= EXCLUDE frame_exclude */
- 318, /* (332) frame_exclude ::= NO OTHERS */
- 318, /* (333) frame_exclude ::= CURRENT ROW */
- 318, /* (334) frame_exclude ::= GROUP|TIES */
- 251, /* (335) window_clause ::= WINDOW windowdefn_list */
- 273, /* (336) filter_over ::= filter_clause over_clause */
- 273, /* (337) filter_over ::= over_clause */
- 273, /* (338) filter_over ::= filter_clause */
- 312, /* (339) over_clause ::= OVER LP window RP */
- 312, /* (340) over_clause ::= OVER nm */
- 311, /* (341) filter_clause ::= FILTER LP WHERE expr RP */
- 185, /* (342) input ::= cmdlist */
- 186, /* (343) cmdlist ::= cmdlist ecmd */
- 186, /* (344) cmdlist ::= ecmd */
- 187, /* (345) ecmd ::= SEMI */
- 187, /* (346) ecmd ::= cmdx SEMI */
- 187, /* (347) ecmd ::= explain cmdx SEMI */
- 192, /* (348) trans_opt ::= */
- 192, /* (349) trans_opt ::= TRANSACTION */
- 192, /* (350) trans_opt ::= TRANSACTION nm */
- 194, /* (351) savepoint_opt ::= SAVEPOINT */
- 194, /* (352) savepoint_opt ::= */
- 190, /* (353) cmd ::= create_table create_table_args */
- 203, /* (354) table_option_set ::= table_option */
- 201, /* (355) columnlist ::= columnlist COMMA columnname carglist */
- 201, /* (356) columnlist ::= columnname carglist */
- 193, /* (357) nm ::= ID|INDEXED */
- 193, /* (358) nm ::= STRING */
- 193, /* (359) nm ::= JOIN_KW */
- 208, /* (360) typetoken ::= typename */
- 209, /* (361) typename ::= ID|STRING */
- 210, /* (362) signed ::= plus_num */
- 210, /* (363) signed ::= minus_num */
- 207, /* (364) carglist ::= carglist ccons */
- 207, /* (365) carglist ::= */
- 215, /* (366) ccons ::= NULL onconf */
- 215, /* (367) ccons ::= GENERATED ALWAYS AS generated */
- 215, /* (368) ccons ::= AS generated */
- 202, /* (369) conslist_opt ::= COMMA conslist */
- 228, /* (370) conslist ::= conslist tconscomma tcons */
- 228, /* (371) conslist ::= tcons */
- 229, /* (372) tconscomma ::= */
- 233, /* (373) defer_subclause_opt ::= defer_subclause */
- 235, /* (374) resolvetype ::= raisetype */
- 239, /* (375) selectnowith ::= oneselect */
- 240, /* (376) oneselect ::= values */
- 254, /* (377) sclp ::= selcollist COMMA */
- 255, /* (378) as ::= ID|STRING */
- 264, /* (379) indexed_opt ::= indexed_by */
- 272, /* (380) returning ::= */
- 217, /* (381) expr ::= term */
- 274, /* (382) likeop ::= LIKE_KW|MATCH */
- 261, /* (383) exprlist ::= nexprlist */
- 284, /* (384) nmnum ::= plus_num */
- 284, /* (385) nmnum ::= nm */
- 284, /* (386) nmnum ::= ON */
- 284, /* (387) nmnum ::= DELETE */
- 284, /* (388) nmnum ::= DEFAULT */
- 211, /* (389) plus_num ::= INTEGER|FLOAT */
- 289, /* (390) foreach_clause ::= */
- 289, /* (391) foreach_clause ::= FOR EACH ROW */
- 292, /* (392) trnm ::= nm */
- 293, /* (393) tridxby ::= */
- 294, /* (394) database_kw_opt ::= DATABASE */
- 294, /* (395) database_kw_opt ::= */
- 297, /* (396) kwcolumn_opt ::= */
- 297, /* (397) kwcolumn_opt ::= COLUMNKW */
- 299, /* (398) vtabarglist ::= vtabarg */
- 299, /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */
- 300, /* (400) vtabarg ::= vtabarg vtabargtoken */
- 303, /* (401) anylist ::= */
- 303, /* (402) anylist ::= anylist LP anylist RP */
- 303, /* (403) anylist ::= anylist ANY */
- 266, /* (404) with ::= */
+ 190, /* (0) explain ::= EXPLAIN */
+ 190, /* (1) explain ::= EXPLAIN QUERY PLAN */
+ 189, /* (2) cmdx ::= cmd */
+ 191, /* (3) cmd ::= BEGIN transtype trans_opt */
+ 192, /* (4) transtype ::= */
+ 192, /* (5) transtype ::= DEFERRED */
+ 192, /* (6) transtype ::= IMMEDIATE */
+ 192, /* (7) transtype ::= EXCLUSIVE */
+ 191, /* (8) cmd ::= COMMIT|END trans_opt */
+ 191, /* (9) cmd ::= ROLLBACK trans_opt */
+ 191, /* (10) cmd ::= SAVEPOINT nm */
+ 191, /* (11) cmd ::= RELEASE savepoint_opt nm */
+ 191, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ 196, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+ 198, /* (14) createkw ::= CREATE */
+ 200, /* (15) ifnotexists ::= */
+ 200, /* (16) ifnotexists ::= IF NOT EXISTS */
+ 199, /* (17) temp ::= TEMP */
+ 199, /* (18) temp ::= */
+ 197, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
+ 197, /* (20) create_table_args ::= AS select */
+ 204, /* (21) table_option_set ::= */
+ 204, /* (22) table_option_set ::= table_option_set COMMA table_option */
+ 206, /* (23) table_option ::= WITHOUT nm */
+ 206, /* (24) table_option ::= nm */
+ 207, /* (25) columnname ::= nm typetoken */
+ 209, /* (26) typetoken ::= */
+ 209, /* (27) typetoken ::= typename LP signed RP */
+ 209, /* (28) typetoken ::= typename LP signed COMMA signed RP */
+ 210, /* (29) typename ::= typename ID|STRING */
+ 214, /* (30) scanpt ::= */
+ 215, /* (31) scantok ::= */
+ 216, /* (32) ccons ::= CONSTRAINT nm */
+ 216, /* (33) ccons ::= DEFAULT scantok term */
+ 216, /* (34) ccons ::= DEFAULT LP expr RP */
+ 216, /* (35) ccons ::= DEFAULT PLUS scantok term */
+ 216, /* (36) ccons ::= DEFAULT MINUS scantok term */
+ 216, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */
+ 216, /* (38) ccons ::= NOT NULL onconf */
+ 216, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */
+ 216, /* (40) ccons ::= UNIQUE onconf */
+ 216, /* (41) ccons ::= CHECK LP expr RP */
+ 216, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */
+ 216, /* (43) ccons ::= defer_subclause */
+ 216, /* (44) ccons ::= COLLATE ID|STRING */
+ 225, /* (45) generated ::= LP expr RP */
+ 225, /* (46) generated ::= LP expr RP ID */
+ 221, /* (47) autoinc ::= */
+ 221, /* (48) autoinc ::= AUTOINCR */
+ 223, /* (49) refargs ::= */
+ 223, /* (50) refargs ::= refargs refarg */
+ 226, /* (51) refarg ::= MATCH nm */
+ 226, /* (52) refarg ::= ON INSERT refact */
+ 226, /* (53) refarg ::= ON DELETE refact */
+ 226, /* (54) refarg ::= ON UPDATE refact */
+ 227, /* (55) refact ::= SET NULL */
+ 227, /* (56) refact ::= SET DEFAULT */
+ 227, /* (57) refact ::= CASCADE */
+ 227, /* (58) refact ::= RESTRICT */
+ 227, /* (59) refact ::= NO ACTION */
+ 224, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+ 224, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ 228, /* (62) init_deferred_pred_opt ::= */
+ 228, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */
+ 228, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+ 203, /* (65) conslist_opt ::= */
+ 230, /* (66) tconscomma ::= COMMA */
+ 231, /* (67) tcons ::= CONSTRAINT nm */
+ 231, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
+ 231, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */
+ 231, /* (70) tcons ::= CHECK LP expr RP onconf */
+ 231, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+ 234, /* (72) defer_subclause_opt ::= */
+ 219, /* (73) onconf ::= */
+ 219, /* (74) onconf ::= ON CONFLICT resolvetype */
+ 235, /* (75) orconf ::= */
+ 235, /* (76) orconf ::= OR resolvetype */
+ 236, /* (77) resolvetype ::= IGNORE */
+ 236, /* (78) resolvetype ::= REPLACE */
+ 191, /* (79) cmd ::= DROP TABLE ifexists fullname */
+ 238, /* (80) ifexists ::= IF EXISTS */
+ 238, /* (81) ifexists ::= */
+ 191, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+ 191, /* (83) cmd ::= DROP VIEW ifexists fullname */
+ 191, /* (84) cmd ::= select */
+ 205, /* (85) select ::= WITH wqlist selectnowith */
+ 205, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */
+ 205, /* (87) select ::= selectnowith */
+ 240, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */
+ 243, /* (89) multiselect_op ::= UNION */
+ 243, /* (90) multiselect_op ::= UNION ALL */
+ 243, /* (91) multiselect_op ::= EXCEPT|INTERSECT */
+ 241, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+ 241, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
+ 253, /* (94) values ::= VALUES LP nexprlist RP */
+ 241, /* (95) oneselect ::= mvalues */
+ 255, /* (96) mvalues ::= values COMMA LP nexprlist RP */
+ 255, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */
+ 244, /* (98) distinct ::= DISTINCT */
+ 244, /* (99) distinct ::= ALL */
+ 244, /* (100) distinct ::= */
+ 256, /* (101) sclp ::= */
+ 245, /* (102) selcollist ::= sclp scanpt expr scanpt as */
+ 245, /* (103) selcollist ::= sclp scanpt STAR */
+ 245, /* (104) selcollist ::= sclp scanpt nm DOT STAR */
+ 257, /* (105) as ::= AS nm */
+ 257, /* (106) as ::= */
+ 246, /* (107) from ::= */
+ 246, /* (108) from ::= FROM seltablist */
+ 259, /* (109) stl_prefix ::= seltablist joinop */
+ 259, /* (110) stl_prefix ::= */
+ 258, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */
+ 258, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
+ 258, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
+ 258, /* (114) seltablist ::= stl_prefix LP select RP as on_using */
+ 258, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */
+ 201, /* (116) dbnm ::= */
+ 201, /* (117) dbnm ::= DOT nm */
+ 239, /* (118) fullname ::= nm */
+ 239, /* (119) fullname ::= nm DOT nm */
+ 264, /* (120) xfullname ::= nm */
+ 264, /* (121) xfullname ::= nm DOT nm */
+ 264, /* (122) xfullname ::= nm DOT nm AS nm */
+ 264, /* (123) xfullname ::= nm AS nm */
+ 260, /* (124) joinop ::= COMMA|JOIN */
+ 260, /* (125) joinop ::= JOIN_KW JOIN */
+ 260, /* (126) joinop ::= JOIN_KW nm JOIN */
+ 260, /* (127) joinop ::= JOIN_KW nm nm JOIN */
+ 261, /* (128) on_using ::= ON expr */
+ 261, /* (129) on_using ::= USING LP idlist RP */
+ 261, /* (130) on_using ::= */
+ 266, /* (131) indexed_opt ::= */
+ 262, /* (132) indexed_by ::= INDEXED BY nm */
+ 262, /* (133) indexed_by ::= NOT INDEXED */
+ 250, /* (134) orderby_opt ::= */
+ 250, /* (135) orderby_opt ::= ORDER BY sortlist */
+ 232, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */
+ 232, /* (137) sortlist ::= expr sortorder nulls */
+ 220, /* (138) sortorder ::= ASC */
+ 220, /* (139) sortorder ::= DESC */
+ 220, /* (140) sortorder ::= */
+ 267, /* (141) nulls ::= NULLS FIRST */
+ 267, /* (142) nulls ::= NULLS LAST */
+ 267, /* (143) nulls ::= */
+ 248, /* (144) groupby_opt ::= */
+ 248, /* (145) groupby_opt ::= GROUP BY nexprlist */
+ 249, /* (146) having_opt ::= */
+ 249, /* (147) having_opt ::= HAVING expr */
+ 251, /* (148) limit_opt ::= */
+ 251, /* (149) limit_opt ::= LIMIT expr */
+ 251, /* (150) limit_opt ::= LIMIT expr OFFSET expr */
+ 251, /* (151) limit_opt ::= LIMIT expr COMMA expr */
+ 191, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */
+ 247, /* (153) where_opt ::= */
+ 247, /* (154) where_opt ::= WHERE expr */
+ 269, /* (155) where_opt_ret ::= */
+ 269, /* (156) where_opt_ret ::= WHERE expr */
+ 269, /* (157) where_opt_ret ::= RETURNING selcollist */
+ 269, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */
+ 191, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */
+ 270, /* (160) setlist ::= setlist COMMA nm EQ expr */
+ 270, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */
+ 270, /* (162) setlist ::= nm EQ expr */
+ 270, /* (163) setlist ::= LP idlist RP EQ expr */
+ 191, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ 191, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
+ 273, /* (166) upsert ::= */
+ 273, /* (167) upsert ::= RETURNING selcollist */
+ 273, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
+ 273, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
+ 273, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */
+ 273, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
+ 274, /* (172) returning ::= RETURNING selcollist */
+ 271, /* (173) insert_cmd ::= INSERT orconf */
+ 271, /* (174) insert_cmd ::= REPLACE */
+ 272, /* (175) idlist_opt ::= */
+ 272, /* (176) idlist_opt ::= LP idlist RP */
+ 265, /* (177) idlist ::= idlist COMMA nm */
+ 265, /* (178) idlist ::= nm */
+ 218, /* (179) expr ::= LP expr RP */
+ 218, /* (180) expr ::= ID|INDEXED|JOIN_KW */
+ 218, /* (181) expr ::= nm DOT nm */
+ 218, /* (182) expr ::= nm DOT nm DOT nm */
+ 217, /* (183) term ::= NULL|FLOAT|BLOB */
+ 217, /* (184) term ::= STRING */
+ 217, /* (185) term ::= INTEGER */
+ 218, /* (186) expr ::= VARIABLE */
+ 218, /* (187) expr ::= expr COLLATE ID|STRING */
+ 218, /* (188) expr ::= CAST LP expr AS typetoken RP */
+ 218, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+ 218, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
+ 218, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
+ 218, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
+ 218, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
+ 218, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
+ 217, /* (195) term ::= CTIME_KW */
+ 218, /* (196) expr ::= LP nexprlist COMMA expr RP */
+ 218, /* (197) expr ::= expr AND expr */
+ 218, /* (198) expr ::= expr OR expr */
+ 218, /* (199) expr ::= expr LT|GT|GE|LE expr */
+ 218, /* (200) expr ::= expr EQ|NE expr */
+ 218, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ 218, /* (202) expr ::= expr PLUS|MINUS expr */
+ 218, /* (203) expr ::= expr STAR|SLASH|REM expr */
+ 218, /* (204) expr ::= expr CONCAT expr */
+ 276, /* (205) likeop ::= NOT LIKE_KW|MATCH */
+ 218, /* (206) expr ::= expr likeop expr */
+ 218, /* (207) expr ::= expr likeop expr ESCAPE expr */
+ 218, /* (208) expr ::= expr ISNULL|NOTNULL */
+ 218, /* (209) expr ::= expr NOT NULL */
+ 218, /* (210) expr ::= expr IS expr */
+ 218, /* (211) expr ::= expr IS NOT expr */
+ 218, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */
+ 218, /* (213) expr ::= expr IS DISTINCT FROM expr */
+ 218, /* (214) expr ::= NOT expr */
+ 218, /* (215) expr ::= BITNOT expr */
+ 218, /* (216) expr ::= PLUS|MINUS expr */
+ 218, /* (217) expr ::= expr PTR expr */
+ 277, /* (218) between_op ::= BETWEEN */
+ 277, /* (219) between_op ::= NOT BETWEEN */
+ 218, /* (220) expr ::= expr between_op expr AND expr */
+ 278, /* (221) in_op ::= IN */
+ 278, /* (222) in_op ::= NOT IN */
+ 218, /* (223) expr ::= expr in_op LP exprlist RP */
+ 218, /* (224) expr ::= LP select RP */
+ 218, /* (225) expr ::= expr in_op LP select RP */
+ 218, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */
+ 218, /* (227) expr ::= EXISTS LP select RP */
+ 218, /* (228) expr ::= CASE case_operand case_exprlist case_else END */
+ 281, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ 281, /* (230) case_exprlist ::= WHEN expr THEN expr */
+ 282, /* (231) case_else ::= ELSE expr */
+ 282, /* (232) case_else ::= */
+ 280, /* (233) case_operand ::= */
+ 263, /* (234) exprlist ::= */
+ 254, /* (235) nexprlist ::= nexprlist COMMA expr */
+ 254, /* (236) nexprlist ::= expr */
+ 279, /* (237) paren_exprlist ::= */
+ 279, /* (238) paren_exprlist ::= LP exprlist RP */
+ 191, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ 283, /* (240) uniqueflag ::= UNIQUE */
+ 283, /* (241) uniqueflag ::= */
+ 222, /* (242) eidlist_opt ::= */
+ 222, /* (243) eidlist_opt ::= LP eidlist RP */
+ 233, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */
+ 233, /* (245) eidlist ::= nm collate sortorder */
+ 284, /* (246) collate ::= */
+ 284, /* (247) collate ::= COLLATE ID|STRING */
+ 191, /* (248) cmd ::= DROP INDEX ifexists fullname */
+ 191, /* (249) cmd ::= VACUUM vinto */
+ 191, /* (250) cmd ::= VACUUM nm vinto */
+ 285, /* (251) vinto ::= INTO expr */
+ 285, /* (252) vinto ::= */
+ 191, /* (253) cmd ::= PRAGMA nm dbnm */
+ 191, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */
+ 191, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ 191, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */
+ 191, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ 212, /* (258) plus_num ::= PLUS INTEGER|FLOAT */
+ 213, /* (259) minus_num ::= MINUS INTEGER|FLOAT */
+ 191, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ 287, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ 289, /* (262) trigger_time ::= BEFORE|AFTER */
+ 289, /* (263) trigger_time ::= INSTEAD OF */
+ 289, /* (264) trigger_time ::= */
+ 290, /* (265) trigger_event ::= DELETE|INSERT */
+ 290, /* (266) trigger_event ::= UPDATE */
+ 290, /* (267) trigger_event ::= UPDATE OF idlist */
+ 292, /* (268) when_clause ::= */
+ 292, /* (269) when_clause ::= WHEN expr */
+ 288, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ 288, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */
+ 294, /* (272) trnm ::= nm DOT nm */
+ 295, /* (273) tridxby ::= INDEXED BY nm */
+ 295, /* (274) tridxby ::= NOT INDEXED */
+ 293, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ 293, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ 293, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ 293, /* (278) trigger_cmd ::= scanpt select scanpt */
+ 218, /* (279) expr ::= RAISE LP IGNORE RP */
+ 218, /* (280) expr ::= RAISE LP raisetype COMMA nm RP */
+ 237, /* (281) raisetype ::= ROLLBACK */
+ 237, /* (282) raisetype ::= ABORT */
+ 237, /* (283) raisetype ::= FAIL */
+ 191, /* (284) cmd ::= DROP TRIGGER ifexists fullname */
+ 191, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ 191, /* (286) cmd ::= DETACH database_kw_opt expr */
+ 297, /* (287) key_opt ::= */
+ 297, /* (288) key_opt ::= KEY expr */
+ 191, /* (289) cmd ::= REINDEX */
+ 191, /* (290) cmd ::= REINDEX nm dbnm */
+ 191, /* (291) cmd ::= ANALYZE */
+ 191, /* (292) cmd ::= ANALYZE nm dbnm */
+ 191, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */
+ 191, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ 191, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ 298, /* (296) add_column_fullname ::= fullname */
+ 191, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ 191, /* (298) cmd ::= create_vtab */
+ 191, /* (299) cmd ::= create_vtab LP vtabarglist RP */
+ 300, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ 302, /* (301) vtabarg ::= */
+ 303, /* (302) vtabargtoken ::= ANY */
+ 303, /* (303) vtabargtoken ::= lp anylist RP */
+ 304, /* (304) lp ::= LP */
+ 268, /* (305) with ::= WITH wqlist */
+ 268, /* (306) with ::= WITH RECURSIVE wqlist */
+ 307, /* (307) wqas ::= AS */
+ 307, /* (308) wqas ::= AS MATERIALIZED */
+ 307, /* (309) wqas ::= AS NOT MATERIALIZED */
+ 306, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */
+ 308, /* (311) withnm ::= nm */
+ 242, /* (312) wqlist ::= wqitem */
+ 242, /* (313) wqlist ::= wqlist COMMA wqitem */
+ 309, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ 310, /* (315) windowdefn ::= nm AS LP window RP */
+ 311, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ 311, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ 311, /* (318) window ::= ORDER BY sortlist frame_opt */
+ 311, /* (319) window ::= nm ORDER BY sortlist frame_opt */
+ 311, /* (320) window ::= nm frame_opt */
+ 312, /* (321) frame_opt ::= */
+ 312, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ 312, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ 316, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */
+ 318, /* (325) frame_bound_s ::= frame_bound */
+ 318, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */
+ 319, /* (327) frame_bound_e ::= frame_bound */
+ 319, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ 317, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */
+ 317, /* (330) frame_bound ::= CURRENT ROW */
+ 320, /* (331) frame_exclude_opt ::= */
+ 320, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ 321, /* (333) frame_exclude ::= NO OTHERS */
+ 321, /* (334) frame_exclude ::= CURRENT ROW */
+ 321, /* (335) frame_exclude ::= GROUP|TIES */
+ 252, /* (336) window_clause ::= WINDOW windowdefn_list */
+ 275, /* (337) filter_over ::= filter_clause over_clause */
+ 275, /* (338) filter_over ::= over_clause */
+ 275, /* (339) filter_over ::= filter_clause */
+ 315, /* (340) over_clause ::= OVER LP window RP */
+ 315, /* (341) over_clause ::= OVER nm */
+ 314, /* (342) filter_clause ::= FILTER LP WHERE expr RP */
+ 217, /* (343) term ::= QNUMBER */
+ 186, /* (344) input ::= cmdlist */
+ 187, /* (345) cmdlist ::= cmdlist ecmd */
+ 187, /* (346) cmdlist ::= ecmd */
+ 188, /* (347) ecmd ::= SEMI */
+ 188, /* (348) ecmd ::= cmdx SEMI */
+ 188, /* (349) ecmd ::= explain cmdx SEMI */
+ 193, /* (350) trans_opt ::= */
+ 193, /* (351) trans_opt ::= TRANSACTION */
+ 193, /* (352) trans_opt ::= TRANSACTION nm */
+ 195, /* (353) savepoint_opt ::= SAVEPOINT */
+ 195, /* (354) savepoint_opt ::= */
+ 191, /* (355) cmd ::= create_table create_table_args */
+ 204, /* (356) table_option_set ::= table_option */
+ 202, /* (357) columnlist ::= columnlist COMMA columnname carglist */
+ 202, /* (358) columnlist ::= columnname carglist */
+ 194, /* (359) nm ::= ID|INDEXED|JOIN_KW */
+ 194, /* (360) nm ::= STRING */
+ 209, /* (361) typetoken ::= typename */
+ 210, /* (362) typename ::= ID|STRING */
+ 211, /* (363) signed ::= plus_num */
+ 211, /* (364) signed ::= minus_num */
+ 208, /* (365) carglist ::= carglist ccons */
+ 208, /* (366) carglist ::= */
+ 216, /* (367) ccons ::= NULL onconf */
+ 216, /* (368) ccons ::= GENERATED ALWAYS AS generated */
+ 216, /* (369) ccons ::= AS generated */
+ 203, /* (370) conslist_opt ::= COMMA conslist */
+ 229, /* (371) conslist ::= conslist tconscomma tcons */
+ 229, /* (372) conslist ::= tcons */
+ 230, /* (373) tconscomma ::= */
+ 234, /* (374) defer_subclause_opt ::= defer_subclause */
+ 236, /* (375) resolvetype ::= raisetype */
+ 240, /* (376) selectnowith ::= oneselect */
+ 241, /* (377) oneselect ::= values */
+ 256, /* (378) sclp ::= selcollist COMMA */
+ 257, /* (379) as ::= ID|STRING */
+ 266, /* (380) indexed_opt ::= indexed_by */
+ 274, /* (381) returning ::= */
+ 218, /* (382) expr ::= term */
+ 276, /* (383) likeop ::= LIKE_KW|MATCH */
+ 280, /* (384) case_operand ::= expr */
+ 263, /* (385) exprlist ::= nexprlist */
+ 286, /* (386) nmnum ::= plus_num */
+ 286, /* (387) nmnum ::= nm */
+ 286, /* (388) nmnum ::= ON */
+ 286, /* (389) nmnum ::= DELETE */
+ 286, /* (390) nmnum ::= DEFAULT */
+ 212, /* (391) plus_num ::= INTEGER|FLOAT */
+ 291, /* (392) foreach_clause ::= */
+ 291, /* (393) foreach_clause ::= FOR EACH ROW */
+ 294, /* (394) trnm ::= nm */
+ 295, /* (395) tridxby ::= */
+ 296, /* (396) database_kw_opt ::= DATABASE */
+ 296, /* (397) database_kw_opt ::= */
+ 299, /* (398) kwcolumn_opt ::= */
+ 299, /* (399) kwcolumn_opt ::= COLUMNKW */
+ 301, /* (400) vtabarglist ::= vtabarg */
+ 301, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */
+ 302, /* (402) vtabarg ::= vtabarg vtabargtoken */
+ 305, /* (403) anylist ::= */
+ 305, /* (404) anylist ::= anylist LP anylist RP */
+ 305, /* (405) anylist ::= anylist ANY */
+ 268, /* (406) with ::= */
+ 309, /* (407) windowdefn_list ::= windowdefn */
+ 311, /* (408) window ::= frame_opt */
};
/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
@@ -172118,316 +181002,320 @@ static const signed char yyRuleInfoNRhs[] = {
-9, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
-10, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
-4, /* (94) values ::= VALUES LP nexprlist RP */
- -5, /* (95) values ::= values COMMA LP nexprlist RP */
- -1, /* (96) distinct ::= DISTINCT */
- -1, /* (97) distinct ::= ALL */
- 0, /* (98) distinct ::= */
- 0, /* (99) sclp ::= */
- -5, /* (100) selcollist ::= sclp scanpt expr scanpt as */
- -3, /* (101) selcollist ::= sclp scanpt STAR */
- -5, /* (102) selcollist ::= sclp scanpt nm DOT STAR */
- -2, /* (103) as ::= AS nm */
- 0, /* (104) as ::= */
- 0, /* (105) from ::= */
- -2, /* (106) from ::= FROM seltablist */
- -2, /* (107) stl_prefix ::= seltablist joinop */
- 0, /* (108) stl_prefix ::= */
- -5, /* (109) seltablist ::= stl_prefix nm dbnm as on_using */
- -6, /* (110) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
- -8, /* (111) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
- -6, /* (112) seltablist ::= stl_prefix LP select RP as on_using */
- -6, /* (113) seltablist ::= stl_prefix LP seltablist RP as on_using */
- 0, /* (114) dbnm ::= */
- -2, /* (115) dbnm ::= DOT nm */
- -1, /* (116) fullname ::= nm */
- -3, /* (117) fullname ::= nm DOT nm */
- -1, /* (118) xfullname ::= nm */
- -3, /* (119) xfullname ::= nm DOT nm */
- -5, /* (120) xfullname ::= nm DOT nm AS nm */
- -3, /* (121) xfullname ::= nm AS nm */
- -1, /* (122) joinop ::= COMMA|JOIN */
- -2, /* (123) joinop ::= JOIN_KW JOIN */
- -3, /* (124) joinop ::= JOIN_KW nm JOIN */
- -4, /* (125) joinop ::= JOIN_KW nm nm JOIN */
- -2, /* (126) on_using ::= ON expr */
- -4, /* (127) on_using ::= USING LP idlist RP */
- 0, /* (128) on_using ::= */
- 0, /* (129) indexed_opt ::= */
- -3, /* (130) indexed_by ::= INDEXED BY nm */
- -2, /* (131) indexed_by ::= NOT INDEXED */
- 0, /* (132) orderby_opt ::= */
- -3, /* (133) orderby_opt ::= ORDER BY sortlist */
- -5, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */
- -3, /* (135) sortlist ::= expr sortorder nulls */
- -1, /* (136) sortorder ::= ASC */
- -1, /* (137) sortorder ::= DESC */
- 0, /* (138) sortorder ::= */
- -2, /* (139) nulls ::= NULLS FIRST */
- -2, /* (140) nulls ::= NULLS LAST */
- 0, /* (141) nulls ::= */
- 0, /* (142) groupby_opt ::= */
- -3, /* (143) groupby_opt ::= GROUP BY nexprlist */
- 0, /* (144) having_opt ::= */
- -2, /* (145) having_opt ::= HAVING expr */
- 0, /* (146) limit_opt ::= */
- -2, /* (147) limit_opt ::= LIMIT expr */
- -4, /* (148) limit_opt ::= LIMIT expr OFFSET expr */
- -4, /* (149) limit_opt ::= LIMIT expr COMMA expr */
- -8, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */
- 0, /* (151) where_opt ::= */
- -2, /* (152) where_opt ::= WHERE expr */
- 0, /* (153) where_opt_ret ::= */
- -2, /* (154) where_opt_ret ::= WHERE expr */
- -2, /* (155) where_opt_ret ::= RETURNING selcollist */
- -4, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */
- -11, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */
- -5, /* (158) setlist ::= setlist COMMA nm EQ expr */
- -7, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */
- -3, /* (160) setlist ::= nm EQ expr */
- -5, /* (161) setlist ::= LP idlist RP EQ expr */
- -7, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
- -8, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
- 0, /* (164) upsert ::= */
- -2, /* (165) upsert ::= RETURNING selcollist */
- -12, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
- -9, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
- -5, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */
- -8, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
- -2, /* (170) returning ::= RETURNING selcollist */
- -2, /* (171) insert_cmd ::= INSERT orconf */
- -1, /* (172) insert_cmd ::= REPLACE */
- 0, /* (173) idlist_opt ::= */
- -3, /* (174) idlist_opt ::= LP idlist RP */
- -3, /* (175) idlist ::= idlist COMMA nm */
- -1, /* (176) idlist ::= nm */
- -3, /* (177) expr ::= LP expr RP */
- -1, /* (178) expr ::= ID|INDEXED */
- -1, /* (179) expr ::= JOIN_KW */
- -3, /* (180) expr ::= nm DOT nm */
- -5, /* (181) expr ::= nm DOT nm DOT nm */
- -1, /* (182) term ::= NULL|FLOAT|BLOB */
- -1, /* (183) term ::= STRING */
- -1, /* (184) term ::= INTEGER */
- -1, /* (185) expr ::= VARIABLE */
- -3, /* (186) expr ::= expr COLLATE ID|STRING */
- -6, /* (187) expr ::= CAST LP expr AS typetoken RP */
- -5, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
- -4, /* (189) expr ::= ID|INDEXED LP STAR RP */
- -6, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
- -5, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
- -1, /* (192) term ::= CTIME_KW */
- -5, /* (193) expr ::= LP nexprlist COMMA expr RP */
- -3, /* (194) expr ::= expr AND expr */
- -3, /* (195) expr ::= expr OR expr */
- -3, /* (196) expr ::= expr LT|GT|GE|LE expr */
- -3, /* (197) expr ::= expr EQ|NE expr */
- -3, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
- -3, /* (199) expr ::= expr PLUS|MINUS expr */
- -3, /* (200) expr ::= expr STAR|SLASH|REM expr */
- -3, /* (201) expr ::= expr CONCAT expr */
- -2, /* (202) likeop ::= NOT LIKE_KW|MATCH */
- -3, /* (203) expr ::= expr likeop expr */
- -5, /* (204) expr ::= expr likeop expr ESCAPE expr */
- -2, /* (205) expr ::= expr ISNULL|NOTNULL */
- -3, /* (206) expr ::= expr NOT NULL */
- -3, /* (207) expr ::= expr IS expr */
- -4, /* (208) expr ::= expr IS NOT expr */
- -6, /* (209) expr ::= expr IS NOT DISTINCT FROM expr */
- -5, /* (210) expr ::= expr IS DISTINCT FROM expr */
- -2, /* (211) expr ::= NOT expr */
- -2, /* (212) expr ::= BITNOT expr */
- -2, /* (213) expr ::= PLUS|MINUS expr */
- -3, /* (214) expr ::= expr PTR expr */
- -1, /* (215) between_op ::= BETWEEN */
- -2, /* (216) between_op ::= NOT BETWEEN */
- -5, /* (217) expr ::= expr between_op expr AND expr */
- -1, /* (218) in_op ::= IN */
- -2, /* (219) in_op ::= NOT IN */
- -5, /* (220) expr ::= expr in_op LP exprlist RP */
- -3, /* (221) expr ::= LP select RP */
- -5, /* (222) expr ::= expr in_op LP select RP */
- -5, /* (223) expr ::= expr in_op nm dbnm paren_exprlist */
- -4, /* (224) expr ::= EXISTS LP select RP */
- -5, /* (225) expr ::= CASE case_operand case_exprlist case_else END */
- -5, /* (226) case_exprlist ::= case_exprlist WHEN expr THEN expr */
- -4, /* (227) case_exprlist ::= WHEN expr THEN expr */
- -2, /* (228) case_else ::= ELSE expr */
- 0, /* (229) case_else ::= */
- -1, /* (230) case_operand ::= expr */
- 0, /* (231) case_operand ::= */
- 0, /* (232) exprlist ::= */
- -3, /* (233) nexprlist ::= nexprlist COMMA expr */
- -1, /* (234) nexprlist ::= expr */
- 0, /* (235) paren_exprlist ::= */
- -3, /* (236) paren_exprlist ::= LP exprlist RP */
- -12, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
- -1, /* (238) uniqueflag ::= UNIQUE */
- 0, /* (239) uniqueflag ::= */
- 0, /* (240) eidlist_opt ::= */
- -3, /* (241) eidlist_opt ::= LP eidlist RP */
- -5, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */
- -3, /* (243) eidlist ::= nm collate sortorder */
- 0, /* (244) collate ::= */
- -2, /* (245) collate ::= COLLATE ID|STRING */
- -4, /* (246) cmd ::= DROP INDEX ifexists fullname */
- -2, /* (247) cmd ::= VACUUM vinto */
- -3, /* (248) cmd ::= VACUUM nm vinto */
- -2, /* (249) vinto ::= INTO expr */
- 0, /* (250) vinto ::= */
- -3, /* (251) cmd ::= PRAGMA nm dbnm */
- -5, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */
- -6, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */
- -5, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */
- -6, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */
- -2, /* (256) plus_num ::= PLUS INTEGER|FLOAT */
- -2, /* (257) minus_num ::= MINUS INTEGER|FLOAT */
- -5, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
- -11, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
- -1, /* (260) trigger_time ::= BEFORE|AFTER */
- -2, /* (261) trigger_time ::= INSTEAD OF */
- 0, /* (262) trigger_time ::= */
- -1, /* (263) trigger_event ::= DELETE|INSERT */
- -1, /* (264) trigger_event ::= UPDATE */
- -3, /* (265) trigger_event ::= UPDATE OF idlist */
- 0, /* (266) when_clause ::= */
- -2, /* (267) when_clause ::= WHEN expr */
- -3, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
- -2, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */
- -3, /* (270) trnm ::= nm DOT nm */
- -3, /* (271) tridxby ::= INDEXED BY nm */
- -2, /* (272) tridxby ::= NOT INDEXED */
- -9, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
- -8, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
- -6, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
- -3, /* (276) trigger_cmd ::= scanpt select scanpt */
- -4, /* (277) expr ::= RAISE LP IGNORE RP */
- -6, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */
- -1, /* (279) raisetype ::= ROLLBACK */
- -1, /* (280) raisetype ::= ABORT */
- -1, /* (281) raisetype ::= FAIL */
- -4, /* (282) cmd ::= DROP TRIGGER ifexists fullname */
- -6, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
- -3, /* (284) cmd ::= DETACH database_kw_opt expr */
- 0, /* (285) key_opt ::= */
- -2, /* (286) key_opt ::= KEY expr */
- -1, /* (287) cmd ::= REINDEX */
- -3, /* (288) cmd ::= REINDEX nm dbnm */
- -1, /* (289) cmd ::= ANALYZE */
- -3, /* (290) cmd ::= ANALYZE nm dbnm */
- -6, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */
- -7, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
- -6, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
- -1, /* (294) add_column_fullname ::= fullname */
- -8, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
- -1, /* (296) cmd ::= create_vtab */
- -4, /* (297) cmd ::= create_vtab LP vtabarglist RP */
- -8, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
- 0, /* (299) vtabarg ::= */
- -1, /* (300) vtabargtoken ::= ANY */
- -3, /* (301) vtabargtoken ::= lp anylist RP */
- -1, /* (302) lp ::= LP */
- -2, /* (303) with ::= WITH wqlist */
- -3, /* (304) with ::= WITH RECURSIVE wqlist */
- -1, /* (305) wqas ::= AS */
- -2, /* (306) wqas ::= AS MATERIALIZED */
- -3, /* (307) wqas ::= AS NOT MATERIALIZED */
- -6, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */
- -1, /* (309) wqlist ::= wqitem */
- -3, /* (310) wqlist ::= wqlist COMMA wqitem */
- -1, /* (311) windowdefn_list ::= windowdefn */
- -3, /* (312) windowdefn_list ::= windowdefn_list COMMA windowdefn */
- -5, /* (313) windowdefn ::= nm AS LP window RP */
- -5, /* (314) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
- -6, /* (315) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
- -4, /* (316) window ::= ORDER BY sortlist frame_opt */
- -5, /* (317) window ::= nm ORDER BY sortlist frame_opt */
- -1, /* (318) window ::= frame_opt */
- -2, /* (319) window ::= nm frame_opt */
- 0, /* (320) frame_opt ::= */
- -3, /* (321) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
- -6, /* (322) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
- -1, /* (323) range_or_rows ::= RANGE|ROWS|GROUPS */
- -1, /* (324) frame_bound_s ::= frame_bound */
- -2, /* (325) frame_bound_s ::= UNBOUNDED PRECEDING */
- -1, /* (326) frame_bound_e ::= frame_bound */
- -2, /* (327) frame_bound_e ::= UNBOUNDED FOLLOWING */
- -2, /* (328) frame_bound ::= expr PRECEDING|FOLLOWING */
- -2, /* (329) frame_bound ::= CURRENT ROW */
- 0, /* (330) frame_exclude_opt ::= */
- -2, /* (331) frame_exclude_opt ::= EXCLUDE frame_exclude */
- -2, /* (332) frame_exclude ::= NO OTHERS */
- -2, /* (333) frame_exclude ::= CURRENT ROW */
- -1, /* (334) frame_exclude ::= GROUP|TIES */
- -2, /* (335) window_clause ::= WINDOW windowdefn_list */
- -2, /* (336) filter_over ::= filter_clause over_clause */
- -1, /* (337) filter_over ::= over_clause */
- -1, /* (338) filter_over ::= filter_clause */
- -4, /* (339) over_clause ::= OVER LP window RP */
- -2, /* (340) over_clause ::= OVER nm */
- -5, /* (341) filter_clause ::= FILTER LP WHERE expr RP */
- -1, /* (342) input ::= cmdlist */
- -2, /* (343) cmdlist ::= cmdlist ecmd */
- -1, /* (344) cmdlist ::= ecmd */
- -1, /* (345) ecmd ::= SEMI */
- -2, /* (346) ecmd ::= cmdx SEMI */
- -3, /* (347) ecmd ::= explain cmdx SEMI */
- 0, /* (348) trans_opt ::= */
- -1, /* (349) trans_opt ::= TRANSACTION */
- -2, /* (350) trans_opt ::= TRANSACTION nm */
- -1, /* (351) savepoint_opt ::= SAVEPOINT */
- 0, /* (352) savepoint_opt ::= */
- -2, /* (353) cmd ::= create_table create_table_args */
- -1, /* (354) table_option_set ::= table_option */
- -4, /* (355) columnlist ::= columnlist COMMA columnname carglist */
- -2, /* (356) columnlist ::= columnname carglist */
- -1, /* (357) nm ::= ID|INDEXED */
- -1, /* (358) nm ::= STRING */
- -1, /* (359) nm ::= JOIN_KW */
- -1, /* (360) typetoken ::= typename */
- -1, /* (361) typename ::= ID|STRING */
- -1, /* (362) signed ::= plus_num */
- -1, /* (363) signed ::= minus_num */
- -2, /* (364) carglist ::= carglist ccons */
- 0, /* (365) carglist ::= */
- -2, /* (366) ccons ::= NULL onconf */
- -4, /* (367) ccons ::= GENERATED ALWAYS AS generated */
- -2, /* (368) ccons ::= AS generated */
- -2, /* (369) conslist_opt ::= COMMA conslist */
- -3, /* (370) conslist ::= conslist tconscomma tcons */
- -1, /* (371) conslist ::= tcons */
- 0, /* (372) tconscomma ::= */
- -1, /* (373) defer_subclause_opt ::= defer_subclause */
- -1, /* (374) resolvetype ::= raisetype */
- -1, /* (375) selectnowith ::= oneselect */
- -1, /* (376) oneselect ::= values */
- -2, /* (377) sclp ::= selcollist COMMA */
- -1, /* (378) as ::= ID|STRING */
- -1, /* (379) indexed_opt ::= indexed_by */
- 0, /* (380) returning ::= */
- -1, /* (381) expr ::= term */
- -1, /* (382) likeop ::= LIKE_KW|MATCH */
- -1, /* (383) exprlist ::= nexprlist */
- -1, /* (384) nmnum ::= plus_num */
- -1, /* (385) nmnum ::= nm */
- -1, /* (386) nmnum ::= ON */
- -1, /* (387) nmnum ::= DELETE */
- -1, /* (388) nmnum ::= DEFAULT */
- -1, /* (389) plus_num ::= INTEGER|FLOAT */
- 0, /* (390) foreach_clause ::= */
- -3, /* (391) foreach_clause ::= FOR EACH ROW */
- -1, /* (392) trnm ::= nm */
- 0, /* (393) tridxby ::= */
- -1, /* (394) database_kw_opt ::= DATABASE */
- 0, /* (395) database_kw_opt ::= */
- 0, /* (396) kwcolumn_opt ::= */
- -1, /* (397) kwcolumn_opt ::= COLUMNKW */
- -1, /* (398) vtabarglist ::= vtabarg */
- -3, /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */
- -2, /* (400) vtabarg ::= vtabarg vtabargtoken */
- 0, /* (401) anylist ::= */
- -4, /* (402) anylist ::= anylist LP anylist RP */
- -2, /* (403) anylist ::= anylist ANY */
- 0, /* (404) with ::= */
+ -1, /* (95) oneselect ::= mvalues */
+ -5, /* (96) mvalues ::= values COMMA LP nexprlist RP */
+ -5, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */
+ -1, /* (98) distinct ::= DISTINCT */
+ -1, /* (99) distinct ::= ALL */
+ 0, /* (100) distinct ::= */
+ 0, /* (101) sclp ::= */
+ -5, /* (102) selcollist ::= sclp scanpt expr scanpt as */
+ -3, /* (103) selcollist ::= sclp scanpt STAR */
+ -5, /* (104) selcollist ::= sclp scanpt nm DOT STAR */
+ -2, /* (105) as ::= AS nm */
+ 0, /* (106) as ::= */
+ 0, /* (107) from ::= */
+ -2, /* (108) from ::= FROM seltablist */
+ -2, /* (109) stl_prefix ::= seltablist joinop */
+ 0, /* (110) stl_prefix ::= */
+ -5, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */
+ -6, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
+ -8, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
+ -6, /* (114) seltablist ::= stl_prefix LP select RP as on_using */
+ -6, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */
+ 0, /* (116) dbnm ::= */
+ -2, /* (117) dbnm ::= DOT nm */
+ -1, /* (118) fullname ::= nm */
+ -3, /* (119) fullname ::= nm DOT nm */
+ -1, /* (120) xfullname ::= nm */
+ -3, /* (121) xfullname ::= nm DOT nm */
+ -5, /* (122) xfullname ::= nm DOT nm AS nm */
+ -3, /* (123) xfullname ::= nm AS nm */
+ -1, /* (124) joinop ::= COMMA|JOIN */
+ -2, /* (125) joinop ::= JOIN_KW JOIN */
+ -3, /* (126) joinop ::= JOIN_KW nm JOIN */
+ -4, /* (127) joinop ::= JOIN_KW nm nm JOIN */
+ -2, /* (128) on_using ::= ON expr */
+ -4, /* (129) on_using ::= USING LP idlist RP */
+ 0, /* (130) on_using ::= */
+ 0, /* (131) indexed_opt ::= */
+ -3, /* (132) indexed_by ::= INDEXED BY nm */
+ -2, /* (133) indexed_by ::= NOT INDEXED */
+ 0, /* (134) orderby_opt ::= */
+ -3, /* (135) orderby_opt ::= ORDER BY sortlist */
+ -5, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */
+ -3, /* (137) sortlist ::= expr sortorder nulls */
+ -1, /* (138) sortorder ::= ASC */
+ -1, /* (139) sortorder ::= DESC */
+ 0, /* (140) sortorder ::= */
+ -2, /* (141) nulls ::= NULLS FIRST */
+ -2, /* (142) nulls ::= NULLS LAST */
+ 0, /* (143) nulls ::= */
+ 0, /* (144) groupby_opt ::= */
+ -3, /* (145) groupby_opt ::= GROUP BY nexprlist */
+ 0, /* (146) having_opt ::= */
+ -2, /* (147) having_opt ::= HAVING expr */
+ 0, /* (148) limit_opt ::= */
+ -2, /* (149) limit_opt ::= LIMIT expr */
+ -4, /* (150) limit_opt ::= LIMIT expr OFFSET expr */
+ -4, /* (151) limit_opt ::= LIMIT expr COMMA expr */
+ -8, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */
+ 0, /* (153) where_opt ::= */
+ -2, /* (154) where_opt ::= WHERE expr */
+ 0, /* (155) where_opt_ret ::= */
+ -2, /* (156) where_opt_ret ::= WHERE expr */
+ -2, /* (157) where_opt_ret ::= RETURNING selcollist */
+ -4, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */
+ -11, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */
+ -5, /* (160) setlist ::= setlist COMMA nm EQ expr */
+ -7, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */
+ -3, /* (162) setlist ::= nm EQ expr */
+ -5, /* (163) setlist ::= LP idlist RP EQ expr */
+ -7, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ -8, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
+ 0, /* (166) upsert ::= */
+ -2, /* (167) upsert ::= RETURNING selcollist */
+ -12, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
+ -9, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
+ -5, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */
+ -8, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
+ -2, /* (172) returning ::= RETURNING selcollist */
+ -2, /* (173) insert_cmd ::= INSERT orconf */
+ -1, /* (174) insert_cmd ::= REPLACE */
+ 0, /* (175) idlist_opt ::= */
+ -3, /* (176) idlist_opt ::= LP idlist RP */
+ -3, /* (177) idlist ::= idlist COMMA nm */
+ -1, /* (178) idlist ::= nm */
+ -3, /* (179) expr ::= LP expr RP */
+ -1, /* (180) expr ::= ID|INDEXED|JOIN_KW */
+ -3, /* (181) expr ::= nm DOT nm */
+ -5, /* (182) expr ::= nm DOT nm DOT nm */
+ -1, /* (183) term ::= NULL|FLOAT|BLOB */
+ -1, /* (184) term ::= STRING */
+ -1, /* (185) term ::= INTEGER */
+ -1, /* (186) expr ::= VARIABLE */
+ -3, /* (187) expr ::= expr COLLATE ID|STRING */
+ -6, /* (188) expr ::= CAST LP expr AS typetoken RP */
+ -5, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+ -8, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
+ -4, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
+ -6, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
+ -9, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
+ -5, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
+ -1, /* (195) term ::= CTIME_KW */
+ -5, /* (196) expr ::= LP nexprlist COMMA expr RP */
+ -3, /* (197) expr ::= expr AND expr */
+ -3, /* (198) expr ::= expr OR expr */
+ -3, /* (199) expr ::= expr LT|GT|GE|LE expr */
+ -3, /* (200) expr ::= expr EQ|NE expr */
+ -3, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ -3, /* (202) expr ::= expr PLUS|MINUS expr */
+ -3, /* (203) expr ::= expr STAR|SLASH|REM expr */
+ -3, /* (204) expr ::= expr CONCAT expr */
+ -2, /* (205) likeop ::= NOT LIKE_KW|MATCH */
+ -3, /* (206) expr ::= expr likeop expr */
+ -5, /* (207) expr ::= expr likeop expr ESCAPE expr */
+ -2, /* (208) expr ::= expr ISNULL|NOTNULL */
+ -3, /* (209) expr ::= expr NOT NULL */
+ -3, /* (210) expr ::= expr IS expr */
+ -4, /* (211) expr ::= expr IS NOT expr */
+ -6, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */
+ -5, /* (213) expr ::= expr IS DISTINCT FROM expr */
+ -2, /* (214) expr ::= NOT expr */
+ -2, /* (215) expr ::= BITNOT expr */
+ -2, /* (216) expr ::= PLUS|MINUS expr */
+ -3, /* (217) expr ::= expr PTR expr */
+ -1, /* (218) between_op ::= BETWEEN */
+ -2, /* (219) between_op ::= NOT BETWEEN */
+ -5, /* (220) expr ::= expr between_op expr AND expr */
+ -1, /* (221) in_op ::= IN */
+ -2, /* (222) in_op ::= NOT IN */
+ -5, /* (223) expr ::= expr in_op LP exprlist RP */
+ -3, /* (224) expr ::= LP select RP */
+ -5, /* (225) expr ::= expr in_op LP select RP */
+ -5, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */
+ -4, /* (227) expr ::= EXISTS LP select RP */
+ -5, /* (228) expr ::= CASE case_operand case_exprlist case_else END */
+ -5, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ -4, /* (230) case_exprlist ::= WHEN expr THEN expr */
+ -2, /* (231) case_else ::= ELSE expr */
+ 0, /* (232) case_else ::= */
+ 0, /* (233) case_operand ::= */
+ 0, /* (234) exprlist ::= */
+ -3, /* (235) nexprlist ::= nexprlist COMMA expr */
+ -1, /* (236) nexprlist ::= expr */
+ 0, /* (237) paren_exprlist ::= */
+ -3, /* (238) paren_exprlist ::= LP exprlist RP */
+ -12, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ -1, /* (240) uniqueflag ::= UNIQUE */
+ 0, /* (241) uniqueflag ::= */
+ 0, /* (242) eidlist_opt ::= */
+ -3, /* (243) eidlist_opt ::= LP eidlist RP */
+ -5, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */
+ -3, /* (245) eidlist ::= nm collate sortorder */
+ 0, /* (246) collate ::= */
+ -2, /* (247) collate ::= COLLATE ID|STRING */
+ -4, /* (248) cmd ::= DROP INDEX ifexists fullname */
+ -2, /* (249) cmd ::= VACUUM vinto */
+ -3, /* (250) cmd ::= VACUUM nm vinto */
+ -2, /* (251) vinto ::= INTO expr */
+ 0, /* (252) vinto ::= */
+ -3, /* (253) cmd ::= PRAGMA nm dbnm */
+ -5, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */
+ -6, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ -5, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */
+ -6, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ -2, /* (258) plus_num ::= PLUS INTEGER|FLOAT */
+ -2, /* (259) minus_num ::= MINUS INTEGER|FLOAT */
+ -5, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ -11, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ -1, /* (262) trigger_time ::= BEFORE|AFTER */
+ -2, /* (263) trigger_time ::= INSTEAD OF */
+ 0, /* (264) trigger_time ::= */
+ -1, /* (265) trigger_event ::= DELETE|INSERT */
+ -1, /* (266) trigger_event ::= UPDATE */
+ -3, /* (267) trigger_event ::= UPDATE OF idlist */
+ 0, /* (268) when_clause ::= */
+ -2, /* (269) when_clause ::= WHEN expr */
+ -3, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ -2, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */
+ -3, /* (272) trnm ::= nm DOT nm */
+ -3, /* (273) tridxby ::= INDEXED BY nm */
+ -2, /* (274) tridxby ::= NOT INDEXED */
+ -9, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ -8, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ -6, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ -3, /* (278) trigger_cmd ::= scanpt select scanpt */
+ -4, /* (279) expr ::= RAISE LP IGNORE RP */
+ -6, /* (280) expr ::= RAISE LP raisetype COMMA nm RP */
+ -1, /* (281) raisetype ::= ROLLBACK */
+ -1, /* (282) raisetype ::= ABORT */
+ -1, /* (283) raisetype ::= FAIL */
+ -4, /* (284) cmd ::= DROP TRIGGER ifexists fullname */
+ -6, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ -3, /* (286) cmd ::= DETACH database_kw_opt expr */
+ 0, /* (287) key_opt ::= */
+ -2, /* (288) key_opt ::= KEY expr */
+ -1, /* (289) cmd ::= REINDEX */
+ -3, /* (290) cmd ::= REINDEX nm dbnm */
+ -1, /* (291) cmd ::= ANALYZE */
+ -3, /* (292) cmd ::= ANALYZE nm dbnm */
+ -6, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */
+ -7, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ -6, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ -1, /* (296) add_column_fullname ::= fullname */
+ -8, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ -1, /* (298) cmd ::= create_vtab */
+ -4, /* (299) cmd ::= create_vtab LP vtabarglist RP */
+ -8, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ 0, /* (301) vtabarg ::= */
+ -1, /* (302) vtabargtoken ::= ANY */
+ -3, /* (303) vtabargtoken ::= lp anylist RP */
+ -1, /* (304) lp ::= LP */
+ -2, /* (305) with ::= WITH wqlist */
+ -3, /* (306) with ::= WITH RECURSIVE wqlist */
+ -1, /* (307) wqas ::= AS */
+ -2, /* (308) wqas ::= AS MATERIALIZED */
+ -3, /* (309) wqas ::= AS NOT MATERIALIZED */
+ -6, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */
+ -1, /* (311) withnm ::= nm */
+ -1, /* (312) wqlist ::= wqitem */
+ -3, /* (313) wqlist ::= wqlist COMMA wqitem */
+ -3, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ -5, /* (315) windowdefn ::= nm AS LP window RP */
+ -5, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ -6, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ -4, /* (318) window ::= ORDER BY sortlist frame_opt */
+ -5, /* (319) window ::= nm ORDER BY sortlist frame_opt */
+ -2, /* (320) window ::= nm frame_opt */
+ 0, /* (321) frame_opt ::= */
+ -3, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ -6, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ -1, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */
+ -1, /* (325) frame_bound_s ::= frame_bound */
+ -2, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */
+ -1, /* (327) frame_bound_e ::= frame_bound */
+ -2, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ -2, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */
+ -2, /* (330) frame_bound ::= CURRENT ROW */
+ 0, /* (331) frame_exclude_opt ::= */
+ -2, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ -2, /* (333) frame_exclude ::= NO OTHERS */
+ -2, /* (334) frame_exclude ::= CURRENT ROW */
+ -1, /* (335) frame_exclude ::= GROUP|TIES */
+ -2, /* (336) window_clause ::= WINDOW windowdefn_list */
+ -2, /* (337) filter_over ::= filter_clause over_clause */
+ -1, /* (338) filter_over ::= over_clause */
+ -1, /* (339) filter_over ::= filter_clause */
+ -4, /* (340) over_clause ::= OVER LP window RP */
+ -2, /* (341) over_clause ::= OVER nm */
+ -5, /* (342) filter_clause ::= FILTER LP WHERE expr RP */
+ -1, /* (343) term ::= QNUMBER */
+ -1, /* (344) input ::= cmdlist */
+ -2, /* (345) cmdlist ::= cmdlist ecmd */
+ -1, /* (346) cmdlist ::= ecmd */
+ -1, /* (347) ecmd ::= SEMI */
+ -2, /* (348) ecmd ::= cmdx SEMI */
+ -3, /* (349) ecmd ::= explain cmdx SEMI */
+ 0, /* (350) trans_opt ::= */
+ -1, /* (351) trans_opt ::= TRANSACTION */
+ -2, /* (352) trans_opt ::= TRANSACTION nm */
+ -1, /* (353) savepoint_opt ::= SAVEPOINT */
+ 0, /* (354) savepoint_opt ::= */
+ -2, /* (355) cmd ::= create_table create_table_args */
+ -1, /* (356) table_option_set ::= table_option */
+ -4, /* (357) columnlist ::= columnlist COMMA columnname carglist */
+ -2, /* (358) columnlist ::= columnname carglist */
+ -1, /* (359) nm ::= ID|INDEXED|JOIN_KW */
+ -1, /* (360) nm ::= STRING */
+ -1, /* (361) typetoken ::= typename */
+ -1, /* (362) typename ::= ID|STRING */
+ -1, /* (363) signed ::= plus_num */
+ -1, /* (364) signed ::= minus_num */
+ -2, /* (365) carglist ::= carglist ccons */
+ 0, /* (366) carglist ::= */
+ -2, /* (367) ccons ::= NULL onconf */
+ -4, /* (368) ccons ::= GENERATED ALWAYS AS generated */
+ -2, /* (369) ccons ::= AS generated */
+ -2, /* (370) conslist_opt ::= COMMA conslist */
+ -3, /* (371) conslist ::= conslist tconscomma tcons */
+ -1, /* (372) conslist ::= tcons */
+ 0, /* (373) tconscomma ::= */
+ -1, /* (374) defer_subclause_opt ::= defer_subclause */
+ -1, /* (375) resolvetype ::= raisetype */
+ -1, /* (376) selectnowith ::= oneselect */
+ -1, /* (377) oneselect ::= values */
+ -2, /* (378) sclp ::= selcollist COMMA */
+ -1, /* (379) as ::= ID|STRING */
+ -1, /* (380) indexed_opt ::= indexed_by */
+ 0, /* (381) returning ::= */
+ -1, /* (382) expr ::= term */
+ -1, /* (383) likeop ::= LIKE_KW|MATCH */
+ -1, /* (384) case_operand ::= expr */
+ -1, /* (385) exprlist ::= nexprlist */
+ -1, /* (386) nmnum ::= plus_num */
+ -1, /* (387) nmnum ::= nm */
+ -1, /* (388) nmnum ::= ON */
+ -1, /* (389) nmnum ::= DELETE */
+ -1, /* (390) nmnum ::= DEFAULT */
+ -1, /* (391) plus_num ::= INTEGER|FLOAT */
+ 0, /* (392) foreach_clause ::= */
+ -3, /* (393) foreach_clause ::= FOR EACH ROW */
+ -1, /* (394) trnm ::= nm */
+ 0, /* (395) tridxby ::= */
+ -1, /* (396) database_kw_opt ::= DATABASE */
+ 0, /* (397) database_kw_opt ::= */
+ 0, /* (398) kwcolumn_opt ::= */
+ -1, /* (399) kwcolumn_opt ::= COLUMNKW */
+ -1, /* (400) vtabarglist ::= vtabarg */
+ -3, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */
+ -2, /* (402) vtabarg ::= vtabarg vtabargtoken */
+ 0, /* (403) anylist ::= */
+ -4, /* (404) anylist ::= anylist LP anylist RP */
+ -2, /* (405) anylist ::= anylist ANY */
+ 0, /* (406) with ::= */
+ -1, /* (407) windowdefn_list ::= windowdefn */
+ -1, /* (408) window ::= frame_opt */
};
static void yy_accept(yyParser*); /* Forward Declaration */
@@ -172470,25 +181358,25 @@ static YYACTIONTYPE yy_reduce(
/********** Begin reduce actions **********************************************/
YYMINORTYPE yylhsminor;
case 0: /* explain ::= EXPLAIN */
-{ pParse->explain = 1; }
+{ if( pParse->pReprepare==0 ) pParse->explain = 1; }
break;
case 1: /* explain ::= EXPLAIN QUERY PLAN */
-{ pParse->explain = 2; }
+{ if( pParse->pReprepare==0 ) pParse->explain = 2; }
break;
case 2: /* cmdx ::= cmd */
{ sqlcipher_sqlite3FinishCoding(pParse); }
break;
case 3: /* cmd ::= BEGIN transtype trans_opt */
-{sqlcipher_sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy394);}
+{sqlcipher_sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy144);}
break;
case 4: /* transtype ::= */
-{yymsp[1].minor.yy394 = TK_DEFERRED;}
+{yymsp[1].minor.yy144 = TK_DEFERRED;}
break;
case 5: /* transtype ::= DEFERRED */
case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
- case 323: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==323);
-{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/}
+ case 324: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==324);
+{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/}
break;
case 8: /* cmd ::= COMMIT|END trans_opt */
case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9);
@@ -172511,7 +181399,7 @@ static YYACTIONTYPE yy_reduce(
break;
case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
- sqlcipher_sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy394,0,0,yymsp[-2].minor.yy394);
+ sqlcipher_sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy144,0,0,yymsp[-2].minor.yy144);
}
break;
case 14: /* createkw ::= CREATE */
@@ -172523,40 +181411,40 @@ static YYACTIONTYPE yy_reduce(
case 62: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==62);
case 72: /* defer_subclause_opt ::= */ yytestcase(yyruleno==72);
case 81: /* ifexists ::= */ yytestcase(yyruleno==81);
- case 98: /* distinct ::= */ yytestcase(yyruleno==98);
- case 244: /* collate ::= */ yytestcase(yyruleno==244);
-{yymsp[1].minor.yy394 = 0;}
+ case 100: /* distinct ::= */ yytestcase(yyruleno==100);
+ case 246: /* collate ::= */ yytestcase(yyruleno==246);
+{yymsp[1].minor.yy144 = 0;}
break;
case 16: /* ifnotexists ::= IF NOT EXISTS */
-{yymsp[-2].minor.yy394 = 1;}
+{yymsp[-2].minor.yy144 = 1;}
break;
case 17: /* temp ::= TEMP */
-{yymsp[0].minor.yy394 = pParse->db->init.busy==0;}
+{yymsp[0].minor.yy144 = pParse->db->init.busy==0;}
break;
case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */
{
- sqlcipher_sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy285,0);
+ sqlcipher_sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy391,0);
}
break;
case 20: /* create_table_args ::= AS select */
{
- sqlcipher_sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy47);
- sqlcipher_sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47);
+ sqlcipher_sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy555);
+ sqlcipher_sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555);
}
break;
case 21: /* table_option_set ::= */
-{yymsp[1].minor.yy285 = 0;}
+{yymsp[1].minor.yy391 = 0;}
break;
case 22: /* table_option_set ::= table_option_set COMMA table_option */
-{yylhsminor.yy285 = yymsp[-2].minor.yy285|yymsp[0].minor.yy285;}
- yymsp[-2].minor.yy285 = yylhsminor.yy285;
+{yylhsminor.yy391 = yymsp[-2].minor.yy391|yymsp[0].minor.yy391;}
+ yymsp[-2].minor.yy391 = yylhsminor.yy391;
break;
case 23: /* table_option ::= WITHOUT nm */
{
if( yymsp[0].minor.yy0.n==5 && sqlcipher_sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
- yymsp[-1].minor.yy285 = TF_WithoutRowid | TF_NoVisibleRowid;
+ yymsp[-1].minor.yy391 = TF_WithoutRowid | TF_NoVisibleRowid;
}else{
- yymsp[-1].minor.yy285 = 0;
+ yymsp[-1].minor.yy391 = 0;
sqlcipher_sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
@@ -172564,20 +181452,20 @@ static YYACTIONTYPE yy_reduce(
case 24: /* table_option ::= nm */
{
if( yymsp[0].minor.yy0.n==6 && sqlcipher_sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){
- yylhsminor.yy285 = TF_Strict;
+ yylhsminor.yy391 = TF_Strict;
}else{
- yylhsminor.yy285 = 0;
+ yylhsminor.yy391 = 0;
sqlcipher_sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
- yymsp[0].minor.yy285 = yylhsminor.yy285;
+ yymsp[0].minor.yy391 = yylhsminor.yy391;
break;
case 25: /* columnname ::= nm typetoken */
{sqlcipher_sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);}
break;
case 26: /* typetoken ::= */
case 65: /* conslist_opt ::= */ yytestcase(yyruleno==65);
- case 104: /* as ::= */ yytestcase(yyruleno==104);
+ case 106: /* as ::= */ yytestcase(yyruleno==106);
{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
break;
case 27: /* typetoken ::= typename LP signed RP */
@@ -172596,7 +181484,7 @@ static YYACTIONTYPE yy_reduce(
case 30: /* scanpt ::= */
{
assert( yyLookahead!=YYNOCODE );
- yymsp[1].minor.yy522 = yyLookaheadToken.z;
+ yymsp[1].minor.yy168 = yyLookaheadToken.z;
}
break;
case 31: /* scantok ::= */
@@ -172610,17 +181498,17 @@ static YYACTIONTYPE yy_reduce(
{pParse->constraintName = yymsp[0].minor.yy0;}
break;
case 33: /* ccons ::= DEFAULT scantok term */
-{sqlcipher_sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
+{sqlcipher_sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
break;
case 34: /* ccons ::= DEFAULT LP expr RP */
-{sqlcipher_sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
+{sqlcipher_sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
break;
case 35: /* ccons ::= DEFAULT PLUS scantok term */
-{sqlcipher_sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
+{sqlcipher_sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
break;
case 36: /* ccons ::= DEFAULT MINUS scantok term */
{
- Expr *p = sqlcipher_sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy528, 0);
+ Expr *p = sqlcipher_sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy454, 0);
sqlcipher_sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);
}
break;
@@ -172635,161 +181523,160 @@ static YYACTIONTYPE yy_reduce(
}
break;
case 38: /* ccons ::= NOT NULL onconf */
-{sqlcipher_sqlite3AddNotNull(pParse, yymsp[0].minor.yy394);}
+{sqlcipher_sqlite3AddNotNull(pParse, yymsp[0].minor.yy144);}
break;
case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
-{sqlcipher_sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy394,yymsp[0].minor.yy394,yymsp[-2].minor.yy394);}
+{sqlcipher_sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy144,yymsp[0].minor.yy144,yymsp[-2].minor.yy144);}
break;
case 40: /* ccons ::= UNIQUE onconf */
-{sqlcipher_sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy394,0,0,0,0,
+{sqlcipher_sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy144,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
break;
case 41: /* ccons ::= CHECK LP expr RP */
-{sqlcipher_sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);}
+{sqlcipher_sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);}
break;
case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */
-{sqlcipher_sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy394);}
+{sqlcipher_sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy14,yymsp[0].minor.yy144);}
break;
case 43: /* ccons ::= defer_subclause */
-{sqlcipher_sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy394);}
+{sqlcipher_sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy144);}
break;
case 44: /* ccons ::= COLLATE ID|STRING */
{sqlcipher_sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
break;
case 45: /* generated ::= LP expr RP */
-{sqlcipher_sqlite3AddGenerated(pParse,yymsp[-1].minor.yy528,0);}
+{sqlcipher_sqlite3AddGenerated(pParse,yymsp[-1].minor.yy454,0);}
break;
case 46: /* generated ::= LP expr RP ID */
-{sqlcipher_sqlite3AddGenerated(pParse,yymsp[-2].minor.yy528,&yymsp[0].minor.yy0);}
+{sqlcipher_sqlite3AddGenerated(pParse,yymsp[-2].minor.yy454,&yymsp[0].minor.yy0);}
break;
case 48: /* autoinc ::= AUTOINCR */
-{yymsp[0].minor.yy394 = 1;}
+{yymsp[0].minor.yy144 = 1;}
break;
case 49: /* refargs ::= */
-{ yymsp[1].minor.yy394 = OE_None*0x0101; /* EV: R-19803-45884 */}
+{ yymsp[1].minor.yy144 = OE_None*0x0101; /* EV: R-19803-45884 */}
break;
case 50: /* refargs ::= refargs refarg */
-{ yymsp[-1].minor.yy394 = (yymsp[-1].minor.yy394 & ~yymsp[0].minor.yy231.mask) | yymsp[0].minor.yy231.value; }
+{ yymsp[-1].minor.yy144 = (yymsp[-1].minor.yy144 & ~yymsp[0].minor.yy383.mask) | yymsp[0].minor.yy383.value; }
break;
case 51: /* refarg ::= MATCH nm */
-{ yymsp[-1].minor.yy231.value = 0; yymsp[-1].minor.yy231.mask = 0x000000; }
+{ yymsp[-1].minor.yy383.value = 0; yymsp[-1].minor.yy383.mask = 0x000000; }
break;
case 52: /* refarg ::= ON INSERT refact */
-{ yymsp[-2].minor.yy231.value = 0; yymsp[-2].minor.yy231.mask = 0x000000; }
+{ yymsp[-2].minor.yy383.value = 0; yymsp[-2].minor.yy383.mask = 0x000000; }
break;
case 53: /* refarg ::= ON DELETE refact */
-{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394; yymsp[-2].minor.yy231.mask = 0x0000ff; }
+{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144; yymsp[-2].minor.yy383.mask = 0x0000ff; }
break;
case 54: /* refarg ::= ON UPDATE refact */
-{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394<<8; yymsp[-2].minor.yy231.mask = 0x00ff00; }
+{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144<<8; yymsp[-2].minor.yy383.mask = 0x00ff00; }
break;
case 55: /* refact ::= SET NULL */
-{ yymsp[-1].minor.yy394 = OE_SetNull; /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy144 = OE_SetNull; /* EV: R-33326-45252 */}
break;
case 56: /* refact ::= SET DEFAULT */
-{ yymsp[-1].minor.yy394 = OE_SetDflt; /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy144 = OE_SetDflt; /* EV: R-33326-45252 */}
break;
case 57: /* refact ::= CASCADE */
-{ yymsp[0].minor.yy394 = OE_Cascade; /* EV: R-33326-45252 */}
+{ yymsp[0].minor.yy144 = OE_Cascade; /* EV: R-33326-45252 */}
break;
case 58: /* refact ::= RESTRICT */
-{ yymsp[0].minor.yy394 = OE_Restrict; /* EV: R-33326-45252 */}
+{ yymsp[0].minor.yy144 = OE_Restrict; /* EV: R-33326-45252 */}
break;
case 59: /* refact ::= NO ACTION */
-{ yymsp[-1].minor.yy394 = OE_None; /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy144 = OE_None; /* EV: R-33326-45252 */}
break;
case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
-{yymsp[-2].minor.yy394 = 0;}
+{yymsp[-2].minor.yy144 = 0;}
break;
case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76);
- case 171: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==171);
-{yymsp[-1].minor.yy394 = yymsp[0].minor.yy394;}
+ case 173: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==173);
+{yymsp[-1].minor.yy144 = yymsp[0].minor.yy144;}
break;
case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80);
- case 216: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==216);
- case 219: /* in_op ::= NOT IN */ yytestcase(yyruleno==219);
- case 245: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==245);
-{yymsp[-1].minor.yy394 = 1;}
+ case 219: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==219);
+ case 222: /* in_op ::= NOT IN */ yytestcase(yyruleno==222);
+ case 247: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==247);
+{yymsp[-1].minor.yy144 = 1;}
break;
case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
-{yymsp[-1].minor.yy394 = 0;}
+{yymsp[-1].minor.yy144 = 0;}
break;
case 66: /* tconscomma ::= COMMA */
{pParse->constraintName.n = 0;}
break;
case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
-{sqlcipher_sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy394,yymsp[-2].minor.yy394,0);}
+{sqlcipher_sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy144,yymsp[-2].minor.yy144,0);}
break;
case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */
-{sqlcipher_sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy394,0,0,0,0,
+{sqlcipher_sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy14,yymsp[0].minor.yy144,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
break;
case 70: /* tcons ::= CHECK LP expr RP onconf */
-{sqlcipher_sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy528,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);}
+{sqlcipher_sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy454,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);}
break;
case 71: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
{
- sqlcipher_sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy394);
- sqlcipher_sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy394);
+ sqlcipher_sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy14, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[-1].minor.yy144);
+ sqlcipher_sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy144);
}
break;
case 73: /* onconf ::= */
case 75: /* orconf ::= */ yytestcase(yyruleno==75);
-{yymsp[1].minor.yy394 = OE_Default;}
+{yymsp[1].minor.yy144 = OE_Default;}
break;
case 74: /* onconf ::= ON CONFLICT resolvetype */
-{yymsp[-2].minor.yy394 = yymsp[0].minor.yy394;}
+{yymsp[-2].minor.yy144 = yymsp[0].minor.yy144;}
break;
case 77: /* resolvetype ::= IGNORE */
-{yymsp[0].minor.yy394 = OE_Ignore;}
+{yymsp[0].minor.yy144 = OE_Ignore;}
break;
case 78: /* resolvetype ::= REPLACE */
- case 172: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==172);
-{yymsp[0].minor.yy394 = OE_Replace;}
+ case 174: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==174);
+{yymsp[0].minor.yy144 = OE_Replace;}
break;
case 79: /* cmd ::= DROP TABLE ifexists fullname */
{
- sqlcipher_sqlite3DropTable(pParse, yymsp[0].minor.yy131, 0, yymsp[-1].minor.yy394);
+ sqlcipher_sqlite3DropTable(pParse, yymsp[0].minor.yy203, 0, yymsp[-1].minor.yy144);
}
break;
case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
{
- sqlcipher_sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[0].minor.yy47, yymsp[-7].minor.yy394, yymsp[-5].minor.yy394);
+ sqlcipher_sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[0].minor.yy555, yymsp[-7].minor.yy144, yymsp[-5].minor.yy144);
}
break;
case 83: /* cmd ::= DROP VIEW ifexists fullname */
{
- sqlcipher_sqlite3DropTable(pParse, yymsp[0].minor.yy131, 1, yymsp[-1].minor.yy394);
+ sqlcipher_sqlite3DropTable(pParse, yymsp[0].minor.yy203, 1, yymsp[-1].minor.yy144);
}
break;
case 84: /* cmd ::= select */
{
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
- sqlcipher_sqlite3Select(pParse, yymsp[0].minor.yy47, &dest);
- sqlcipher_sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47);
+ sqlcipher_sqlite3Select(pParse, yymsp[0].minor.yy555, &dest);
+ sqlcipher_sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555);
}
break;
case 85: /* select ::= WITH wqlist selectnowith */
-{yymsp[-2].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);}
+{yymsp[-2].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);}
break;
case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */
-{yymsp[-3].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);}
+{yymsp[-3].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);}
break;
case 87: /* select ::= selectnowith */
{
- Select *p = yymsp[0].minor.yy47;
+ Select *p = yymsp[0].minor.yy555;
if( p ){
parserDoubleLinkSelect(pParse, p);
}
- yymsp[0].minor.yy47 = p; /*A-overwrites-X*/
}
break;
case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */
{
- Select *pRhs = yymsp[0].minor.yy47;
- Select *pLhs = yymsp[-2].minor.yy47;
+ Select *pRhs = yymsp[0].minor.yy555;
+ Select *pLhs = yymsp[-2].minor.yy555;
if( pRhs && pRhs->pPrior ){
SrcList *pFrom;
Token x;
@@ -172799,145 +181686,145 @@ static YYACTIONTYPE yy_reduce(
pRhs = sqlcipher_sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
}
if( pRhs ){
- pRhs->op = (u8)yymsp[-1].minor.yy394;
+ pRhs->op = (u8)yymsp[-1].minor.yy144;
pRhs->pPrior = pLhs;
if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
pRhs->selFlags &= ~SF_MultiValue;
- if( yymsp[-1].minor.yy394!=TK_ALL ) pParse->hasCompound = 1;
+ if( yymsp[-1].minor.yy144!=TK_ALL ) pParse->hasCompound = 1;
}else{
sqlcipher_sqlite3SelectDelete(pParse->db, pLhs);
}
- yymsp[-2].minor.yy47 = pRhs;
+ yymsp[-2].minor.yy555 = pRhs;
}
break;
case 89: /* multiselect_op ::= UNION */
case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91);
-{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-OP*/}
+{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-OP*/}
break;
case 90: /* multiselect_op ::= UNION ALL */
-{yymsp[-1].minor.yy394 = TK_ALL;}
+{yymsp[-1].minor.yy144 = TK_ALL;}
break;
case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
- yymsp[-8].minor.yy47 = sqlcipher_sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy131,yymsp[-4].minor.yy528,yymsp[-3].minor.yy322,yymsp[-2].minor.yy528,yymsp[-1].minor.yy322,yymsp[-7].minor.yy394,yymsp[0].minor.yy528);
+ yymsp[-8].minor.yy555 = sqlcipher_sqlite3SelectNew(pParse,yymsp[-6].minor.yy14,yymsp[-5].minor.yy203,yymsp[-4].minor.yy454,yymsp[-3].minor.yy14,yymsp[-2].minor.yy454,yymsp[-1].minor.yy14,yymsp[-7].minor.yy144,yymsp[0].minor.yy454);
}
break;
case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
{
- yymsp[-9].minor.yy47 = sqlcipher_sqlite3SelectNew(pParse,yymsp[-7].minor.yy322,yymsp[-6].minor.yy131,yymsp[-5].minor.yy528,yymsp[-4].minor.yy322,yymsp[-3].minor.yy528,yymsp[-1].minor.yy322,yymsp[-8].minor.yy394,yymsp[0].minor.yy528);
- if( yymsp[-9].minor.yy47 ){
- yymsp[-9].minor.yy47->pWinDefn = yymsp[-2].minor.yy41;
+ yymsp[-9].minor.yy555 = sqlcipher_sqlite3SelectNew(pParse,yymsp[-7].minor.yy14,yymsp[-6].minor.yy203,yymsp[-5].minor.yy454,yymsp[-4].minor.yy14,yymsp[-3].minor.yy454,yymsp[-1].minor.yy14,yymsp[-8].minor.yy144,yymsp[0].minor.yy454);
+ if( yymsp[-9].minor.yy555 ){
+ yymsp[-9].minor.yy555->pWinDefn = yymsp[-2].minor.yy211;
}else{
- sqlcipher_sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy41);
+ sqlcipher_sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy211);
}
}
break;
case 94: /* values ::= VALUES LP nexprlist RP */
{
- yymsp[-3].minor.yy47 = sqlcipher_sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0);
+ yymsp[-3].minor.yy555 = sqlcipher_sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values,0);
}
break;
- case 95: /* values ::= values COMMA LP nexprlist RP */
+ case 95: /* oneselect ::= mvalues */
{
- Select *pRight, *pLeft = yymsp[-4].minor.yy47;
- pRight = sqlcipher_sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values|SF_MultiValue,0);
- if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
- if( pRight ){
- pRight->op = TK_ALL;
- pRight->pPrior = pLeft;
- yymsp[-4].minor.yy47 = pRight;
- }else{
- yymsp[-4].minor.yy47 = pLeft;
- }
+ sqlcipher_sqlite3MultiValuesEnd(pParse, yymsp[0].minor.yy555);
}
break;
- case 96: /* distinct ::= DISTINCT */
-{yymsp[0].minor.yy394 = SF_Distinct;}
+ case 96: /* mvalues ::= values COMMA LP nexprlist RP */
+ case 97: /* mvalues ::= mvalues COMMA LP nexprlist RP */ yytestcase(yyruleno==97);
+{
+ yymsp[-4].minor.yy555 = sqlcipher_sqlite3MultiValues(pParse, yymsp[-4].minor.yy555, yymsp[-1].minor.yy14);
+}
+ break;
+ case 98: /* distinct ::= DISTINCT */
+{yymsp[0].minor.yy144 = SF_Distinct;}
break;
- case 97: /* distinct ::= ALL */
-{yymsp[0].minor.yy394 = SF_All;}
+ case 99: /* distinct ::= ALL */
+{yymsp[0].minor.yy144 = SF_All;}
break;
- case 99: /* sclp ::= */
- case 132: /* orderby_opt ::= */ yytestcase(yyruleno==132);
- case 142: /* groupby_opt ::= */ yytestcase(yyruleno==142);
- case 232: /* exprlist ::= */ yytestcase(yyruleno==232);
- case 235: /* paren_exprlist ::= */ yytestcase(yyruleno==235);
- case 240: /* eidlist_opt ::= */ yytestcase(yyruleno==240);
-{yymsp[1].minor.yy322 = 0;}
+ case 101: /* sclp ::= */
+ case 134: /* orderby_opt ::= */ yytestcase(yyruleno==134);
+ case 144: /* groupby_opt ::= */ yytestcase(yyruleno==144);
+ case 234: /* exprlist ::= */ yytestcase(yyruleno==234);
+ case 237: /* paren_exprlist ::= */ yytestcase(yyruleno==237);
+ case 242: /* eidlist_opt ::= */ yytestcase(yyruleno==242);
+{yymsp[1].minor.yy14 = 0;}
break;
- case 100: /* selcollist ::= sclp scanpt expr scanpt as */
+ case 102: /* selcollist ::= sclp scanpt expr scanpt as */
{
- yymsp[-4].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[-2].minor.yy528);
- if( yymsp[0].minor.yy0.n>0 ) sqlcipher_sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[0].minor.yy0, 1);
- sqlcipher_sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy322,yymsp[-3].minor.yy522,yymsp[-1].minor.yy522);
+ yymsp[-4].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[-2].minor.yy454);
+ if( yymsp[0].minor.yy0.n>0 ) sqlcipher_sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[0].minor.yy0, 1);
+ sqlcipher_sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy14,yymsp[-3].minor.yy168,yymsp[-1].minor.yy168);
}
break;
- case 101: /* selcollist ::= sclp scanpt STAR */
+ case 103: /* selcollist ::= sclp scanpt STAR */
{
Expr *p = sqlcipher_sqlite3Expr(pParse->db, TK_ASTERISK, 0);
- yymsp[-2].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, p);
+ sqlcipher_sqlite3ExprSetErrorOffset(p, (int)(yymsp[0].minor.yy0.z - pParse->zTail));
+ yymsp[-2].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy14, p);
}
break;
- case 102: /* selcollist ::= sclp scanpt nm DOT STAR */
+ case 104: /* selcollist ::= sclp scanpt nm DOT STAR */
{
- Expr *pRight = sqlcipher_sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
- Expr *pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0);
- Expr *pDot = sqlcipher_sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
- yymsp[-4].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, pDot);
+ Expr *pRight, *pLeft, *pDot;
+ pRight = sqlcipher_sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
+ sqlcipher_sqlite3ExprSetErrorOffset(pRight, (int)(yymsp[0].minor.yy0.z - pParse->zTail));
+ pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0);
+ pDot = sqlcipher_sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
+ yymsp[-4].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, pDot);
}
break;
- case 103: /* as ::= AS nm */
- case 115: /* dbnm ::= DOT nm */ yytestcase(yyruleno==115);
- case 256: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==256);
- case 257: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==257);
+ case 105: /* as ::= AS nm */
+ case 117: /* dbnm ::= DOT nm */ yytestcase(yyruleno==117);
+ case 258: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==258);
+ case 259: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==259);
{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
break;
- case 105: /* from ::= */
- case 108: /* stl_prefix ::= */ yytestcase(yyruleno==108);
-{yymsp[1].minor.yy131 = 0;}
+ case 107: /* from ::= */
+ case 110: /* stl_prefix ::= */ yytestcase(yyruleno==110);
+{yymsp[1].minor.yy203 = 0;}
break;
- case 106: /* from ::= FROM seltablist */
+ case 108: /* from ::= FROM seltablist */
{
- yymsp[-1].minor.yy131 = yymsp[0].minor.yy131;
- sqlcipher_sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy131);
+ yymsp[-1].minor.yy203 = yymsp[0].minor.yy203;
+ sqlcipher_sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy203);
}
break;
- case 107: /* stl_prefix ::= seltablist joinop */
+ case 109: /* stl_prefix ::= seltablist joinop */
{
- if( ALWAYS(yymsp[-1].minor.yy131 && yymsp[-1].minor.yy131->nSrc>0) ) yymsp[-1].minor.yy131->a[yymsp[-1].minor.yy131->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy394;
+ if( ALWAYS(yymsp[-1].minor.yy203 && yymsp[-1].minor.yy203->nSrc>0) ) yymsp[-1].minor.yy203->a[yymsp[-1].minor.yy203->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy144;
}
break;
- case 109: /* seltablist ::= stl_prefix nm dbnm as on_using */
+ case 111: /* seltablist ::= stl_prefix nm dbnm as on_using */
{
- yymsp[-4].minor.yy131 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy131,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561);
+ yymsp[-4].minor.yy203 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy203,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
}
break;
- case 110: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
+ case 112: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
{
- yymsp[-5].minor.yy131 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy561);
- sqlcipher_sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-1].minor.yy0);
+ yymsp[-5].minor.yy203 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy269);
+ sqlcipher_sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-1].minor.yy0);
}
break;
- case 111: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
+ case 113: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
{
- yymsp[-7].minor.yy131 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy131,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561);
- sqlcipher_sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy131, yymsp[-3].minor.yy322);
+ yymsp[-7].minor.yy203 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy203,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
+ sqlcipher_sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy203, yymsp[-3].minor.yy14);
}
break;
- case 112: /* seltablist ::= stl_prefix LP select RP as on_using */
+ case 114: /* seltablist ::= stl_prefix LP select RP as on_using */
{
- yymsp[-5].minor.yy131 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy47,&yymsp[0].minor.yy561);
+ yymsp[-5].minor.yy203 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy555,&yymsp[0].minor.yy269);
}
break;
- case 113: /* seltablist ::= stl_prefix LP seltablist RP as on_using */
+ case 115: /* seltablist ::= stl_prefix LP seltablist RP as on_using */
{
- if( yymsp[-5].minor.yy131==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy561.pOn==0 && yymsp[0].minor.yy561.pUsing==0 ){
- yymsp[-5].minor.yy131 = yymsp[-3].minor.yy131;
- }else if( yymsp[-3].minor.yy131->nSrc==1 ){
- yymsp[-5].minor.yy131 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561);
- if( yymsp[-5].minor.yy131 ){
- SrcItem *pNew = &yymsp[-5].minor.yy131->a[yymsp[-5].minor.yy131->nSrc-1];
- SrcItem *pOld = yymsp[-3].minor.yy131->a;
+ if( yymsp[-5].minor.yy203==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy269.pOn==0 && yymsp[0].minor.yy269.pUsing==0 ){
+ yymsp[-5].minor.yy203 = yymsp[-3].minor.yy203;
+ }else if( ALWAYS(yymsp[-3].minor.yy203!=0) && yymsp[-3].minor.yy203->nSrc==1 ){
+ yymsp[-5].minor.yy203 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
+ if( yymsp[-5].minor.yy203 ){
+ SrcItem *pNew = &yymsp[-5].minor.yy203->a[yymsp[-5].minor.yy203->nSrc-1];
+ SrcItem *pOld = yymsp[-3].minor.yy203->a;
pNew->zName = pOld->zName;
pNew->zDatabase = pOld->zDatabase;
pNew->pSelect = pOld->pSelect;
@@ -172953,159 +181840,159 @@ static YYACTIONTYPE yy_reduce(
pOld->zName = pOld->zDatabase = 0;
pOld->pSelect = 0;
}
- sqlcipher_sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy131);
+ sqlcipher_sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203);
}else{
Select *pSubquery;
- sqlcipher_sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy131);
- pSubquery = sqlcipher_sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy131,0,0,0,0,SF_NestedFrom,0);
- yymsp[-5].minor.yy131 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy561);
+ sqlcipher_sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy203);
+ pSubquery = sqlcipher_sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy203,0,0,0,0,SF_NestedFrom,0);
+ yymsp[-5].minor.yy203 = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy269);
}
}
break;
- case 114: /* dbnm ::= */
- case 129: /* indexed_opt ::= */ yytestcase(yyruleno==129);
+ case 116: /* dbnm ::= */
+ case 131: /* indexed_opt ::= */ yytestcase(yyruleno==131);
{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
break;
- case 116: /* fullname ::= nm */
+ case 118: /* fullname ::= nm */
{
- yylhsminor.yy131 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
- if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlcipher_sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0);
+ yylhsminor.yy203 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
+ if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlcipher_sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0);
}
- yymsp[0].minor.yy131 = yylhsminor.yy131;
+ yymsp[0].minor.yy203 = yylhsminor.yy203;
break;
- case 117: /* fullname ::= nm DOT nm */
+ case 119: /* fullname ::= nm DOT nm */
{
- yylhsminor.yy131 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
- if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlcipher_sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0);
+ yylhsminor.yy203 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
+ if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlcipher_sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0);
}
- yymsp[-2].minor.yy131 = yylhsminor.yy131;
+ yymsp[-2].minor.yy203 = yylhsminor.yy203;
break;
- case 118: /* xfullname ::= nm */
-{yymsp[0].minor.yy131 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
+ case 120: /* xfullname ::= nm */
+{yymsp[0].minor.yy203 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
break;
- case 119: /* xfullname ::= nm DOT nm */
-{yymsp[-2].minor.yy131 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 121: /* xfullname ::= nm DOT nm */
+{yymsp[-2].minor.yy203 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 120: /* xfullname ::= nm DOT nm AS nm */
+ case 122: /* xfullname ::= nm DOT nm AS nm */
{
- yymsp[-4].minor.yy131 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
- if( yymsp[-4].minor.yy131 ) yymsp[-4].minor.yy131->a[0].zAlias = sqlcipher_sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+ yymsp[-4].minor.yy203 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
+ if( yymsp[-4].minor.yy203 ) yymsp[-4].minor.yy203->a[0].zAlias = sqlcipher_sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
break;
- case 121: /* xfullname ::= nm AS nm */
+ case 123: /* xfullname ::= nm AS nm */
{
- yymsp[-2].minor.yy131 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
- if( yymsp[-2].minor.yy131 ) yymsp[-2].minor.yy131->a[0].zAlias = sqlcipher_sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+ yymsp[-2].minor.yy203 = sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
+ if( yymsp[-2].minor.yy203 ) yymsp[-2].minor.yy203->a[0].zAlias = sqlcipher_sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
break;
- case 122: /* joinop ::= COMMA|JOIN */
-{ yymsp[0].minor.yy394 = JT_INNER; }
+ case 124: /* joinop ::= COMMA|JOIN */
+{ yymsp[0].minor.yy144 = JT_INNER; }
break;
- case 123: /* joinop ::= JOIN_KW JOIN */
-{yymsp[-1].minor.yy394 = sqlcipher_sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
+ case 125: /* joinop ::= JOIN_KW JOIN */
+{yymsp[-1].minor.yy144 = sqlcipher_sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
break;
- case 124: /* joinop ::= JOIN_KW nm JOIN */
-{yymsp[-2].minor.yy394 = sqlcipher_sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
+ case 126: /* joinop ::= JOIN_KW nm JOIN */
+{yymsp[-2].minor.yy144 = sqlcipher_sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
break;
- case 125: /* joinop ::= JOIN_KW nm nm JOIN */
-{yymsp[-3].minor.yy394 = sqlcipher_sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
+ case 127: /* joinop ::= JOIN_KW nm nm JOIN */
+{yymsp[-3].minor.yy144 = sqlcipher_sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
break;
- case 126: /* on_using ::= ON expr */
-{yymsp[-1].minor.yy561.pOn = yymsp[0].minor.yy528; yymsp[-1].minor.yy561.pUsing = 0;}
+ case 128: /* on_using ::= ON expr */
+{yymsp[-1].minor.yy269.pOn = yymsp[0].minor.yy454; yymsp[-1].minor.yy269.pUsing = 0;}
break;
- case 127: /* on_using ::= USING LP idlist RP */
-{yymsp[-3].minor.yy561.pOn = 0; yymsp[-3].minor.yy561.pUsing = yymsp[-1].minor.yy254;}
+ case 129: /* on_using ::= USING LP idlist RP */
+{yymsp[-3].minor.yy269.pOn = 0; yymsp[-3].minor.yy269.pUsing = yymsp[-1].minor.yy132;}
break;
- case 128: /* on_using ::= */
-{yymsp[1].minor.yy561.pOn = 0; yymsp[1].minor.yy561.pUsing = 0;}
+ case 130: /* on_using ::= */
+{yymsp[1].minor.yy269.pOn = 0; yymsp[1].minor.yy269.pUsing = 0;}
break;
- case 130: /* indexed_by ::= INDEXED BY nm */
+ case 132: /* indexed_by ::= INDEXED BY nm */
{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
break;
- case 131: /* indexed_by ::= NOT INDEXED */
+ case 133: /* indexed_by ::= NOT INDEXED */
{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
break;
- case 133: /* orderby_opt ::= ORDER BY sortlist */
- case 143: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==143);
-{yymsp[-2].minor.yy322 = yymsp[0].minor.yy322;}
+ case 135: /* orderby_opt ::= ORDER BY sortlist */
+ case 145: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==145);
+{yymsp[-2].minor.yy14 = yymsp[0].minor.yy14;}
break;
- case 134: /* sortlist ::= sortlist COMMA expr sortorder nulls */
+ case 136: /* sortlist ::= sortlist COMMA expr sortorder nulls */
{
- yymsp[-4].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322,yymsp[-2].minor.yy528);
- sqlcipher_sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394);
+ yymsp[-4].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14,yymsp[-2].minor.yy454);
+ sqlcipher_sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144);
}
break;
- case 135: /* sortlist ::= expr sortorder nulls */
+ case 137: /* sortlist ::= expr sortorder nulls */
{
- yymsp[-2].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy528); /*A-overwrites-Y*/
- sqlcipher_sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394);
+ yymsp[-2].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy454); /*A-overwrites-Y*/
+ sqlcipher_sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144);
}
break;
- case 136: /* sortorder ::= ASC */
-{yymsp[0].minor.yy394 = SQLITE_SO_ASC;}
+ case 138: /* sortorder ::= ASC */
+{yymsp[0].minor.yy144 = SQLITE_SO_ASC;}
break;
- case 137: /* sortorder ::= DESC */
-{yymsp[0].minor.yy394 = SQLITE_SO_DESC;}
+ case 139: /* sortorder ::= DESC */
+{yymsp[0].minor.yy144 = SQLITE_SO_DESC;}
break;
- case 138: /* sortorder ::= */
- case 141: /* nulls ::= */ yytestcase(yyruleno==141);
-{yymsp[1].minor.yy394 = SQLITE_SO_UNDEFINED;}
+ case 140: /* sortorder ::= */
+ case 143: /* nulls ::= */ yytestcase(yyruleno==143);
+{yymsp[1].minor.yy144 = SQLITE_SO_UNDEFINED;}
break;
- case 139: /* nulls ::= NULLS FIRST */
-{yymsp[-1].minor.yy394 = SQLITE_SO_ASC;}
+ case 141: /* nulls ::= NULLS FIRST */
+{yymsp[-1].minor.yy144 = SQLITE_SO_ASC;}
break;
- case 140: /* nulls ::= NULLS LAST */
-{yymsp[-1].minor.yy394 = SQLITE_SO_DESC;}
+ case 142: /* nulls ::= NULLS LAST */
+{yymsp[-1].minor.yy144 = SQLITE_SO_DESC;}
break;
- case 144: /* having_opt ::= */
- case 146: /* limit_opt ::= */ yytestcase(yyruleno==146);
- case 151: /* where_opt ::= */ yytestcase(yyruleno==151);
- case 153: /* where_opt_ret ::= */ yytestcase(yyruleno==153);
- case 229: /* case_else ::= */ yytestcase(yyruleno==229);
- case 231: /* case_operand ::= */ yytestcase(yyruleno==231);
- case 250: /* vinto ::= */ yytestcase(yyruleno==250);
-{yymsp[1].minor.yy528 = 0;}
+ case 146: /* having_opt ::= */
+ case 148: /* limit_opt ::= */ yytestcase(yyruleno==148);
+ case 153: /* where_opt ::= */ yytestcase(yyruleno==153);
+ case 155: /* where_opt_ret ::= */ yytestcase(yyruleno==155);
+ case 232: /* case_else ::= */ yytestcase(yyruleno==232);
+ case 233: /* case_operand ::= */ yytestcase(yyruleno==233);
+ case 252: /* vinto ::= */ yytestcase(yyruleno==252);
+{yymsp[1].minor.yy454 = 0;}
break;
- case 145: /* having_opt ::= HAVING expr */
- case 152: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==152);
- case 154: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==154);
- case 228: /* case_else ::= ELSE expr */ yytestcase(yyruleno==228);
- case 249: /* vinto ::= INTO expr */ yytestcase(yyruleno==249);
-{yymsp[-1].minor.yy528 = yymsp[0].minor.yy528;}
+ case 147: /* having_opt ::= HAVING expr */
+ case 154: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==154);
+ case 156: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==156);
+ case 231: /* case_else ::= ELSE expr */ yytestcase(yyruleno==231);
+ case 251: /* vinto ::= INTO expr */ yytestcase(yyruleno==251);
+{yymsp[-1].minor.yy454 = yymsp[0].minor.yy454;}
break;
- case 147: /* limit_opt ::= LIMIT expr */
-{yymsp[-1].minor.yy528 = sqlcipher_sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,0);}
+ case 149: /* limit_opt ::= LIMIT expr */
+{yymsp[-1].minor.yy454 = sqlcipher_sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,0);}
break;
- case 148: /* limit_opt ::= LIMIT expr OFFSET expr */
-{yymsp[-3].minor.yy528 = sqlcipher_sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
+ case 150: /* limit_opt ::= LIMIT expr OFFSET expr */
+{yymsp[-3].minor.yy454 = sqlcipher_sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
break;
- case 149: /* limit_opt ::= LIMIT expr COMMA expr */
-{yymsp[-3].minor.yy528 = sqlcipher_sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,yymsp[-2].minor.yy528);}
+ case 151: /* limit_opt ::= LIMIT expr COMMA expr */
+{yymsp[-3].minor.yy454 = sqlcipher_sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,yymsp[-2].minor.yy454);}
break;
- case 150: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */
+ case 152: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */
{
- sqlcipher_sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy131, &yymsp[-3].minor.yy0);
+ sqlcipher_sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy203, &yymsp[-3].minor.yy0);
#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
- if( yymsp[-1].minor.yy322 || yymsp[0].minor.yy528 ){
- updateDeleteLimitError(pParse,yymsp[-1].minor.yy322,yymsp[0].minor.yy528);
- yymsp[-1].minor.yy322 = 0;
- yymsp[0].minor.yy528 = 0;
+ if( yymsp[-1].minor.yy14 || yymsp[0].minor.yy454 ){
+ updateDeleteLimitError(pParse,yymsp[-1].minor.yy14,yymsp[0].minor.yy454);
+ yymsp[-1].minor.yy14 = 0;
+ yymsp[0].minor.yy454 = 0;
}
#endif
- sqlcipher_sqlite3DeleteFrom(pParse,yymsp[-4].minor.yy131,yymsp[-2].minor.yy528,yymsp[-1].minor.yy322,yymsp[0].minor.yy528);
+ sqlcipher_sqlite3DeleteFrom(pParse,yymsp[-4].minor.yy203,yymsp[-2].minor.yy454,yymsp[-1].minor.yy14,yymsp[0].minor.yy454);
}
break;
- case 155: /* where_opt_ret ::= RETURNING selcollist */
-{sqlcipher_sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-1].minor.yy528 = 0;}
+ case 157: /* where_opt_ret ::= RETURNING selcollist */
+{sqlcipher_sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-1].minor.yy454 = 0;}
break;
- case 156: /* where_opt_ret ::= WHERE expr RETURNING selcollist */
-{sqlcipher_sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-3].minor.yy528 = yymsp[-2].minor.yy528;}
+ case 158: /* where_opt_ret ::= WHERE expr RETURNING selcollist */
+{sqlcipher_sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-3].minor.yy454 = yymsp[-2].minor.yy454;}
break;
- case 157: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */
+ case 159: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */
{
- sqlcipher_sqlite3SrcListIndexedBy(pParse, yymsp[-7].minor.yy131, &yymsp[-6].minor.yy0);
- if( yymsp[-3].minor.yy131 ){
- SrcList *pFromClause = yymsp[-3].minor.yy131;
+ sqlcipher_sqlite3SrcListIndexedBy(pParse, yymsp[-7].minor.yy203, &yymsp[-6].minor.yy0);
+ if( yymsp[-3].minor.yy203 ){
+ SrcList *pFromClause = yymsp[-3].minor.yy203;
if( pFromClause->nSrc>1 ){
Select *pSubquery;
Token as;
@@ -173114,101 +182001,100 @@ static YYACTIONTYPE yy_reduce(
as.z = 0;
pFromClause = sqlcipher_sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0);
}
- yymsp[-7].minor.yy131 = sqlcipher_sqlite3SrcListAppendList(pParse, yymsp[-7].minor.yy131, pFromClause);
+ yymsp[-7].minor.yy203 = sqlcipher_sqlite3SrcListAppendList(pParse, yymsp[-7].minor.yy203, pFromClause);
}
- sqlcipher_sqlite3ExprListCheckLength(pParse,yymsp[-4].minor.yy322,"set list");
+ sqlcipher_sqlite3ExprListCheckLength(pParse,yymsp[-4].minor.yy14,"set list");
#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
- if( yymsp[-1].minor.yy322 || yymsp[0].minor.yy528 ){
- updateDeleteLimitError(pParse,yymsp[-1].minor.yy322,yymsp[0].minor.yy528);
- yymsp[-1].minor.yy322 = 0;
- yymsp[0].minor.yy528 = 0;
+ if( yymsp[-1].minor.yy14 || yymsp[0].minor.yy454 ){
+ updateDeleteLimitError(pParse,yymsp[-1].minor.yy14,yymsp[0].minor.yy454);
+ yymsp[-1].minor.yy14 = 0;
+ yymsp[0].minor.yy454 = 0;
}
#endif
- sqlcipher_sqlite3Update(pParse,yymsp[-7].minor.yy131,yymsp[-4].minor.yy322,yymsp[-2].minor.yy528,yymsp[-8].minor.yy394,yymsp[-1].minor.yy322,yymsp[0].minor.yy528,0);
+ sqlcipher_sqlite3Update(pParse,yymsp[-7].minor.yy203,yymsp[-4].minor.yy14,yymsp[-2].minor.yy454,yymsp[-8].minor.yy144,yymsp[-1].minor.yy14,yymsp[0].minor.yy454,0);
}
break;
- case 158: /* setlist ::= setlist COMMA nm EQ expr */
+ case 160: /* setlist ::= setlist COMMA nm EQ expr */
{
- yymsp[-4].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy528);
- sqlcipher_sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, 1);
+ yymsp[-4].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[0].minor.yy454);
+ sqlcipher_sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, 1);
}
break;
- case 159: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
+ case 161: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
{
- yymsp[-6].minor.yy322 = sqlcipher_sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy322, yymsp[-3].minor.yy254, yymsp[0].minor.yy528);
+ yymsp[-6].minor.yy14 = sqlcipher_sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy14, yymsp[-3].minor.yy132, yymsp[0].minor.yy454);
}
break;
- case 160: /* setlist ::= nm EQ expr */
+ case 162: /* setlist ::= nm EQ expr */
{
- yylhsminor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy528);
- sqlcipher_sqlite3ExprListSetName(pParse, yylhsminor.yy322, &yymsp[-2].minor.yy0, 1);
+ yylhsminor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy454);
+ sqlcipher_sqlite3ExprListSetName(pParse, yylhsminor.yy14, &yymsp[-2].minor.yy0, 1);
}
- yymsp[-2].minor.yy322 = yylhsminor.yy322;
+ yymsp[-2].minor.yy14 = yylhsminor.yy14;
break;
- case 161: /* setlist ::= LP idlist RP EQ expr */
+ case 163: /* setlist ::= LP idlist RP EQ expr */
{
- yymsp[-4].minor.yy322 = sqlcipher_sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy528);
+ yymsp[-4].minor.yy14 = sqlcipher_sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy132, yymsp[0].minor.yy454);
}
break;
- case 162: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ case 164: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
{
- sqlcipher_sqlite3Insert(pParse, yymsp[-3].minor.yy131, yymsp[-1].minor.yy47, yymsp[-2].minor.yy254, yymsp[-5].minor.yy394, yymsp[0].minor.yy444);
+ sqlcipher_sqlite3Insert(pParse, yymsp[-3].minor.yy203, yymsp[-1].minor.yy555, yymsp[-2].minor.yy132, yymsp[-5].minor.yy144, yymsp[0].minor.yy122);
}
break;
- case 163: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
+ case 165: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
{
- sqlcipher_sqlite3Insert(pParse, yymsp[-4].minor.yy131, 0, yymsp[-3].minor.yy254, yymsp[-6].minor.yy394, 0);
+ sqlcipher_sqlite3Insert(pParse, yymsp[-4].minor.yy203, 0, yymsp[-3].minor.yy132, yymsp[-6].minor.yy144, 0);
}
break;
- case 164: /* upsert ::= */
-{ yymsp[1].minor.yy444 = 0; }
+ case 166: /* upsert ::= */
+{ yymsp[1].minor.yy122 = 0; }
break;
- case 165: /* upsert ::= RETURNING selcollist */
-{ yymsp[-1].minor.yy444 = 0; sqlcipher_sqlite3AddReturning(pParse,yymsp[0].minor.yy322); }
+ case 167: /* upsert ::= RETURNING selcollist */
+{ yymsp[-1].minor.yy122 = 0; sqlcipher_sqlite3AddReturning(pParse,yymsp[0].minor.yy14); }
break;
- case 166: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
-{ yymsp[-11].minor.yy444 = sqlcipher_sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy322,yymsp[-6].minor.yy528,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,yymsp[0].minor.yy444);}
+ case 168: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
+{ yymsp[-11].minor.yy122 = sqlcipher_sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy14,yymsp[-6].minor.yy454,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,yymsp[0].minor.yy122);}
break;
- case 167: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
-{ yymsp[-8].minor.yy444 = sqlcipher_sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy322,yymsp[-3].minor.yy528,0,0,yymsp[0].minor.yy444); }
+ case 169: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
+{ yymsp[-8].minor.yy122 = sqlcipher_sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy14,yymsp[-3].minor.yy454,0,0,yymsp[0].minor.yy122); }
break;
- case 168: /* upsert ::= ON CONFLICT DO NOTHING returning */
-{ yymsp[-4].minor.yy444 = sqlcipher_sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
+ case 170: /* upsert ::= ON CONFLICT DO NOTHING returning */
+{ yymsp[-4].minor.yy122 = sqlcipher_sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
break;
- case 169: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
-{ yymsp[-7].minor.yy444 = sqlcipher_sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,0);}
+ case 171: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
+{ yymsp[-7].minor.yy122 = sqlcipher_sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,0);}
break;
- case 170: /* returning ::= RETURNING selcollist */
-{sqlcipher_sqlite3AddReturning(pParse,yymsp[0].minor.yy322);}
+ case 172: /* returning ::= RETURNING selcollist */
+{sqlcipher_sqlite3AddReturning(pParse,yymsp[0].minor.yy14);}
break;
- case 173: /* idlist_opt ::= */
-{yymsp[1].minor.yy254 = 0;}
+ case 175: /* idlist_opt ::= */
+{yymsp[1].minor.yy132 = 0;}
break;
- case 174: /* idlist_opt ::= LP idlist RP */
-{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;}
+ case 176: /* idlist_opt ::= LP idlist RP */
+{yymsp[-2].minor.yy132 = yymsp[-1].minor.yy132;}
break;
- case 175: /* idlist ::= idlist COMMA nm */
-{yymsp[-2].minor.yy254 = sqlcipher_sqlite3IdListAppend(pParse,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);}
+ case 177: /* idlist ::= idlist COMMA nm */
+{yymsp[-2].minor.yy132 = sqlcipher_sqlite3IdListAppend(pParse,yymsp[-2].minor.yy132,&yymsp[0].minor.yy0);}
break;
- case 176: /* idlist ::= nm */
-{yymsp[0].minor.yy254 = sqlcipher_sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
+ case 178: /* idlist ::= nm */
+{yymsp[0].minor.yy132 = sqlcipher_sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
break;
- case 177: /* expr ::= LP expr RP */
-{yymsp[-2].minor.yy528 = yymsp[-1].minor.yy528;}
+ case 179: /* expr ::= LP expr RP */
+{yymsp[-2].minor.yy454 = yymsp[-1].minor.yy454;}
break;
- case 178: /* expr ::= ID|INDEXED */
- case 179: /* expr ::= JOIN_KW */ yytestcase(yyruleno==179);
-{yymsp[0].minor.yy528=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 180: /* expr ::= ID|INDEXED|JOIN_KW */
+{yymsp[0].minor.yy454=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 180: /* expr ::= nm DOT nm */
+ case 181: /* expr ::= nm DOT nm */
{
Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0);
- yylhsminor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
+ yylhsminor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
}
- yymsp[-2].minor.yy528 = yylhsminor.yy528;
+ yymsp[-2].minor.yy454 = yylhsminor.yy454;
break;
- case 181: /* expr ::= nm DOT nm DOT nm */
+ case 182: /* expr ::= nm DOT nm DOT nm */
{
Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-4].minor.yy0);
Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
@@ -173217,27 +182103,27 @@ static YYACTIONTYPE yy_reduce(
if( IN_RENAME_OBJECT ){
sqlcipher_sqlite3RenameTokenRemap(pParse, 0, temp1);
}
- yylhsminor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
+ yylhsminor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
}
- yymsp[-4].minor.yy528 = yylhsminor.yy528;
+ yymsp[-4].minor.yy454 = yylhsminor.yy454;
break;
- case 182: /* term ::= NULL|FLOAT|BLOB */
- case 183: /* term ::= STRING */ yytestcase(yyruleno==183);
-{yymsp[0].minor.yy528=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 183: /* term ::= NULL|FLOAT|BLOB */
+ case 184: /* term ::= STRING */ yytestcase(yyruleno==184);
+{yymsp[0].minor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 184: /* term ::= INTEGER */
+ case 185: /* term ::= INTEGER */
{
- yylhsminor.yy528 = sqlcipher_sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
- if( yylhsminor.yy528 ) yylhsminor.yy528->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail);
+ yylhsminor.yy454 = sqlcipher_sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
+ if( yylhsminor.yy454 ) yylhsminor.yy454->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail);
}
- yymsp[0].minor.yy528 = yylhsminor.yy528;
+ yymsp[0].minor.yy454 = yylhsminor.yy454;
break;
- case 185: /* expr ::= VARIABLE */
+ case 186: /* expr ::= VARIABLE */
{
if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlcipher_sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
u32 n = yymsp[0].minor.yy0.n;
- yymsp[0].minor.yy528 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
- sqlcipher_sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy528, n);
+ yymsp[0].minor.yy454 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
+ sqlcipher_sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy454, n);
}else{
/* When doing a nested parse, one can include terms in an expression
** that look like this: #1 #2 ... These terms refer to registers
@@ -173246,179 +182132,203 @@ static YYACTIONTYPE yy_reduce(
assert( t.n>=2 );
if( pParse->nested==0 ){
sqlcipher_sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
- yymsp[0].minor.yy528 = 0;
+ yymsp[0].minor.yy454 = 0;
}else{
- yymsp[0].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
- if( yymsp[0].minor.yy528 ) sqlcipher_sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy528->iTable);
+ yymsp[0].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
+ if( yymsp[0].minor.yy454 ) sqlcipher_sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy454->iTable);
}
}
}
break;
- case 186: /* expr ::= expr COLLATE ID|STRING */
+ case 187: /* expr ::= expr COLLATE ID|STRING */
+{
+ yymsp[-2].minor.yy454 = sqlcipher_sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy454, &yymsp[0].minor.yy0, 1);
+}
+ break;
+ case 188: /* expr ::= CAST LP expr AS typetoken RP */
{
- yymsp[-2].minor.yy528 = sqlcipher_sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy528, &yymsp[0].minor.yy0, 1);
+ yymsp[-5].minor.yy454 = sqlcipher_sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
+ sqlcipher_sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy454, yymsp[-3].minor.yy454, 0);
}
break;
- case 187: /* expr ::= CAST LP expr AS typetoken RP */
+ case 189: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
{
- yymsp[-5].minor.yy528 = sqlcipher_sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
- sqlcipher_sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy528, yymsp[-3].minor.yy528, 0);
+ yylhsminor.yy454 = sqlcipher_sqlite3ExprFunction(pParse, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy144);
}
+ yymsp[-4].minor.yy454 = yylhsminor.yy454;
break;
- case 188: /* expr ::= ID|INDEXED LP distinct exprlist RP */
+ case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
{
- yylhsminor.yy528 = sqlcipher_sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy394);
+ yylhsminor.yy454 = sqlcipher_sqlite3ExprFunction(pParse, yymsp[-4].minor.yy14, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy144);
+ sqlcipher_sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-1].minor.yy14);
}
- yymsp[-4].minor.yy528 = yylhsminor.yy528;
+ yymsp[-7].minor.yy454 = yylhsminor.yy454;
break;
- case 189: /* expr ::= ID|INDEXED LP STAR RP */
+ case 191: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
{
- yylhsminor.yy528 = sqlcipher_sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
+ yylhsminor.yy454 = sqlcipher_sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
}
- yymsp[-3].minor.yy528 = yylhsminor.yy528;
+ yymsp[-3].minor.yy454 = yylhsminor.yy454;
break;
- case 190: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
+ case 192: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
{
- yylhsminor.yy528 = sqlcipher_sqlite3ExprFunction(pParse, yymsp[-2].minor.yy322, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy394);
- sqlcipher_sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41);
+ yylhsminor.yy454 = sqlcipher_sqlite3ExprFunction(pParse, yymsp[-2].minor.yy14, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy144);
+ sqlcipher_sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
}
- yymsp[-5].minor.yy528 = yylhsminor.yy528;
+ yymsp[-5].minor.yy454 = yylhsminor.yy454;
break;
- case 191: /* expr ::= ID|INDEXED LP STAR RP filter_over */
+ case 193: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
{
- yylhsminor.yy528 = sqlcipher_sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
- sqlcipher_sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41);
+ yylhsminor.yy454 = sqlcipher_sqlite3ExprFunction(pParse, yymsp[-5].minor.yy14, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy144);
+ sqlcipher_sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
+ sqlcipher_sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-2].minor.yy14);
}
- yymsp[-4].minor.yy528 = yylhsminor.yy528;
+ yymsp[-8].minor.yy454 = yylhsminor.yy454;
break;
- case 192: /* term ::= CTIME_KW */
+ case 194: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
{
- yylhsminor.yy528 = sqlcipher_sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
+ yylhsminor.yy454 = sqlcipher_sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
+ sqlcipher_sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
}
- yymsp[0].minor.yy528 = yylhsminor.yy528;
+ yymsp[-4].minor.yy454 = yylhsminor.yy454;
break;
- case 193: /* expr ::= LP nexprlist COMMA expr RP */
+ case 195: /* term ::= CTIME_KW */
{
- ExprList *pList = sqlcipher_sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528);
- yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
- if( yymsp[-4].minor.yy528 ){
- yymsp[-4].minor.yy528->x.pList = pList;
+ yylhsminor.yy454 = sqlcipher_sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
+}
+ yymsp[0].minor.yy454 = yylhsminor.yy454;
+ break;
+ case 196: /* expr ::= LP nexprlist COMMA expr RP */
+{
+ ExprList *pList = sqlcipher_sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454);
+ yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
+ if( yymsp[-4].minor.yy454 ){
+ yymsp[-4].minor.yy454->x.pList = pList;
if( ALWAYS(pList->nExpr) ){
- yymsp[-4].minor.yy528->flags |= pList->a[0].pExpr->flags & EP_Propagate;
+ yymsp[-4].minor.yy454->flags |= pList->a[0].pExpr->flags & EP_Propagate;
}
}else{
sqlcipher_sqlite3ExprListDelete(pParse->db, pList);
}
}
break;
- case 194: /* expr ::= expr AND expr */
-{yymsp[-2].minor.yy528=sqlcipher_sqlite3ExprAnd(pParse,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
+ case 197: /* expr ::= expr AND expr */
+{yymsp[-2].minor.yy454=sqlcipher_sqlite3ExprAnd(pParse,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
break;
- case 195: /* expr ::= expr OR expr */
- case 196: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==196);
- case 197: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==197);
- case 198: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==198);
- case 199: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==199);
- case 200: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==200);
- case 201: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==201);
-{yymsp[-2].minor.yy528=sqlcipher_sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
+ case 198: /* expr ::= expr OR expr */
+ case 199: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==199);
+ case 200: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==200);
+ case 201: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==201);
+ case 202: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==202);
+ case 203: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==203);
+ case 204: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==204);
+{yymsp[-2].minor.yy454=sqlcipher_sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
break;
- case 202: /* likeop ::= NOT LIKE_KW|MATCH */
+ case 205: /* likeop ::= NOT LIKE_KW|MATCH */
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
break;
- case 203: /* expr ::= expr likeop expr */
+ case 206: /* expr ::= expr likeop expr */
{
ExprList *pList;
int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
yymsp[-1].minor.yy0.n &= 0x7fffffff;
- pList = sqlcipher_sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy528);
- pList = sqlcipher_sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy528);
- yymsp[-2].minor.yy528 = sqlcipher_sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
- if( bNot ) yymsp[-2].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy528, 0);
- if( yymsp[-2].minor.yy528 ) yymsp[-2].minor.yy528->flags |= EP_InfixFunc;
+ pList = sqlcipher_sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy454);
+ pList = sqlcipher_sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy454);
+ yymsp[-2].minor.yy454 = sqlcipher_sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
+ if( bNot ) yymsp[-2].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy454, 0);
+ if( yymsp[-2].minor.yy454 ) yymsp[-2].minor.yy454->flags |= EP_InfixFunc;
}
break;
- case 204: /* expr ::= expr likeop expr ESCAPE expr */
+ case 207: /* expr ::= expr likeop expr ESCAPE expr */
{
ExprList *pList;
int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
yymsp[-3].minor.yy0.n &= 0x7fffffff;
- pList = sqlcipher_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
- pList = sqlcipher_sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy528);
- pList = sqlcipher_sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528);
- yymsp[-4].minor.yy528 = sqlcipher_sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
- if( bNot ) yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
- if( yymsp[-4].minor.yy528 ) yymsp[-4].minor.yy528->flags |= EP_InfixFunc;
+ pList = sqlcipher_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
+ pList = sqlcipher_sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy454);
+ pList = sqlcipher_sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454);
+ yymsp[-4].minor.yy454 = sqlcipher_sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
+ if( bNot ) yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454 ) yymsp[-4].minor.yy454->flags |= EP_InfixFunc;
}
break;
- case 205: /* expr ::= expr ISNULL|NOTNULL */
-{yymsp[-1].minor.yy528 = sqlcipher_sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy528,0);}
+ case 208: /* expr ::= expr ISNULL|NOTNULL */
+{yymsp[-1].minor.yy454 = sqlcipher_sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy454,0);}
break;
- case 206: /* expr ::= expr NOT NULL */
-{yymsp[-2].minor.yy528 = sqlcipher_sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy528,0);}
+ case 209: /* expr ::= expr NOT NULL */
+{yymsp[-2].minor.yy454 = sqlcipher_sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy454,0);}
break;
- case 207: /* expr ::= expr IS expr */
+ case 210: /* expr ::= expr IS expr */
{
- yymsp[-2].minor.yy528 = sqlcipher_sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-2].minor.yy528, TK_ISNULL);
+ yymsp[-2].minor.yy454 = sqlcipher_sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-2].minor.yy454, TK_ISNULL);
}
break;
- case 208: /* expr ::= expr IS NOT expr */
+ case 211: /* expr ::= expr IS NOT expr */
{
- yymsp[-3].minor.yy528 = sqlcipher_sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy528,yymsp[0].minor.yy528);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-3].minor.yy528, TK_NOTNULL);
+ yymsp[-3].minor.yy454 = sqlcipher_sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-3].minor.yy454, TK_NOTNULL);
}
break;
- case 209: /* expr ::= expr IS NOT DISTINCT FROM expr */
+ case 212: /* expr ::= expr IS NOT DISTINCT FROM expr */
{
- yymsp[-5].minor.yy528 = sqlcipher_sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy528,yymsp[0].minor.yy528);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-5].minor.yy528, TK_ISNULL);
+ yymsp[-5].minor.yy454 = sqlcipher_sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-5].minor.yy454, TK_ISNULL);
}
break;
- case 210: /* expr ::= expr IS DISTINCT FROM expr */
+ case 213: /* expr ::= expr IS DISTINCT FROM expr */
{
- yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy528,yymsp[0].minor.yy528);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-4].minor.yy528, TK_NOTNULL);
+ yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-4].minor.yy454, TK_NOTNULL);
}
break;
- case 211: /* expr ::= NOT expr */
- case 212: /* expr ::= BITNOT expr */ yytestcase(yyruleno==212);
-{yymsp[-1].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy528, 0);/*A-overwrites-B*/}
+ case 214: /* expr ::= NOT expr */
+ case 215: /* expr ::= BITNOT expr */ yytestcase(yyruleno==215);
+{yymsp[-1].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy454, 0);/*A-overwrites-B*/}
break;
- case 213: /* expr ::= PLUS|MINUS expr */
+ case 216: /* expr ::= PLUS|MINUS expr */
{
- yymsp[-1].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy528, 0);
- /*A-overwrites-B*/
+ Expr *p = yymsp[0].minor.yy454;
+ u8 op = yymsp[-1].major + (TK_UPLUS-TK_PLUS);
+ assert( TK_UPLUS>TK_PLUS );
+ assert( TK_UMINUS == TK_MINUS + (TK_UPLUS - TK_PLUS) );
+ if( p && p->op==TK_UPLUS ){
+ p->op = op;
+ yymsp[-1].minor.yy454 = p;
+ }else{
+ yymsp[-1].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, op, p, 0);
+ /*A-overwrites-B*/
+ }
}
break;
- case 214: /* expr ::= expr PTR expr */
+ case 217: /* expr ::= expr PTR expr */
{
- ExprList *pList = sqlcipher_sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy528);
- pList = sqlcipher_sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy528);
- yylhsminor.yy528 = sqlcipher_sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
+ ExprList *pList = sqlcipher_sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy454);
+ pList = sqlcipher_sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy454);
+ yylhsminor.yy454 = sqlcipher_sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
}
- yymsp[-2].minor.yy528 = yylhsminor.yy528;
+ yymsp[-2].minor.yy454 = yylhsminor.yy454;
break;
- case 215: /* between_op ::= BETWEEN */
- case 218: /* in_op ::= IN */ yytestcase(yyruleno==218);
-{yymsp[0].minor.yy394 = 0;}
+ case 218: /* between_op ::= BETWEEN */
+ case 221: /* in_op ::= IN */ yytestcase(yyruleno==221);
+{yymsp[0].minor.yy144 = 0;}
break;
- case 217: /* expr ::= expr between_op expr AND expr */
+ case 220: /* expr ::= expr between_op expr AND expr */
{
- ExprList *pList = sqlcipher_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
- pList = sqlcipher_sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528);
- yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy528, 0);
- if( yymsp[-4].minor.yy528 ){
- yymsp[-4].minor.yy528->x.pList = pList;
+ ExprList *pList = sqlcipher_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
+ pList = sqlcipher_sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454);
+ yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454 ){
+ yymsp[-4].minor.yy454->x.pList = pList;
}else{
sqlcipher_sqlite3ExprListDelete(pParse->db, pList);
}
- if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
break;
- case 220: /* expr ::= expr in_op LP exprlist RP */
+ case 223: /* expr ::= expr in_op LP exprlist RP */
{
- if( yymsp[-1].minor.yy322==0 ){
+ if( yymsp[-1].minor.yy14==0 ){
/* Expressions of the form
**
** expr1 IN ()
@@ -173427,206 +182337,208 @@ static YYACTIONTYPE yy_reduce(
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
- sqlcipher_sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy528);
- yymsp[-4].minor.yy528 = sqlcipher_sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy394 ? "true" : "false");
- if( yymsp[-4].minor.yy528 ) sqlcipher_sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy528);
- }else{
- Expr *pRHS = yymsp[-1].minor.yy322->a[0].pExpr;
- if( yymsp[-1].minor.yy322->nExpr==1 && sqlcipher_sqlite3ExprIsConstant(pRHS) && yymsp[-4].minor.yy528->op!=TK_VECTOR ){
- yymsp[-1].minor.yy322->a[0].pExpr = 0;
- sqlcipher_sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
+ sqlcipher_sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy454);
+ yymsp[-4].minor.yy454 = sqlcipher_sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy144 ? "true" : "false");
+ if( yymsp[-4].minor.yy454 ) sqlcipher_sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy454);
+ }else{
+ Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr;
+ if( yymsp[-1].minor.yy14->nExpr==1 && sqlcipher_sqlite3ExprIsConstant(pParse,pRHS) && yymsp[-4].minor.yy454->op!=TK_VECTOR ){
+ yymsp[-1].minor.yy14->a[0].pExpr = 0;
+ sqlcipher_sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
pRHS = sqlcipher_sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
- yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy528, pRHS);
- }else{
- yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
- if( yymsp[-4].minor.yy528==0 ){
- sqlcipher_sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
- }else if( yymsp[-4].minor.yy528->pLeft->op==TK_VECTOR ){
- int nExpr = yymsp[-4].minor.yy528->pLeft->x.pList->nExpr;
- Select *pSelectRHS = sqlcipher_sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy322);
+ yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy454, pRHS);
+ }else if( yymsp[-1].minor.yy14->nExpr==1 && pRHS->op==TK_SELECT ){
+ yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ sqlcipher_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pRHS->x.pSelect);
+ pRHS->x.pSelect = 0;
+ sqlcipher_sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
+ }else{
+ yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454==0 ){
+ sqlcipher_sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
+ }else if( yymsp[-4].minor.yy454->pLeft->op==TK_VECTOR ){
+ int nExpr = yymsp[-4].minor.yy454->pLeft->x.pList->nExpr;
+ Select *pSelectRHS = sqlcipher_sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy14);
if( pSelectRHS ){
parserDoubleLinkSelect(pParse, pSelectRHS);
- sqlcipher_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelectRHS);
+ sqlcipher_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelectRHS);
}
}else{
- yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy322;
- sqlcipher_sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528);
+ yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy14;
+ sqlcipher_sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454);
}
}
- if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
}
break;
- case 221: /* expr ::= LP select RP */
+ case 224: /* expr ::= LP select RP */
{
- yymsp[-2].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_SELECT, 0, 0);
- sqlcipher_sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy528, yymsp[-1].minor.yy47);
+ yymsp[-2].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_SELECT, 0, 0);
+ sqlcipher_sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy454, yymsp[-1].minor.yy555);
}
break;
- case 222: /* expr ::= expr in_op LP select RP */
+ case 225: /* expr ::= expr in_op LP select RP */
{
- yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
- sqlcipher_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, yymsp[-1].minor.yy47);
- if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
+ yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ sqlcipher_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, yymsp[-1].minor.yy555);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
break;
- case 223: /* expr ::= expr in_op nm dbnm paren_exprlist */
+ case 226: /* expr ::= expr in_op nm dbnm paren_exprlist */
{
SrcList *pSrc = sqlcipher_sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
Select *pSelect = sqlcipher_sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
- if( yymsp[0].minor.yy322 ) sqlcipher_sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy322);
- yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
- sqlcipher_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelect);
- if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
+ if( yymsp[0].minor.yy14 ) sqlcipher_sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy14);
+ yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ sqlcipher_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelect);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
break;
- case 224: /* expr ::= EXISTS LP select RP */
+ case 227: /* expr ::= EXISTS LP select RP */
{
Expr *p;
- p = yymsp[-3].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
- sqlcipher_sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy47);
+ p = yymsp[-3].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
+ sqlcipher_sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy555);
}
break;
- case 225: /* expr ::= CASE case_operand case_exprlist case_else END */
+ case 228: /* expr ::= CASE case_operand case_exprlist case_else END */
{
- yymsp[-4].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy528, 0);
- if( yymsp[-4].minor.yy528 ){
- yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy528 ? sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528) : yymsp[-2].minor.yy322;
- sqlcipher_sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528);
+ yymsp[-4].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454 ){
+ yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy454 ? sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454) : yymsp[-2].minor.yy14;
+ sqlcipher_sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454);
}else{
- sqlcipher_sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322);
- sqlcipher_sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528);
+ sqlcipher_sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14);
+ sqlcipher_sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454);
}
}
break;
- case 226: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ case 229: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
- yymsp[-4].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy528);
- yymsp[-4].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy528);
+ yymsp[-4].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[-2].minor.yy454);
+ yymsp[-4].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[0].minor.yy454);
}
break;
- case 227: /* case_exprlist ::= WHEN expr THEN expr */
+ case 230: /* case_exprlist ::= WHEN expr THEN expr */
{
- yymsp[-3].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
- yymsp[-3].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy528);
+ yymsp[-3].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
+ yymsp[-3].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14, yymsp[0].minor.yy454);
}
break;
- case 230: /* case_operand ::= expr */
-{yymsp[0].minor.yy528 = yymsp[0].minor.yy528; /*A-overwrites-X*/}
- break;
- case 233: /* nexprlist ::= nexprlist COMMA expr */
-{yymsp[-2].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy528);}
+ case 235: /* nexprlist ::= nexprlist COMMA expr */
+{yymsp[-2].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[0].minor.yy454);}
break;
- case 234: /* nexprlist ::= expr */
-{yymsp[0].minor.yy322 = sqlcipher_sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy528); /*A-overwrites-Y*/}
+ case 236: /* nexprlist ::= expr */
+{yymsp[0].minor.yy14 = sqlcipher_sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy454); /*A-overwrites-Y*/}
break;
- case 236: /* paren_exprlist ::= LP exprlist RP */
- case 241: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==241);
-{yymsp[-2].minor.yy322 = yymsp[-1].minor.yy322;}
+ case 238: /* paren_exprlist ::= LP exprlist RP */
+ case 243: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==243);
+{yymsp[-2].minor.yy14 = yymsp[-1].minor.yy14;}
break;
- case 237: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ case 239: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
{
sqlcipher_sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
- sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy394,
- &yymsp[-11].minor.yy0, yymsp[0].minor.yy528, SQLITE_SO_ASC, yymsp[-8].minor.yy394, SQLITE_IDXTYPE_APPDEF);
+ sqlcipher_sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy14, yymsp[-10].minor.yy144,
+ &yymsp[-11].minor.yy0, yymsp[0].minor.yy454, SQLITE_SO_ASC, yymsp[-8].minor.yy144, SQLITE_IDXTYPE_APPDEF);
if( IN_RENAME_OBJECT && pParse->pNewIndex ){
sqlcipher_sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0);
}
}
break;
- case 238: /* uniqueflag ::= UNIQUE */
- case 280: /* raisetype ::= ABORT */ yytestcase(yyruleno==280);
-{yymsp[0].minor.yy394 = OE_Abort;}
+ case 240: /* uniqueflag ::= UNIQUE */
+ case 282: /* raisetype ::= ABORT */ yytestcase(yyruleno==282);
+{yymsp[0].minor.yy144 = OE_Abort;}
break;
- case 239: /* uniqueflag ::= */
-{yymsp[1].minor.yy394 = OE_None;}
+ case 241: /* uniqueflag ::= */
+{yymsp[1].minor.yy144 = OE_None;}
break;
- case 242: /* eidlist ::= eidlist COMMA nm collate sortorder */
+ case 244: /* eidlist ::= eidlist COMMA nm collate sortorder */
{
- yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394);
+ yymsp[-4].minor.yy14 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144);
}
break;
- case 243: /* eidlist ::= nm collate sortorder */
+ case 245: /* eidlist ::= nm collate sortorder */
{
- yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); /*A-overwrites-Y*/
+ yymsp[-2].minor.yy14 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144); /*A-overwrites-Y*/
}
break;
- case 246: /* cmd ::= DROP INDEX ifexists fullname */
-{sqlcipher_sqlite3DropIndex(pParse, yymsp[0].minor.yy131, yymsp[-1].minor.yy394);}
+ case 248: /* cmd ::= DROP INDEX ifexists fullname */
+{sqlcipher_sqlite3DropIndex(pParse, yymsp[0].minor.yy203, yymsp[-1].minor.yy144);}
break;
- case 247: /* cmd ::= VACUUM vinto */
-{sqlcipher_sqlite3Vacuum(pParse,0,yymsp[0].minor.yy528);}
+ case 249: /* cmd ::= VACUUM vinto */
+{sqlcipher_sqlite3Vacuum(pParse,0,yymsp[0].minor.yy454);}
break;
- case 248: /* cmd ::= VACUUM nm vinto */
-{sqlcipher_sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy528);}
+ case 250: /* cmd ::= VACUUM nm vinto */
+{sqlcipher_sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy454);}
break;
- case 251: /* cmd ::= PRAGMA nm dbnm */
+ case 253: /* cmd ::= PRAGMA nm dbnm */
{sqlcipher_sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
break;
- case 252: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+ case 254: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{sqlcipher_sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
break;
- case 253: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ case 255: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{sqlcipher_sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
break;
- case 254: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
+ case 256: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{sqlcipher_sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
break;
- case 255: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ case 257: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
{sqlcipher_sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
break;
- case 258: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ case 260: /* 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;
- sqlcipher_sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy33, &all);
+ sqlcipher_sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy427, &all);
}
break;
- case 259: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ case 261: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
{
- sqlcipher_sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy394, yymsp[-4].minor.yy180.a, yymsp[-4].minor.yy180.b, yymsp[-2].minor.yy131, yymsp[0].minor.yy528, yymsp[-10].minor.yy394, yymsp[-8].minor.yy394);
+ sqlcipher_sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy144, yymsp[-4].minor.yy286.a, yymsp[-4].minor.yy286.b, yymsp[-2].minor.yy203, yymsp[0].minor.yy454, yymsp[-10].minor.yy144, yymsp[-8].minor.yy144);
yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
}
break;
- case 260: /* trigger_time ::= BEFORE|AFTER */
-{ yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/ }
+ case 262: /* trigger_time ::= BEFORE|AFTER */
+{ yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/ }
break;
- case 261: /* trigger_time ::= INSTEAD OF */
-{ yymsp[-1].minor.yy394 = TK_INSTEAD;}
+ case 263: /* trigger_time ::= INSTEAD OF */
+{ yymsp[-1].minor.yy144 = TK_INSTEAD;}
break;
- case 262: /* trigger_time ::= */
-{ yymsp[1].minor.yy394 = TK_BEFORE; }
+ case 264: /* trigger_time ::= */
+{ yymsp[1].minor.yy144 = TK_BEFORE; }
break;
- case 263: /* trigger_event ::= DELETE|INSERT */
- case 264: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==264);
-{yymsp[0].minor.yy180.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy180.b = 0;}
+ case 265: /* trigger_event ::= DELETE|INSERT */
+ case 266: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==266);
+{yymsp[0].minor.yy286.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy286.b = 0;}
break;
- case 265: /* trigger_event ::= UPDATE OF idlist */
-{yymsp[-2].minor.yy180.a = TK_UPDATE; yymsp[-2].minor.yy180.b = yymsp[0].minor.yy254;}
+ case 267: /* trigger_event ::= UPDATE OF idlist */
+{yymsp[-2].minor.yy286.a = TK_UPDATE; yymsp[-2].minor.yy286.b = yymsp[0].minor.yy132;}
break;
- case 266: /* when_clause ::= */
- case 285: /* key_opt ::= */ yytestcase(yyruleno==285);
-{ yymsp[1].minor.yy528 = 0; }
+ case 268: /* when_clause ::= */
+ case 287: /* key_opt ::= */ yytestcase(yyruleno==287);
+{ yymsp[1].minor.yy454 = 0; }
break;
- case 267: /* when_clause ::= WHEN expr */
- case 286: /* key_opt ::= KEY expr */ yytestcase(yyruleno==286);
-{ yymsp[-1].minor.yy528 = yymsp[0].minor.yy528; }
+ case 269: /* when_clause ::= WHEN expr */
+ case 288: /* key_opt ::= KEY expr */ yytestcase(yyruleno==288);
+{ yymsp[-1].minor.yy454 = yymsp[0].minor.yy454; }
break;
- case 268: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ case 270: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
- assert( yymsp[-2].minor.yy33!=0 );
- yymsp[-2].minor.yy33->pLast->pNext = yymsp[-1].minor.yy33;
- yymsp[-2].minor.yy33->pLast = yymsp[-1].minor.yy33;
+ assert( yymsp[-2].minor.yy427!=0 );
+ yymsp[-2].minor.yy427->pLast->pNext = yymsp[-1].minor.yy427;
+ yymsp[-2].minor.yy427->pLast = yymsp[-1].minor.yy427;
}
break;
- case 269: /* trigger_cmd_list ::= trigger_cmd SEMI */
+ case 271: /* trigger_cmd_list ::= trigger_cmd SEMI */
{
- assert( yymsp[-1].minor.yy33!=0 );
- yymsp[-1].minor.yy33->pLast = yymsp[-1].minor.yy33;
+ assert( yymsp[-1].minor.yy427!=0 );
+ yymsp[-1].minor.yy427->pLast = yymsp[-1].minor.yy427;
}
break;
- case 270: /* trnm ::= nm DOT nm */
+ case 272: /* trnm ::= nm DOT nm */
{
yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
sqlcipher_sqlite3ErrorMsg(pParse,
@@ -173634,370 +182546,377 @@ static YYACTIONTYPE yy_reduce(
"statements within triggers");
}
break;
- case 271: /* tridxby ::= INDEXED BY nm */
+ case 273: /* tridxby ::= INDEXED BY nm */
{
sqlcipher_sqlite3ErrorMsg(pParse,
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 272: /* tridxby ::= NOT INDEXED */
+ case 274: /* tridxby ::= NOT INDEXED */
{
sqlcipher_sqlite3ErrorMsg(pParse,
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 273: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
-{yylhsminor.yy33 = sqlcipher_sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy131, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528, yymsp[-7].minor.yy394, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy522);}
- yymsp[-8].minor.yy33 = yylhsminor.yy33;
+ case 275: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+{yylhsminor.yy427 = sqlcipher_sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy203, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454, yymsp[-7].minor.yy144, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy168);}
+ yymsp[-8].minor.yy427 = yylhsminor.yy427;
break;
- case 274: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ case 276: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
{
- yylhsminor.yy33 = sqlcipher_sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy254,yymsp[-2].minor.yy47,yymsp[-6].minor.yy394,yymsp[-1].minor.yy444,yymsp[-7].minor.yy522,yymsp[0].minor.yy522);/*yylhsminor.yy33-overwrites-yymsp[-6].minor.yy394*/
+ yylhsminor.yy427 = sqlcipher_sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy132,yymsp[-2].minor.yy555,yymsp[-6].minor.yy144,yymsp[-1].minor.yy122,yymsp[-7].minor.yy168,yymsp[0].minor.yy168);/*yylhsminor.yy427-overwrites-yymsp[-6].minor.yy144*/
}
- yymsp[-7].minor.yy33 = yylhsminor.yy33;
+ yymsp[-7].minor.yy427 = yylhsminor.yy427;
break;
- case 275: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
-{yylhsminor.yy33 = sqlcipher_sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy528, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy522);}
- yymsp[-5].minor.yy33 = yylhsminor.yy33;
+ case 277: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+{yylhsminor.yy427 = sqlcipher_sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy454, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy168);}
+ yymsp[-5].minor.yy427 = yylhsminor.yy427;
break;
- case 276: /* trigger_cmd ::= scanpt select scanpt */
-{yylhsminor.yy33 = sqlcipher_sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy47, yymsp[-2].minor.yy522, yymsp[0].minor.yy522); /*yylhsminor.yy33-overwrites-yymsp[-1].minor.yy47*/}
- yymsp[-2].minor.yy33 = yylhsminor.yy33;
+ case 278: /* trigger_cmd ::= scanpt select scanpt */
+{yylhsminor.yy427 = sqlcipher_sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy555, yymsp[-2].minor.yy168, yymsp[0].minor.yy168); /*yylhsminor.yy427-overwrites-yymsp[-1].minor.yy555*/}
+ yymsp[-2].minor.yy427 = yylhsminor.yy427;
break;
- case 277: /* expr ::= RAISE LP IGNORE RP */
+ case 279: /* expr ::= RAISE LP IGNORE RP */
{
- yymsp[-3].minor.yy528 = sqlcipher_sqlite3PExpr(pParse, TK_RAISE, 0, 0);
- if( yymsp[-3].minor.yy528 ){
- yymsp[-3].minor.yy528->affExpr = OE_Ignore;
+ yymsp[-3].minor.yy454 = sqlcipher_sqlite3PExpr(pParse, TK_RAISE, 0, 0);
+ if( yymsp[-3].minor.yy454 ){
+ yymsp[-3].minor.yy454->affExpr = OE_Ignore;
}
}
break;
- case 278: /* expr ::= RAISE LP raisetype COMMA nm RP */
+ case 280: /* expr ::= RAISE LP raisetype COMMA nm RP */
{
- yymsp[-5].minor.yy528 = sqlcipher_sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
- if( yymsp[-5].minor.yy528 ) {
- yymsp[-5].minor.yy528->affExpr = (char)yymsp[-3].minor.yy394;
+ yymsp[-5].minor.yy454 = sqlcipher_sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
+ if( yymsp[-5].minor.yy454 ) {
+ yymsp[-5].minor.yy454->affExpr = (char)yymsp[-3].minor.yy144;
}
}
break;
- case 279: /* raisetype ::= ROLLBACK */
-{yymsp[0].minor.yy394 = OE_Rollback;}
+ case 281: /* raisetype ::= ROLLBACK */
+{yymsp[0].minor.yy144 = OE_Rollback;}
break;
- case 281: /* raisetype ::= FAIL */
-{yymsp[0].minor.yy394 = OE_Fail;}
+ case 283: /* raisetype ::= FAIL */
+{yymsp[0].minor.yy144 = OE_Fail;}
break;
- case 282: /* cmd ::= DROP TRIGGER ifexists fullname */
+ case 284: /* cmd ::= DROP TRIGGER ifexists fullname */
{
- sqlcipher_sqlite3DropTrigger(pParse,yymsp[0].minor.yy131,yymsp[-1].minor.yy394);
+ sqlcipher_sqlite3DropTrigger(pParse,yymsp[0].minor.yy203,yymsp[-1].minor.yy144);
}
break;
- case 283: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ case 285: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
- sqlcipher_sqlite3Attach(pParse, yymsp[-3].minor.yy528, yymsp[-1].minor.yy528, yymsp[0].minor.yy528);
+ sqlcipher_sqlite3Attach(pParse, yymsp[-3].minor.yy454, yymsp[-1].minor.yy454, yymsp[0].minor.yy454);
}
break;
- case 284: /* cmd ::= DETACH database_kw_opt expr */
+ case 286: /* cmd ::= DETACH database_kw_opt expr */
{
- sqlcipher_sqlite3Detach(pParse, yymsp[0].minor.yy528);
+ sqlcipher_sqlite3Detach(pParse, yymsp[0].minor.yy454);
}
break;
- case 287: /* cmd ::= REINDEX */
+ case 289: /* cmd ::= REINDEX */
{sqlcipher_sqlite3Reindex(pParse, 0, 0);}
break;
- case 288: /* cmd ::= REINDEX nm dbnm */
+ case 290: /* cmd ::= REINDEX nm dbnm */
{sqlcipher_sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 289: /* cmd ::= ANALYZE */
+ case 291: /* cmd ::= ANALYZE */
{sqlcipher_sqlite3Analyze(pParse, 0, 0);}
break;
- case 290: /* cmd ::= ANALYZE nm dbnm */
+ case 292: /* cmd ::= ANALYZE nm dbnm */
{sqlcipher_sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 291: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+ case 293: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
- sqlcipher_sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy131,&yymsp[0].minor.yy0);
+ sqlcipher_sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy203,&yymsp[0].minor.yy0);
}
break;
- case 292: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ case 294: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
{
yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
sqlcipher_sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
}
break;
- case 293: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ case 295: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
{
- sqlcipher_sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy131, &yymsp[0].minor.yy0);
+ sqlcipher_sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy203, &yymsp[0].minor.yy0);
}
break;
- case 294: /* add_column_fullname ::= fullname */
+ case 296: /* add_column_fullname ::= fullname */
{
disableLookaside(pParse);
- sqlcipher_sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy131);
+ sqlcipher_sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy203);
}
break;
- case 295: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ case 297: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
{
- sqlcipher_sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy131, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
+ sqlcipher_sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy203, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
}
break;
- case 296: /* cmd ::= create_vtab */
+ case 298: /* cmd ::= create_vtab */
{sqlcipher_sqlite3VtabFinishParse(pParse,0);}
break;
- case 297: /* cmd ::= create_vtab LP vtabarglist RP */
+ case 299: /* cmd ::= create_vtab LP vtabarglist RP */
{sqlcipher_sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
break;
- case 298: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ case 300: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
{
- sqlcipher_sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy394);
+ sqlcipher_sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy144);
}
break;
- case 299: /* vtabarg ::= */
+ case 301: /* vtabarg ::= */
{sqlcipher_sqlite3VtabArgInit(pParse);}
break;
- case 300: /* vtabargtoken ::= ANY */
- case 301: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==301);
- case 302: /* lp ::= LP */ yytestcase(yyruleno==302);
+ case 302: /* vtabargtoken ::= ANY */
+ case 303: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==303);
+ case 304: /* lp ::= LP */ yytestcase(yyruleno==304);
{sqlcipher_sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
break;
- case 303: /* with ::= WITH wqlist */
- case 304: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==304);
-{ sqlcipher_sqlite3WithPush(pParse, yymsp[0].minor.yy521, 1); }
+ case 305: /* with ::= WITH wqlist */
+ case 306: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==306);
+{ sqlcipher_sqlite3WithPush(pParse, yymsp[0].minor.yy59, 1); }
break;
- case 305: /* wqas ::= AS */
-{yymsp[0].minor.yy516 = M10d_Any;}
+ case 307: /* wqas ::= AS */
+{yymsp[0].minor.yy462 = M10d_Any;}
break;
- case 306: /* wqas ::= AS MATERIALIZED */
-{yymsp[-1].minor.yy516 = M10d_Yes;}
+ case 308: /* wqas ::= AS MATERIALIZED */
+{yymsp[-1].minor.yy462 = M10d_Yes;}
break;
- case 307: /* wqas ::= AS NOT MATERIALIZED */
-{yymsp[-2].minor.yy516 = M10d_No;}
+ case 309: /* wqas ::= AS NOT MATERIALIZED */
+{yymsp[-2].minor.yy462 = M10d_No;}
break;
- case 308: /* wqitem ::= nm eidlist_opt wqas LP select RP */
+ case 310: /* wqitem ::= withnm eidlist_opt wqas LP select RP */
{
- yymsp[-5].minor.yy385 = sqlcipher_sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy47, yymsp[-3].minor.yy516); /*A-overwrites-X*/
+ yymsp[-5].minor.yy67 = sqlcipher_sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy555, yymsp[-3].minor.yy462); /*A-overwrites-X*/
}
break;
- case 309: /* wqlist ::= wqitem */
-{
- yymsp[0].minor.yy521 = sqlcipher_sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy385); /*A-overwrites-X*/
-}
+ case 311: /* withnm ::= nm */
+{pParse->bHasWith = 1;}
break;
- case 310: /* wqlist ::= wqlist COMMA wqitem */
+ case 312: /* wqlist ::= wqitem */
{
- yymsp[-2].minor.yy521 = sqlcipher_sqlite3WithAdd(pParse, yymsp[-2].minor.yy521, yymsp[0].minor.yy385);
+ yymsp[0].minor.yy59 = sqlcipher_sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy67); /*A-overwrites-X*/
}
break;
- case 311: /* windowdefn_list ::= windowdefn */
-{ yylhsminor.yy41 = yymsp[0].minor.yy41; }
- yymsp[0].minor.yy41 = yylhsminor.yy41;
- break;
- case 312: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ case 313: /* wqlist ::= wqlist COMMA wqitem */
{
- assert( yymsp[0].minor.yy41!=0 );
- sqlcipher_sqlite3WindowChain(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy41);
- yymsp[0].minor.yy41->pNextWin = yymsp[-2].minor.yy41;
- yylhsminor.yy41 = yymsp[0].minor.yy41;
+ yymsp[-2].minor.yy59 = sqlcipher_sqlite3WithAdd(pParse, yymsp[-2].minor.yy59, yymsp[0].minor.yy67);
}
- yymsp[-2].minor.yy41 = yylhsminor.yy41;
break;
- case 313: /* windowdefn ::= nm AS LP window RP */
+ case 314: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
{
- if( ALWAYS(yymsp[-1].minor.yy41) ){
- yymsp[-1].minor.yy41->zName = sqlcipher_sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
- }
- yylhsminor.yy41 = yymsp[-1].minor.yy41;
+ assert( yymsp[0].minor.yy211!=0 );
+ sqlcipher_sqlite3WindowChain(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy211);
+ yymsp[0].minor.yy211->pNextWin = yymsp[-2].minor.yy211;
+ yylhsminor.yy211 = yymsp[0].minor.yy211;
}
- yymsp[-4].minor.yy41 = yylhsminor.yy41;
+ yymsp[-2].minor.yy211 = yylhsminor.yy211;
break;
- case 314: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ case 315: /* windowdefn ::= nm AS LP window RP */
{
- yymsp[-4].minor.yy41 = sqlcipher_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, 0);
+ if( ALWAYS(yymsp[-1].minor.yy211) ){
+ yymsp[-1].minor.yy211->zName = sqlcipher_sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
+ }
+ yylhsminor.yy211 = yymsp[-1].minor.yy211;
}
+ yymsp[-4].minor.yy211 = yylhsminor.yy211;
break;
- case 315: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ case 316: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
{
- yylhsminor.yy41 = sqlcipher_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, &yymsp[-5].minor.yy0);
+ yymsp[-4].minor.yy211 = sqlcipher_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, 0);
}
- yymsp[-5].minor.yy41 = yylhsminor.yy41;
break;
- case 316: /* window ::= ORDER BY sortlist frame_opt */
+ case 317: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
{
- yymsp[-3].minor.yy41 = sqlcipher_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, 0);
+ yylhsminor.yy211 = sqlcipher_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, &yymsp[-5].minor.yy0);
}
+ yymsp[-5].minor.yy211 = yylhsminor.yy211;
break;
- case 317: /* window ::= nm ORDER BY sortlist frame_opt */
+ case 318: /* window ::= ORDER BY sortlist frame_opt */
{
- yylhsminor.yy41 = sqlcipher_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0);
+ yymsp[-3].minor.yy211 = sqlcipher_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, 0);
}
- yymsp[-4].minor.yy41 = yylhsminor.yy41;
break;
- case 318: /* window ::= frame_opt */
- case 337: /* filter_over ::= over_clause */ yytestcase(yyruleno==337);
+ case 319: /* window ::= nm ORDER BY sortlist frame_opt */
{
- yylhsminor.yy41 = yymsp[0].minor.yy41;
+ yylhsminor.yy211 = sqlcipher_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0);
}
- yymsp[0].minor.yy41 = yylhsminor.yy41;
+ yymsp[-4].minor.yy211 = yylhsminor.yy211;
break;
- case 319: /* window ::= nm frame_opt */
+ case 320: /* window ::= nm frame_opt */
{
- yylhsminor.yy41 = sqlcipher_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, 0, &yymsp[-1].minor.yy0);
+ yylhsminor.yy211 = sqlcipher_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, 0, &yymsp[-1].minor.yy0);
}
- yymsp[-1].minor.yy41 = yylhsminor.yy41;
+ yymsp[-1].minor.yy211 = yylhsminor.yy211;
break;
- case 320: /* frame_opt ::= */
+ case 321: /* frame_opt ::= */
{
- yymsp[1].minor.yy41 = sqlcipher_sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
+ yymsp[1].minor.yy211 = sqlcipher_sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
}
break;
- case 321: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ case 322: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
{
- yylhsminor.yy41 = sqlcipher_sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy394, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy516);
+ yylhsminor.yy211 = sqlcipher_sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy144, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy462);
}
- yymsp[-2].minor.yy41 = yylhsminor.yy41;
+ yymsp[-2].minor.yy211 = yylhsminor.yy211;
break;
- case 322: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ case 323: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
{
- yylhsminor.yy41 = sqlcipher_sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy394, yymsp[-3].minor.yy595.eType, yymsp[-3].minor.yy595.pExpr, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, yymsp[0].minor.yy516);
+ yylhsminor.yy211 = sqlcipher_sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy144, yymsp[-3].minor.yy509.eType, yymsp[-3].minor.yy509.pExpr, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, yymsp[0].minor.yy462);
}
- yymsp[-5].minor.yy41 = yylhsminor.yy41;
+ yymsp[-5].minor.yy211 = yylhsminor.yy211;
break;
- case 324: /* frame_bound_s ::= frame_bound */
- case 326: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==326);
-{yylhsminor.yy595 = yymsp[0].minor.yy595;}
- yymsp[0].minor.yy595 = yylhsminor.yy595;
+ case 325: /* frame_bound_s ::= frame_bound */
+ case 327: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==327);
+{yylhsminor.yy509 = yymsp[0].minor.yy509;}
+ yymsp[0].minor.yy509 = yylhsminor.yy509;
break;
- case 325: /* frame_bound_s ::= UNBOUNDED PRECEDING */
- case 327: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==327);
- case 329: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==329);
-{yylhsminor.yy595.eType = yymsp[-1].major; yylhsminor.yy595.pExpr = 0;}
- yymsp[-1].minor.yy595 = yylhsminor.yy595;
+ case 326: /* frame_bound_s ::= UNBOUNDED PRECEDING */
+ case 328: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==328);
+ case 330: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==330);
+{yylhsminor.yy509.eType = yymsp[-1].major; yylhsminor.yy509.pExpr = 0;}
+ yymsp[-1].minor.yy509 = yylhsminor.yy509;
break;
- case 328: /* frame_bound ::= expr PRECEDING|FOLLOWING */
-{yylhsminor.yy595.eType = yymsp[0].major; yylhsminor.yy595.pExpr = yymsp[-1].minor.yy528;}
- yymsp[-1].minor.yy595 = yylhsminor.yy595;
+ case 329: /* frame_bound ::= expr PRECEDING|FOLLOWING */
+{yylhsminor.yy509.eType = yymsp[0].major; yylhsminor.yy509.pExpr = yymsp[-1].minor.yy454;}
+ yymsp[-1].minor.yy509 = yylhsminor.yy509;
break;
- case 330: /* frame_exclude_opt ::= */
-{yymsp[1].minor.yy516 = 0;}
+ case 331: /* frame_exclude_opt ::= */
+{yymsp[1].minor.yy462 = 0;}
break;
- case 331: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
-{yymsp[-1].minor.yy516 = yymsp[0].minor.yy516;}
+ case 332: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
+{yymsp[-1].minor.yy462 = yymsp[0].minor.yy462;}
break;
- case 332: /* frame_exclude ::= NO OTHERS */
- case 333: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==333);
-{yymsp[-1].minor.yy516 = yymsp[-1].major; /*A-overwrites-X*/}
+ case 333: /* frame_exclude ::= NO OTHERS */
+ case 334: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==334);
+{yymsp[-1].minor.yy462 = yymsp[-1].major; /*A-overwrites-X*/}
break;
- case 334: /* frame_exclude ::= GROUP|TIES */
-{yymsp[0].minor.yy516 = yymsp[0].major; /*A-overwrites-X*/}
+ case 335: /* frame_exclude ::= GROUP|TIES */
+{yymsp[0].minor.yy462 = yymsp[0].major; /*A-overwrites-X*/}
break;
- case 335: /* window_clause ::= WINDOW windowdefn_list */
-{ yymsp[-1].minor.yy41 = yymsp[0].minor.yy41; }
+ case 336: /* window_clause ::= WINDOW windowdefn_list */
+{ yymsp[-1].minor.yy211 = yymsp[0].minor.yy211; }
break;
- case 336: /* filter_over ::= filter_clause over_clause */
+ case 337: /* filter_over ::= filter_clause over_clause */
{
- if( yymsp[0].minor.yy41 ){
- yymsp[0].minor.yy41->pFilter = yymsp[-1].minor.yy528;
+ if( yymsp[0].minor.yy211 ){
+ yymsp[0].minor.yy211->pFilter = yymsp[-1].minor.yy454;
}else{
- sqlcipher_sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528);
+ sqlcipher_sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454);
}
- yylhsminor.yy41 = yymsp[0].minor.yy41;
+ yylhsminor.yy211 = yymsp[0].minor.yy211;
+}
+ yymsp[-1].minor.yy211 = yylhsminor.yy211;
+ break;
+ case 338: /* filter_over ::= over_clause */
+{
+ yylhsminor.yy211 = yymsp[0].minor.yy211;
}
- yymsp[-1].minor.yy41 = yylhsminor.yy41;
+ yymsp[0].minor.yy211 = yylhsminor.yy211;
break;
- case 338: /* filter_over ::= filter_clause */
+ case 339: /* filter_over ::= filter_clause */
{
- yylhsminor.yy41 = (Window*)sqlcipher_sqlite3DbMallocZero(pParse->db, sizeof(Window));
- if( yylhsminor.yy41 ){
- yylhsminor.yy41->eFrmType = TK_FILTER;
- yylhsminor.yy41->pFilter = yymsp[0].minor.yy528;
+ yylhsminor.yy211 = (Window*)sqlcipher_sqlite3DbMallocZero(pParse->db, sizeof(Window));
+ if( yylhsminor.yy211 ){
+ yylhsminor.yy211->eFrmType = TK_FILTER;
+ yylhsminor.yy211->pFilter = yymsp[0].minor.yy454;
}else{
- sqlcipher_sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy528);
+ sqlcipher_sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy454);
}
}
- yymsp[0].minor.yy41 = yylhsminor.yy41;
+ yymsp[0].minor.yy211 = yylhsminor.yy211;
break;
- case 339: /* over_clause ::= OVER LP window RP */
+ case 340: /* over_clause ::= OVER LP window RP */
{
- yymsp[-3].minor.yy41 = yymsp[-1].minor.yy41;
- assert( yymsp[-3].minor.yy41!=0 );
+ yymsp[-3].minor.yy211 = yymsp[-1].minor.yy211;
+ assert( yymsp[-3].minor.yy211!=0 );
}
break;
- case 340: /* over_clause ::= OVER nm */
+ case 341: /* over_clause ::= OVER nm */
{
- yymsp[-1].minor.yy41 = (Window*)sqlcipher_sqlite3DbMallocZero(pParse->db, sizeof(Window));
- if( yymsp[-1].minor.yy41 ){
- yymsp[-1].minor.yy41->zName = sqlcipher_sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
+ yymsp[-1].minor.yy211 = (Window*)sqlcipher_sqlite3DbMallocZero(pParse->db, sizeof(Window));
+ if( yymsp[-1].minor.yy211 ){
+ yymsp[-1].minor.yy211->zName = sqlcipher_sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
}
}
break;
- case 341: /* filter_clause ::= FILTER LP WHERE expr RP */
-{ yymsp[-4].minor.yy528 = yymsp[-1].minor.yy528; }
+ case 342: /* filter_clause ::= FILTER LP WHERE expr RP */
+{ yymsp[-4].minor.yy454 = yymsp[-1].minor.yy454; }
+ break;
+ case 343: /* term ::= QNUMBER */
+{
+ yylhsminor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0);
+ sqlcipher_sqlite3DequoteNumber(pParse, yylhsminor.yy454);
+}
+ yymsp[0].minor.yy454 = yylhsminor.yy454;
break;
default:
- /* (342) input ::= cmdlist */ yytestcase(yyruleno==342);
- /* (343) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==343);
- /* (344) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=344);
- /* (345) ecmd ::= SEMI */ yytestcase(yyruleno==345);
- /* (346) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==346);
- /* (347) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=347);
- /* (348) trans_opt ::= */ yytestcase(yyruleno==348);
- /* (349) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==349);
- /* (350) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==350);
- /* (351) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==351);
- /* (352) savepoint_opt ::= */ yytestcase(yyruleno==352);
- /* (353) cmd ::= create_table create_table_args */ yytestcase(yyruleno==353);
- /* (354) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=354);
- /* (355) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==355);
- /* (356) columnlist ::= columnname carglist */ yytestcase(yyruleno==356);
- /* (357) nm ::= ID|INDEXED */ yytestcase(yyruleno==357);
- /* (358) nm ::= STRING */ yytestcase(yyruleno==358);
- /* (359) nm ::= JOIN_KW */ yytestcase(yyruleno==359);
- /* (360) typetoken ::= typename */ yytestcase(yyruleno==360);
- /* (361) typename ::= ID|STRING */ yytestcase(yyruleno==361);
- /* (362) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=362);
- /* (363) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=363);
- /* (364) carglist ::= carglist ccons */ yytestcase(yyruleno==364);
- /* (365) carglist ::= */ yytestcase(yyruleno==365);
- /* (366) ccons ::= NULL onconf */ yytestcase(yyruleno==366);
- /* (367) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==367);
- /* (368) ccons ::= AS generated */ yytestcase(yyruleno==368);
- /* (369) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==369);
- /* (370) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==370);
- /* (371) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=371);
- /* (372) tconscomma ::= */ yytestcase(yyruleno==372);
- /* (373) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=373);
- /* (374) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=374);
- /* (375) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=375);
- /* (376) oneselect ::= values */ yytestcase(yyruleno==376);
- /* (377) sclp ::= selcollist COMMA */ yytestcase(yyruleno==377);
- /* (378) as ::= ID|STRING */ yytestcase(yyruleno==378);
- /* (379) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=379);
- /* (380) returning ::= */ yytestcase(yyruleno==380);
- /* (381) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=381);
- /* (382) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==382);
- /* (383) exprlist ::= nexprlist */ yytestcase(yyruleno==383);
- /* (384) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=384);
- /* (385) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=385);
- /* (386) nmnum ::= ON */ yytestcase(yyruleno==386);
- /* (387) nmnum ::= DELETE */ yytestcase(yyruleno==387);
- /* (388) nmnum ::= DEFAULT */ yytestcase(yyruleno==388);
- /* (389) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==389);
- /* (390) foreach_clause ::= */ yytestcase(yyruleno==390);
- /* (391) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==391);
- /* (392) trnm ::= nm */ yytestcase(yyruleno==392);
- /* (393) tridxby ::= */ yytestcase(yyruleno==393);
- /* (394) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==394);
- /* (395) database_kw_opt ::= */ yytestcase(yyruleno==395);
- /* (396) kwcolumn_opt ::= */ yytestcase(yyruleno==396);
- /* (397) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==397);
- /* (398) vtabarglist ::= vtabarg */ yytestcase(yyruleno==398);
- /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==399);
- /* (400) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==400);
- /* (401) anylist ::= */ yytestcase(yyruleno==401);
- /* (402) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==402);
- /* (403) anylist ::= anylist ANY */ yytestcase(yyruleno==403);
- /* (404) with ::= */ yytestcase(yyruleno==404);
+ /* (344) input ::= cmdlist */ yytestcase(yyruleno==344);
+ /* (345) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==345);
+ /* (346) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=346);
+ /* (347) ecmd ::= SEMI */ yytestcase(yyruleno==347);
+ /* (348) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==348);
+ /* (349) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=349);
+ /* (350) trans_opt ::= */ yytestcase(yyruleno==350);
+ /* (351) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==351);
+ /* (352) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==352);
+ /* (353) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==353);
+ /* (354) savepoint_opt ::= */ yytestcase(yyruleno==354);
+ /* (355) cmd ::= create_table create_table_args */ yytestcase(yyruleno==355);
+ /* (356) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=356);
+ /* (357) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==357);
+ /* (358) columnlist ::= columnname carglist */ yytestcase(yyruleno==358);
+ /* (359) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==359);
+ /* (360) nm ::= STRING */ yytestcase(yyruleno==360);
+ /* (361) typetoken ::= typename */ yytestcase(yyruleno==361);
+ /* (362) typename ::= ID|STRING */ yytestcase(yyruleno==362);
+ /* (363) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=363);
+ /* (364) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=364);
+ /* (365) carglist ::= carglist ccons */ yytestcase(yyruleno==365);
+ /* (366) carglist ::= */ yytestcase(yyruleno==366);
+ /* (367) ccons ::= NULL onconf */ yytestcase(yyruleno==367);
+ /* (368) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==368);
+ /* (369) ccons ::= AS generated */ yytestcase(yyruleno==369);
+ /* (370) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==370);
+ /* (371) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==371);
+ /* (372) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=372);
+ /* (373) tconscomma ::= */ yytestcase(yyruleno==373);
+ /* (374) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=374);
+ /* (375) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=375);
+ /* (376) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=376);
+ /* (377) oneselect ::= values */ yytestcase(yyruleno==377);
+ /* (378) sclp ::= selcollist COMMA */ yytestcase(yyruleno==378);
+ /* (379) as ::= ID|STRING */ yytestcase(yyruleno==379);
+ /* (380) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=380);
+ /* (381) returning ::= */ yytestcase(yyruleno==381);
+ /* (382) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=382);
+ /* (383) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==383);
+ /* (384) case_operand ::= expr */ yytestcase(yyruleno==384);
+ /* (385) exprlist ::= nexprlist */ yytestcase(yyruleno==385);
+ /* (386) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=386);
+ /* (387) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=387);
+ /* (388) nmnum ::= ON */ yytestcase(yyruleno==388);
+ /* (389) nmnum ::= DELETE */ yytestcase(yyruleno==389);
+ /* (390) nmnum ::= DEFAULT */ yytestcase(yyruleno==390);
+ /* (391) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==391);
+ /* (392) foreach_clause ::= */ yytestcase(yyruleno==392);
+ /* (393) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==393);
+ /* (394) trnm ::= nm */ yytestcase(yyruleno==394);
+ /* (395) tridxby ::= */ yytestcase(yyruleno==395);
+ /* (396) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==396);
+ /* (397) database_kw_opt ::= */ yytestcase(yyruleno==397);
+ /* (398) kwcolumn_opt ::= */ yytestcase(yyruleno==398);
+ /* (399) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==399);
+ /* (400) vtabarglist ::= vtabarg */ yytestcase(yyruleno==400);
+ /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==401);
+ /* (402) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==402);
+ /* (403) anylist ::= */ yytestcase(yyruleno==403);
+ /* (404) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==404);
+ /* (405) anylist ::= anylist ANY */ yytestcase(yyruleno==405);
+ /* (406) with ::= */ yytestcase(yyruleno==406);
+ /* (407) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=407);
+ /* (408) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=408);
break;
/********** End reduce actions ************************************************/
};
@@ -174184,19 +183103,12 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Parser(
(int)(yypParser->yytos - yypParser->yystack));
}
#endif
-#if YYSTACKDEPTH>0
if( yypParser->yytos>=yypParser->yystackEnd ){
- yyStackOverflow(yypParser);
- break;
- }
-#else
- if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
if( yyGrowStack(yypParser) ){
yyStackOverflow(yypParser);
break;
}
}
-#endif
}
yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor sqlcipher_sqlite3ParserCTX_PARAM);
}else if( yyact <= YY_MAX_SHIFTREDUCE ){
@@ -174573,7 +183485,7 @@ static const unsigned char aKWHash[127] = {
/* aKWNext[] forms the hash collision chain. If aKWHash[i]==0
** then the i-th keyword has no more hash collisions. Otherwise,
** the next keyword with the same hash is aKWHash[i]-1. */
-static const unsigned char aKWNext[147] = {
+static const unsigned char aKWNext[148] = {0,
0, 0, 0, 0, 4, 0, 43, 0, 0, 106, 114, 0, 0,
0, 2, 0, 0, 143, 0, 0, 0, 13, 0, 0, 0, 0,
141, 0, 0, 119, 52, 0, 0, 137, 12, 0, 0, 62, 0,
@@ -174588,7 +183500,7 @@ static const unsigned char aKWNext[147] = {
102, 0, 0, 87,
};
/* aKWLen[i] is the length (in bytes) of the i-th keyword */
-static const unsigned char aKWLen[147] = {
+static const unsigned char aKWLen[148] = {0,
7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6,
7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7,
6, 9, 4, 2, 6, 5, 9, 9, 4, 7, 3, 2, 4,
@@ -174604,7 +183516,7 @@ static const unsigned char aKWLen[147] = {
};
/* aKWOffset[i] is the index into zKWText[] of the start of
** the text for the i-th keyword. */
-static const unsigned short int aKWOffset[147] = {
+static const unsigned short int aKWOffset[148] = {0,
0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33,
36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81,
86, 90, 90, 94, 99, 101, 105, 111, 119, 123, 123, 123, 126,
@@ -174619,7 +183531,7 @@ static const unsigned short int aKWOffset[147] = {
648, 650, 655, 659,
};
/* aKWCode[i] is the parser symbol code for the i-th keyword */
-static const unsigned char aKWCode[147] = {
+static const unsigned char aKWCode[148] = {0,
TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE,
TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN,
TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD,
@@ -174786,185 +183698,185 @@ static const unsigned char aKWCode[147] = {
static int keywordCode(const char *z, int n, int *pType){
int i, j;
const char *zKW;
- if( n>=2 ){
- i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127;
- for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){
- if( aKWLen[i]!=n ) continue;
- zKW = &zKWText[aKWOffset[i]];
+ assert( n>=2 );
+ i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127;
+ for(i=(int)aKWHash[i]; i>0; i=aKWNext[i]){
+ if( aKWLen[i]!=n ) continue;
+ zKW = &zKWText[aKWOffset[i]];
#ifdef SQLITE_ASCII
- if( (z[0]&~0x20)!=zKW[0] ) continue;
- if( (z[1]&~0x20)!=zKW[1] ) continue;
- j = 2;
- while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
+ if( (z[0]&~0x20)!=zKW[0] ) continue;
+ if( (z[1]&~0x20)!=zKW[1] ) continue;
+ j = 2;
+ while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
#endif
#ifdef SQLITE_EBCDIC
- if( toupper(z[0])!=zKW[0] ) continue;
- if( toupper(z[1])!=zKW[1] ) continue;
- j = 2;
- while( j<n && toupper(z[j])==zKW[j] ){ j++; }
-#endif
- if( j<n ) continue;
- testcase( i==0 ); /* REINDEX */
- testcase( i==1 ); /* INDEXED */
- testcase( i==2 ); /* INDEX */
- testcase( i==3 ); /* DESC */
- testcase( i==4 ); /* ESCAPE */
- testcase( i==5 ); /* EACH */
- testcase( i==6 ); /* CHECK */
- testcase( i==7 ); /* KEY */
- testcase( i==8 ); /* BEFORE */
- testcase( i==9 ); /* FOREIGN */
- testcase( i==10 ); /* FOR */
- testcase( i==11 ); /* IGNORE */
- testcase( i==12 ); /* REGEXP */
- testcase( i==13 ); /* EXPLAIN */
- testcase( i==14 ); /* INSTEAD */
- testcase( i==15 ); /* ADD */
- testcase( i==16 ); /* DATABASE */
- testcase( i==17 ); /* AS */
- testcase( i==18 ); /* SELECT */
- testcase( i==19 ); /* TABLE */
- testcase( i==20 ); /* LEFT */
- testcase( i==21 ); /* THEN */
- testcase( i==22 ); /* END */
- testcase( i==23 ); /* DEFERRABLE */
- testcase( i==24 ); /* ELSE */
- testcase( i==25 ); /* EXCLUDE */
- testcase( i==26 ); /* DELETE */
- testcase( i==27 ); /* TEMPORARY */
- testcase( i==28 ); /* TEMP */
- testcase( i==29 ); /* OR */
- testcase( i==30 ); /* ISNULL */
- testcase( i==31 ); /* NULLS */
- testcase( i==32 ); /* SAVEPOINT */
- testcase( i==33 ); /* INTERSECT */
- testcase( i==34 ); /* TIES */
- testcase( i==35 ); /* NOTNULL */
- testcase( i==36 ); /* NOT */
- testcase( i==37 ); /* NO */
- testcase( i==38 ); /* NULL */
- testcase( i==39 ); /* LIKE */
- testcase( i==40 ); /* EXCEPT */
- testcase( i==41 ); /* TRANSACTION */
- testcase( i==42 ); /* ACTION */
- testcase( i==43 ); /* ON */
- testcase( i==44 ); /* NATURAL */
- testcase( i==45 ); /* ALTER */
- testcase( i==46 ); /* RAISE */
- testcase( i==47 ); /* EXCLUSIVE */
- testcase( i==48 ); /* EXISTS */
- testcase( i==49 ); /* CONSTRAINT */
- testcase( i==50 ); /* INTO */
- testcase( i==51 ); /* OFFSET */
- testcase( i==52 ); /* OF */
- testcase( i==53 ); /* SET */
- testcase( i==54 ); /* TRIGGER */
- testcase( i==55 ); /* RANGE */
- testcase( i==56 ); /* GENERATED */
- testcase( i==57 ); /* DETACH */
- testcase( i==58 ); /* HAVING */
- testcase( i==59 ); /* GLOB */
- testcase( i==60 ); /* BEGIN */
- testcase( i==61 ); /* INNER */
- testcase( i==62 ); /* REFERENCES */
- testcase( i==63 ); /* UNIQUE */
- testcase( i==64 ); /* QUERY */
- testcase( i==65 ); /* WITHOUT */
- testcase( i==66 ); /* WITH */
- testcase( i==67 ); /* OUTER */
- testcase( i==68 ); /* RELEASE */
- testcase( i==69 ); /* ATTACH */
- testcase( i==70 ); /* BETWEEN */
- testcase( i==71 ); /* NOTHING */
- testcase( i==72 ); /* GROUPS */
- testcase( i==73 ); /* GROUP */
- testcase( i==74 ); /* CASCADE */
- testcase( i==75 ); /* ASC */
- testcase( i==76 ); /* DEFAULT */
- testcase( i==77 ); /* CASE */
- testcase( i==78 ); /* COLLATE */
- testcase( i==79 ); /* CREATE */
- testcase( i==80 ); /* CURRENT_DATE */
- testcase( i==81 ); /* IMMEDIATE */
- testcase( i==82 ); /* JOIN */
- testcase( i==83 ); /* INSERT */
- testcase( i==84 ); /* MATCH */
- testcase( i==85 ); /* PLAN */
- testcase( i==86 ); /* ANALYZE */
- testcase( i==87 ); /* PRAGMA */
- testcase( i==88 ); /* MATERIALIZED */
- testcase( i==89 ); /* DEFERRED */
- testcase( i==90 ); /* DISTINCT */
- testcase( i==91 ); /* IS */
- testcase( i==92 ); /* UPDATE */
- testcase( i==93 ); /* VALUES */
- testcase( i==94 ); /* VIRTUAL */
- testcase( i==95 ); /* ALWAYS */
- testcase( i==96 ); /* WHEN */
- testcase( i==97 ); /* WHERE */
- testcase( i==98 ); /* RECURSIVE */
- testcase( i==99 ); /* ABORT */
- testcase( i==100 ); /* AFTER */
- testcase( i==101 ); /* RENAME */
- testcase( i==102 ); /* AND */
- testcase( i==103 ); /* DROP */
- testcase( i==104 ); /* PARTITION */
- testcase( i==105 ); /* AUTOINCREMENT */
- testcase( i==106 ); /* TO */
- testcase( i==107 ); /* IN */
- testcase( i==108 ); /* CAST */
- testcase( i==109 ); /* COLUMN */
- testcase( i==110 ); /* COMMIT */
- testcase( i==111 ); /* CONFLICT */
- testcase( i==112 ); /* CROSS */
- testcase( i==113 ); /* CURRENT_TIMESTAMP */
- testcase( i==114 ); /* CURRENT_TIME */
- testcase( i==115 ); /* CURRENT */
- testcase( i==116 ); /* PRECEDING */
- testcase( i==117 ); /* FAIL */
- testcase( i==118 ); /* LAST */
- testcase( i==119 ); /* FILTER */
- testcase( i==120 ); /* REPLACE */
- testcase( i==121 ); /* FIRST */
- testcase( i==122 ); /* FOLLOWING */
- testcase( i==123 ); /* FROM */
- testcase( i==124 ); /* FULL */
- testcase( i==125 ); /* LIMIT */
- testcase( i==126 ); /* IF */
- testcase( i==127 ); /* ORDER */
- testcase( i==128 ); /* RESTRICT */
- testcase( i==129 ); /* OTHERS */
- testcase( i==130 ); /* OVER */
- testcase( i==131 ); /* RETURNING */
- testcase( i==132 ); /* RIGHT */
- testcase( i==133 ); /* ROLLBACK */
- testcase( i==134 ); /* ROWS */
- testcase( i==135 ); /* ROW */
- testcase( i==136 ); /* UNBOUNDED */
- testcase( i==137 ); /* UNION */
- testcase( i==138 ); /* USING */
- testcase( i==139 ); /* VACUUM */
- testcase( i==140 ); /* VIEW */
- testcase( i==141 ); /* WINDOW */
- testcase( i==142 ); /* DO */
- testcase( i==143 ); /* BY */
- testcase( i==144 ); /* INITIALLY */
- testcase( i==145 ); /* ALL */
- testcase( i==146 ); /* PRIMARY */
- *pType = aKWCode[i];
- break;
- }
+ if( toupper(z[0])!=zKW[0] ) continue;
+ if( toupper(z[1])!=zKW[1] ) continue;
+ j = 2;
+ while( j<n && toupper(z[j])==zKW[j] ){ j++; }
+#endif
+ if( j<n ) continue;
+ testcase( i==1 ); /* REINDEX */
+ testcase( i==2 ); /* INDEXED */
+ testcase( i==3 ); /* INDEX */
+ testcase( i==4 ); /* DESC */
+ testcase( i==5 ); /* ESCAPE */
+ testcase( i==6 ); /* EACH */
+ testcase( i==7 ); /* CHECK */
+ testcase( i==8 ); /* KEY */
+ testcase( i==9 ); /* BEFORE */
+ testcase( i==10 ); /* FOREIGN */
+ testcase( i==11 ); /* FOR */
+ testcase( i==12 ); /* IGNORE */
+ testcase( i==13 ); /* REGEXP */
+ testcase( i==14 ); /* EXPLAIN */
+ testcase( i==15 ); /* INSTEAD */
+ testcase( i==16 ); /* ADD */
+ testcase( i==17 ); /* DATABASE */
+ testcase( i==18 ); /* AS */
+ testcase( i==19 ); /* SELECT */
+ testcase( i==20 ); /* TABLE */
+ testcase( i==21 ); /* LEFT */
+ testcase( i==22 ); /* THEN */
+ testcase( i==23 ); /* END */
+ testcase( i==24 ); /* DEFERRABLE */
+ testcase( i==25 ); /* ELSE */
+ testcase( i==26 ); /* EXCLUDE */
+ testcase( i==27 ); /* DELETE */
+ testcase( i==28 ); /* TEMPORARY */
+ testcase( i==29 ); /* TEMP */
+ testcase( i==30 ); /* OR */
+ testcase( i==31 ); /* ISNULL */
+ testcase( i==32 ); /* NULLS */
+ testcase( i==33 ); /* SAVEPOINT */
+ testcase( i==34 ); /* INTERSECT */
+ testcase( i==35 ); /* TIES */
+ testcase( i==36 ); /* NOTNULL */
+ testcase( i==37 ); /* NOT */
+ testcase( i==38 ); /* NO */
+ testcase( i==39 ); /* NULL */
+ testcase( i==40 ); /* LIKE */
+ testcase( i==41 ); /* EXCEPT */
+ testcase( i==42 ); /* TRANSACTION */
+ testcase( i==43 ); /* ACTION */
+ testcase( i==44 ); /* ON */
+ testcase( i==45 ); /* NATURAL */
+ testcase( i==46 ); /* ALTER */
+ testcase( i==47 ); /* RAISE */
+ testcase( i==48 ); /* EXCLUSIVE */
+ testcase( i==49 ); /* EXISTS */
+ testcase( i==50 ); /* CONSTRAINT */
+ testcase( i==51 ); /* INTO */
+ testcase( i==52 ); /* OFFSET */
+ testcase( i==53 ); /* OF */
+ testcase( i==54 ); /* SET */
+ testcase( i==55 ); /* TRIGGER */
+ testcase( i==56 ); /* RANGE */
+ testcase( i==57 ); /* GENERATED */
+ testcase( i==58 ); /* DETACH */
+ testcase( i==59 ); /* HAVING */
+ testcase( i==60 ); /* GLOB */
+ testcase( i==61 ); /* BEGIN */
+ testcase( i==62 ); /* INNER */
+ testcase( i==63 ); /* REFERENCES */
+ testcase( i==64 ); /* UNIQUE */
+ testcase( i==65 ); /* QUERY */
+ testcase( i==66 ); /* WITHOUT */
+ testcase( i==67 ); /* WITH */
+ testcase( i==68 ); /* OUTER */
+ testcase( i==69 ); /* RELEASE */
+ testcase( i==70 ); /* ATTACH */
+ testcase( i==71 ); /* BETWEEN */
+ testcase( i==72 ); /* NOTHING */
+ testcase( i==73 ); /* GROUPS */
+ testcase( i==74 ); /* GROUP */
+ testcase( i==75 ); /* CASCADE */
+ testcase( i==76 ); /* ASC */
+ testcase( i==77 ); /* DEFAULT */
+ testcase( i==78 ); /* CASE */
+ testcase( i==79 ); /* COLLATE */
+ testcase( i==80 ); /* CREATE */
+ testcase( i==81 ); /* CURRENT_DATE */
+ testcase( i==82 ); /* IMMEDIATE */
+ testcase( i==83 ); /* JOIN */
+ testcase( i==84 ); /* INSERT */
+ testcase( i==85 ); /* MATCH */
+ testcase( i==86 ); /* PLAN */
+ testcase( i==87 ); /* ANALYZE */
+ testcase( i==88 ); /* PRAGMA */
+ testcase( i==89 ); /* MATERIALIZED */
+ testcase( i==90 ); /* DEFERRED */
+ testcase( i==91 ); /* DISTINCT */
+ testcase( i==92 ); /* IS */
+ testcase( i==93 ); /* UPDATE */
+ testcase( i==94 ); /* VALUES */
+ testcase( i==95 ); /* VIRTUAL */
+ testcase( i==96 ); /* ALWAYS */
+ testcase( i==97 ); /* WHEN */
+ testcase( i==98 ); /* WHERE */
+ testcase( i==99 ); /* RECURSIVE */
+ testcase( i==100 ); /* ABORT */
+ testcase( i==101 ); /* AFTER */
+ testcase( i==102 ); /* RENAME */
+ testcase( i==103 ); /* AND */
+ testcase( i==104 ); /* DROP */
+ testcase( i==105 ); /* PARTITION */
+ testcase( i==106 ); /* AUTOINCREMENT */
+ testcase( i==107 ); /* TO */
+ testcase( i==108 ); /* IN */
+ testcase( i==109 ); /* CAST */
+ testcase( i==110 ); /* COLUMN */
+ testcase( i==111 ); /* COMMIT */
+ testcase( i==112 ); /* CONFLICT */
+ testcase( i==113 ); /* CROSS */
+ testcase( i==114 ); /* CURRENT_TIMESTAMP */
+ testcase( i==115 ); /* CURRENT_TIME */
+ testcase( i==116 ); /* CURRENT */
+ testcase( i==117 ); /* PRECEDING */
+ testcase( i==118 ); /* FAIL */
+ testcase( i==119 ); /* LAST */
+ testcase( i==120 ); /* FILTER */
+ testcase( i==121 ); /* REPLACE */
+ testcase( i==122 ); /* FIRST */
+ testcase( i==123 ); /* FOLLOWING */
+ testcase( i==124 ); /* FROM */
+ testcase( i==125 ); /* FULL */
+ testcase( i==126 ); /* LIMIT */
+ testcase( i==127 ); /* IF */
+ testcase( i==128 ); /* ORDER */
+ testcase( i==129 ); /* RESTRICT */
+ testcase( i==130 ); /* OTHERS */
+ testcase( i==131 ); /* OVER */
+ testcase( i==132 ); /* RETURNING */
+ testcase( i==133 ); /* RIGHT */
+ testcase( i==134 ); /* ROLLBACK */
+ testcase( i==135 ); /* ROWS */
+ testcase( i==136 ); /* ROW */
+ testcase( i==137 ); /* UNBOUNDED */
+ testcase( i==138 ); /* UNION */
+ testcase( i==139 ); /* USING */
+ testcase( i==140 ); /* VACUUM */
+ testcase( i==141 ); /* VIEW */
+ testcase( i==142 ); /* WINDOW */
+ testcase( i==143 ); /* DO */
+ testcase( i==144 ); /* BY */
+ testcase( i==145 ); /* INITIALLY */
+ testcase( i==146 ); /* ALL */
+ testcase( i==147 ); /* PRIMARY */
+ *pType = aKWCode[i];
+ break;
}
return n;
}
SQLITE_PRIVATE int sqlcipher_sqlite3KeywordCode(const unsigned char *z, int n){
int id = TK_ID;
- keywordCode((char*)z, n, &id);
+ if( n>=2 ) keywordCode((char*)z, n, &id);
return id;
}
#define SQLITE_N_KEYWORD 147
SQLITE_API int sqlcipher_sqlite3_keyword_name(int i,const char **pzName,int *pnName){
if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR;
+ i++;
*pzName = zKWText + aKWOffset[i];
*pnName = aKWLen[i];
return SQLITE_OK;
@@ -175263,31 +184175,62 @@ SQLITE_PRIVATE int sqlcipher_sqlite3GetToken(const unsigned char *z, int *tokenT
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
- testcase( z[0]=='9' );
+ testcase( z[0]=='9' ); testcase( z[0]=='.' );
*tokenType = TK_INTEGER;
#ifndef SQLITE_OMIT_HEX_INTEGER
if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlcipher_sqlite3Isxdigit(z[2]) ){
- for(i=3; sqlcipher_sqlite3Isxdigit(z[i]); i++){}
- return i;
- }
+ for(i=3; 1; i++){
+ if( sqlcipher_sqlite3Isxdigit(z[i])==0 ){
+ if( z[i]==SQLITE_DIGIT_SEPARATOR ){
+ *tokenType = TK_QNUMBER;
+ }else{
+ break;
+ }
+ }
+ }
+ }else
#endif
- for(i=0; sqlcipher_sqlite3Isdigit(z[i]); i++){}
+ {
+ for(i=0; 1; i++){
+ if( sqlcipher_sqlite3Isdigit(z[i])==0 ){
+ if( z[i]==SQLITE_DIGIT_SEPARATOR ){
+ *tokenType = TK_QNUMBER;
+ }else{
+ break;
+ }
+ }
+ }
#ifndef SQLITE_OMIT_FLOATING_POINT
- if( z[i]=='.' ){
- i++;
- while( sqlcipher_sqlite3Isdigit(z[i]) ){ i++; }
- *tokenType = TK_FLOAT;
- }
- if( (z[i]=='e' || z[i]=='E') &&
- ( sqlcipher_sqlite3Isdigit(z[i+1])
- || ((z[i+1]=='+' || z[i+1]=='-') && sqlcipher_sqlite3Isdigit(z[i+2]))
- )
- ){
- i += 2;
- while( sqlcipher_sqlite3Isdigit(z[i]) ){ i++; }
- *tokenType = TK_FLOAT;
- }
+ if( z[i]=='.' ){
+ if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
+ for(i++; 1; i++){
+ if( sqlcipher_sqlite3Isdigit(z[i])==0 ){
+ if( z[i]==SQLITE_DIGIT_SEPARATOR ){
+ *tokenType = TK_QNUMBER;
+ }else{
+ break;
+ }
+ }
+ }
+ }
+ if( (z[i]=='e' || z[i]=='E') &&
+ ( sqlcipher_sqlite3Isdigit(z[i+1])
+ || ((z[i+1]=='+' || z[i+1]=='-') && sqlcipher_sqlite3Isdigit(z[i+2]))
+ )
+ ){
+ if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
+ for(i+=2; 1; i++){
+ if( sqlcipher_sqlite3Isdigit(z[i])==0 ){
+ if( z[i]==SQLITE_DIGIT_SEPARATOR ){
+ *tokenType = TK_QNUMBER;
+ }else{
+ break;
+ }
+ }
+ }
+ }
#endif
+ }
while( IdChar(z[i]) ){
*tokenType = TK_ILLEGAL;
i++;
@@ -175335,7 +184278,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3GetToken(const unsigned char *z, int *tokenT
return i;
}
case CC_KYWD0: {
- for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
+ if( aiClass[z[1]]>CC_KYWD ){ i = 1; break; }
+ for(i=2; aiClass[z[i]]<=CC_KYWD; i++){}
if( IdChar(z[i]) ){
/* This token started out using characters that can appear in keywords,
** but z[i] is a character not allowed within keywords, so this must
@@ -175451,10 +184395,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3RunParser(Parse *pParse, const char *zSql){
if( tokenType>=TK_WINDOW ){
assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
|| tokenType==TK_ILLEGAL || tokenType==TK_WINDOW
+ || tokenType==TK_QNUMBER
);
#else
if( tokenType>=TK_SPACE ){
- assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
+ assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL
+ || tokenType==TK_QNUMBER
+ );
#endif /* SQLITE_OMIT_WINDOWFUNC */
if( AtomicLoad(&db->u1.isInterrupted) ){
pParse->rc = SQLITE_INTERRUPT;
@@ -175487,7 +184434,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3RunParser(Parse *pParse, const char *zSql){
assert( n==6 );
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
#endif /* SQLITE_OMIT_WINDOWFUNC */
- }else{
+ }else if( tokenType!=TK_QNUMBER ){
Token x;
x.z = zSql;
x.n = n;
@@ -175541,7 +184488,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3RunParser(Parse *pParse, const char *zSql){
if( pParse->pNewTrigger && !IN_RENAME_OBJECT ){
sqlcipher_sqlite3DeleteTrigger(db, pParse->pNewTrigger);
}
- if( pParse->pVList ) sqlcipher_sqlite3DbFreeNN(db, pParse->pVList);
+ if( pParse->pVList ) sqlcipher_sqlite3DbNNFreeNN(db, pParse->pVList);
db->pParse = pParentParse;
assert( nErr==0 || pParse->rc!=SQLITE_OK );
return nErr;
@@ -176114,30 +185061,20 @@ static int sqlcipher_sqlite3TestExtInit(sqlcipher_sqlite3 *db){
** Forward declarations of external module initializer functions
** for modules that need them.
*/
-#ifdef SQLITE_ENABLE_FTS1
-SQLITE_PRIVATE int sqlcipher_sqlite3Fts1Init(sqlcipher_sqlite3*);
-#endif
-#ifdef SQLITE_ENABLE_FTS2
-SQLITE_PRIVATE int sqlcipher_sqlite3Fts2Init(sqlcipher_sqlite3*);
-#endif
#ifdef SQLITE_ENABLE_FTS5
SQLITE_PRIVATE int sqlcipher_sqlite3Fts5Init(sqlcipher_sqlite3*);
#endif
#ifdef SQLITE_ENABLE_STMTVTAB
SQLITE_PRIVATE int sqlcipher_sqlite3StmtVtabInit(sqlcipher_sqlite3*);
#endif
-
+#ifdef SQLITE_EXTRA_AUTOEXT
+int SQLITE_EXTRA_AUTOEXT(sqlcipher_sqlite3*);
+#endif
/*
** An array of pointers to extension initializer functions for
** built-in extensions.
*/
static int (*const sqlcipher_sqlite3BuiltinExtensions[])(sqlcipher_sqlite3*) = {
-#ifdef SQLITE_ENABLE_FTS1
- sqlcipher_sqlite3Fts1Init,
-#endif
-#ifdef SQLITE_ENABLE_FTS2
- sqlcipher_sqlite3Fts2Init,
-#endif
#ifdef SQLITE_ENABLE_FTS3
sqlcipher_sqlite3Fts3Init,
#endif
@@ -176166,6 +185103,9 @@ static int (*const sqlcipher_sqlite3BuiltinExtensions[])(sqlcipher_sqlite3*) = {
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
sqlcipher_sqlite3VdbeBytecodeVtabInit,
#endif
+#ifdef SQLITE_EXTRA_AUTOEXT
+ SQLITE_EXTRA_AUTOEXT,
+#endif
};
#ifndef SQLITE_AMALGAMATION
@@ -176240,6 +185180,32 @@ SQLITE_API char *sqlcipher_sqlite3_temp_directory = 0;
SQLITE_API char *sqlcipher_sqlite3_data_directory = 0;
/*
+** Determine whether or not high-precision (long double) floating point
+** math works correctly on CPU currently running.
+*/
+static SQLITE_NOINLINE int hasHighPrecisionDouble(int rc){
+ if( sizeof(LONGDOUBLE_TYPE)<=8 ){
+ /* If the size of "long double" is not more than 8, then
+ ** high-precision math is not possible. */
+ return 0;
+ }else{
+ /* Just because sizeof(long double)>8 does not mean that the underlying
+ ** hardware actually supports high-precision floating point. For example,
+ ** clearing the 0x100 bit in the floating-point control word on Intel
+ ** processors will make long double work like double, even though long
+ ** double takes up more space. The only way to determine if long double
+ ** actually works is to run an experiment. */
+ LONGDOUBLE_TYPE a, b, c;
+ rc++;
+ a = 1.0+rc*0.1;
+ b = 1.0e+18+rc*25.0;
+ c = a+b;
+ return b!=c;
+ }
+}
+
+
+/*
** Initialize SQLite.
**
** This routine must be called to initialize the memory allocation,
@@ -176434,6 +185400,12 @@ SQLITE_API int sqlcipher_sqlite3_initialize(void){
}
#endif
+ /* Experimentally determine if high-precision floating point is
+ ** available. */
+#ifndef SQLITE_OMIT_WSD
+ sqlcipher_sqlite3Config.bUseLongDouble = hasHighPrecisionDouble(rc);
+#endif
+
return rc;
}
@@ -176503,9 +185475,21 @@ SQLITE_API int sqlcipher_sqlite3_config(int op, ...){
va_list ap;
int rc = SQLITE_OK;
- /* sqlcipher_sqlite3_config() shall return SQLITE_MISUSE if it is invoked while
- ** the SQLite library is in use. */
- if( sqlcipher_sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT;
+ /* sqlcipher_sqlite3_config() normally returns SQLITE_MISUSE if it is invoked while
+ ** the SQLite library is in use. Except, a few selected opcodes
+ ** are allowed.
+ */
+ if( sqlcipher_sqlite3GlobalConfig.isInit ){
+ static const u64 mAnytimeConfigOption = 0
+ | MASKBIT64( SQLITE_CONFIG_LOG )
+ | MASKBIT64( SQLITE_CONFIG_PCACHE_HDRSZ )
+ ;
+ if( op<0 || op>63 || (MASKBIT64(op) & mAnytimeConfigOption)==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+ testcase( op==SQLITE_CONFIG_LOG );
+ testcase( op==SQLITE_CONFIG_PCACHE_HDRSZ );
+ }
va_start(ap, op);
switch( op ){
@@ -176574,6 +185558,7 @@ SQLITE_API int sqlcipher_sqlite3_config(int op, ...){
break;
}
case SQLITE_CONFIG_MEMSTATUS: {
+ assert( !sqlcipher_sqlite3GlobalConfig.isInit ); /* Cannot change at runtime */
/* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes
** single argument of type int, interpreted as a boolean, which enables
** or disables the collection of memory allocation statistics. */
@@ -176697,8 +185682,10 @@ SQLITE_API int sqlcipher_sqlite3_config(int op, ...){
** sqlcipher_sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*));
*/
typedef void(*LOGFUNC_t)(void*,int,const char*);
- sqlcipher_sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t);
- sqlcipher_sqlite3GlobalConfig.pLogArg = va_arg(ap, void*);
+ LOGFUNC_t xLog = va_arg(ap, LOGFUNC_t);
+ void *pLogArg = va_arg(ap, void*);
+ AtomicStore(&sqlcipher_sqlite3GlobalConfig.xLog, xLog);
+ AtomicStore(&sqlcipher_sqlite3GlobalConfig.pLogArg, pLogArg);
break;
}
@@ -176712,7 +185699,8 @@ SQLITE_API int sqlcipher_sqlite3_config(int op, ...){
** argument of type int. If non-zero, then URI handling is globally
** enabled. If the parameter is zero, then URI handling is globally
** disabled. */
- sqlcipher_sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
+ int bOpenUri = va_arg(ap, int);
+ AtomicStore(&sqlcipher_sqlite3GlobalConfig.bOpenUri, bOpenUri);
break;
}
@@ -176797,6 +185785,18 @@ SQLITE_API int sqlcipher_sqlite3_config(int op, ...){
}
#endif /* SQLITE_OMIT_DESERIALIZE */
+ case SQLITE_CONFIG_ROWID_IN_VIEW: {
+ int *pVal = va_arg(ap,int*);
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ if( 0==*pVal ) sqlcipher_sqlite3GlobalConfig.mNoVisibleRowid = TF_NoVisibleRowid;
+ if( 1==*pVal ) sqlcipher_sqlite3GlobalConfig.mNoVisibleRowid = 0;
+ *pVal = (sqlcipher_sqlite3GlobalConfig.mNoVisibleRowid==0);
+#else
+ *pVal = 0;
+#endif
+ break;
+ }
+
default: {
rc = SQLITE_ERROR;
break;
@@ -176897,18 +185897,19 @@ static int setupLookaside(sqlcipher_sqlite3 *db, void *pBuf, int sz, int cnt){
db->lookaside.bMalloced = pBuf==0 ?1:0;
db->lookaside.nSlot = nBig+nSm;
}else{
- db->lookaside.pStart = db;
+ db->lookaside.pStart = 0;
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
db->lookaside.pSmallInit = 0;
db->lookaside.pSmallFree = 0;
- db->lookaside.pMiddle = db;
+ db->lookaside.pMiddle = 0;
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
- db->lookaside.pEnd = db;
+ db->lookaside.pEnd = 0;
db->lookaside.bDisable = 1;
db->lookaside.sz = 0;
db->lookaside.bMalloced = 0;
db->lookaside.nSlot = 0;
}
+ db->lookaside.pTrueEnd = db->lookaside.pEnd;
assert( sqlcipher_sqlite3LookasideUsed(db,0)==0 );
#endif /* SQLITE_OMIT_LOOKASIDE */
return SQLITE_OK;
@@ -176987,6 +185988,11 @@ SQLITE_API int sqlcipher_sqlite3_db_cacheflush(sqlcipher_sqlite3 *db){
SQLITE_API int sqlcipher_sqlite3_db_config(sqlcipher_sqlite3 *db, int op, ...){
va_list ap;
int rc;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlcipher_sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
+ sqlcipher_sqlite3_mutex_enter(db->mutex);
va_start(ap, op);
switch( op ){
case SQLITE_DBCONFIG_MAINDBNAME: {
@@ -177025,6 +186031,8 @@ SQLITE_API int sqlcipher_sqlite3_db_config(sqlcipher_sqlite3 *db, int op, ...){
{ SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML },
{ SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, SQLITE_LegacyFileFmt },
{ SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema },
+ { SQLITE_DBCONFIG_STMT_SCANSTATUS, SQLITE_StmtScanStatus },
+ { SQLITE_DBCONFIG_REVERSE_SCANORDER, SQLITE_ReverseOrder },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -177052,6 +186060,7 @@ SQLITE_API int sqlcipher_sqlite3_db_config(sqlcipher_sqlite3 *db, int op, ...){
}
}
va_end(ap);
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -177312,6 +186321,14 @@ static int sqlcipher_sqlite3Close(sqlcipher_sqlite3 *db, int forceZombie){
}
#endif
+ while( db->pDbData ){
+ DbClientData *p = db->pDbData;
+ db->pDbData = p->pNext;
+ assert( p->pData!=0 );
+ if( p->xDestructor ) p->xDestructor(p->pData);
+ sqlcipher_sqlite3_free(p);
+ }
+
/* Convert the connection into a zombie and then close it.
*/
db->eOpenState = SQLITE_STATE_ZOMBIE;
@@ -177636,6 +186653,7 @@ SQLITE_PRIVATE const char *sqlcipher_sqlite3ErrName(int rc){
case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break;
case SQLITE_NOTICE_RECOVER_ROLLBACK:
zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break;
+ case SQLITE_NOTICE_RBU: zName = "SQLITE_NOTICE_RBU"; break;
case SQLITE_WARNING: zName = "SQLITE_WARNING"; break;
case SQLITE_WARNING_AUTOINDEX: zName = "SQLITE_WARNING_AUTOINDEX"; break;
case SQLITE_DONE: zName = "SQLITE_DONE"; break;
@@ -177728,9 +186746,9 @@ static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
){
-#if SQLITE_OS_WIN || HAVE_USLEEP
+#if SQLITE_OS_WIN || !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP
/* This case is for systems that have support for sleeping for fractions of
- ** a second. Examples: All windows systems, unix systems with usleep() */
+ ** a second. Examples: All windows systems, unix systems with nanosleep() */
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
@@ -177865,7 +186883,9 @@ SQLITE_API int sqlcipher_sqlite3_busy_timeout(sqlcipher_sqlite3 *db, int ms){
*/
SQLITE_API void sqlcipher_sqlite3_interrupt(sqlcipher_sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlcipher_sqlite3SafetyCheckOk(db) && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE) ){
+ if( !sqlcipher_sqlite3SafetyCheckOk(db)
+ && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE)
+ ){
(void)SQLITE_MISUSE_BKPT;
return;
}
@@ -177873,6 +186893,21 @@ SQLITE_API void sqlcipher_sqlite3_interrupt(sqlcipher_sqlite3 *db){
AtomicStore(&db->u1.isInterrupted, 1);
}
+/*
+** Return true or false depending on whether or not an interrupt is
+** pending on connection db.
+*/
+SQLITE_API int sqlcipher_sqlite3_is_interrupted(sqlcipher_sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlcipher_sqlite3SafetyCheckOk(db)
+ && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE)
+ ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+ return AtomicLoad(&db->u1.isInterrupted)!=0;
+}
/*
** This function is exactly the same as sqlcipher_sqlite3_create_function(), except
@@ -177911,13 +186946,13 @@ SQLITE_PRIVATE int sqlcipher_sqlite3CreateFunc(
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
- SQLITE_SUBTYPE|SQLITE_INNOCUOUS);
+ SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE);
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
/* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
** the meaning is inverted. So flip the bit. */
assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS );
- extraFlags ^= SQLITE_FUNC_UNSAFE;
+ extraFlags ^= SQLITE_FUNC_UNSAFE; /* tag-20230109-1 */
#ifndef SQLITE_OMIT_UTF16
@@ -177935,11 +186970,11 @@ SQLITE_PRIVATE int sqlcipher_sqlite3CreateFunc(
case SQLITE_ANY: {
int rc;
rc = sqlcipher_sqlite3CreateFunc(db, zFunctionName, nArg,
- (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE,
+ (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE, /* tag-20230109-1 */
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
if( rc==SQLITE_OK ){
rc = sqlcipher_sqlite3CreateFunc(db, zFunctionName, nArg,
- (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE,
+ (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE, /* tag-20230109-1*/
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
}
if( rc!=SQLITE_OK ){
@@ -178188,7 +187223,7 @@ SQLITE_API int sqlcipher_sqlite3_overload_function(
rc = sqlcipher_sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0;
sqlcipher_sqlite3_mutex_leave(db->mutex);
if( rc ) return SQLITE_OK;
- zCopy = sqlcipher_sqlite3_mprintf(zName);
+ zCopy = sqlcipher_sqlite3_mprintf("%s", zName);
if( zCopy==0 ) return SQLITE_NOMEM;
return sqlcipher_sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8,
zCopy, sqlcipher_sqlite3InvalidFunction, 0, 0, sqlcipher_sqlite3_free);
@@ -178368,6 +187403,12 @@ SQLITE_API void *sqlcipher_sqlite3_preupdate_hook(
void *pArg /* First callback argument */
){
void *pRet;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 ){
+ return 0;
+ }
+#endif
sqlcipher_sqlite3_mutex_enter(db->mutex);
pRet = db->pPreUpdateArg;
db->xPreUpdateCallback = xCallback;
@@ -178514,7 +187555,7 @@ SQLITE_API int sqlcipher_sqlite3_wal_checkpoint_v2(
if( eMode<SQLITE_CHECKPOINT_PASSIVE || eMode>SQLITE_CHECKPOINT_TRUNCATE ){
/* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint
** mode: */
- return SQLITE_MISUSE;
+ return SQLITE_MISUSE_BKPT;
}
sqlcipher_sqlite3_mutex_enter(db->mutex);
@@ -178991,9 +188032,9 @@ SQLITE_PRIVATE int sqlcipher_sqlite3ParseUri(
assert( *pzErrMsg==0 );
- if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */
- || sqlcipher_sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */
- && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
+ if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */
+ || AtomicLoad(&sqlcipher_sqlite3GlobalConfig.bOpenUri)) /* IMP: R-51689-46548 */
+ && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
){
char *zOpt;
int eState; /* Parser state when parsing URI */
@@ -179388,7 +188429,7 @@ static int openDatabase(
** 0 off off
**
** Legacy behavior is 3 (double-quoted string literals are allowed anywhere)
-** and so that is the default. But developers are encouranged to use
+** and so that is the default. But developers are encouraged to use
** -DSQLITE_DQS=0 (best) or -DSQLITE_DQS=1 (second choice) if possible.
*/
#if !defined(SQLITE_DQS)
@@ -179437,6 +188478,9 @@ static int openDatabase(
#if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
| SQLITE_LegacyAlter
#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ | SQLITE_StmtScanStatus
+#endif
;
sqlcipher_sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -179459,6 +188503,19 @@ static int openDatabase(
goto opendb_out;
}
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
+ /* Process magic filenames ":localStorage:" and ":sessionStorage:" */
+ if( zFilename && zFilename[0]==':' ){
+ if( strcmp(zFilename, ":localStorage:")==0 ){
+ zFilename = "file:local?vfs=kvvfs";
+ flags |= SQLITE_OPEN_URI;
+ }else if( strcmp(zFilename, ":sessionStorage:")==0 ){
+ zFilename = "file:session?vfs=kvvfs";
+ flags |= SQLITE_OPEN_URI;
+ }
+ }
+#endif /* SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) */
+
/* Parse the filename/URI argument
**
** Only allow sensible combinations of bits in the flags argument.
@@ -179489,6 +188546,12 @@ static int openDatabase(
sqlcipher_sqlite3_free(zErrMsg);
goto opendb_out;
}
+ assert( db->pVfs!=0 );
+#if SQLITE_OS_KV || defined(SQLITE_OS_KV_OPTIONAL)
+ if( sqlcipher_sqlite3_stricmp(db->pVfs->zName, "kvvfs")==0 ){
+ db->temp_store = 2;
+ }
+#endif
/* Open the backend database driver */
rc = sqlcipher_sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,
@@ -179546,13 +188609,6 @@ static int openDatabase(
}
}
-#ifdef SQLCIPHER_EXT
- if( !db->mallocFailed && rc==SQLITE_OK ){
- extern int sqlcipherVtabInit(sqlcipher_sqlite3 *);
- rc = sqlcipherVtabInit(db);
- }
-#endif
-
#ifdef SQLITE_ENABLE_INTERNAL_FUNCTIONS
/* Testing use only!!! The -DSQLITE_ENABLE_INTERNAL_FUNCTIONS=1 compile-time
** option gives access to internal functions by default.
@@ -179778,6 +188834,69 @@ SQLITE_API int sqlcipher_sqlite3_collation_needed16(
}
#endif /* SQLITE_OMIT_UTF16 */
+/*
+** Find existing client data.
+*/
+SQLITE_API void *sqlcipher_sqlite3_get_clientdata(sqlcipher_sqlite3 *db, const char *zName){
+ DbClientData *p;
+ sqlcipher_sqlite3_mutex_enter(db->mutex);
+ for(p=db->pDbData; p; p=p->pNext){
+ if( strcmp(p->zName, zName)==0 ){
+ void *pResult = p->pData;
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
+ return pResult;
+ }
+ }
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
+ return 0;
+}
+
+/*
+** Add new client data to a database connection.
+*/
+SQLITE_API int sqlcipher_sqlite3_set_clientdata(
+ sqlcipher_sqlite3 *db, /* Attach client data to this connection */
+ const char *zName, /* Name of the client data */
+ void *pData, /* The client data itself */
+ void (*xDestructor)(void*) /* Destructor */
+){
+ DbClientData *p, **pp;
+ sqlcipher_sqlite3_mutex_enter(db->mutex);
+ pp = &db->pDbData;
+ for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){
+ pp = &p->pNext;
+ }
+ if( p ){
+ assert( p->pData!=0 );
+ if( p->xDestructor ) p->xDestructor(p->pData);
+ if( pData==0 ){
+ *pp = p->pNext;
+ sqlcipher_sqlite3_free(p);
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+ }
+ }else if( pData==0 ){
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+ }else{
+ size_t n = strlen(zName);
+ p = sqlcipher_sqlite3_malloc64( sizeof(DbClientData)+n+1 );
+ if( p==0 ){
+ if( xDestructor ) xDestructor(pData);
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
+ return SQLITE_NOMEM;
+ }
+ memcpy(p->zName, zName, n+1);
+ p->pNext = db->pDbData;
+ db->pDbData = p;
+ }
+ p->pData = pData;
+ p->xDestructor = xDestructor;
+ sqlcipher_sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+}
+
+
#ifndef SQLITE_OMIT_DEPRECATED
/*
** This function is now an anachronism. It used to be used to recover from a
@@ -179913,7 +189032,7 @@ SQLITE_API int sqlcipher_sqlite3_table_column_metadata(
/* Find the column for which info is requested */
if( zColumnName==0 ){
- /* Query for existance of table only */
+ /* Query for existence of table only */
}else{
for(iCol=0; iCol<pTab->nCol; iCol++){
pCol = &pTab->aCol[iCol];
@@ -179994,7 +189113,7 @@ SQLITE_API int sqlcipher_sqlite3_sleep(int ms){
/* This function works in milliseconds, but the underlying OsSleep()
** API uses microseconds. Hence the 1000's.
*/
- rc = (sqlcipher_sqlite3OsSleep(pVfs, 1000*ms)/1000);
+ rc = (sqlcipher_sqlite3OsSleep(pVfs, ms<0 ? 0 : 1000*ms)/1000);
return rc;
}
@@ -180050,6 +189169,9 @@ SQLITE_API int sqlcipher_sqlite3_file_control(sqlcipher_sqlite3 *db, const char
sqlcipher_sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
}
rc = SQLITE_OK;
+ }else if( op==SQLITE_FCNTL_RESET_CACHE ){
+ sqlcipher_sqlite3BtreeClearCache(pBtree);
+ rc = SQLITE_OK;
}else{
int nSave = db->busyHandler.nBusy;
rc = sqlcipher_sqlite3OsFileControl(fd, op, pArg);
@@ -180124,6 +189246,28 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...){
}
#endif
+ /* sqlcipher_sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlcipher_sqlite3 *db, int b);
+ **
+ ** If b is true, then activate the SQLITE_FkNoAction setting. If b is
+ ** false then clearn that setting. If the SQLITE_FkNoAction setting is
+ ** abled, all foreign key ON DELETE and ON UPDATE actions behave as if
+ ** they were NO ACTION, regardless of how they are defined.
+ **
+ ** NB: One must usually run "PRAGMA writable_schema=RESET" after
+ ** using this test-control, before it will take full effect. failing
+ ** to reset the schema can result in some unexpected behavior.
+ */
+ case SQLITE_TESTCTRL_FK_NO_ACTION: {
+ sqlcipher_sqlite3 *db = va_arg(ap, sqlcipher_sqlite3*);
+ int b = va_arg(ap, int);
+ if( b ){
+ db->flags |= SQLITE_FkNoAction;
+ }else{
+ db->flags &= ~SQLITE_FkNoAction;
+ }
+ break;
+ }
+
/*
** sqlcipher_sqlite3_test_control(BITVEC_TEST, size, program)
**
@@ -180230,10 +189374,12 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...){
sqlcipher_sqlite3ShowSrcList(0);
sqlcipher_sqlite3ShowWith(0);
sqlcipher_sqlite3ShowUpsert(0);
+#ifndef SQLITE_OMIT_TRIGGER
sqlcipher_sqlite3ShowTriggerStep(0);
sqlcipher_sqlite3ShowTriggerStepList(0);
sqlcipher_sqlite3ShowTrigger(0);
sqlcipher_sqlite3ShowTriggerList(0);
+#endif
#ifndef SQLITE_OMIT_WINDOWFUNC
sqlcipher_sqlite3ShowWindow(0);
sqlcipher_sqlite3ShowWinFunc(0);
@@ -180350,7 +189496,7 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...){
** formed and never corrupt. This flag is clear by default, indicating that
** database files might have arbitrary corruption. Setting the flag during
** testing causes certain assert() statements in the code to be activated
- ** that demonstrat invariants on well-formed database files.
+ ** that demonstrate invariants on well-formed database files.
*/
case SQLITE_TESTCTRL_NEVER_CORRUPT: {
sqlcipher_sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int);
@@ -180504,7 +189650,7 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...){
**
** op==0 Store the current sqlcipher_sqlite3TreeTrace in *ptr
** op==1 Set sqlcipher_sqlite3TreeTrace to the value *ptr
- ** op==3 Store the current sqlcipher_sqlite3WhereTrace in *ptr
+ ** op==2 Store the current sqlcipher_sqlite3WhereTrace in *ptr
** op==3 Set sqlcipher_sqlite3WhereTrace to the value *ptr
*/
case SQLITE_TESTCTRL_TRACEFLAGS: {
@@ -180540,6 +189686,23 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...){
break;
}
+#if !defined(SQLITE_OMIT_WSD)
+ /* sqlcipher_sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X);
+ **
+ ** X<0 Make no changes to the bUseLongDouble. Just report value.
+ ** X==0 Disable bUseLongDouble
+ ** X==1 Enable bUseLongDouble
+ ** X>=2 Set bUseLongDouble to its default value for this platform
+ */
+ case SQLITE_TESTCTRL_USELONGDOUBLE: {
+ int b = va_arg(ap, int);
+ if( b>=2 ) b = hasHighPrecisionDouble(b);
+ if( b>=0 ) sqlcipher_sqlite3Config.bUseLongDouble = b>0;
+ rc = sqlcipher_sqlite3Config.bUseLongDouble!=0;
+ break;
+ }
+#endif
+
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
/* sqlcipher_sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
@@ -180570,6 +189733,28 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...){
break;
}
#endif
+
+ /* sqlcipher_sqlite3_test_control(SQLITE_TESTCTRL_JSON_SELFCHECK, &onOff);
+ **
+ ** Activate or deactivate validation of JSONB that is generated from
+ ** text. Off by default, as the validation is slow. Validation is
+ ** only available if compiled using SQLITE_DEBUG.
+ **
+ ** If onOff is initially 1, then turn it on. If onOff is initially
+ ** off, turn it off. If onOff is initially -1, then change onOff
+ ** to be the current setting.
+ */
+ case SQLITE_TESTCTRL_JSON_SELFCHECK: {
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
+ int *pOnOff = va_arg(ap, int*);
+ if( *pOnOff<0 ){
+ *pOnOff = sqlcipher_sqlite3Config.bJsonSelfcheck;
+ }else{
+ sqlcipher_sqlite3Config.bJsonSelfcheck = (u8)((*pOnOff)&0xff);
+ }
+#endif
+ break;
+ }
}
va_end(ap);
#endif /* SQLITE_UNTESTABLE */
@@ -180610,7 +189795,7 @@ static char *appendText(char *p, const char *z){
** Memory layout must be compatible with that generated by the pager
** and expected by sqlcipher_sqlite3_uri_parameter() and databaseName().
*/
-SQLITE_API char *sqlcipher_sqlite3_create_filename(
+SQLITE_API const char *sqlcipher_sqlite3_create_filename(
const char *zDatabase,
const char *zJournal,
const char *zWal,
@@ -180646,10 +189831,10 @@ SQLITE_API char *sqlcipher_sqlite3_create_filename(
** error to call this routine with any parameter other than a pointer
** previously obtained from sqlcipher_sqlite3_create_filename() or a NULL pointer.
*/
-SQLITE_API void sqlcipher_sqlite3_free_filename(char *p){
+SQLITE_API void sqlcipher_sqlite3_free_filename(const char *p){
if( p==0 ) return;
- p = (char*)databaseName(p);
- sqlcipher_sqlite3_free(p - 4);
+ p = databaseName(p);
+ sqlcipher_sqlite3_free((char*)p - 4);
}
@@ -180840,7 +190025,7 @@ SQLITE_API int sqlcipher_sqlite3_snapshot_get(
}
/*
-** Open a read-transaction on the snapshot idendified by pSnapshot.
+** Open a read-transaction on the snapshot identified by pSnapshot.
*/
SQLITE_API int sqlcipher_sqlite3_snapshot_open(
sqlcipher_sqlite3 *db,
@@ -180900,8 +190085,8 @@ SQLITE_API int sqlcipher_sqlite3_snapshot_open(
*/
SQLITE_API int sqlcipher_sqlite3_snapshot_recover(sqlcipher_sqlite3 *db, const char *zDb){
int rc = SQLITE_ERROR;
- int iDb;
#ifndef SQLITE_OMIT_WAL
+ int iDb;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlcipher_sqlite3SafetyCheckOk(db) ){
@@ -180947,7 +190132,7 @@ SQLITE_API int sqlcipher_sqlite3_compileoption_used(const char *zOptName){
int nOpt;
const char **azCompileOpt;
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( zOptName==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
@@ -181142,6 +190327,9 @@ SQLITE_API int sqlcipher_sqlite3_unlock_notify(
){
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlcipher_sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlcipher_sqlite3_mutex_enter(db->mutex);
enterMutex();
@@ -182163,6 +191351,7 @@ struct Fts3Table {
int nPgsz; /* Page size for host database */
char *zSegmentsTbl; /* Name of %_segments table */
sqlcipher_sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
+ int iSavepoint;
/*
** The following array of hash tables is used to buffer pending index
@@ -182548,6 +191737,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3FtsUnicodeIsalnum(int);
SQLITE_PRIVATE int sqlcipher_sqlite3FtsUnicodeIsdiacritic(int);
#endif
+SQLITE_PRIVATE int sqlcipher_sqlite3Fts3ExprIterate(Fts3Expr*, int (*x)(Fts3Expr*,int,void*), void*);
+
+SQLITE_PRIVATE int sqlcipher_sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk);
+
#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
#endif /* _FTSINT_H */
@@ -182904,6 +192097,7 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid");
sqlcipher_sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ sqlcipher_sqlite3_vtab_config(p->db, SQLITE_VTAB_INNOCUOUS);
/* Create a list of user columns for the virtual table */
zCols = sqlcipher_sqlite3_mprintf("%Q, ", p->azColumn[0]);
@@ -186153,6 +195347,8 @@ static int fts3RenameMethod(
rc = sqlcipher_sqlite3Fts3PendingTermsFlush(p);
}
+ p->bIgnoreSavepoint = 1;
+
if( p->zContentTbl==0 ){
fts3DbExec(&rc, db,
"ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
@@ -186180,6 +195376,8 @@ static int fts3RenameMethod(
"ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';",
p->zDb, p->zName, zName
);
+
+ p->bIgnoreSavepoint = 0;
return rc;
}
@@ -186190,12 +195388,28 @@ static int fts3RenameMethod(
*/
static int fts3SavepointMethod(sqlcipher_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 );
- if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){
- rc = fts3SyncMethod(pVtab);
+ Fts3Table *pTab = (Fts3Table*)pVtab;
+ assert( pTab->inTransaction );
+ assert( pTab->mxSavepoint<=iSavepoint );
+ TESTONLY( pTab->mxSavepoint = iSavepoint );
+
+ if( pTab->bIgnoreSavepoint==0 ){
+ if( fts3HashCount(&pTab->aIndex[0].hPending)>0 ){
+ char *zSql = sqlcipher_sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')",
+ pTab->zDb, pTab->zName, pTab->zName
+ );
+ if( zSql ){
+ pTab->bIgnoreSavepoint = 1;
+ rc = sqlcipher_sqlite3_exec(pTab->db, zSql, 0, 0, 0);
+ pTab->bIgnoreSavepoint = 0;
+ sqlcipher_sqlite3_free(zSql);
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint+1;
+ }
}
return rc;
}
@@ -186206,12 +195420,11 @@ static int fts3SavepointMethod(sqlcipher_sqlite3_vtab *pVtab, int iSavepoint){
** This is a no-op.
*/
static int fts3ReleaseMethod(sqlcipher_sqlite3_vtab *pVtab, int iSavepoint){
- TESTONLY( Fts3Table *p = (Fts3Table*)pVtab );
- UNUSED_PARAMETER(iSavepoint);
- UNUSED_PARAMETER(pVtab);
- assert( p->inTransaction );
- assert( p->mxSavepoint >= iSavepoint );
- TESTONLY( p->mxSavepoint = iSavepoint-1 );
+ Fts3Table *pTab = (Fts3Table*)pVtab;
+ assert( pTab->inTransaction );
+ assert( pTab->mxSavepoint >= iSavepoint );
+ TESTONLY( pTab->mxSavepoint = iSavepoint-1 );
+ pTab->iSavepoint = iSavepoint;
return SQLITE_OK;
}
@@ -186221,11 +195434,13 @@ static int fts3ReleaseMethod(sqlcipher_sqlite3_vtab *pVtab, int iSavepoint){
** Discard the contents of the pending terms table.
*/
static int fts3RollbackToMethod(sqlcipher_sqlite3_vtab *pVtab, int iSavepoint){
- Fts3Table *p = (Fts3Table*)pVtab;
+ Fts3Table *pTab = (Fts3Table*)pVtab;
UNUSED_PARAMETER(iSavepoint);
- assert( p->inTransaction );
- TESTONLY( p->mxSavepoint = iSavepoint );
- sqlcipher_sqlite3Fts3PendingTermsClear(p);
+ assert( pTab->inTransaction );
+ TESTONLY( pTab->mxSavepoint = iSavepoint );
+ if( (iSavepoint+1)<=pTab->iSavepoint ){
+ sqlcipher_sqlite3Fts3PendingTermsClear(pTab);
+ }
return SQLITE_OK;
}
@@ -186244,8 +195459,42 @@ static int fts3ShadowName(const char *zName){
return 0;
}
+/*
+** Implementation of the xIntegrity() method on the FTS3/FTS4 virtual
+** table.
+*/
+static int fts3IntegrityMethod(
+ sqlcipher_sqlite3_vtab *pVtab, /* The virtual table to be checked */
+ const char *zSchema, /* Name of schema in which pVtab lives */
+ const char *zTabname, /* Name of the pVTab table */
+ int isQuick, /* True if this is a quick_check */
+ char **pzErr /* Write error message here */
+){
+ Fts3Table *p = (Fts3Table*)pVtab;
+ int rc = SQLITE_OK;
+ int bOk = 0;
+
+ UNUSED_PARAMETER(isQuick);
+ rc = sqlcipher_sqlite3Fts3IntegrityCheck(p, &bOk);
+ assert( rc!=SQLITE_CORRUPT_VTAB );
+ if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){
+ *pzErr = sqlcipher_sqlite3_mprintf("unable to validate the inverted index for"
+ " FTS%d table %s.%s: %s",
+ p->bFts4 ? 4 : 3, zSchema, zTabname, sqlcipher_sqlite3_errstr(rc));
+ if( *pzErr ) rc = SQLITE_OK;
+ }else if( rc==SQLITE_OK && bOk==0 ){
+ *pzErr = sqlcipher_sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s",
+ p->bFts4 ? 4 : 3, zSchema, zTabname);
+ if( *pzErr==0 ) rc = SQLITE_NOMEM;
+ }
+ sqlcipher_sqlite3Fts3SegmentsClose(p);
+ return rc;
+}
+
+
+
static const sqlcipher_sqlite3_module fts3Module = {
- /* iVersion */ 3,
+ /* iVersion */ 4,
/* xCreate */ fts3CreateMethod,
/* xConnect */ fts3ConnectMethod,
/* xBestIndex */ fts3BestIndexMethod,
@@ -186269,6 +195518,7 @@ static const sqlcipher_sqlite3_module fts3Module = {
/* xRelease */ fts3ReleaseMethod,
/* xRollbackTo */ fts3RollbackToMethod,
/* xShadowName */ fts3ShadowName,
+ /* xIntegrity */ fts3IntegrityMethod,
};
/*
@@ -187551,9 +196801,8 @@ static void fts3EvalNextRow(
Fts3Expr *pExpr, /* Expr. to advance to next matching row */
int *pRc /* IN/OUT: Error code */
){
- if( *pRc==SQLITE_OK ){
+ if( *pRc==SQLITE_OK && pExpr->bEof==0 ){
int bDescDoclist = pCsr->bDesc; /* Used by DOCID_CMP() macro */
- assert( pExpr->bEof==0 );
pExpr->bStart = 1;
switch( pExpr->eType ){
@@ -188030,6 +197279,22 @@ static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){
}
/*
+** This is an sqlcipher_sqlite3Fts3ExprIterate() callback. If the Fts3Expr.aMI[] array
+** has not yet been allocated, allocate and zero it. Otherwise, just zero
+** it.
+*/
+static int fts3AllocateMSI(Fts3Expr *pExpr, int iPhrase, void *pCtx){
+ Fts3Table *pTab = (Fts3Table*)pCtx;
+ UNUSED_PARAMETER(iPhrase);
+ if( pExpr->aMI==0 ){
+ pExpr->aMI = (u32 *)sqlcipher_sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
+ if( pExpr->aMI==0 ) return SQLITE_NOMEM;
+ }
+ memset(pExpr->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
+ return SQLITE_OK;
+}
+
+/*
** Expression pExpr must be of type FTSQUERY_PHRASE.
**
** If it is not already allocated and populated, this function allocates and
@@ -188050,7 +197315,6 @@ static int fts3EvalGatherStats(
if( pExpr->aMI==0 ){
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
Fts3Expr *pRoot; /* Root of NEAR expression */
- Fts3Expr *p; /* Iterator used for several purposes */
sqlcipher_sqlite3_int64 iPrevId = pCsr->iPrevId;
sqlcipher_sqlite3_int64 iDocid;
@@ -188058,7 +197322,9 @@ static int fts3EvalGatherStats(
/* Find the root of the NEAR expression */
pRoot = pExpr;
- while( pRoot->pParent && pRoot->pParent->eType==FTSQUERY_NEAR ){
+ while( pRoot->pParent
+ && (pRoot->pParent->eType==FTSQUERY_NEAR || pRoot->bDeferred)
+ ){
pRoot = pRoot->pParent;
}
iDocid = pRoot->iDocid;
@@ -188066,14 +197332,8 @@ static int fts3EvalGatherStats(
assert( pRoot->bStart );
/* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */
- for(p=pRoot; p; p=p->pLeft){
- Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight);
- assert( pE->aMI==0 );
- pE->aMI = (u32 *)sqlcipher_sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
- if( !pE->aMI ) return SQLITE_NOMEM;
- memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
- }
-
+ rc = sqlcipher_sqlite3Fts3ExprIterate(pRoot, fts3AllocateMSI, (void*)pTab);
+ if( rc!=SQLITE_OK ) return rc;
fts3EvalRestart(pCsr, pRoot, &rc);
while( pCsr->isEof==0 && rc==SQLITE_OK ){
@@ -188229,6 +197489,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Fts3EvalPhrasePoslist(
u8 bTreeEof = 0;
Fts3Expr *p; /* Used to iterate from pExpr to root */
Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */
+ Fts3Expr *pRun; /* Closest non-deferred ancestor of pNear */
int bMatch;
/* Check if this phrase descends from an OR expression node. If not,
@@ -188243,25 +197504,30 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Fts3EvalPhrasePoslist(
if( p->bEof ) bTreeEof = 1;
}
if( bOr==0 ) return SQLITE_OK;
+ pRun = pNear;
+ while( pRun->bDeferred ){
+ assert( pRun->pParent );
+ pRun = pRun->pParent;
+ }
/* 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 bEofSave = pNear->bEof;
- fts3EvalRestart(pCsr, pNear, &rc);
- while( rc==SQLITE_OK && !pNear->bEof ){
- fts3EvalNextRow(pCsr, pNear, &rc);
- if( bEofSave==0 && pNear->iDocid==iDocid ) break;
+ int bEofSave = pRun->bEof;
+ fts3EvalRestart(pCsr, pRun, &rc);
+ while( rc==SQLITE_OK && !pRun->bEof ){
+ fts3EvalNextRow(pCsr, pRun, &rc);
+ if( bEofSave==0 && pRun->iDocid==iDocid ) break;
}
assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
- if( rc==SQLITE_OK && pNear->bEof!=bEofSave ){
+ if( rc==SQLITE_OK && pRun->bEof!=bEofSave ){
rc = FTS_CORRUPT_VTAB;
}
}
if( bTreeEof ){
- while( rc==SQLITE_OK && !pNear->bEof ){
- fts3EvalNextRow(pCsr, pNear, &rc);
+ while( rc==SQLITE_OK && !pRun->bEof ){
+ fts3EvalNextRow(pCsr, pRun, &rc);
}
}
if( rc!=SQLITE_OK ) return rc;
@@ -188928,7 +198194,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Fts3InitAux(sqlcipher_sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
int rc; /* Return code */
@@ -192494,7 +201761,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Fts3InitTok(sqlcipher_sqlite3 *db, Fts3Hash
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
int rc; /* Return code */
@@ -195177,16 +204445,18 @@ static int fts3MsrBufferData(
char *pList,
i64 nList
){
- if( nList>pMsr->nBuffer ){
+ if( (nList+FTS3_NODE_PADDING)>pMsr->nBuffer ){
char *pNew;
- pMsr->nBuffer = nList*2;
- pNew = (char *)sqlcipher_sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer);
+ int nNew = nList*2 + FTS3_NODE_PADDING;
+ pNew = (char *)sqlcipher_sqlite3_realloc64(pMsr->aBuffer, nNew);
if( !pNew ) return SQLITE_NOMEM;
pMsr->aBuffer = pNew;
+ pMsr->nBuffer = nNew;
}
assert( nList>0 );
memcpy(pMsr->aBuffer, pList, nList);
+ memset(&pMsr->aBuffer[nList], 0, FTS3_NODE_PADDING);
return SQLITE_OK;
}
@@ -195833,7 +205103,6 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Fts3PendingTermsFlush(Fts3Table *p){
rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
}
- sqlcipher_sqlite3Fts3PendingTermsClear(p);
/* Determine the auto-incr-merge setting if unknown. If enabled,
** estimate the number of leaf blocks of content to be written
@@ -195855,6 +205124,10 @@ SQLITE_PRIVATE int sqlcipher_sqlite3Fts3PendingTermsFlush(Fts3Table *p){
rc = sqlcipher_sqlite3_reset(pStmt);
}
}
+
+ if( rc==SQLITE_OK ){
+ sqlcipher_sqlite3Fts3PendingTermsClear(p);
+ }
return rc;
}
@@ -196486,6 +205759,8 @@ static int fts3AppendToNode(
blobGrowBuffer(pPrev, nTerm, &rc);
if( rc!=SQLITE_OK ) return rc;
+ assert( pPrev!=0 );
+ assert( pPrev->a!=0 );
nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm);
nSuffix = nTerm - nPrefix;
@@ -196542,9 +205817,13 @@ static int fts3IncrmergeAppend(
nSpace += sqlcipher_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 ){
+ ** to the current block would make it larger than Fts3Table.nNodeSize bytes,
+ ** and if there is still room for another leaf page, write this block out to
+ ** the database. */
+ if( pLeaf->block.n>0
+ && (pLeaf->block.n + nSpace)>p->nNodeSize
+ && pLeaf->iBlock < (pWriter->iStart + pWriter->nLeafEst)
+ ){
rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n);
pWriter->nWork++;
@@ -196855,6 +206134,7 @@ static int fts3IncrmergeLoad(
for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){
NodeReader reader;
+ memset(&reader, 0, sizeof(reader));
pNode = &pWriter->aNodeWriter[i];
if( pNode->block.a){
@@ -196875,7 +206155,7 @@ static int fts3IncrmergeLoad(
rc = sqlcipher_sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock,0);
blobGrowBuffer(&pNode->block,
MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc
- );
+ );
if( rc==SQLITE_OK ){
memcpy(pNode->block.a, aBlock, nBlock);
pNode->block.n = nBlock;
@@ -197725,7 +207005,7 @@ static u64 fts3ChecksumIndex(
int rc;
u64 cksum = 0;
- assert( *pRc==SQLITE_OK );
+ if( *pRc ) return 0;
memset(&filter, 0, sizeof(filter));
memset(&csr, 0, sizeof(csr));
@@ -197792,7 +207072,7 @@ static u64 fts3ChecksumIndex(
** 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){
+SQLITE_PRIVATE int sqlcipher_sqlite3Fts3IntegrityCheck(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 */
@@ -197870,7 +207150,12 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
sqlcipher_sqlite3_finalize(pStmt);
}
- *pbOk = (cksum1==cksum2);
+ if( rc==SQLITE_CORRUPT_VTAB ){
+ rc = SQLITE_OK;
+ *pbOk = 0;
+ }else{
+ *pbOk = (rc==SQLITE_OK && cksum1==cksum2);
+ }
return rc;
}
@@ -197910,7 +207195,7 @@ static int fts3DoIntegrityCheck(
){
int rc;
int bOk = 0;
- rc = fts3IntegrityCheck(p, &bOk);
+ rc = sqlcipher_sqlite3Fts3IntegrityCheck(p, &bOk);
if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB;
return rc;
}
@@ -197940,8 +207225,11 @@ static int fts3SpecialInsert(Fts3Table *p, sqlcipher_sqlite3_value *pVal){
rc = fts3DoIncrmerge(p, &zVal[6]);
}else if( nVal>10 && 0==sqlcipher_sqlite3_strnicmp(zVal, "automerge=", 10) ){
rc = fts3DoAutoincrmerge(p, &zVal[10]);
+ }else if( nVal==5 && 0==sqlcipher_sqlite3_strnicmp(zVal, "flush", 5) ){
+ rc = sqlcipher_sqlite3Fts3PendingTermsFlush(p);
+ }
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
- }else{
+ else{
int v;
if( nVal>9 && 0==sqlcipher_sqlite3_strnicmp(zVal, "nodesize=", 9) ){
v = atoi(&zVal[9]);
@@ -197959,8 +207247,8 @@ static int fts3SpecialInsert(Fts3Table *p, sqlcipher_sqlite3_value *pVal){
if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v;
rc = SQLITE_OK;
}
-#endif
}
+#endif
return rc;
}
@@ -198368,7 +207656,7 @@ typedef sqlcipher_sqlite3_int64 i64;
/*
-** Used as an fts3ExprIterate() context when loading phrase doclists to
+** Used as an sqlcipher_sqlite3Fts3ExprIterate() context when loading phrase doclists to
** Fts3Expr.aDoclist[]/nDoclist.
*/
typedef struct LoadDoclistCtx LoadDoclistCtx;
@@ -198412,7 +207700,7 @@ struct SnippetFragment {
};
/*
-** This type is used as an fts3ExprIterate() context object while
+** This type is used as an sqlcipher_sqlite3Fts3ExprIterate() context object while
** accumulating the data returned by the matchinfo() function.
*/
typedef struct MatchInfo MatchInfo;
@@ -198571,7 +207859,7 @@ static void fts3GetDeltaPosition(char **pp, i64 *piPos){
}
/*
-** Helper function for fts3ExprIterate() (see below).
+** Helper function for sqlcipher_sqlite3Fts3ExprIterate() (see below).
*/
static int fts3ExprIterate2(
Fts3Expr *pExpr, /* Expression to iterate phrases of */
@@ -198605,7 +207893,7 @@ static int fts3ExprIterate2(
** Otherwise, SQLITE_OK is returned after a callback has been made for
** all eligible phrase nodes.
*/
-static int fts3ExprIterate(
+SQLITE_PRIVATE int sqlcipher_sqlite3Fts3ExprIterate(
Fts3Expr *pExpr, /* Expression to iterate phrases of */
int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */
void *pCtx /* Second argument to pass to callback */
@@ -198614,10 +207902,9 @@ static int fts3ExprIterate(
return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx);
}
-
/*
-** This is an fts3ExprIterate() callback used while loading the doclists
-** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
+** This is an sqlcipher_sqlite3Fts3ExprIterate() callback used while loading the
+** doclists for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
** fts3ExprLoadDoclists().
*/
static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
@@ -198649,9 +207936,9 @@ static int fts3ExprLoadDoclists(
int *pnToken /* OUT: Number of tokens in query */
){
int rc; /* Return Code */
- LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */
+ LoadDoclistCtx sCtx = {0,0,0}; /* Context for sqlcipher_sqlite3Fts3ExprIterate() */
sCtx.pCsr = pCsr;
- rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx);
+ rc = sqlcipher_sqlite3Fts3ExprIterate(pCsr->pExpr,fts3ExprLoadDoclistsCb,(void*)&sCtx);
if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
if( pnToken ) *pnToken = sCtx.nToken;
return rc;
@@ -198664,7 +207951,7 @@ static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
}
static int fts3ExprPhraseCount(Fts3Expr *pExpr){
int nPhrase = 0;
- (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
+ (void)sqlcipher_sqlite3Fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
return nPhrase;
}
@@ -198774,7 +208061,7 @@ static void fts3SnippetDetails(
}
mCover |= mPhrase;
- for(j=0; j<pPhrase->nToken; j++){
+ for(j=0; j<pPhrase->nToken && j<pIter->nSnippet; j++){
mHighlight |= (mPos>>j);
}
@@ -198792,8 +208079,9 @@ static void fts3SnippetDetails(
}
/*
-** This function is an fts3ExprIterate() callback used by fts3BestSnippet().
-** Each invocation populates an element of the SnippetIter.aPhrase[] array.
+** This function is an sqlcipher_sqlite3Fts3ExprIterate() callback used by
+** fts3BestSnippet(). Each invocation populates an element of the
+** SnippetIter.aPhrase[] array.
*/
static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
SnippetIter *p = (SnippetIter *)ctx;
@@ -198883,7 +208171,9 @@ static int fts3BestSnippet(
sIter.nSnippet = nSnippet;
sIter.nPhrase = nList;
sIter.iCurrent = -1;
- rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter);
+ rc = sqlcipher_sqlite3Fts3ExprIterate(
+ pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter
+ );
if( rc==SQLITE_OK ){
/* Set the *pmSeen output variable. */
@@ -199244,10 +208534,10 @@ static int fts3ExprLHitGather(
}
/*
-** fts3ExprIterate() callback used to collect the "global" matchinfo stats
-** for a single query.
+** sqlcipher_sqlite3Fts3ExprIterate() callback used to collect the "global" matchinfo
+** stats for a single query.
**
-** fts3ExprIterate() callback to load the 'global' elements of a
+** sqlcipher_sqlite3Fts3ExprIterate() callback to load the 'global' elements of a
** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements
** of the matchinfo array that are constant for all rows returned by the
** current query.
@@ -199282,7 +208572,7 @@ static int fts3ExprGlobalHitsCb(
}
/*
-** fts3ExprIterate() callback used to collect the "local" part of the
+** sqlcipher_sqlite3Fts3ExprIterate() callback used to collect the "local" part of the
** FTS3_MATCHINFO_HITS array. The local stats are those elements of the
** array that are different for each row returned by the query.
*/
@@ -199478,7 +208768,7 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
**/
aIter = sqlcipher_sqlite3Fts3MallocZero(sizeof(LcsIterator) * pCsr->nPhrase);
if( !aIter ) return SQLITE_NOMEM;
- (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
+ (void)sqlcipher_sqlite3Fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
for(i=0; i<pInfo->nPhrase; i++){
LcsIterator *pIter = &aIter[i];
@@ -199655,11 +208945,11 @@ static int fts3MatchinfoValues(
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0);
if( rc!=SQLITE_OK ) break;
}
- rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
+ rc = sqlcipher_sqlite3Fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
sqlcipher_sqlite3Fts3EvalTestDeferred(pCsr, &rc);
if( rc!=SQLITE_OK ) break;
}
- (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
+ (void)sqlcipher_sqlite3Fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
break;
}
}
@@ -199882,7 +209172,7 @@ struct TermOffsetCtx {
};
/*
-** This function is an fts3ExprIterate() callback used by sqlcipher_sqlite3Fts3Offsets().
+** This function is an sqlcipher_sqlite3Fts3ExprIterate() callback used by sqlcipher_sqlite3Fts3Offsets().
*/
static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
TermOffsetCtx *p = (TermOffsetCtx *)ctx;
@@ -199964,7 +209254,9 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Fts3Offsets(
*/
sCtx.iCol = iCol;
sCtx.iTerm = 0;
- rc = fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx);
+ rc = sqlcipher_sqlite3Fts3ExprIterate(
+ pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx
+ );
if( rc!=SQLITE_OK ) goto offsets_out;
/* Retreive the text stored in column iCol. If an SQL NULL is stored
@@ -200877,59 +210169,242 @@ SQLITE_PRIVATE int sqlcipher_sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
**
******************************************************************************
**
-** This SQLite JSON functions.
+** SQLite JSON functions.
**
** This file began as an extension in ext/misc/json1.c in 2015. That
** extension proved so useful that it has now been moved into the core.
**
-** For the time being, all JSON is stored as pure text. (We might add
-** a JSONB type in the future which stores a binary encoding of JSON in
-** a BLOB, but there is no support for JSONB in the current implementation.
-** This implementation parses JSON text at 250 MB/s, so it is hard to see
-** how JSONB might improve on that.)
+** The original design stored all JSON as pure text, canonical RFC-8259.
+** Support for JSON-5 extensions was added with version 3.42.0 (2023-05-16).
+** All generated JSON text still conforms strictly to RFC-8259, but text
+** with JSON-5 extensions is accepted as input.
+**
+** Beginning with version 3.45.0 (circa 2024-01-01), these routines also
+** accept BLOB values that have JSON encoded using a binary representation
+** called "JSONB". The name JSONB comes from PostgreSQL, however the on-disk
+** format SQLite JSONB is completely different and incompatible with
+** PostgreSQL JSONB.
+**
+** Decoding and interpreting JSONB is still O(N) where N is the size of
+** the input, the same as text JSON. However, the constant of proportionality
+** for JSONB is much smaller due to faster parsing. The size of each
+** element in JSONB is encoded in its header, so there is no need to search
+** for delimiters using persnickety syntax rules. JSONB seems to be about
+** 3x faster than text JSON as a result. JSONB is also tends to be slightly
+** smaller than text JSON, by 5% or 10%, but there are corner cases where
+** JSONB can be slightly larger. So you are not far mistaken to say that
+** a JSONB blob is the same size as the equivalent RFC-8259 text.
+**
+**
+** THE JSONB ENCODING:
+**
+** Every JSON element is encoded in JSONB as a header and a payload.
+** The header is between 1 and 9 bytes in size. The payload is zero
+** or more bytes.
+**
+** The lower 4 bits of the first byte of the header determines the
+** element type:
+**
+** 0: NULL
+** 1: TRUE
+** 2: FALSE
+** 3: INT -- RFC-8259 integer literal
+** 4: INT5 -- JSON5 integer literal
+** 5: FLOAT -- RFC-8259 floating point literal
+** 6: FLOAT5 -- JSON5 floating point literal
+** 7: TEXT -- Text literal acceptable to both SQL and JSON
+** 8: TEXTJ -- Text containing RFC-8259 escapes
+** 9: TEXT5 -- Text containing JSON5 and/or RFC-8259 escapes
+** 10: TEXTRAW -- Text containing unescaped syntax characters
+** 11: ARRAY
+** 12: OBJECT
+**
+** The other three possible values (13-15) are reserved for future
+** enhancements.
+**
+** The upper 4 bits of the first byte determine the size of the header
+** and sometimes also the size of the payload. If X is the first byte
+** of the element and if X>>4 is between 0 and 11, then the payload
+** will be that many bytes in size and the header is exactly one byte
+** in size. Other four values for X>>4 (12-15) indicate that the header
+** is more than one byte in size and that the payload size is determined
+** by the remainder of the header, interpreted as a unsigned big-endian
+** integer.
+**
+** Value of X>>4 Size integer Total header size
+** ------------- -------------------- -----------------
+** 12 1 byte (0-255) 2
+** 13 2 byte (0-65535) 3
+** 14 4 byte (0-4294967295) 5
+** 15 8 byte (0-1.8e19) 9
+**
+** The payload size need not be expressed in its minimal form. For example,
+** if the payload size is 10, the size can be expressed in any of 5 different
+** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte,
+** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by
+** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and
+** a single byte of 0x0a. The shorter forms are preferred, of course, but
+** sometimes when generating JSONB, the payload size is not known in advance
+** and it is convenient to reserve sufficient header space to cover the
+** largest possible payload size and then come back later and patch up
+** the size when it becomes known, resulting in a non-minimal encoding.
+**
+** The value (X>>4)==15 is not actually used in the current implementation
+** (as SQLite is currently unable handle BLOBs larger than about 2GB)
+** but is included in the design to allow for future enhancements.
+**
+** The payload follows the header. NULL, TRUE, and FALSE have no payload and
+** their payload size must always be zero. The payload for INT, INT5,
+** FLOAT, FLOAT5, TEXT, TEXTJ, TEXT5, and TEXTROW is text. Note that the
+** "..." or '...' delimiters are omitted from the various text encodings.
+** The payload for ARRAY and OBJECT is a list of additional elements that
+** are the content for the array or object. The payload for an OBJECT
+** must be an even number of elements. The first element of each pair is
+** the label and must be of type TEXT, TEXTJ, TEXT5, or TEXTRAW.
+**
+** A valid JSONB blob consists of a single element, as described above.
+** Usually this will be an ARRAY or OBJECT element which has many more
+** elements as its content. But the overall blob is just a single element.
+**
+** Input validation for JSONB blobs simply checks that the element type
+** code is between 0 and 12 and that the total size of the element
+** (header plus payload) is the same as the size of the BLOB. If those
+** checks are true, the BLOB is assumed to be JSONB and processing continues.
+** Errors are only raised if some other miscoding is discovered during
+** processing.
+**
+** Additional information can be found in the doc/jsonb.md file of the
+** canonical SQLite source tree.
*/
#ifndef SQLITE_OMIT_JSON
/* #include "sqliteInt.h" */
+/* JSONB element types
+*/
+#define JSONB_NULL 0 /* "null" */
+#define JSONB_TRUE 1 /* "true" */
+#define JSONB_FALSE 2 /* "false" */
+#define JSONB_INT 3 /* integer acceptable to JSON and SQL */
+#define JSONB_INT5 4 /* integer in 0x000 notation */
+#define JSONB_FLOAT 5 /* float acceptable to JSON and SQL */
+#define JSONB_FLOAT5 6 /* float with JSON5 extensions */
+#define JSONB_TEXT 7 /* Text compatible with both JSON and SQL */
+#define JSONB_TEXTJ 8 /* Text with JSON escapes */
+#define JSONB_TEXT5 9 /* Text with JSON-5 escape */
+#define JSONB_TEXTRAW 10 /* SQL text that needs escaping for JSON */
+#define JSONB_ARRAY 11 /* An array */
+#define JSONB_OBJECT 12 /* An object */
+
+/* Human-readable names for the JSONB values. The index for each
+** string must correspond to the JSONB_* integer above.
+*/
+static const char * const jsonbType[] = {
+ "null", "true", "false", "integer", "integer",
+ "real", "real", "text", "text", "text",
+ "text", "array", "object", "", "", "", ""
+};
+
/*
** Growing our own isspace() routine this way is twice as fast as
** the library isspace() function, resulting in a 7% overall performance
-** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
+** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
*/
static const char jsonIsSpace[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define jsonIsspace(x) (jsonIsSpace[(unsigned char)x])
+
+/*
+** The set of all space characters recognized by jsonIsspace().
+** Useful as the second argument to strspn().
+*/
+static const char jsonSpaces[] = "\011\012\015\040";
+
+/*
+** Characters that are special to JSON. Control characters,
+** '"' and '\\' and '\''. Actually, '\'' is not special to
+** canonical JSON, but it is special in JSON-5, so we include
+** it in the set of special characters.
+*/
+static const char jsonIsOk[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
-#define fast_isspace(x) (jsonIsSpace[(unsigned char)x])
-
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST)
-# define VVA(X)
-#else
-# define VVA(X) X
-#endif
/* Objects */
+typedef struct JsonCache JsonCache;
typedef struct JsonString JsonString;
-typedef struct JsonNode JsonNode;
typedef struct JsonParse JsonParse;
+/*
+** Magic number used for the JSON parse cache in sqlcipher_sqlite3_get_auxdata()
+*/
+#define JSON_CACHE_ID (-429938) /* Cache entry */
+#define JSON_CACHE_SIZE 4 /* Max number of cache entries */
+
+/*
+** jsonUnescapeOneChar() returns this invalid code point if it encounters
+** a syntax error.
+*/
+#define JSON_INVALID_CHAR 0x99999
+
+/* A cache mapping JSON text into JSONB blobs.
+**
+** Each cache entry is a JsonParse object with the following restrictions:
+**
+** * The bReadOnly flag must be set
+**
+** * The aBlob[] array must be owned by the JsonParse object. In other
+** words, nBlobAlloc must be non-zero.
+**
+** * eEdit and delta must be zero.
+**
+** * zJson must be an RCStr. In other words bJsonIsRCStr must be true.
+*/
+struct JsonCache {
+ sqlcipher_sqlite3 *db; /* Database connection */
+ int nUsed; /* Number of active entries in the cache */
+ JsonParse *a[JSON_CACHE_SIZE]; /* One line for each cache entry */
+};
+
/* An instance of this object represents a JSON string
** under construction. Really, this is a generic string accumulator
** that can be and is used to create strings other than JSON.
+**
+** If the generated string is longer than will fit into the zSpace[] buffer,
+** then it will be an RCStr string. This aids with caching of large
+** JSON strings.
*/
struct JsonString {
sqlcipher_sqlite3_context *pCtx; /* Function context - put error messages here */
@@ -200937,89 +210412,227 @@ struct JsonString {
u64 nAlloc; /* Bytes of storage available in zBuf[] */
u64 nUsed; /* Bytes of zBuf[] currently used */
u8 bStatic; /* True if zBuf is static space */
- u8 bErr; /* True if an error has been encountered */
+ u8 eErr; /* True if an error has been encountered */
char zSpace[100]; /* Initial static space */
};
-/* JSON type values
-*/
-#define JSON_NULL 0
-#define JSON_TRUE 1
-#define JSON_FALSE 2
-#define JSON_INT 3
-#define JSON_REAL 4
-#define JSON_STRING 5
-#define JSON_ARRAY 6
-#define JSON_OBJECT 7
+/* Allowed values for JsonString.eErr */
+#define JSTRING_OOM 0x01 /* Out of memory */
+#define JSTRING_MALFORMED 0x02 /* Malformed JSONB */
+#define JSTRING_ERR 0x04 /* Error already sent to sqlcipher_sqlite3_result */
-/* The "subtype" set for JSON values */
+/* The "subtype" set for text JSON values passed through using
+** sqlcipher_sqlite3_result_subtype() and sqlcipher_sqlite3_value_subtype().
+*/
#define JSON_SUBTYPE 74 /* Ascii for "J" */
/*
-** Names of the various JSON types:
-*/
-static const char * const jsonType[] = {
- "null", "true", "false", "integer", "real", "text", "array", "object"
-};
-
-/* Bit values for the JsonNode.jnFlag field
+** Bit values for the flags passed into various SQL function implementations
+** via the sqlcipher_sqlite3_user_data() value.
*/
-#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
-#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */
-#define JNODE_REMOVE 0x04 /* Do not output */
-#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */
-#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */
-#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */
-#define JNODE_LABEL 0x40 /* Is a label of an object */
-
+#define JSON_JSON 0x01 /* Result is always JSON */
+#define JSON_SQL 0x02 /* Result is always SQL */
+#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */
+#define JSON_ISSET 0x04 /* json_set(), not json_insert() */
+#define JSON_BLOB 0x08 /* Use the BLOB output format */
-/* A single node of parsed JSON
-*/
-struct JsonNode {
- u8 eType; /* One of the JSON_ type values */
- u8 jnFlags; /* JNODE flags */
- u8 eU; /* Which union element to use */
- u32 n; /* Bytes of content, or number of sub-nodes */
- union {
- const char *zJContent; /* 1: Content for INT, REAL, and STRING */
- u32 iAppend; /* 2: More terms for ARRAY and OBJECT */
- u32 iKey; /* 3: Key for ARRAY objects in json_tree() */
- u32 iReplace; /* 4: Replacement content for JNODE_REPLACE */
- JsonNode *pPatch; /* 5: Node chain of patch for JNODE_PATCH */
- } u;
-};
-/* A completely parsed JSON string
+/* A parsed JSON value. Lifecycle:
+**
+** 1. JSON comes in and is parsed into a JSONB value in aBlob. The
+** original text is stored in zJson. This step is skipped if the
+** input is JSONB instead of text JSON.
+**
+** 2. The aBlob[] array is searched using the JSON path notation, if needed.
+**
+** 3. Zero or more changes are made to aBlob[] (via json_remove() or
+** json_replace() or json_patch() or similar).
+**
+** 4. New JSON text is generated from the aBlob[] for output. This step
+** is skipped if the function is one of the jsonb_* functions that
+** returns JSONB instead of text JSON.
*/
struct JsonParse {
- u32 nNode; /* Number of slots of aNode[] used */
- u32 nAlloc; /* Number of slots of aNode[] allocated */
- JsonNode *aNode; /* Array of nodes containing the parse */
- const char *zJson; /* Original JSON string */
- u32 *aUp; /* Index of parent of each node */
- u8 oom; /* Set to true if out of memory */
- u8 nErr; /* Number of errors seen */
- u16 iDepth; /* Nesting depth */
+ u8 *aBlob; /* JSONB representation of JSON value */
+ u32 nBlob; /* Bytes of aBlob[] actually used */
+ u32 nBlobAlloc; /* Bytes allocated to aBlob[]. 0 if aBlob is external */
+ char *zJson; /* Json text used for parsing */
+ sqlcipher_sqlite3 *db; /* The database connection to which this object belongs */
int nJson; /* Length of the zJson string in bytes */
- u32 iHold; /* Replace cache line with the lowest iHold value */
+ u32 nJPRef; /* Number of references to this object */
+ u32 iErr; /* Error location in zJson[] */
+ u16 iDepth; /* Nesting depth */
+ u8 nErr; /* Number of errors seen */
+ u8 oom; /* Set to true if out of memory */
+ u8 bJsonIsRCStr; /* True if zJson is an RCStr */
+ u8 hasNonstd; /* True if input uses non-standard features like JSON5 */
+ u8 bReadOnly; /* Do not modify. */
+ /* Search and edit information. See jsonLookupStep() */
+ u8 eEdit; /* Edit operation to apply */
+ int delta; /* Size change due to the edit */
+ u32 nIns; /* Number of bytes to insert */
+ u32 iLabel; /* Location of label if search landed on an object value */
+ u8 *aIns; /* Content to be inserted */
};
+/* Allowed values for JsonParse.eEdit */
+#define JEDIT_DEL 1 /* Delete if exists */
+#define JEDIT_REPL 2 /* Overwrite if exists */
+#define JEDIT_INS 3 /* Insert if not exists */
+#define JEDIT_SET 4 /* Insert or overwrite */
+
/*
** Maximum nesting depth of JSON for this implementation.
**
** This limit is needed to avoid a stack overflow in the recursive
-** descent parser. A depth of 2000 is far deeper than any sane JSON
-** should go.
+** descent parser. A depth of 1000 is far deeper than any sane JSON
+** should go. Historical note: This limit was 2000 prior to version 3.42.0
*/
-#define JSON_MAX_DEPTH 2000
+#ifndef SQLITE_JSON_MAX_DEPTH
+# define JSON_MAX_DEPTH 1000
+#else
+# define JSON_MAX_DEPTH SQLITE_JSON_MAX_DEPTH
+#endif
+
+/*
+** Allowed values for the flgs argument to jsonParseFuncArg();
+*/
+#define JSON_EDITABLE 0x01 /* Generate a writable JsonParse object */
+#define JSON_KEEPERROR 0x02 /* Return non-NULL even if there is an error */
+
+/**************************************************************************
+** Forward references
+**************************************************************************/
+static void jsonReturnStringAsBlob(JsonString*);
+static int jsonFuncArgMightBeBinary(sqlcipher_sqlite3_value *pJson);
+static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*);
+static void jsonReturnParse(sqlcipher_sqlite3_context*,JsonParse*);
+static JsonParse *jsonParseFuncArg(sqlcipher_sqlite3_context*,sqlcipher_sqlite3_value*,u32);
+static void jsonParseFree(JsonParse*);
+static u32 jsonbPayloadSize(const JsonParse*, u32, u32*);
+static u32 jsonUnescapeOneChar(const char*, u32, u32*);
+
+/**************************************************************************
+** Utility routines for dealing with JsonCache objects
+**************************************************************************/
+
+/*
+** Free a JsonCache object.
+*/
+static void jsonCacheDelete(JsonCache *p){
+ int i;
+ for(i=0; i<p->nUsed; i++){
+ jsonParseFree(p->a[i]);
+ }
+ sqlcipher_sqlite3DbFree(p->db, p);
+}
+static void jsonCacheDeleteGeneric(void *p){
+ jsonCacheDelete((JsonCache*)p);
+}
+
+/*
+** Insert a new entry into the cache. If the cache is full, expel
+** the least recently used entry. Return SQLITE_OK on success or a
+** result code otherwise.
+**
+** Cache entries are stored in age order, oldest first.
+*/
+static int jsonCacheInsert(
+ sqlcipher_sqlite3_context *ctx, /* The SQL statement context holding the cache */
+ JsonParse *pParse /* The parse object to be added to the cache */
+){
+ JsonCache *p;
+
+ assert( pParse->zJson!=0 );
+ assert( pParse->bJsonIsRCStr );
+ assert( pParse->delta==0 );
+ p = sqlcipher_sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
+ if( p==0 ){
+ sqlcipher_sqlite3 *db = sqlcipher_sqlite3_context_db_handle(ctx);
+ p = sqlcipher_sqlite3DbMallocZero(db, sizeof(*p));
+ if( p==0 ) return SQLITE_NOMEM;
+ p->db = db;
+ sqlcipher_sqlite3_set_auxdata(ctx, JSON_CACHE_ID, p, jsonCacheDeleteGeneric);
+ p = sqlcipher_sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
+ if( p==0 ) return SQLITE_NOMEM;
+ }
+ if( p->nUsed >= JSON_CACHE_SIZE ){
+ jsonParseFree(p->a[0]);
+ memmove(p->a, &p->a[1], (JSON_CACHE_SIZE-1)*sizeof(p->a[0]));
+ p->nUsed = JSON_CACHE_SIZE-1;
+ }
+ assert( pParse->nBlobAlloc>0 );
+ pParse->eEdit = 0;
+ pParse->nJPRef++;
+ pParse->bReadOnly = 1;
+ p->a[p->nUsed] = pParse;
+ p->nUsed++;
+ return SQLITE_OK;
+}
+
+/*
+** Search for a cached translation the json text supplied by pArg. Return
+** the JsonParse object if found. Return NULL if not found.
+**
+** When a match if found, the matching entry is moved to become the
+** most-recently used entry if it isn't so already.
+**
+** The JsonParse object returned still belongs to the Cache and might
+** be deleted at any moment. If the caller whants the JsonParse to
+** linger, it needs to increment the nPJRef reference counter.
+*/
+static JsonParse *jsonCacheSearch(
+ sqlcipher_sqlite3_context *ctx, /* The SQL statement context holding the cache */
+ sqlcipher_sqlite3_value *pArg /* Function argument containing SQL text */
+){
+ JsonCache *p;
+ int i;
+ const char *zJson;
+ int nJson;
+
+ if( sqlcipher_sqlite3_value_type(pArg)!=SQLITE_TEXT ){
+ return 0;
+ }
+ zJson = (const char*)sqlcipher_sqlite3_value_text(pArg);
+ if( zJson==0 ) return 0;
+ nJson = sqlcipher_sqlite3_value_bytes(pArg);
+
+ p = sqlcipher_sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
+ if( p==0 ){
+ return 0;
+ }
+ for(i=0; i<p->nUsed; i++){
+ if( p->a[i]->zJson==zJson ) break;
+ }
+ if( i>=p->nUsed ){
+ for(i=0; i<p->nUsed; i++){
+ if( p->a[i]->nJson!=nJson ) continue;
+ if( memcmp(p->a[i]->zJson, zJson, nJson)==0 ) break;
+ }
+ }
+ if( i<p->nUsed ){
+ if( i<p->nUsed-1 ){
+ /* Make the matching entry the most recently used entry */
+ JsonParse *tmp = p->a[i];
+ memmove(&p->a[i], &p->a[i+1], (p->nUsed-i-1)*sizeof(tmp));
+ p->a[p->nUsed-1] = tmp;
+ i = p->nUsed - 1;
+ }
+ assert( p->a[i]->delta==0 );
+ return p->a[i];
+ }else{
+ return 0;
+ }
+}
/**************************************************************************
** Utility routines for dealing with JsonString objects
**************************************************************************/
-/* Set the JsonString object to an empty string
+/* Turn uninitialized bulk memory into a valid JsonString object
+** holding a zero-length string.
*/
-static void jsonZero(JsonString *p){
+static void jsonStringZero(JsonString *p){
p->zBuf = p->zSpace;
p->nAlloc = sizeof(p->zSpace);
p->nUsed = 0;
@@ -201028,53 +210641,51 @@ static void jsonZero(JsonString *p){
/* Initialize the JsonString object
*/
-static void jsonInit(JsonString *p, sqlcipher_sqlite3_context *pCtx){
+static void jsonStringInit(JsonString *p, sqlcipher_sqlite3_context *pCtx){
p->pCtx = pCtx;
- p->bErr = 0;
- jsonZero(p);
+ p->eErr = 0;
+ jsonStringZero(p);
}
-
/* Free all allocated memory and reset the JsonString object back to its
** initial state.
*/
-static void jsonReset(JsonString *p){
- if( !p->bStatic ) sqlcipher_sqlite3_free(p->zBuf);
- jsonZero(p);
+static void jsonStringReset(JsonString *p){
+ if( !p->bStatic ) sqlcipher_sqlite3RCStrUnref(p->zBuf);
+ jsonStringZero(p);
}
-
/* Report an out-of-memory (OOM) condition
*/
-static void jsonOom(JsonString *p){
- p->bErr = 1;
- sqlcipher_sqlite3_result_error_nomem(p->pCtx);
- jsonReset(p);
+static void jsonStringOom(JsonString *p){
+ p->eErr |= JSTRING_OOM;
+ if( p->pCtx ) sqlcipher_sqlite3_result_error_nomem(p->pCtx);
+ jsonStringReset(p);
}
/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
** Return zero on success. Return non-zero on an OOM error
*/
-static int jsonGrow(JsonString *p, u32 N){
+static int jsonStringGrow(JsonString *p, u32 N){
u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
char *zNew;
if( p->bStatic ){
- if( p->bErr ) return 1;
- zNew = sqlcipher_sqlite3_malloc64(nTotal);
+ if( p->eErr ) return 1;
+ zNew = sqlcipher_sqlite3RCStrNew(nTotal);
if( zNew==0 ){
- jsonOom(p);
+ jsonStringOom(p);
return SQLITE_NOMEM;
}
memcpy(zNew, p->zBuf, (size_t)p->nUsed);
p->zBuf = zNew;
p->bStatic = 0;
}else{
- zNew = sqlcipher_sqlite3_realloc64(p->zBuf, nTotal);
- if( zNew==0 ){
- jsonOom(p);
+ p->zBuf = sqlcipher_sqlite3RCStrResize(p->zBuf, nTotal);
+ if( p->zBuf==0 ){
+ p->eErr |= JSTRING_OOM;
+ jsonStringZero(p);
return SQLITE_NOMEM;
}
- p->zBuf = zNew;
}
p->nAlloc = nTotal;
return SQLITE_OK;
@@ -201082,18 +210693,40 @@ static int jsonGrow(JsonString *p, u32 N){
/* Append N bytes from zIn onto the end of the JsonString string.
*/
-static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
- if( N==0 ) return;
- if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
+static SQLITE_NOINLINE void jsonStringExpandAndAppend(
+ JsonString *p,
+ const char *zIn,
+ u32 N
+){
+ assert( N>0 );
+ if( jsonStringGrow(p,N) ) return;
memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N;
}
+static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
+ if( N==0 ) return;
+ if( N+p->nUsed >= p->nAlloc ){
+ jsonStringExpandAndAppend(p,zIn,N);
+ }else{
+ memcpy(p->zBuf+p->nUsed, zIn, N);
+ p->nUsed += N;
+ }
+}
+static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){
+ assert( N>0 );
+ if( N+p->nUsed >= p->nAlloc ){
+ jsonStringExpandAndAppend(p,zIn,N);
+ }else{
+ memcpy(p->zBuf+p->nUsed, zIn, N);
+ p->nUsed += N;
+ }
+}
/* Append formatted text (not to exceed N bytes) to the JsonString.
*/
static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
va_list ap;
- if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
+ if( (p->nUsed + N >= p->nAlloc) && jsonStringGrow(p, N) ) return;
va_start(ap, zFormat);
sqlcipher_sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
va_end(ap);
@@ -201102,10 +210735,38 @@ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
/* Append a single character
*/
-static void jsonAppendChar(JsonString *p, char c){
- if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
+static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){
+ if( jsonStringGrow(p,1) ) return;
p->zBuf[p->nUsed++] = c;
}
+static void jsonAppendChar(JsonString *p, char c){
+ if( p->nUsed>=p->nAlloc ){
+ jsonAppendCharExpand(p,c);
+ }else{
+ p->zBuf[p->nUsed++] = c;
+ }
+}
+
+/* Remove a single character from the end of the string
+*/
+static void jsonStringTrimOneChar(JsonString *p){
+ if( p->eErr==0 ){
+ assert( p->nUsed>0 );
+ p->nUsed--;
+ }
+}
+
+
+/* Make sure there is a zero terminator on p->zBuf[]
+**
+** Return true on success. Return false if an OOM prevents this
+** from happening.
+*/
+static int jsonStringTerminate(JsonString *p){
+ jsonAppendChar(p, 0);
+ jsonStringTrimOneChar(p);
+ return p->eErr==0;
+}
/* Append a comma separator to the output buffer, if the previous
** character is not '[' or '{'.
@@ -201114,68 +210775,137 @@ static void jsonAppendSeparator(JsonString *p){
char c;
if( p->nUsed==0 ) return;
c = p->zBuf[p->nUsed-1];
- if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
+ if( c=='[' || c=='{' ) return;
+ jsonAppendChar(p, ',');
+}
+
+/* c is a control character. Append the canonical JSON representation
+** of that control character to p.
+**
+** This routine assumes that the output buffer has already been enlarged
+** sufficiently to hold the worst-case encoding plus a nul terminator.
+*/
+static void jsonAppendControlChar(JsonString *p, u8 c){
+ static const char aSpecial[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ assert( sizeof(aSpecial)==32 );
+ assert( aSpecial['\b']=='b' );
+ assert( aSpecial['\f']=='f' );
+ assert( aSpecial['\n']=='n' );
+ assert( aSpecial['\r']=='r' );
+ assert( aSpecial['\t']=='t' );
+ assert( c>=0 && c<sizeof(aSpecial) );
+ assert( p->nUsed+7 <= p->nAlloc );
+ if( aSpecial[c] ){
+ p->zBuf[p->nUsed] = '\\';
+ p->zBuf[p->nUsed+1] = aSpecial[c];
+ p->nUsed += 2;
+ }else{
+ p->zBuf[p->nUsed] = '\\';
+ p->zBuf[p->nUsed+1] = 'u';
+ p->zBuf[p->nUsed+2] = '0';
+ p->zBuf[p->nUsed+3] = '0';
+ p->zBuf[p->nUsed+4] = "0123456789abcdef"[c>>4];
+ p->zBuf[p->nUsed+5] = "0123456789abcdef"[c&0xf];
+ p->nUsed += 6;
+ }
}
/* Append the N-byte string in zIn to the end of the JsonString string
-** under construction. Enclose the string in "..." and escape
-** any double-quotes or backslash characters contained within the
+** under construction. Enclose the string in double-quotes ("...") and
+** escape any double-quotes or backslash characters contained within the
** string.
+**
+** This routine is a high-runner. There is a measurable performance
+** increase associated with unwinding the jsonIsOk[] loop.
*/
static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
- u32 i;
- if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return;
+ u32 k;
+ u8 c;
+ const u8 *z = (const u8*)zIn;
+ if( z==0 ) return;
+ if( (N+p->nUsed+2 >= p->nAlloc) && jsonStringGrow(p,N+2)!=0 ) return;
p->zBuf[p->nUsed++] = '"';
- for(i=0; i<N; i++){
- unsigned char c = ((unsigned const char*)zIn)[i];
+ while( 1 /*exit-by-break*/ ){
+ k = 0;
+ /* The following while() is the 4-way unwound equivalent of
+ **
+ ** while( k<N && jsonIsOk[z[k]] ){ k++; }
+ */
+ while( 1 /* Exit by break */ ){
+ if( k+3>=N ){
+ while( k<N && jsonIsOk[z[k]] ){ k++; }
+ break;
+ }
+ if( !jsonIsOk[z[k]] ){
+ break;
+ }
+ if( !jsonIsOk[z[k+1]] ){
+ k += 1;
+ break;
+ }
+ if( !jsonIsOk[z[k+2]] ){
+ k += 2;
+ break;
+ }
+ if( !jsonIsOk[z[k+3]] ){
+ k += 3;
+ break;
+ }else{
+ k += 4;
+ }
+ }
+ if( k>=N ){
+ if( k>0 ){
+ memcpy(&p->zBuf[p->nUsed], z, k);
+ p->nUsed += k;
+ }
+ break;
+ }
+ if( k>0 ){
+ memcpy(&p->zBuf[p->nUsed], z, k);
+ p->nUsed += k;
+ z += k;
+ N -= k;
+ }
+ c = z[0];
if( c=='"' || c=='\\' ){
- json_simple_escape:
- if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
+ if( (p->nUsed+N+3 > p->nAlloc) && jsonStringGrow(p,N+3)!=0 ) return;
p->zBuf[p->nUsed++] = '\\';
- }else if( c<=0x1f ){
- static const char aSpecial[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- assert( sizeof(aSpecial)==32 );
- assert( aSpecial['\b']=='b' );
- assert( aSpecial['\f']=='f' );
- assert( aSpecial['\n']=='n' );
- assert( aSpecial['\r']=='r' );
- assert( aSpecial['\t']=='t' );
- if( aSpecial[c] ){
- c = aSpecial[c];
- goto json_simple_escape;
- }
- if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
- p->zBuf[p->nUsed++] = '\\';
- p->zBuf[p->nUsed++] = 'u';
- p->zBuf[p->nUsed++] = '0';
- p->zBuf[p->nUsed++] = '0';
- p->zBuf[p->nUsed++] = '0' + (c>>4);
- c = "0123456789abcdef"[c&0xf];
+ p->zBuf[p->nUsed++] = c;
+ }else if( c=='\'' ){
+ p->zBuf[p->nUsed++] = c;
+ }else{
+ if( (p->nUsed+N+7 > p->nAlloc) && jsonStringGrow(p,N+7)!=0 ) return;
+ jsonAppendControlChar(p, c);
}
- p->zBuf[p->nUsed++] = c;
+ z++;
+ N--;
}
p->zBuf[p->nUsed++] = '"';
assert( p->nUsed<p->nAlloc );
}
/*
-** Append a function parameter value to the JSON string under
-** construction.
+** Append an sqlcipher_sqlite3_value (such as a function parameter) to the JSON
+** string under construction in p.
*/
-static void jsonAppendValue(
+static void jsonAppendSqlValue(
JsonString *p, /* Append to this JSON string */
sqlcipher_sqlite3_value *pValue /* Value to append */
){
switch( sqlcipher_sqlite3_value_type(pValue) ){
case SQLITE_NULL: {
- jsonAppendRaw(p, "null", 4);
+ jsonAppendRawNZ(p, "null", 4);
break;
}
- case SQLITE_INTEGER:
case SQLITE_FLOAT: {
+ jsonPrintf(100, p, "%!0.15g", sqlcipher_sqlite3_value_double(pValue));
+ break;
+ }
+ case SQLITE_INTEGER: {
const char *z = (const char*)sqlcipher_sqlite3_value_text(pValue);
u32 n = (u32)sqlcipher_sqlite3_value_bytes(pValue);
jsonAppendRaw(p, z, n);
@@ -201192,184 +210922,127 @@ static void jsonAppendValue(
break;
}
default: {
- if( p->bErr==0 ){
+ if( jsonFuncArgMightBeBinary(pValue) ){
+ JsonParse px;
+ memset(&px, 0, sizeof(px));
+ px.aBlob = (u8*)sqlcipher_sqlite3_value_blob(pValue);
+ px.nBlob = sqlcipher_sqlite3_value_bytes(pValue);
+ jsonTranslateBlobToText(&px, 0, p);
+ }else if( p->eErr==0 ){
sqlcipher_sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
- p->bErr = 2;
- jsonReset(p);
+ p->eErr = JSTRING_ERR;
+ jsonStringReset(p);
}
break;
}
}
}
-
-/* Make the JSON in p the result of the SQL function.
+/* Make the text in p (which is probably a generated JSON text string)
+** the result of the SQL function.
+**
+** The JsonString is reset.
+**
+** If pParse and ctx are both non-NULL, then the SQL string in p is
+** loaded into the zJson field of the pParse object as a RCStr and the
+** pParse is added to the cache.
*/
-static void jsonResult(JsonString *p){
- if( p->bErr==0 ){
- sqlcipher_sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
- p->bStatic ? SQLITE_TRANSIENT : sqlcipher_sqlite3_free,
- SQLITE_UTF8);
- jsonZero(p);
+static void jsonReturnString(
+ JsonString *p, /* String to return */
+ JsonParse *pParse, /* JSONB source or NULL */
+ sqlcipher_sqlite3_context *ctx /* Where to cache */
+){
+ assert( (pParse!=0)==(ctx!=0) );
+ assert( ctx==0 || ctx==p->pCtx );
+ if( p->eErr==0 ){
+ int flags = SQLITE_PTR_TO_INT(sqlcipher_sqlite3_user_data(p->pCtx));
+ if( flags & JSON_BLOB ){
+ jsonReturnStringAsBlob(p);
+ }else if( p->bStatic ){
+ sqlcipher_sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
+ SQLITE_TRANSIENT, SQLITE_UTF8);
+ }else if( jsonStringTerminate(p) ){
+ if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){
+ int rc;
+ pParse->zJson = sqlcipher_sqlite3RCStrRef(p->zBuf);
+ pParse->nJson = p->nUsed;
+ pParse->bJsonIsRCStr = 1;
+ rc = jsonCacheInsert(ctx, pParse);
+ if( rc==SQLITE_NOMEM ){
+ sqlcipher_sqlite3_result_error_nomem(ctx);
+ jsonStringReset(p);
+ return;
+ }
+ }
+ sqlcipher_sqlite3_result_text64(p->pCtx, sqlcipher_sqlite3RCStrRef(p->zBuf), p->nUsed,
+ sqlcipher_sqlite3RCStrUnref,
+ SQLITE_UTF8);
+ }else{
+ sqlcipher_sqlite3_result_error_nomem(p->pCtx);
+ }
+ }else if( p->eErr & JSTRING_OOM ){
+ sqlcipher_sqlite3_result_error_nomem(p->pCtx);
+ }else if( p->eErr & JSTRING_MALFORMED ){
+ sqlcipher_sqlite3_result_error(p->pCtx, "malformed JSON", -1);
}
- assert( p->bStatic );
+ jsonStringReset(p);
}
/**************************************************************************
-** Utility routines for dealing with JsonNode and JsonParse objects
+** Utility routines for dealing with JsonParse objects
**************************************************************************/
/*
-** Return the number of consecutive JsonNode slots need to represent
-** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and
-** OBJECT types, the number might be larger.
-**
-** Appended elements are not counted. The value returned is the number
-** by which the JsonNode counter should increment in order to go to the
-** next peer value.
-*/
-static u32 jsonNodeSize(JsonNode *pNode){
- return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
-}
-
-/*
** Reclaim all memory allocated by a JsonParse object. But do not
** delete the JsonParse object itself.
*/
static void jsonParseReset(JsonParse *pParse){
- sqlcipher_sqlite3_free(pParse->aNode);
- pParse->aNode = 0;
- pParse->nNode = 0;
- pParse->nAlloc = 0;
- sqlcipher_sqlite3_free(pParse->aUp);
- pParse->aUp = 0;
+ assert( pParse->nJPRef<=1 );
+ if( pParse->bJsonIsRCStr ){
+ sqlcipher_sqlite3RCStrUnref(pParse->zJson);
+ pParse->zJson = 0;
+ pParse->nJson = 0;
+ pParse->bJsonIsRCStr = 0;
+ }
+ if( pParse->nBlobAlloc ){
+ sqlcipher_sqlite3DbFree(pParse->db, pParse->aBlob);
+ pParse->aBlob = 0;
+ pParse->nBlob = 0;
+ pParse->nBlobAlloc = 0;
+ }
}
/*
-** Free a JsonParse object that was obtained from sqlcipher_sqlite3_malloc().
+** Decrement the reference count on the JsonParse object. When the
+** count reaches zero, free the object.
*/
static void jsonParseFree(JsonParse *pParse){
- jsonParseReset(pParse);
- sqlcipher_sqlite3_free(pParse);
-}
-
-/*
-** Convert the JsonNode pNode into a pure JSON string and
-** append to pOut. Subsubstructure is also included. Return
-** the number of JsonNode objects that are encoded.
-*/
-static void jsonRenderNode(
- JsonNode *pNode, /* The node to render */
- JsonString *pOut, /* Write JSON here */
- sqlcipher_sqlite3_value **aReplace /* Replacement values */
-){
- assert( pNode!=0 );
- if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
- if( (pNode->jnFlags & JNODE_REPLACE)!=0 && ALWAYS(aReplace!=0) ){
- assert( pNode->eU==4 );
- jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
- return;
- }
- assert( pNode->eU==5 );
- pNode = pNode->u.pPatch;
- }
- switch( pNode->eType ){
- default: {
- assert( pNode->eType==JSON_NULL );
- jsonAppendRaw(pOut, "null", 4);
- break;
- }
- case JSON_TRUE: {
- jsonAppendRaw(pOut, "true", 4);
- break;
- }
- case JSON_FALSE: {
- jsonAppendRaw(pOut, "false", 5);
- break;
- }
- case JSON_STRING: {
- if( pNode->jnFlags & JNODE_RAW ){
- assert( pNode->eU==1 );
- jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
- break;
- }
- /* no break */ deliberate_fall_through
- }
- case JSON_REAL:
- case JSON_INT: {
- assert( pNode->eU==1 );
- jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
- break;
- }
- case JSON_ARRAY: {
- u32 j = 1;
- jsonAppendChar(pOut, '[');
- for(;;){
- while( j<=pNode->n ){
- if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
- jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
- }
- j += jsonNodeSize(&pNode[j]);
- }
- if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pNode->eU==2 );
- pNode = &pNode[pNode->u.iAppend];
- j = 1;
- }
- jsonAppendChar(pOut, ']');
- break;
- }
- case JSON_OBJECT: {
- u32 j = 1;
- jsonAppendChar(pOut, '{');
- for(;;){
- while( j<=pNode->n ){
- if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
- jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
- jsonAppendChar(pOut, ':');
- jsonRenderNode(&pNode[j+1], pOut, aReplace);
- }
- j += 1 + jsonNodeSize(&pNode[j+1]);
- }
- if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pNode->eU==2 );
- pNode = &pNode[pNode->u.iAppend];
- j = 1;
- }
- jsonAppendChar(pOut, '}');
- break;
+ if( pParse ){
+ if( pParse->nJPRef>1 ){
+ pParse->nJPRef--;
+ }else{
+ jsonParseReset(pParse);
+ sqlcipher_sqlite3DbFree(pParse->db, pParse);
}
}
}
-/*
-** Return a JsonNode and all its descendents as a JSON string.
-*/
-static void jsonReturnJson(
- JsonNode *pNode, /* Node to return */
- sqlcipher_sqlite3_context *pCtx, /* Return value for this function */
- sqlcipher_sqlite3_value **aReplace /* Array of replacement values */
-){
- JsonString s;
- jsonInit(&s, pCtx);
- jsonRenderNode(pNode, &s, aReplace);
- jsonResult(&s);
- sqlcipher_sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
-}
+/**************************************************************************
+** Utility routines for the JSON text parser
+**************************************************************************/
/*
** Translate a single byte of Hex into an integer.
-** This routine only works if h really is a valid hexadecimal
-** character: 0..9a..fA..F
+** This routine only gives a correct answer if h really is a valid hexadecimal
+** character: 0..9a..fA..F. But unlike sqlcipher_sqlite3HexToInt(), it does not
+** assert() if the digit is not hex.
*/
static u8 jsonHexToInt(int h){
- assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
+#ifdef SQLITE_ASCII
+ h += 9*(1&(h>>6));
+#endif
#ifdef SQLITE_EBCDIC
h += 9*(1&~(h>>4));
-#else
- h += 9*(1&(h>>6));
#endif
return (u8)(h & 0xf);
}
@@ -201379,10 +211052,6 @@ static u8 jsonHexToInt(int h){
*/
static u32 jsonHexToInt4(const char *z){
u32 v;
- assert( sqlcipher_sqlite3Isxdigit(z[0]) );
- assert( sqlcipher_sqlite3Isxdigit(z[1]) );
- assert( sqlcipher_sqlite3Isxdigit(z[2]) );
- assert( sqlcipher_sqlite3Isxdigit(z[3]) );
v = (jsonHexToInt(z[0])<<12)
+ (jsonHexToInt(z[1])<<8)
+ (jsonHexToInt(z[2])<<4)
@@ -201391,420 +211060,1108 @@ static u32 jsonHexToInt4(const char *z){
}
/*
-** Make the JsonNode the return value of the function.
+** Return true if z[] begins with 2 (or more) hexadecimal digits
*/
-static void jsonReturn(
- JsonNode *pNode, /* Node to return */
- sqlcipher_sqlite3_context *pCtx, /* Return value for this function */
- sqlcipher_sqlite3_value **aReplace /* Array of replacement values */
-){
- switch( pNode->eType ){
- default: {
- assert( pNode->eType==JSON_NULL );
- sqlcipher_sqlite3_result_null(pCtx);
- break;
- }
- case JSON_TRUE: {
- sqlcipher_sqlite3_result_int(pCtx, 1);
- break;
- }
- case JSON_FALSE: {
- sqlcipher_sqlite3_result_int(pCtx, 0);
- break;
- }
- case JSON_INT: {
- sqlcipher_sqlite3_int64 i = 0;
- const char *z;
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- if( z[0]=='-' ){ z++; }
- while( z[0]>='0' && z[0]<='9' ){
- unsigned v = *(z++) - '0';
- if( i>=LARGEST_INT64/10 ){
- if( i>LARGEST_INT64/10 ) goto int_as_real;
- if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
- if( v==9 ) goto int_as_real;
- if( v==8 ){
- if( pNode->u.zJContent[0]=='-' ){
- sqlcipher_sqlite3_result_int64(pCtx, SMALLEST_INT64);
- goto int_done;
- }else{
- goto int_as_real;
+static int jsonIs2Hex(const char *z){
+ return sqlcipher_sqlite3Isxdigit(z[0]) && sqlcipher_sqlite3Isxdigit(z[1]);
+}
+
+/*
+** Return true if z[] begins with 4 (or more) hexadecimal digits
+*/
+static int jsonIs4Hex(const char *z){
+ return jsonIs2Hex(z) && jsonIs2Hex(&z[2]);
+}
+
+/*
+** Return the number of bytes of JSON5 whitespace at the beginning of
+** the input string z[].
+**
+** JSON5 whitespace consists of any of the following characters:
+**
+** Unicode UTF-8 Name
+** U+0009 09 horizontal tab
+** U+000a 0a line feed
+** U+000b 0b vertical tab
+** U+000c 0c form feed
+** U+000d 0d carriage return
+** U+0020 20 space
+** U+00a0 c2 a0 non-breaking space
+** U+1680 e1 9a 80 ogham space mark
+** U+2000 e2 80 80 en quad
+** U+2001 e2 80 81 em quad
+** U+2002 e2 80 82 en space
+** U+2003 e2 80 83 em space
+** U+2004 e2 80 84 three-per-em space
+** U+2005 e2 80 85 four-per-em space
+** U+2006 e2 80 86 six-per-em space
+** U+2007 e2 80 87 figure space
+** U+2008 e2 80 88 punctuation space
+** U+2009 e2 80 89 thin space
+** U+200a e2 80 8a hair space
+** U+2028 e2 80 a8 line separator
+** U+2029 e2 80 a9 paragraph separator
+** U+202f e2 80 af narrow no-break space (NNBSP)
+** U+205f e2 81 9f medium mathematical space (MMSP)
+** U+3000 e3 80 80 ideographical space
+** U+FEFF ef bb bf byte order mark
+**
+** In addition, comments between '/', '*' and '*', '/' and
+** from '/', '/' to end-of-line are also considered to be whitespace.
+*/
+static int json5Whitespace(const char *zIn){
+ int n = 0;
+ const u8 *z = (u8*)zIn;
+ while( 1 /*exit by "goto whitespace_done"*/ ){
+ switch( z[n] ){
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x20: {
+ n++;
+ break;
+ }
+ case '/': {
+ if( z[n+1]=='*' && z[n+2]!=0 ){
+ int j;
+ for(j=n+3; z[j]!='/' || z[j-1]!='*'; j++){
+ if( z[j]==0 ) goto whitespace_done;
+ }
+ n = j+1;
+ break;
+ }else if( z[n+1]=='/' ){
+ int j;
+ char c;
+ for(j=n+2; (c = z[j])!=0; j++){
+ if( c=='\n' || c=='\r' ) break;
+ if( 0xe2==(u8)c && 0x80==(u8)z[j+1]
+ && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])
+ ){
+ j += 2;
+ break;
}
}
+ n = j;
+ if( z[n] ) n++;
+ break;
}
- i = i*10 + v;
+ goto whitespace_done;
}
- if( pNode->u.zJContent[0]=='-' ){ i = -i; }
- sqlcipher_sqlite3_result_int64(pCtx, i);
- int_done:
- break;
- int_as_real: ; /* no break */ deliberate_fall_through
- }
- case JSON_REAL: {
- double r;
-#ifdef SQLITE_AMALGAMATION
- const char *z;
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- sqlcipher_sqlite3AtoF(z, &r, sqlcipher_sqlite3Strlen30(z), SQLITE_UTF8);
-#else
- assert( pNode->eU==1 );
- r = strtod(pNode->u.zJContent, 0);
-#endif
- sqlcipher_sqlite3_result_double(pCtx, r);
- break;
- }
- case JSON_STRING: {
-#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
- ** json_insert() and json_replace() and those routines do not
- ** call jsonReturn() */
- if( pNode->jnFlags & JNODE_RAW ){
- assert( pNode->eU==1 );
- sqlcipher_sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
- SQLITE_TRANSIENT);
- }else
-#endif
- assert( (pNode->jnFlags & JNODE_RAW)==0 );
- if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
- /* JSON formatted without any backslash-escapes */
- assert( pNode->eU==1 );
- sqlcipher_sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
- SQLITE_TRANSIENT);
- }else{
- /* Translate JSON formatted string into raw text */
- u32 i;
- u32 n = pNode->n;
- const char *z;
- char *zOut;
- u32 j;
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- zOut = sqlcipher_sqlite3_malloc( n+1 );
- if( zOut==0 ){
- sqlcipher_sqlite3_result_error_nomem(pCtx);
+ case 0xc2: {
+ if( z[n+1]==0xa0 ){
+ n += 2;
break;
}
- for(i=1, j=0; i<n-1; i++){
- char c = z[i];
- if( c!='\\' ){
- zOut[j++] = c;
- }else{
- c = z[++i];
- if( c=='u' ){
- u32 v = jsonHexToInt4(z+i+1);
- i += 4;
- if( v==0 ) break;
- if( v<=0x7f ){
- zOut[j++] = (char)v;
- }else if( v<=0x7ff ){
- zOut[j++] = (char)(0xc0 | (v>>6));
- zOut[j++] = 0x80 | (v&0x3f);
- }else{
- u32 vlo;
- if( (v&0xfc00)==0xd800
- && i<n-6
- && z[i+1]=='\\'
- && z[i+2]=='u'
- && ((vlo = jsonHexToInt4(z+i+3))&0xfc00)==0xdc00
- ){
- /* We have a surrogate pair */
- v = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
- i += 6;
- zOut[j++] = 0xf0 | (v>>18);
- zOut[j++] = 0x80 | ((v>>12)&0x3f);
- zOut[j++] = 0x80 | ((v>>6)&0x3f);
- zOut[j++] = 0x80 | (v&0x3f);
- }else{
- zOut[j++] = 0xe0 | (v>>12);
- zOut[j++] = 0x80 | ((v>>6)&0x3f);
- zOut[j++] = 0x80 | (v&0x3f);
- }
- }
- }else{
- if( c=='b' ){
- c = '\b';
- }else if( c=='f' ){
- c = '\f';
- }else if( c=='n' ){
- c = '\n';
- }else if( c=='r' ){
- c = '\r';
- }else if( c=='t' ){
- c = '\t';
- }
- zOut[j++] = c;
- }
+ goto whitespace_done;
+ }
+ case 0xe1: {
+ if( z[n+1]==0x9a && z[n+2]==0x80 ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xe2: {
+ if( z[n+1]==0x80 ){
+ u8 c = z[n+2];
+ if( c<0x80 ) goto whitespace_done;
+ if( c<=0x8a || c==0xa8 || c==0xa9 || c==0xaf ){
+ n += 3;
+ break;
}
+ }else if( z[n+1]==0x81 && z[n+2]==0x9f ){
+ n += 3;
+ break;
}
- zOut[j] = 0;
- sqlcipher_sqlite3_result_text(pCtx, zOut, j, sqlcipher_sqlite3_free);
+ goto whitespace_done;
+ }
+ case 0xe3: {
+ if( z[n+1]==0x80 && z[n+2]==0x80 ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xef: {
+ if( z[n+1]==0xbb && z[n+2]==0xbf ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ default: {
+ goto whitespace_done;
}
- break;
- }
- case JSON_ARRAY:
- case JSON_OBJECT: {
- jsonReturnJson(pNode, pCtx, aReplace);
- break;
}
}
+ whitespace_done:
+ return n;
}
-/* Forward reference */
-static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
-
/*
-** A macro to hint to the compiler that a function should not be
-** inlined.
+** Extra floating-point literals to allow in JSON.
*/
-#if defined(__GNUC__)
-# define JSON_NOINLINE __attribute__((noinline))
-#elif defined(_MSC_VER) && _MSC_VER>=1310
-# define JSON_NOINLINE __declspec(noinline)
-#else
-# define JSON_NOINLINE
-#endif
+static const struct NanInfName {
+ char c1;
+ char c2;
+ char n;
+ char eType;
+ char nRepl;
+ char *zMatch;
+ char *zRepl;
+} aNanInfName[] = {
+ { 'i', 'I', 3, JSONB_FLOAT, 7, "inf", "9.0e999" },
+ { 'i', 'I', 8, JSONB_FLOAT, 7, "infinity", "9.0e999" },
+ { 'n', 'N', 3, JSONB_NULL, 4, "NaN", "null" },
+ { 'q', 'Q', 4, JSONB_NULL, 4, "QNaN", "null" },
+ { 's', 'S', 4, JSONB_NULL, 4, "SNaN", "null" },
+};
-static JSON_NOINLINE int jsonParseAddNodeExpand(
- JsonParse *pParse, /* Append the node to this object */
- u32 eType, /* Node type */
- u32 n, /* Content size or sub-node count */
- const char *zContent /* Content */
+/*
+** Report the wrong number of arguments for json_insert(), json_replace()
+** or json_set().
+*/
+static void jsonWrongNumArgs(
+ sqlcipher_sqlite3_context *pCtx,
+ const char *zFuncName
){
- u32 nNew;
- JsonNode *pNew;
- assert( pParse->nNode>=pParse->nAlloc );
- if( pParse->oom ) return -1;
- nNew = pParse->nAlloc*2 + 10;
- pNew = sqlcipher_sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew);
- if( pNew==0 ){
- pParse->oom = 1;
- return -1;
+ char *zMsg = sqlcipher_sqlite3_mprintf("json_%s() needs an odd number of arguments",
+ zFuncName);
+ sqlcipher_sqlite3_result_error(pCtx, zMsg, -1);
+ sqlcipher_sqlite3_free(zMsg);
+}
+
+/****************************************************************************
+** Utility routines for dealing with the binary BLOB representation of JSON
+****************************************************************************/
+
+/*
+** Expand pParse->aBlob so that it holds at least N bytes.
+**
+** Return the number of errors.
+*/
+static int jsonBlobExpand(JsonParse *pParse, u32 N){
+ u8 *aNew;
+ u32 t;
+ assert( N>pParse->nBlobAlloc );
+ if( pParse->nBlobAlloc==0 ){
+ t = 100;
+ }else{
+ t = pParse->nBlobAlloc*2;
}
- pParse->nAlloc = nNew;
- pParse->aNode = pNew;
- assert( pParse->nNode<pParse->nAlloc );
- return jsonParseAddNode(pParse, eType, n, zContent);
+ if( t<N ) t = N+100;
+ aNew = sqlcipher_sqlite3DbRealloc(pParse->db, pParse->aBlob, t);
+ if( aNew==0 ){ pParse->oom = 1; return 1; }
+ pParse->aBlob = aNew;
+ pParse->nBlobAlloc = t;
+ return 0;
}
/*
-** Create a new JsonNode instance based on the arguments and append that
-** instance to the JsonParse. Return the index in pParse->aNode[] of the
-** new node, or -1 if a memory allocation fails.
+** If pParse->aBlob is not previously editable (because it is taken
+** from sqlcipher_sqlite3_value_blob(), as indicated by the fact that
+** pParse->nBlobAlloc==0 and pParse->nBlob>0) then make it editable
+** by making a copy into space obtained from malloc.
+**
+** Return true on success. Return false on OOM.
*/
-static int jsonParseAddNode(
- JsonParse *pParse, /* Append the node to this object */
- u32 eType, /* Node type */
- u32 n, /* Content size or sub-node count */
- const char *zContent /* Content */
+static int jsonBlobMakeEditable(JsonParse *pParse, u32 nExtra){
+ u8 *aOld;
+ u32 nSize;
+ assert( !pParse->bReadOnly );
+ if( pParse->oom ) return 0;
+ if( pParse->nBlobAlloc>0 ) return 1;
+ aOld = pParse->aBlob;
+ nSize = pParse->nBlob + nExtra;
+ pParse->aBlob = 0;
+ if( jsonBlobExpand(pParse, nSize) ){
+ return 0;
+ }
+ assert( pParse->nBlobAlloc >= pParse->nBlob + nExtra );
+ memcpy(pParse->aBlob, aOld, pParse->nBlob);
+ return 1;
+}
+
+/* Expand pParse->aBlob and append one bytes.
+*/
+static SQLITE_NOINLINE void jsonBlobExpandAndAppendOneByte(
+ JsonParse *pParse,
+ u8 c
){
- JsonNode *p;
- if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){
- return jsonParseAddNodeExpand(pParse, eType, n, zContent);
+ jsonBlobExpand(pParse, pParse->nBlob+1);
+ if( pParse->oom==0 ){
+ assert( pParse->nBlob+1<=pParse->nBlobAlloc );
+ pParse->aBlob[pParse->nBlob++] = c;
+ }
+}
+
+/* Append a single character.
+*/
+static void jsonBlobAppendOneByte(JsonParse *pParse, u8 c){
+ if( pParse->nBlob >= pParse->nBlobAlloc ){
+ jsonBlobExpandAndAppendOneByte(pParse, c);
+ }else{
+ pParse->aBlob[pParse->nBlob++] = c;
+ }
+}
+
+/* Slow version of jsonBlobAppendNode() that first resizes the
+** pParse->aBlob structure.
+*/
+static void jsonBlobAppendNode(JsonParse*,u8,u32,const void*);
+static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode(
+ JsonParse *pParse,
+ u8 eType,
+ u32 szPayload,
+ const void *aPayload
+){
+ if( jsonBlobExpand(pParse, pParse->nBlob+szPayload+9) ) return;
+ jsonBlobAppendNode(pParse, eType, szPayload, aPayload);
+}
+
+
+/* Append an node type byte together with the payload size and
+** possibly also the payload.
+**
+** If aPayload is not NULL, then it is a pointer to the payload which
+** is also appended. If aPayload is NULL, the pParse->aBlob[] array
+** is resized (if necessary) so that it is big enough to hold the
+** payload, but the payload is not appended and pParse->nBlob is left
+** pointing to where the first byte of payload will eventually be.
+*/
+static void jsonBlobAppendNode(
+ JsonParse *pParse, /* The JsonParse object under construction */
+ u8 eType, /* Node type. One of JSONB_* */
+ u32 szPayload, /* Number of bytes of payload */
+ const void *aPayload /* The payload. Might be NULL */
+){
+ u8 *a;
+ if( pParse->nBlob+szPayload+9 > pParse->nBlobAlloc ){
+ jsonBlobExpandAndAppendNode(pParse,eType,szPayload,aPayload);
+ return;
+ }
+ assert( pParse->aBlob!=0 );
+ a = &pParse->aBlob[pParse->nBlob];
+ if( szPayload<=11 ){
+ a[0] = eType | (szPayload<<4);
+ pParse->nBlob += 1;
+ }else if( szPayload<=0xff ){
+ a[0] = eType | 0xc0;
+ a[1] = szPayload & 0xff;
+ pParse->nBlob += 2;
+ }else if( szPayload<=0xffff ){
+ a[0] = eType | 0xd0;
+ a[1] = (szPayload >> 8) & 0xff;
+ a[2] = szPayload & 0xff;
+ pParse->nBlob += 3;
+ }else{
+ a[0] = eType | 0xe0;
+ a[1] = (szPayload >> 24) & 0xff;
+ a[2] = (szPayload >> 16) & 0xff;
+ a[3] = (szPayload >> 8) & 0xff;
+ a[4] = szPayload & 0xff;
+ pParse->nBlob += 5;
+ }
+ if( aPayload ){
+ pParse->nBlob += szPayload;
+ memcpy(&pParse->aBlob[pParse->nBlob-szPayload], aPayload, szPayload);
}
- p = &pParse->aNode[pParse->nNode];
- p->eType = (u8)eType;
- p->jnFlags = 0;
- VVA( p->eU = zContent ? 1 : 0 );
- p->n = n;
- p->u.zJContent = zContent;
- return pParse->nNode++;
+}
+
+/* Change the payload size for the node at index i to be szPayload.
+*/
+static int jsonBlobChangePayloadSize(
+ JsonParse *pParse,
+ u32 i,
+ u32 szPayload
+){
+ u8 *a;
+ u8 szType;
+ u8 nExtra;
+ u8 nNeeded;
+ int delta;
+ if( pParse->oom ) return 0;
+ a = &pParse->aBlob[i];
+ szType = a[0]>>4;
+ if( szType<=11 ){
+ nExtra = 0;
+ }else if( szType==12 ){
+ nExtra = 1;
+ }else if( szType==13 ){
+ nExtra = 2;
+ }else{
+ nExtra = 4;
+ }
+ if( szPayload<=11 ){
+ nNeeded = 0;
+ }else if( szPayload<=0xff ){
+ nNeeded = 1;
+ }else if( szPayload<=0xffff ){
+ nNeeded = 2;
+ }else{
+ nNeeded = 4;
+ }
+ delta = nNeeded - nExtra;
+ if( delta ){
+ u32 newSize = pParse->nBlob + delta;
+ if( delta>0 ){
+ if( newSize>pParse->nBlobAlloc && jsonBlobExpand(pParse, newSize) ){
+ return 0; /* OOM error. Error state recorded in pParse->oom. */
+ }
+ a = &pParse->aBlob[i];
+ memmove(&a[1+delta], &a[1], pParse->nBlob - (i+1));
+ }else{
+ memmove(&a[1], &a[1-delta], pParse->nBlob - (i+1-delta));
+ }
+ pParse->nBlob = newSize;
+ }
+ if( nNeeded==0 ){
+ a[0] = (a[0] & 0x0f) | (szPayload<<4);
+ }else if( nNeeded==1 ){
+ a[0] = (a[0] & 0x0f) | 0xc0;
+ a[1] = szPayload & 0xff;
+ }else if( nNeeded==2 ){
+ a[0] = (a[0] & 0x0f) | 0xd0;
+ a[1] = (szPayload >> 8) & 0xff;
+ a[2] = szPayload & 0xff;
+ }else{
+ a[0] = (a[0] & 0x0f) | 0xe0;
+ a[1] = (szPayload >> 24) & 0xff;
+ a[2] = (szPayload >> 16) & 0xff;
+ a[3] = (szPayload >> 8) & 0xff;
+ a[4] = szPayload & 0xff;
+ }
+ return delta;
}
/*
-** Return true if z[] begins with 4 (or more) hexadecimal digits
+** If z[0] is 'u' and is followed by exactly 4 hexadecimal character,
+** then set *pOp to JSONB_TEXTJ and return true. If not, do not make
+** any changes to *pOp and return false.
*/
-static int jsonIs4Hex(const char *z){
- int i;
- for(i=0; i<4; i++) if( !sqlcipher_sqlite3Isxdigit(z[i]) ) return 0;
+static int jsonIs4HexB(const char *z, int *pOp){
+ if( z[0]!='u' ) return 0;
+ if( !jsonIs4Hex(&z[1]) ) return 0;
+ *pOp = JSONB_TEXTJ;
return 1;
}
/*
-** Parse a single JSON value which begins at pParse->zJson[i]. Return the
-** index of the first character past the end of the value parsed.
+** Check a single element of the JSONB in pParse for validity.
+**
+** The element to be checked starts at offset i and must end at on the
+** last byte before iEnd.
+**
+** Return 0 if everything is correct. Return the 1-based byte offset of the
+** error if a problem is detected. (In other words, if the error is at offset
+** 0, return 1).
+*/
+static u32 jsonbValidityCheck(
+ const JsonParse *pParse, /* Input JSONB. Only aBlob and nBlob are used */
+ u32 i, /* Start of element as pParse->aBlob[i] */
+ u32 iEnd, /* One more than the last byte of the element */
+ u32 iDepth /* Current nesting depth */
+){
+ u32 n, sz, j, k;
+ const u8 *z;
+ u8 x;
+ if( iDepth>JSON_MAX_DEPTH ) return i+1;
+ sz = 0;
+ n = jsonbPayloadSize(pParse, i, &sz);
+ if( NEVER(n==0) ) return i+1; /* Checked by caller */
+ if( NEVER(i+n+sz!=iEnd) ) return i+1; /* Checked by caller */
+ z = pParse->aBlob;
+ x = z[i] & 0x0f;
+ switch( x ){
+ case JSONB_NULL:
+ case JSONB_TRUE:
+ case JSONB_FALSE: {
+ return n+sz==1 ? 0 : i+1;
+ }
+ case JSONB_INT: {
+ if( sz<1 ) return i+1;
+ j = i+n;
+ if( z[j]=='-' ){
+ j++;
+ if( sz<2 ) return i+1;
+ }
+ k = i+n+sz;
+ while( j<k ){
+ if( sqlcipher_sqlite3Isdigit(z[j]) ){
+ j++;
+ }else{
+ return j+1;
+ }
+ }
+ return 0;
+ }
+ case JSONB_INT5: {
+ if( sz<3 ) return i+1;
+ j = i+n;
+ if( z[j]=='-' ){
+ if( sz<4 ) return i+1;
+ j++;
+ }
+ if( z[j]!='0' ) return i+1;
+ if( z[j+1]!='x' && z[j+1]!='X' ) return j+2;
+ j += 2;
+ k = i+n+sz;
+ while( j<k ){
+ if( sqlcipher_sqlite3Isxdigit(z[j]) ){
+ j++;
+ }else{
+ return j+1;
+ }
+ }
+ return 0;
+ }
+ case JSONB_FLOAT:
+ case JSONB_FLOAT5: {
+ u8 seen = 0; /* 0: initial. 1: '.' seen 2: 'e' seen */
+ if( sz<2 ) return i+1;
+ j = i+n;
+ k = j+sz;
+ if( z[j]=='-' ){
+ j++;
+ if( sz<3 ) return i+1;
+ }
+ if( z[j]=='.' ){
+ if( x==JSONB_FLOAT ) return j+1;
+ if( !sqlcipher_sqlite3Isdigit(z[j+1]) ) return j+1;
+ j += 2;
+ seen = 1;
+ }else if( z[j]=='0' && x==JSONB_FLOAT ){
+ if( j+3>k ) return j+1;
+ if( z[j+1]!='.' && z[j+1]!='e' && z[j+1]!='E' ) return j+1;
+ j++;
+ }
+ for(; j<k; j++){
+ if( sqlcipher_sqlite3Isdigit(z[j]) ) continue;
+ if( z[j]=='.' ){
+ if( seen>0 ) return j+1;
+ if( x==JSONB_FLOAT && (j==k-1 || !sqlcipher_sqlite3Isdigit(z[j+1])) ){
+ return j+1;
+ }
+ seen = 1;
+ continue;
+ }
+ if( z[j]=='e' || z[j]=='E' ){
+ if( seen==2 ) return j+1;
+ if( j==k-1 ) return j+1;
+ if( z[j+1]=='+' || z[j+1]=='-' ){
+ j++;
+ if( j==k-1 ) return j+1;
+ }
+ seen = 2;
+ continue;
+ }
+ return j+1;
+ }
+ if( seen==0 ) return i+1;
+ return 0;
+ }
+ case JSONB_TEXT: {
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ if( !jsonIsOk[z[j]] && z[j]!='\'' ) return j+1;
+ j++;
+ }
+ return 0;
+ }
+ case JSONB_TEXTJ:
+ case JSONB_TEXT5: {
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ if( !jsonIsOk[z[j]] && z[j]!='\'' ){
+ if( z[j]=='"' ){
+ if( x==JSONB_TEXTJ ) return j+1;
+ }else if( z[j]<=0x1f ){
+ /* Control characters in JSON5 string literals are ok */
+ if( x==JSONB_TEXTJ ) return j+1;
+ }else if( NEVER(z[j]!='\\') || j+1>=k ){
+ return j+1;
+ }else if( strchr("\"\\/bfnrt",z[j+1])!=0 ){
+ j++;
+ }else if( z[j+1]=='u' ){
+ if( j+5>=k ) return j+1;
+ if( !jsonIs4Hex((const char*)&z[j+2]) ) return j+1;
+ j++;
+ }else if( x!=JSONB_TEXT5 ){
+ return j+1;
+ }else{
+ u32 c = 0;
+ u32 szC = jsonUnescapeOneChar((const char*)&z[j], k-j, &c);
+ if( c==JSON_INVALID_CHAR ) return j+1;
+ j += szC - 1;
+ }
+ }
+ j++;
+ }
+ return 0;
+ }
+ case JSONB_TEXTRAW: {
+ return 0;
+ }
+ case JSONB_ARRAY: {
+ u32 sub;
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ sz = 0;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return j+1;
+ if( j+n+sz>k ) return j+1;
+ sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1);
+ if( sub ) return sub;
+ j += n + sz;
+ }
+ assert( j==k );
+ return 0;
+ }
+ case JSONB_OBJECT: {
+ u32 cnt = 0;
+ u32 sub;
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ sz = 0;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return j+1;
+ if( j+n+sz>k ) return j+1;
+ if( (cnt & 1)==0 ){
+ x = z[j] & 0x0f;
+ if( x<JSONB_TEXT || x>JSONB_TEXTRAW ) return j+1;
+ }
+ sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1);
+ if( sub ) return sub;
+ cnt++;
+ j += n + sz;
+ }
+ assert( j==k );
+ if( (cnt & 1)!=0 ) return j+1;
+ return 0;
+ }
+ default: {
+ return i+1;
+ }
+ }
+}
+
+/*
+** Translate a single element of JSON text at pParse->zJson[i] into
+** its equivalent binary JSONB representation. Append the translation into
+** pParse->aBlob[] beginning at pParse->nBlob. The size of
+** pParse->aBlob[] is increased as necessary.
+**
+** Return the index of the first character past the end of the element parsed,
+** or one of the following special result codes:
**
-** Return negative for a syntax error. Special cases: return -2 if the
-** first non-whitespace character is '}' and return -3 if the first
-** non-whitespace character is ']'.
+** 0 End of input
+** -1 Syntax error or OOM
+** -2 '}' seen \
+** -3 ']' seen \___ For these returns, pParse->iErr is set to
+** -4 ',' seen / the index in zJson[] of the seen character
+** -5 ':' seen /
*/
-static int jsonParseValue(JsonParse *pParse, u32 i){
+static int jsonTranslateTextToBlob(JsonParse *pParse, u32 i){
char c;
u32 j;
- int iThis;
+ u32 iThis, iStart;
int x;
- JsonNode *pNode;
+ u8 t;
const char *z = pParse->zJson;
- while( fast_isspace(z[i]) ){ i++; }
- if( (c = z[i])=='{' ){
+json_parse_restart:
+ switch( (u8)z[i] ){
+ case '{': {
/* Parse object */
- iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
- if( iThis<0 ) return -1;
+ iThis = pParse->nBlob;
+ jsonBlobAppendNode(pParse, JSONB_OBJECT, pParse->nJson-i, 0);
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+ pParse->iErr = i;
+ return -1;
+ }
+ iStart = pParse->nBlob;
for(j=i+1;;j++){
- while( fast_isspace(z[j]) ){ j++; }
- if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
- x = jsonParseValue(pParse, j);
- if( x<0 ){
- pParse->iDepth--;
- if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
- return -1;
+ u32 iBlob = pParse->nBlob;
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x<=0 ){
+ int op;
+ if( x==(-2) ){
+ j = pParse->iErr;
+ if( pParse->nBlob!=(u32)iStart ) pParse->hasNonstd = 1;
+ break;
+ }
+ j += json5Whitespace(&z[j]);
+ op = JSONB_TEXT;
+ if( sqlcipher_sqlite3JsonId1(z[j])
+ || (z[j]=='\\' && jsonIs4HexB(&z[j+1], &op))
+ ){
+ int k = j+1;
+ while( (sqlcipher_sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0)
+ || (z[k]=='\\' && jsonIs4HexB(&z[k+1], &op))
+ ){
+ k++;
+ }
+ assert( iBlob==pParse->nBlob );
+ jsonBlobAppendNode(pParse, op, k-j, &z[j]);
+ pParse->hasNonstd = 1;
+ x = k;
+ }else{
+ if( x!=-1 ) pParse->iErr = j;
+ return -1;
+ }
}
if( pParse->oom ) return -1;
- pNode = &pParse->aNode[pParse->nNode-1];
- if( pNode->eType!=JSON_STRING ) return -1;
- pNode->jnFlags |= JNODE_LABEL;
+ t = pParse->aBlob[iBlob] & 0x0f;
+ if( t<JSONB_TEXT || t>JSONB_TEXTRAW ){
+ pParse->iErr = j;
+ return -1;
+ }
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- if( z[j]!=':' ) return -1;
- j++;
- x = jsonParseValue(pParse, j);
- pParse->iDepth--;
- if( x<0 ) return -1;
+ if( z[j]==':' ){
+ j++;
+ }else{
+ if( jsonIsspace(z[j]) ){
+ /* strspn() is not helpful here */
+ do{ j++; }while( jsonIsspace(z[j]) );
+ if( z[j]==':' ){
+ j++;
+ goto parse_object_value;
+ }
+ }
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x!=(-5) ){
+ if( x!=(-1) ) pParse->iErr = j;
+ return -1;
+ }
+ j = pParse->iErr+1;
+ }
+ parse_object_value:
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x<=0 ){
+ if( x!=(-1) ) pParse->iErr = j;
+ return -1;
+ }
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- c = z[j];
- if( c==',' ) continue;
- if( c!='}' ) return -1;
- break;
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]=='}' ){
+ break;
+ }else{
+ if( jsonIsspace(z[j]) ){
+ j += 1 + (u32)strspn(&z[j+1], jsonSpaces);
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]=='}' ){
+ break;
+ }
+ }
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x==(-4) ){
+ j = pParse->iErr;
+ continue;
+ }
+ if( x==(-2) ){
+ j = pParse->iErr;
+ break;
+ }
+ }
+ pParse->iErr = j;
+ return -1;
}
- pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart);
+ pParse->iDepth--;
return j+1;
- }else if( c=='[' ){
+ }
+ case '[': {
/* Parse array */
- iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
- if( iThis<0 ) return -1;
- memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u));
+ iThis = pParse->nBlob;
+ assert( i<=(u32)pParse->nJson );
+ jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0);
+ iStart = pParse->nBlob;
+ if( pParse->oom ) return -1;
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+ pParse->iErr = i;
+ return -1;
+ }
for(j=i+1;;j++){
- while( fast_isspace(z[j]) ){ j++; }
- if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
- x = jsonParseValue(pParse, j);
- pParse->iDepth--;
- if( x<0 ){
- if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x<=0 ){
+ if( x==(-3) ){
+ j = pParse->iErr;
+ if( pParse->nBlob!=iStart ) pParse->hasNonstd = 1;
+ break;
+ }
+ if( x!=(-1) ) pParse->iErr = j;
return -1;
}
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- c = z[j];
- if( c==',' ) continue;
- if( c!=']' ) return -1;
- break;
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]==']' ){
+ break;
+ }else{
+ if( jsonIsspace(z[j]) ){
+ j += 1 + (u32)strspn(&z[j+1], jsonSpaces);
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]==']' ){
+ break;
+ }
+ }
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x==(-4) ){
+ j = pParse->iErr;
+ continue;
+ }
+ if( x==(-3) ){
+ j = pParse->iErr;
+ break;
+ }
+ }
+ pParse->iErr = j;
+ return -1;
}
- pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart);
+ pParse->iDepth--;
return j+1;
- }else if( c=='"' ){
+ }
+ case '\'': {
+ u8 opcode;
+ char cDelim;
+ pParse->hasNonstd = 1;
+ opcode = JSONB_TEXT;
+ goto parse_string;
+ case '"':
/* Parse string */
- u8 jnFlags = 0;
+ opcode = JSONB_TEXT;
+ parse_string:
+ cDelim = z[i];
j = i+1;
- for(;;){
- c = z[j];
- if( (c & ~0x1f)==0 ){
- /* Control characters are not allowed in strings */
- return -1;
+ while( 1 /*exit-by-break*/ ){
+ if( jsonIsOk[(u8)z[j]] ){
+ if( !jsonIsOk[(u8)z[j+1]] ){
+ j += 1;
+ }else if( !jsonIsOk[(u8)z[j+2]] ){
+ j += 2;
+ }else{
+ j += 3;
+ continue;
+ }
}
- if( c=='\\' ){
+ c = z[j];
+ if( c==cDelim ){
+ break;
+ }else if( c=='\\' ){
c = z[++j];
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|| c=='n' || c=='r' || c=='t'
- || (c=='u' && jsonIs4Hex(z+j+1)) ){
- jnFlags = JNODE_ESCAPE;
+ || (c=='u' && jsonIs4Hex(&z[j+1])) ){
+ if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ;
+ }else if( c=='\'' || c=='0' || c=='v' || c=='\n'
+ || (0xe2==(u8)c && 0x80==(u8)z[j+1]
+ && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]))
+ || (c=='x' && jsonIs2Hex(&z[j+1])) ){
+ opcode = JSONB_TEXT5;
+ pParse->hasNonstd = 1;
+ }else if( c=='\r' ){
+ if( z[j+1]=='\n' ) j++;
+ opcode = JSONB_TEXT5;
+ pParse->hasNonstd = 1;
}else{
+ pParse->iErr = j;
+ return -1;
+ }
+ }else if( c<=0x1f ){
+ if( c==0 ){
+ pParse->iErr = j;
return -1;
}
+ /* Control characters are not allowed in canonical JSON string
+ ** literals, but are allowed in JSON5 string literals. */
+ opcode = JSONB_TEXT5;
+ pParse->hasNonstd = 1;
}else if( c=='"' ){
- break;
+ opcode = JSONB_TEXT5;
}
j++;
}
- jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
- if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
+ jsonBlobAppendNode(pParse, opcode, j-1-i, &z[i+1]);
return j+1;
- }else if( c=='n'
- && strncmp(z+i,"null",4)==0
- && !sqlcipher_sqlite3Isalnum(z[i+4]) ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return i+4;
- }else if( c=='t'
- && strncmp(z+i,"true",4)==0
- && !sqlcipher_sqlite3Isalnum(z[i+4]) ){
- jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
- return i+4;
- }else if( c=='f'
- && strncmp(z+i,"false",5)==0
- && !sqlcipher_sqlite3Isalnum(z[i+5]) ){
- jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
- return i+5;
- }else if( c=='-' || (c>='0' && c<='9') ){
+ }
+ case 't': {
+ if( strncmp(z+i,"true",4)==0 && !sqlcipher_sqlite3Isalnum(z[i+4]) ){
+ jsonBlobAppendOneByte(pParse, JSONB_TRUE);
+ return i+4;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case 'f': {
+ if( strncmp(z+i,"false",5)==0 && !sqlcipher_sqlite3Isalnum(z[i+5]) ){
+ jsonBlobAppendOneByte(pParse, JSONB_FALSE);
+ return i+5;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case '+': {
+ u8 seenE;
+ pParse->hasNonstd = 1;
+ t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */
+ goto parse_number;
+ case '.':
+ if( sqlcipher_sqlite3Isdigit(z[i+1]) ){
+ pParse->hasNonstd = 1;
+ t = 0x03; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */
+ seenE = 0;
+ goto parse_number_2;
+ }
+ pParse->iErr = i;
+ return -1;
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
/* Parse number */
- u8 seenDP = 0;
- u8 seenE = 0;
+ t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */
+ parse_number:
+ seenE = 0;
assert( '-' < '0' );
+ assert( '+' < '0' );
+ assert( '.' < '0' );
+ c = z[i];
+
if( c<='0' ){
- j = c=='-' ? i+1 : i;
- if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
+ if( c=='0' ){
+ if( (z[i+1]=='x' || z[i+1]=='X') && sqlcipher_sqlite3Isxdigit(z[i+2]) ){
+ assert( t==0x00 );
+ pParse->hasNonstd = 1;
+ t = 0x01;
+ for(j=i+3; sqlcipher_sqlite3Isxdigit(z[j]); j++){}
+ goto parse_number_finish;
+ }else if( sqlcipher_sqlite3Isdigit(z[i+1]) ){
+ pParse->iErr = i+1;
+ return -1;
+ }
+ }else{
+ if( !sqlcipher_sqlite3Isdigit(z[i+1]) ){
+ /* JSON5 allows for "+Infinity" and "-Infinity" using exactly
+ ** that case. SQLite also allows these in any case and it allows
+ ** "+inf" and "-inf". */
+ if( (z[i+1]=='I' || z[i+1]=='i')
+ && sqlcipher_sqlite3StrNICmp(&z[i+1], "inf",3)==0
+ ){
+ pParse->hasNonstd = 1;
+ if( z[i]=='-' ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999");
+ }else{
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
+ }
+ return i + (sqlcipher_sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4);
+ }
+ if( z[i+1]=='.' ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ goto parse_number_2;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ if( z[i+1]=='0' ){
+ if( sqlcipher_sqlite3Isdigit(z[i+2]) ){
+ pParse->iErr = i+1;
+ return -1;
+ }else if( (z[i+2]=='x' || z[i+2]=='X') && sqlcipher_sqlite3Isxdigit(z[i+3]) ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ for(j=i+4; sqlcipher_sqlite3Isxdigit(z[j]); j++){}
+ goto parse_number_finish;
+ }
+ }
+ }
}
- j = i+1;
- for(;; j++){
+
+ parse_number_2:
+ for(j=i+1;; j++){
c = z[j];
- if( c>='0' && c<='9' ) continue;
+ if( sqlcipher_sqlite3Isdigit(c) ) continue;
if( c=='.' ){
- if( z[j-1]=='-' ) return -1;
- if( seenDP ) return -1;
- seenDP = 1;
+ if( (t & 0x02)!=0 ){
+ pParse->iErr = j;
+ return -1;
+ }
+ t |= 0x02;
continue;
}
if( c=='e' || c=='E' ){
- if( z[j-1]<'0' ) return -1;
- if( seenE ) return -1;
- seenDP = seenE = 1;
+ if( z[j-1]<'0' ){
+ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlcipher_sqlite3Isdigit(z[j-2]) ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ }else{
+ pParse->iErr = j;
+ return -1;
+ }
+ }
+ if( seenE ){
+ pParse->iErr = j;
+ return -1;
+ }
+ t |= 0x02;
+ seenE = 1;
c = z[j+1];
if( c=='+' || c=='-' ){
j++;
c = z[j+1];
}
- if( c<'0' || c>'9' ) return -1;
+ if( c<'0' || c>'9' ){
+ pParse->iErr = j;
+ return -1;
+ }
continue;
}
break;
}
- if( z[j-1]<'0' ) return -1;
- jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
- j - i, &z[i]);
+ if( z[j-1]<'0' ){
+ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlcipher_sqlite3Isdigit(z[j-2]) ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ }else{
+ pParse->iErr = j;
+ return -1;
+ }
+ }
+ parse_number_finish:
+ assert( JSONB_INT+0x01==JSONB_INT5 );
+ assert( JSONB_FLOAT+0x01==JSONB_FLOAT5 );
+ assert( JSONB_INT+0x02==JSONB_FLOAT );
+ if( z[i]=='+' ) i++;
+ jsonBlobAppendNode(pParse, JSONB_INT+t, j-i, &z[i]);
return j;
- }else if( c=='}' ){
+ }
+ case '}': {
+ pParse->iErr = i;
return -2; /* End of {...} */
- }else if( c==']' ){
+ }
+ case ']': {
+ pParse->iErr = i;
return -3; /* End of [...] */
- }else if( c==0 ){
+ }
+ case ',': {
+ pParse->iErr = i;
+ return -4; /* List separator */
+ }
+ case ':': {
+ pParse->iErr = i;
+ return -5; /* Object label/value separator */
+ }
+ case 0: {
return 0; /* End of file */
- }else{
+ }
+ case 0x09:
+ case 0x0a:
+ case 0x0d:
+ case 0x20: {
+ i += 1 + (u32)strspn(&z[i+1], jsonSpaces);
+ goto json_parse_restart;
+ }
+ case 0x0b:
+ case 0x0c:
+ case '/':
+ case 0xc2:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xef: {
+ j = json5Whitespace(&z[i]);
+ if( j>0 ){
+ i += j;
+ pParse->hasNonstd = 1;
+ goto json_parse_restart;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case 'n': {
+ if( strncmp(z+i,"null",4)==0 && !sqlcipher_sqlite3Isalnum(z[i+4]) ){
+ jsonBlobAppendOneByte(pParse, JSONB_NULL);
+ return i+4;
+ }
+ /* fall-through into the default case that checks for NaN */
+ /* no break */ deliberate_fall_through
+ }
+ default: {
+ u32 k;
+ int nn;
+ c = z[i];
+ for(k=0; k<sizeof(aNanInfName)/sizeof(aNanInfName[0]); k++){
+ if( c!=aNanInfName[k].c1 && c!=aNanInfName[k].c2 ) continue;
+ nn = aNanInfName[k].n;
+ if( sqlcipher_sqlite3StrNICmp(&z[i], aNanInfName[k].zMatch, nn)!=0 ){
+ continue;
+ }
+ if( sqlcipher_sqlite3Isalnum(z[i+nn]) ) continue;
+ if( aNanInfName[k].eType==JSONB_FLOAT ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
+ }else{
+ jsonBlobAppendOneByte(pParse, JSONB_NULL);
+ }
+ pParse->hasNonstd = 1;
+ return i + nn;
+ }
+ pParse->iErr = i;
return -1; /* Syntax error */
}
+ } /* End switch(z[i]) */
}
+
/*
** Parse a complete JSON string. Return 0 on success or non-zero if there
-** are any errors. If an error occurs, free all memory associated with
-** pParse.
+** are any errors. If an error occurs, free all memory held by pParse,
+** but not pParse itself.
**
-** pParse is uninitialized when this routine is called.
+** pParse must be initialized to an empty parse object prior to calling
+** this routine.
*/
-static int jsonParse(
+static int jsonConvertTextToBlob(
JsonParse *pParse, /* Initialize and fill this JsonParse object */
- sqlcipher_sqlite3_context *pCtx, /* Report errors here */
- const char *zJson /* Input JSON text to be parsed */
+ sqlcipher_sqlite3_context *pCtx /* Report errors here */
){
int i;
- memset(pParse, 0, sizeof(*pParse));
- if( zJson==0 ) return 1;
- pParse->zJson = zJson;
- i = jsonParseValue(pParse, 0);
+ const char *zJson = pParse->zJson;
+ i = jsonTranslateTextToBlob(pParse, 0);
if( pParse->oom ) i = -1;
if( i>0 ){
+#ifdef SQLITE_DEBUG
assert( pParse->iDepth==0 );
- while( fast_isspace(zJson[i]) ) i++;
- if( zJson[i] ) i = -1;
+ if( sqlcipher_sqlite3Config.bJsonSelfcheck ){
+ assert( jsonbValidityCheck(pParse, 0, pParse->nBlob, 0)==0 );
+ }
+#endif
+ while( jsonIsspace(zJson[i]) ) i++;
+ if( zJson[i] ){
+ i += json5Whitespace(&zJson[i]);
+ if( zJson[i] ){
+ if( pCtx ) sqlcipher_sqlite3_result_error(pCtx, "malformed JSON", -1);
+ jsonParseReset(pParse);
+ return 1;
+ }
+ pParse->hasNonstd = 1;
+ }
}
if( i<=0 ){
if( pCtx!=0 ){
@@ -201820,161 +212177,832 @@ static int jsonParse(
return 0;
}
-/* Mark node i of pParse as being a child of iParent. Call recursively
-** to fill in all the descendants of node i.
+/*
+** The input string pStr is a well-formed JSON text string. Convert
+** this into the JSONB format and make it the return value of the
+** SQL function.
*/
-static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
- JsonNode *pNode = &pParse->aNode[i];
- u32 j;
- pParse->aUp[i] = iParent;
- switch( pNode->eType ){
- case JSON_ARRAY: {
- for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
- jsonParseFillInParentage(pParse, i+j, i);
+static void jsonReturnStringAsBlob(JsonString *pStr){
+ JsonParse px;
+ memset(&px, 0, sizeof(px));
+ jsonStringTerminate(pStr);
+ if( pStr->eErr ){
+ sqlcipher_sqlite3_result_error_nomem(pStr->pCtx);
+ return;
+ }
+ px.zJson = pStr->zBuf;
+ px.nJson = pStr->nUsed;
+ px.db = sqlcipher_sqlite3_context_db_handle(pStr->pCtx);
+ (void)jsonTranslateTextToBlob(&px, 0);
+ if( px.oom ){
+ sqlcipher_sqlite3DbFree(px.db, px.aBlob);
+ sqlcipher_sqlite3_result_error_nomem(pStr->pCtx);
+ }else{
+ assert( px.nBlobAlloc>0 );
+ assert( !px.bReadOnly );
+ sqlcipher_sqlite3_result_blob(pStr->pCtx, px.aBlob, px.nBlob, SQLITE_DYNAMIC);
+ }
+}
+
+/* The byte at index i is a node type-code. This routine
+** determines the payload size for that node and writes that
+** payload size in to *pSz. It returns the offset from i to the
+** beginning of the payload. Return 0 on error.
+*/
+static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
+ u8 x;
+ u32 sz;
+ u32 n;
+ if( NEVER(i>pParse->nBlob) ){
+ *pSz = 0;
+ return 0;
+ }
+ x = pParse->aBlob[i]>>4;
+ if( x<=11 ){
+ sz = x;
+ n = 1;
+ }else if( x==12 ){
+ if( i+1>=pParse->nBlob ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = pParse->aBlob[i+1];
+ n = 2;
+ }else if( x==13 ){
+ if( i+2>=pParse->nBlob ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = (pParse->aBlob[i+1]<<8) + pParse->aBlob[i+2];
+ n = 3;
+ }else if( x==14 ){
+ if( i+4>=pParse->nBlob ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = ((u32)pParse->aBlob[i+1]<<24) + (pParse->aBlob[i+2]<<16) +
+ (pParse->aBlob[i+3]<<8) + pParse->aBlob[i+4];
+ n = 5;
+ }else{
+ if( i+8>=pParse->nBlob
+ || pParse->aBlob[i+1]!=0
+ || pParse->aBlob[i+2]!=0
+ || pParse->aBlob[i+3]!=0
+ || pParse->aBlob[i+4]!=0
+ ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) +
+ (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8];
+ n = 9;
+ }
+ if( (i64)i+sz+n > pParse->nBlob
+ && (i64)i+sz+n > pParse->nBlob-pParse->delta
+ ){
+ sz = 0;
+ n = 0;
+ }
+ *pSz = sz;
+ return n;
+}
+
+
+/*
+** Translate the binary JSONB representation of JSON beginning at
+** pParse->aBlob[i] into a JSON text string. Append the JSON
+** text onto the end of pOut. Return the index in pParse->aBlob[]
+** of the first byte past the end of the element that is translated.
+**
+** If an error is detected in the BLOB input, the pOut->eErr flag
+** might get set to JSTRING_MALFORMED. But not all BLOB input errors
+** are detected. So a malformed JSONB input might either result
+** in an error, or in incorrect JSON.
+**
+** The pOut->eErr JSTRING_OOM flag is set on a OOM.
+*/
+static u32 jsonTranslateBlobToText(
+ const JsonParse *pParse, /* the complete parse of the JSON */
+ u32 i, /* Start rendering at this index */
+ JsonString *pOut /* Write JSON here */
+){
+ u32 sz, n, j, iEnd;
+
+ n = jsonbPayloadSize(pParse, i, &sz);
+ if( n==0 ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ return pParse->nBlob+1;
+ }
+ switch( pParse->aBlob[i] & 0x0f ){
+ case JSONB_NULL: {
+ jsonAppendRawNZ(pOut, "null", 4);
+ return i+1;
+ }
+ case JSONB_TRUE: {
+ jsonAppendRawNZ(pOut, "true", 4);
+ return i+1;
+ }
+ case JSONB_FALSE: {
+ jsonAppendRawNZ(pOut, "false", 5);
+ return i+1;
+ }
+ case JSONB_INT:
+ case JSONB_FLOAT: {
+ if( sz==0 ) goto malformed_jsonb;
+ jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz);
+ break;
+ }
+ case JSONB_INT5: { /* Integer literal in hexadecimal notation */
+ u32 k = 2;
+ sqlcipher_sqlite3_uint64 u = 0;
+ const char *zIn = (const char*)&pParse->aBlob[i+n];
+ int bOverflow = 0;
+ if( sz==0 ) goto malformed_jsonb;
+ if( zIn[0]=='-' ){
+ jsonAppendChar(pOut, '-');
+ k++;
+ }else if( zIn[0]=='+' ){
+ k++;
+ }
+ for(; k<sz; k++){
+ if( !sqlcipher_sqlite3Isxdigit(zIn[k]) ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ break;
+ }else if( (u>>60)!=0 ){
+ bOverflow = 1;
+ }else{
+ u = u*16 + sqlcipher_sqlite3HexToInt(zIn[k]);
+ }
}
+ jsonPrintf(100,pOut,bOverflow?"9.0e999":"%llu", u);
break;
}
- case JSON_OBJECT: {
- for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
- pParse->aUp[i+j] = i;
- jsonParseFillInParentage(pParse, i+j+1, i);
+ case JSONB_FLOAT5: { /* Float literal missing digits beside "." */
+ u32 k = 0;
+ const char *zIn = (const char*)&pParse->aBlob[i+n];
+ if( sz==0 ) goto malformed_jsonb;
+ if( zIn[0]=='-' ){
+ jsonAppendChar(pOut, '-');
+ k++;
+ }
+ if( zIn[k]=='.' ){
+ jsonAppendChar(pOut, '0');
+ }
+ for(; k<sz; k++){
+ jsonAppendChar(pOut, zIn[k]);
+ if( zIn[k]=='.' && (k+1==sz || !sqlcipher_sqlite3Isdigit(zIn[k+1])) ){
+ jsonAppendChar(pOut, '0');
+ }
}
break;
}
+ case JSONB_TEXT:
+ case JSONB_TEXTJ: {
+ jsonAppendChar(pOut, '"');
+ jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz);
+ jsonAppendChar(pOut, '"');
+ break;
+ }
+ case JSONB_TEXT5: {
+ const char *zIn;
+ u32 k;
+ u32 sz2 = sz;
+ zIn = (const char*)&pParse->aBlob[i+n];
+ jsonAppendChar(pOut, '"');
+ while( sz2>0 ){
+ for(k=0; k<sz2 && (jsonIsOk[(u8)zIn[k]] || zIn[k]=='\''); k++){}
+ if( k>0 ){
+ jsonAppendRawNZ(pOut, zIn, k);
+ if( k>=sz2 ){
+ break;
+ }
+ zIn += k;
+ sz2 -= k;
+ }
+ if( zIn[0]=='"' ){
+ jsonAppendRawNZ(pOut, "\\\"", 2);
+ zIn++;
+ sz2--;
+ continue;
+ }
+ if( zIn[0]<=0x1f ){
+ if( pOut->nUsed+7>pOut->nAlloc && jsonStringGrow(pOut,7) ) break;
+ jsonAppendControlChar(pOut, zIn[0]);
+ zIn++;
+ sz2--;
+ continue;
+ }
+ assert( zIn[0]=='\\' );
+ assert( sz2>=1 );
+ if( sz2<2 ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ break;
+ }
+ switch( (u8)zIn[1] ){
+ case '\'':
+ jsonAppendChar(pOut, '\'');
+ break;
+ case 'v':
+ jsonAppendRawNZ(pOut, "\\u0009", 6);
+ break;
+ case 'x':
+ if( sz2<4 ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ sz2 = 2;
+ break;
+ }
+ jsonAppendRawNZ(pOut, "\\u00", 4);
+ jsonAppendRawNZ(pOut, &zIn[2], 2);
+ zIn += 2;
+ sz2 -= 2;
+ break;
+ case '0':
+ jsonAppendRawNZ(pOut, "\\u0000", 6);
+ break;
+ case '\r':
+ if( sz2>2 && zIn[2]=='\n' ){
+ zIn++;
+ sz2--;
+ }
+ break;
+ case '\n':
+ break;
+ case 0xe2:
+ /* '\' followed by either U+2028 or U+2029 is ignored as
+ ** whitespace. Not that in UTF8, U+2028 is 0xe2 0x80 0x29.
+ ** U+2029 is the same except for the last byte */
+ if( sz2<4
+ || 0x80!=(u8)zIn[2]
+ || (0xa8!=(u8)zIn[3] && 0xa9!=(u8)zIn[3])
+ ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ sz2 = 2;
+ break;
+ }
+ zIn += 2;
+ sz2 -= 2;
+ break;
+ default:
+ jsonAppendRawNZ(pOut, zIn, 2);
+ break;
+ }
+ assert( sz2>=2 );
+ zIn += 2;
+ sz2 -= 2;
+ }
+ jsonAppendChar(pOut, '"');
+ break;
+ }
+ case JSONB_TEXTRAW: {
+ jsonAppendString(pOut, (const char*)&pParse->aBlob[i+n], sz);
+ break;
+ }
+ case JSONB_ARRAY: {
+ jsonAppendChar(pOut, '[');
+ j = i+n;
+ iEnd = j+sz;
+ while( j<iEnd && pOut->eErr==0 ){
+ j = jsonTranslateBlobToText(pParse, j, pOut);
+ jsonAppendChar(pOut, ',');
+ }
+ if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
+ if( sz>0 ) jsonStringTrimOneChar(pOut);
+ jsonAppendChar(pOut, ']');
+ break;
+ }
+ case JSONB_OBJECT: {
+ int x = 0;
+ jsonAppendChar(pOut, '{');
+ j = i+n;
+ iEnd = j+sz;
+ while( j<iEnd && pOut->eErr==0 ){
+ j = jsonTranslateBlobToText(pParse, j, pOut);
+ jsonAppendChar(pOut, (x++ & 1) ? ',' : ':');
+ }
+ if( (x & 1)!=0 || j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
+ if( sz>0 ) jsonStringTrimOneChar(pOut);
+ jsonAppendChar(pOut, '}');
+ break;
+ }
+
default: {
+ malformed_jsonb:
+ pOut->eErr |= JSTRING_MALFORMED;
break;
}
}
+ return i+n+sz;
+}
+
+/* Context for recursion of json_pretty()
+*/
+typedef struct JsonPretty JsonPretty;
+struct JsonPretty {
+ JsonParse *pParse; /* The BLOB being rendered */
+ JsonString *pOut; /* Generate pretty output into this string */
+ const char *zIndent; /* Use this text for indentation */
+ u32 szIndent; /* Bytes in zIndent[] */
+ u32 nIndent; /* Current level of indentation */
+};
+
+/* Append indentation to the pretty JSON under construction */
+static void jsonPrettyIndent(JsonPretty *pPretty){
+ u32 jj;
+ for(jj=0; jj<pPretty->nIndent; jj++){
+ jsonAppendRaw(pPretty->pOut, pPretty->zIndent, pPretty->szIndent);
+ }
}
/*
-** Compute the parentage of all nodes in a completed parse.
+** Translate the binary JSONB representation of JSON beginning at
+** pParse->aBlob[i] into a JSON text string. Append the JSON
+** text onto the end of pOut. Return the index in pParse->aBlob[]
+** of the first byte past the end of the element that is translated.
+**
+** This is a variant of jsonTranslateBlobToText() that "pretty-prints"
+** the output. Extra whitespace is inserted to make the JSON easier
+** for humans to read.
+**
+** If an error is detected in the BLOB input, the pOut->eErr flag
+** might get set to JSTRING_MALFORMED. But not all BLOB input errors
+** are detected. So a malformed JSONB input might either result
+** in an error, or in incorrect JSON.
+**
+** The pOut->eErr JSTRING_OOM flag is set on a OOM.
*/
-static int jsonParseFindParents(JsonParse *pParse){
- u32 *aUp;
- assert( pParse->aUp==0 );
- aUp = pParse->aUp = sqlcipher_sqlite3_malloc64( sizeof(u32)*pParse->nNode );
- if( aUp==0 ){
- pParse->oom = 1;
- return SQLITE_NOMEM;
+static u32 jsonTranslateBlobToPrettyText(
+ JsonPretty *pPretty, /* Pretty-printing context */
+ u32 i /* Start rendering at this index */
+){
+ u32 sz, n, j, iEnd;
+ const JsonParse *pParse = pPretty->pParse;
+ JsonString *pOut = pPretty->pOut;
+ n = jsonbPayloadSize(pParse, i, &sz);
+ if( n==0 ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ return pParse->nBlob+1;
}
- jsonParseFillInParentage(pParse, 0, 0);
- return SQLITE_OK;
+ switch( pParse->aBlob[i] & 0x0f ){
+ case JSONB_ARRAY: {
+ j = i+n;
+ iEnd = j+sz;
+ jsonAppendChar(pOut, '[');
+ if( j<iEnd ){
+ jsonAppendChar(pOut, '\n');
+ pPretty->nIndent++;
+ while( pOut->eErr==0 ){
+ jsonPrettyIndent(pPretty);
+ j = jsonTranslateBlobToPrettyText(pPretty, j);
+ if( j>=iEnd ) break;
+ jsonAppendRawNZ(pOut, ",\n", 2);
+ }
+ jsonAppendChar(pOut, '\n');
+ pPretty->nIndent--;
+ jsonPrettyIndent(pPretty);
+ }
+ jsonAppendChar(pOut, ']');
+ i = iEnd;
+ break;
+ }
+ case JSONB_OBJECT: {
+ j = i+n;
+ iEnd = j+sz;
+ jsonAppendChar(pOut, '{');
+ if( j<iEnd ){
+ jsonAppendChar(pOut, '\n');
+ pPretty->nIndent++;
+ while( pOut->eErr==0 ){
+ jsonPrettyIndent(pPretty);
+ j = jsonTranslateBlobToText(pParse, j, pOut);
+ if( j>iEnd ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ break;
+ }
+ jsonAppendRawNZ(pOut, ": ", 2);
+ j = jsonTranslateBlobToPrettyText(pPretty, j);
+ if( j>=iEnd ) break;
+ jsonAppendRawNZ(pOut, ",\n", 2);
+ }
+ jsonAppendChar(pOut, '\n');
+ pPretty->nIndent--;
+ jsonPrettyIndent(pPretty);
+ }
+ jsonAppendChar(pOut, '}');
+ i = iEnd;
+ break;
+ }
+ default: {
+ i = jsonTranslateBlobToText(pParse, i, pOut);
+ break;
+ }
+ }
+ return i;
+}
+
+
+/* Return true if the input pJson
+**
+** For performance reasons, this routine does not do a detailed check of the
+** input BLOB to ensure that it is well-formed. Hence, false positives are
+** possible. False negatives should never occur, however.
+*/
+static int jsonFuncArgMightBeBinary(sqlcipher_sqlite3_value *pJson){
+ u32 sz, n;
+ const u8 *aBlob;
+ int nBlob;
+ JsonParse s;
+ if( sqlcipher_sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0;
+ aBlob = sqlcipher_sqlite3_value_blob(pJson);
+ nBlob = sqlcipher_sqlite3_value_bytes(pJson);
+ if( nBlob<1 ) return 0;
+ if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0;
+ memset(&s, 0, sizeof(s));
+ s.aBlob = (u8*)aBlob;
+ s.nBlob = nBlob;
+ n = jsonbPayloadSize(&s, 0, &sz);
+ if( n==0 ) return 0;
+ if( sz+n!=(u32)nBlob ) return 0;
+ if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0;
+ return sz+n==(u32)nBlob;
}
/*
-** Magic number used for the JSON parse cache in sqlcipher_sqlite3_get_auxdata()
+** Given that a JSONB_ARRAY object starts at offset i, return
+** the number of entries in that array.
*/
-#define JSON_CACHE_ID (-429938) /* First cache entry */
-#define JSON_CACHE_SZ 4 /* Max number of cache entries */
+static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){
+ u32 n, sz, i, iEnd;
+ u32 k = 0;
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ iEnd = iRoot+n+sz;
+ for(i=iRoot+n; n>0 && i<iEnd; i+=sz+n, k++){
+ n = jsonbPayloadSize(pParse, i, &sz);
+ }
+ return k;
+}
/*
-** Obtain a complete parse of the JSON found in the first argument
-** of the argv array. Use the sqlcipher_sqlite3_get_auxdata() cache for this
-** parse if it is available. If the cache is not available or if it
-** is no longer valid, parse the JSON again and return the new parse,
-** and also register the new parse so that it will be available for
-** future sqlcipher_sqlite3_get_auxdata() calls.
+** Edit the payload size of the element at iRoot by the amount in
+** pParse->delta.
*/
-static JsonParse *jsonParseCached(
- sqlcipher_sqlite3_context *pCtx,
- sqlcipher_sqlite3_value **argv,
- sqlcipher_sqlite3_context *pErrCtx
+static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){
+ u32 sz = 0;
+ u32 nBlob;
+ assert( pParse->delta!=0 );
+ assert( pParse->nBlobAlloc >= pParse->nBlob );
+ nBlob = pParse->nBlob;
+ pParse->nBlob = pParse->nBlobAlloc;
+ (void)jsonbPayloadSize(pParse, iRoot, &sz);
+ pParse->nBlob = nBlob;
+ sz += pParse->delta;
+ pParse->delta += jsonBlobChangePayloadSize(pParse, iRoot, sz);
+}
+
+/*
+** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of
+** content beginning at iDel, and replacing them with nIns bytes of
+** content given by aIns.
+**
+** nDel may be zero, in which case no bytes are removed. But iDel is
+** still important as new bytes will be insert beginning at iDel.
+**
+** aIns may be zero, in which case space is created to hold nIns bytes
+** beginning at iDel, but that space is uninitialized.
+**
+** Set pParse->oom if an OOM occurs.
+*/
+static void jsonBlobEdit(
+ JsonParse *pParse, /* The JSONB to be modified is in pParse->aBlob */
+ u32 iDel, /* First byte to be removed */
+ u32 nDel, /* Number of bytes to remove */
+ const u8 *aIns, /* Content to insert */
+ u32 nIns /* Bytes of content to insert */
){
- const char *zJson = (const char*)sqlcipher_sqlite3_value_text(argv[0]);
- int nJson = sqlcipher_sqlite3_value_bytes(argv[0]);
- JsonParse *p;
- JsonParse *pMatch = 0;
- int iKey;
- int iMinKey = 0;
- u32 iMinHold = 0xffffffff;
- u32 iMaxHold = 0;
- if( zJson==0 ) return 0;
- for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){
- p = (JsonParse*)sqlcipher_sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey);
- if( p==0 ){
- iMinKey = iKey;
- break;
+ i64 d = (i64)nIns - (i64)nDel;
+ if( d!=0 ){
+ if( pParse->nBlob + d > pParse->nBlobAlloc ){
+ jsonBlobExpand(pParse, pParse->nBlob+d);
+ if( pParse->oom ) return;
}
- if( pMatch==0
- && p->nJson==nJson
- && memcmp(p->zJson,zJson,nJson)==0
- ){
- p->nErr = 0;
- pMatch = p;
- }else if( p->iHold<iMinHold ){
- iMinHold = p->iHold;
- iMinKey = iKey;
+ memmove(&pParse->aBlob[iDel+nIns],
+ &pParse->aBlob[iDel+nDel],
+ pParse->nBlob - (iDel+nDel));
+ pParse->nBlob += d;
+ pParse->delta += d;
+ }
+ if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns);
+}
+
+/*
+** Return the number of escaped newlines to be ignored.
+** An escaped newline is a one of the following byte sequences:
+**
+** 0x5c 0x0a
+** 0x5c 0x0d
+** 0x5c 0x0d 0x0a
+** 0x5c 0xe2 0x80 0xa8
+** 0x5c 0xe2 0x80 0xa9
+*/
+static u32 jsonBytesToBypass(const char *z, u32 n){
+ u32 i = 0;
+ while( i+1<n ){
+ if( z[i]!='\\' ) return i;
+ if( z[i+1]=='\n' ){
+ i += 2;
+ continue;
+ }
+ if( z[i+1]=='\r' ){
+ if( i+2<n && z[i+2]=='\n' ){
+ i += 3;
+ }else{
+ i += 2;
+ }
+ continue;
}
- if( p->iHold>iMaxHold ){
- iMaxHold = p->iHold;
+ if( 0xe2==(u8)z[i+1]
+ && i+3<n
+ && 0x80==(u8)z[i+2]
+ && (0xa8==(u8)z[i+3] || 0xa9==(u8)z[i+3])
+ ){
+ i += 4;
+ continue;
}
+ break;
}
- if( pMatch ){
- pMatch->nErr = 0;
- pMatch->iHold = iMaxHold+1;
- return pMatch;
+ return i;
+}
+
+/*
+** Input z[0..n] defines JSON escape sequence including the leading '\\'.
+** Decode that escape sequence into a single character. Write that
+** character into *piOut. Return the number of bytes in the escape sequence.
+**
+** If there is a syntax error of some kind (for example too few characters
+** after the '\\' to complete the encoding) then *piOut is set to
+** JSON_INVALID_CHAR.
+*/
+static u32 jsonUnescapeOneChar(const char *z, u32 n, u32 *piOut){
+ assert( n>0 );
+ assert( z[0]=='\\' );
+ if( n<2 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
}
- p = sqlcipher_sqlite3_malloc64( sizeof(*p) + nJson + 1 );
- if( p==0 ){
- sqlcipher_sqlite3_result_error_nomem(pCtx);
- return 0;
+ switch( (u8)z[1] ){
+ case 'u': {
+ u32 v, vlo;
+ if( n<6 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
+ }
+ v = jsonHexToInt4(&z[2]);
+ if( (v & 0xfc00)==0xd800
+ && n>=12
+ && z[6]=='\\'
+ && z[7]=='u'
+ && ((vlo = jsonHexToInt4(&z[8]))&0xfc00)==0xdc00
+ ){
+ *piOut = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
+ return 12;
+ }else{
+ *piOut = v;
+ return 6;
+ }
+ }
+ case 'b': { *piOut = '\b'; return 2; }
+ case 'f': { *piOut = '\f'; return 2; }
+ case 'n': { *piOut = '\n'; return 2; }
+ case 'r': { *piOut = '\r'; return 2; }
+ case 't': { *piOut = '\t'; return 2; }
+ case 'v': { *piOut = '\v'; return 2; }
+ case '0': { *piOut = 0; return 2; }
+ case '\'':
+ case '"':
+ case '/':
+ case '\\':{ *piOut = z[1]; return 2; }
+ case 'x': {
+ if( n<4 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
+ }
+ *piOut = (jsonHexToInt(z[2])<<4) | jsonHexToInt(z[3]);
+ return 4;
+ }
+ case 0xe2:
+ case '\r':
+ case '\n': {
+ u32 nSkip = jsonBytesToBypass(z, n);
+ if( nSkip==0 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
+ }else if( nSkip==n ){
+ *piOut = 0;
+ return n;
+ }else if( z[nSkip]=='\\' ){
+ return nSkip + jsonUnescapeOneChar(&z[nSkip], n-nSkip, piOut);
+ }else{
+ int sz = sqlcipher_sqlite3Utf8ReadLimited((u8*)&z[nSkip], n-nSkip, piOut);
+ return nSkip + sz;
+ }
+ }
+ default: {
+ *piOut = JSON_INVALID_CHAR;
+ return 2;
+ }
}
- memset(p, 0, sizeof(*p));
- p->zJson = (char*)&p[1];
- memcpy((char*)p->zJson, zJson, nJson+1);
- if( jsonParse(p, pErrCtx, p->zJson) ){
- sqlcipher_sqlite3_free(p);
- return 0;
+}
+
+
+/*
+** Compare two object labels. Return 1 if they are equal and
+** 0 if they differ.
+**
+** In this version, we know that one or the other or both of the
+** two comparands contains an escape sequence.
+*/
+static SQLITE_NOINLINE int jsonLabelCompareEscaped(
+ const char *zLeft, /* The left label */
+ u32 nLeft, /* Size of the left label in bytes */
+ int rawLeft, /* True if zLeft contains no escapes */
+ const char *zRight, /* The right label */
+ u32 nRight, /* Size of the right label in bytes */
+ int rawRight /* True if zRight is escape-free */
+){
+ u32 cLeft, cRight;
+ assert( rawLeft==0 || rawRight==0 );
+ while( 1 /*exit-by-return*/ ){
+ if( nLeft==0 ){
+ cLeft = 0;
+ }else if( rawLeft || zLeft[0]!='\\' ){
+ cLeft = ((u8*)zLeft)[0];
+ if( cLeft>=0xc0 ){
+ int sz = sqlcipher_sqlite3Utf8ReadLimited((u8*)zLeft, nLeft, &cLeft);
+ zLeft += sz;
+ nLeft -= sz;
+ }else{
+ zLeft++;
+ nLeft--;
+ }
+ }else{
+ u32 n = jsonUnescapeOneChar(zLeft, nLeft, &cLeft);
+ zLeft += n;
+ assert( n<=nLeft );
+ nLeft -= n;
+ }
+ if( nRight==0 ){
+ cRight = 0;
+ }else if( rawRight || zRight[0]!='\\' ){
+ cRight = ((u8*)zRight)[0];
+ if( cRight>=0xc0 ){
+ int sz = sqlcipher_sqlite3Utf8ReadLimited((u8*)zRight, nRight, &cRight);
+ zRight += sz;
+ nRight -= sz;
+ }else{
+ zRight++;
+ nRight--;
+ }
+ }else{
+ u32 n = jsonUnescapeOneChar(zRight, nRight, &cRight);
+ zRight += n;
+ assert( n<=nRight );
+ nRight -= n;
+ }
+ if( cLeft!=cRight ) return 0;
+ if( cLeft==0 ) return 1;
}
- p->nJson = nJson;
- p->iHold = iMaxHold+1;
- sqlcipher_sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
- (void(*)(void*))jsonParseFree);
- return (JsonParse*)sqlcipher_sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
}
/*
-** Compare the OBJECT label at pNode against zKey,nKey. Return true on
-** a match.
+** Compare two object labels. Return 1 if they are equal and
+** 0 if they differ. Return -1 if an OOM occurs.
*/
-static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
- assert( pNode->eU==1 );
- if( pNode->jnFlags & JNODE_RAW ){
- if( pNode->n!=nKey ) return 0;
- return strncmp(pNode->u.zJContent, zKey, nKey)==0;
+static int jsonLabelCompare(
+ const char *zLeft, /* The left label */
+ u32 nLeft, /* Size of the left label in bytes */
+ int rawLeft, /* True if zLeft contains no escapes */
+ const char *zRight, /* The right label */
+ u32 nRight, /* Size of the right label in bytes */
+ int rawRight /* True if zRight is escape-free */
+){
+ if( rawLeft && rawRight ){
+ /* Simpliest case: Neither label contains escapes. A simple
+ ** memcmp() is sufficient. */
+ if( nLeft!=nRight ) return 0;
+ return memcmp(zLeft, zRight, nLeft)==0;
}else{
- if( pNode->n!=nKey+2 ) return 0;
- return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
+ return jsonLabelCompareEscaped(zLeft, nLeft, rawLeft,
+ zRight, nRight, rawRight);
}
}
-/* forward declaration */
-static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
+/*
+** Error returns from jsonLookupStep()
+*/
+#define JSON_LOOKUP_ERROR 0xffffffff
+#define JSON_LOOKUP_NOTFOUND 0xfffffffe
+#define JSON_LOOKUP_PATHERROR 0xfffffffd
+#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR)
+
+/* Forward declaration */
+static u32 jsonLookupStep(JsonParse*,u32,const char*,u32);
+
+
+/* This helper routine for jsonLookupStep() populates pIns with
+** binary data that is to be inserted into pParse.
+**
+** In the common case, pIns just points to pParse->aIns and pParse->nIns.
+** But if the zPath of the original edit operation includes path elements
+** that go deeper, additional substructure must be created.
+**
+** For example:
+**
+** json_insert('{}', '$.a.b.c', 123);
+**
+** The search stops at '$.a' But additional substructure must be
+** created for the ".b.c" part of the patch so that the final result
+** is: {"a":{"b":{"c"::123}}}. This routine populates pIns with
+** the binary equivalent of {"b":{"c":123}} so that it can be inserted.
+**
+** The caller is responsible for resetting pIns when it has finished
+** using the substructure.
+*/
+static u32 jsonCreateEditSubstructure(
+ JsonParse *pParse, /* The original JSONB that is being edited */
+ JsonParse *pIns, /* Populate this with the blob data to insert */
+ const char *zTail /* Tail of the path that determins substructure */
+){
+ static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT };
+ int rc;
+ memset(pIns, 0, sizeof(*pIns));
+ pIns->db = pParse->db;
+ if( zTail[0]==0 ){
+ /* No substructure. Just insert what is given in pParse. */
+ pIns->aBlob = pParse->aIns;
+ pIns->nBlob = pParse->nIns;
+ rc = 0;
+ }else{
+ /* Construct the binary substructure */
+ pIns->nBlob = 1;
+ pIns->aBlob = (u8*)&emptyObject[zTail[0]=='.'];
+ pIns->eEdit = pParse->eEdit;
+ pIns->nIns = pParse->nIns;
+ pIns->aIns = pParse->aIns;
+ rc = jsonLookupStep(pIns, 0, zTail, 0);
+ pParse->oom |= pIns->oom;
+ }
+ return rc; /* Error code only */
+}
/*
-** Search along zPath to find the node specified. Return a pointer
-** to that node, or NULL if zPath is malformed or if there is no such
-** node.
+** Search along zPath to find the Json element specified. Return an
+** index into pParse->aBlob[] for the start of that element's value.
**
-** If pApnd!=0, then try to append new nodes to complete zPath if it is
-** possible to do so and if no existing node corresponds to zPath. If
-** new nodes are appended *pApnd is set to 1.
+** If the value found by this routine is the value half of label/value pair
+** within an object, then set pPath->iLabel to the start of the corresponding
+** label, before returning.
+**
+** Return one of the JSON_LOOKUP error codes if problems are seen.
+**
+** This routine will also modify the blob. If pParse->eEdit is one of
+** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be
+** made to the selected value. If an edit is performed, then the return
+** value does not necessarily point to the select element. If an edit
+** is performed, the return value is only useful for detecting error
+** conditions.
*/
-static JsonNode *jsonLookupStep(
+static u32 jsonLookupStep(
JsonParse *pParse, /* The JSON to search */
- u32 iRoot, /* Begin the search at this node */
+ u32 iRoot, /* Begin the search at this element of aBlob[] */
const char *zPath, /* The path to search */
- int *pApnd, /* Append nodes to complete path if not NULL */
- const char **pzErr /* Make *pzErr point to any syntax error in zPath */
+ u32 iLabel /* Label if iRoot is a value of in an object */
){
- u32 i, j, nKey;
+ u32 i, j, k, nKey, sz, n, iEnd, rc;
const char *zKey;
- JsonNode *pRoot = &pParse->aNode[iRoot];
- if( zPath[0]==0 ) return pRoot;
- if( pRoot->jnFlags & JNODE_REPLACE ) return 0;
+ u8 x;
+
+ if( zPath[0]==0 ){
+ if( pParse->eEdit && jsonBlobMakeEditable(pParse, pParse->nIns) ){
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ sz += n;
+ if( pParse->eEdit==JEDIT_DEL ){
+ if( iLabel>0 ){
+ sz += iRoot - iLabel;
+ iRoot = iLabel;
+ }
+ jsonBlobEdit(pParse, iRoot, sz, 0, 0);
+ }else if( pParse->eEdit==JEDIT_INS ){
+ /* Already exists, so json_insert() is a no-op */
+ }else{
+ /* json_set() or json_replace() */
+ jsonBlobEdit(pParse, iRoot, sz, pParse->aIns, pParse->nIns);
+ }
+ }
+ pParse->iLabel = iLabel;
+ return iRoot;
+ }
if( zPath[0]=='.' ){
- if( pRoot->eType!=JSON_OBJECT ) return 0;
+ int rawKey = 1;
+ x = pParse->aBlob[iRoot];
zPath++;
if( zPath[0]=='"' ){
zKey = zPath + 1;
@@ -201983,303 +213011,851 @@ static JsonNode *jsonLookupStep(
if( zPath[i] ){
i++;
}else{
- *pzErr = zPath;
- return 0;
+ return JSON_LOOKUP_PATHERROR;
}
testcase( nKey==0 );
+ rawKey = memchr(zKey, '\\', nKey)==0;
}else{
zKey = zPath;
for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
nKey = i;
if( nKey==0 ){
- *pzErr = zPath;
- return 0;
- }
- }
- j = 1;
- for(;;){
- while( j<=pRoot->n ){
- if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
- return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
- }
- j++;
- j += jsonNodeSize(&pRoot[j]);
+ return JSON_LOOKUP_PATHERROR;
+ }
+ }
+ if( (x & 0x0f)!=JSONB_OBJECT ) return JSON_LOOKUP_NOTFOUND;
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ j = iRoot + n; /* j is the index of a label */
+ iEnd = j+sz;
+ while( j<iEnd ){
+ int rawLabel;
+ const char *zLabel;
+ x = pParse->aBlob[j] & 0x0f;
+ if( x<JSONB_TEXT || x>JSONB_TEXTRAW ) return JSON_LOOKUP_ERROR;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return JSON_LOOKUP_ERROR;
+ k = j+n; /* k is the index of the label text */
+ if( k+sz>=iEnd ) return JSON_LOOKUP_ERROR;
+ zLabel = (const char*)&pParse->aBlob[k];
+ rawLabel = x==JSONB_TEXT || x==JSONB_TEXTRAW;
+ if( jsonLabelCompare(zKey, nKey, rawKey, zLabel, sz, rawLabel) ){
+ u32 v = k+sz; /* v is the index of the value */
+ if( ((pParse->aBlob[v])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR;
+ n = jsonbPayloadSize(pParse, v, &sz);
+ if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR;
+ assert( j>0 );
+ rc = jsonLookupStep(pParse, v, &zPath[i], j);
+ if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ return rc;
}
- if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pRoot->eU==2 );
- iRoot += pRoot->u.iAppend;
- pRoot = &pParse->aNode[iRoot];
- j = 1;
- }
- if( pApnd ){
- u32 iStart, iLabel;
- JsonNode *pNode;
- iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
- iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
- zPath += i;
- pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
- if( pParse->oom ) return 0;
- if( pNode ){
- pRoot = &pParse->aNode[iRoot];
- assert( pRoot->eU==0 );
- pRoot->u.iAppend = iStart - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
- VVA( pRoot->eU = 2 );
- pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
- }
- return pNode;
+ j = k+sz;
+ if( ((pParse->aBlob[j])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return JSON_LOOKUP_ERROR;
+ j += n+sz;
+ }
+ if( j>iEnd ) return JSON_LOOKUP_ERROR;
+ if( pParse->eEdit>=JEDIT_INS ){
+ u32 nIns; /* Total bytes to insert (label+value) */
+ JsonParse v; /* BLOB encoding of the value to be inserted */
+ JsonParse ix; /* Header of the label to be inserted */
+ testcase( pParse->eEdit==JEDIT_INS );
+ testcase( pParse->eEdit==JEDIT_SET );
+ memset(&ix, 0, sizeof(ix));
+ ix.db = pParse->db;
+ jsonBlobAppendNode(&ix, rawKey?JSONB_TEXTRAW:JSONB_TEXT5, nKey, 0);
+ pParse->oom |= ix.oom;
+ rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i]);
+ if( !JSON_LOOKUP_ISERROR(rc)
+ && jsonBlobMakeEditable(pParse, ix.nBlob+nKey+v.nBlob)
+ ){
+ assert( !pParse->oom );
+ nIns = ix.nBlob + nKey + v.nBlob;
+ jsonBlobEdit(pParse, j, 0, 0, nIns);
+ if( !pParse->oom ){
+ assert( pParse->aBlob!=0 ); /* Because pParse->oom!=0 */
+ assert( ix.aBlob!=0 ); /* Because pPasre->oom!=0 */
+ memcpy(&pParse->aBlob[j], ix.aBlob, ix.nBlob);
+ k = j + ix.nBlob;
+ memcpy(&pParse->aBlob[k], zKey, nKey);
+ k += nKey;
+ memcpy(&pParse->aBlob[k], v.aBlob, v.nBlob);
+ if( ALWAYS(pParse->delta) ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ }
+ }
+ jsonParseReset(&v);
+ jsonParseReset(&ix);
+ return rc;
}
}else if( zPath[0]=='[' ){
- i = 0;
- j = 1;
- while( sqlcipher_sqlite3Isdigit(zPath[j]) ){
- i = i*10 + zPath[j] - '0';
- j++;
+ x = pParse->aBlob[iRoot] & 0x0f;
+ if( x!=JSONB_ARRAY ) return JSON_LOOKUP_NOTFOUND;
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ k = 0;
+ i = 1;
+ while( sqlcipher_sqlite3Isdigit(zPath[i]) ){
+ k = k*10 + zPath[i] - '0';
+ i++;
}
- if( j<2 || zPath[j]!=']' ){
+ if( i<2 || zPath[i]!=']' ){
if( zPath[1]=='#' ){
- JsonNode *pBase = pRoot;
- int iBase = iRoot;
- if( pRoot->eType!=JSON_ARRAY ) return 0;
- for(;;){
- while( j<=pBase->n ){
- if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++;
- j += jsonNodeSize(&pBase[j]);
- }
- if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pBase->eU==2 );
- iBase += pBase->u.iAppend;
- pBase = &pParse->aNode[iBase];
- j = 1;
- }
- j = 2;
+ k = jsonbArrayCount(pParse, iRoot);
+ i = 2;
if( zPath[2]=='-' && sqlcipher_sqlite3Isdigit(zPath[3]) ){
- unsigned int x = 0;
- j = 3;
+ unsigned int nn = 0;
+ i = 3;
do{
- x = x*10 + zPath[j] - '0';
- j++;
- }while( sqlcipher_sqlite3Isdigit(zPath[j]) );
- if( x>i ) return 0;
- i -= x;
+ nn = nn*10 + zPath[i] - '0';
+ i++;
+ }while( sqlcipher_sqlite3Isdigit(zPath[i]) );
+ if( nn>k ) return JSON_LOOKUP_NOTFOUND;
+ k -= nn;
}
- if( zPath[j]!=']' ){
- *pzErr = zPath;
- return 0;
+ if( zPath[i]!=']' ){
+ return JSON_LOOKUP_PATHERROR;
}
}else{
- *pzErr = zPath;
- return 0;
+ return JSON_LOOKUP_PATHERROR;
}
}
- if( pRoot->eType!=JSON_ARRAY ) return 0;
- zPath += j + 1;
- j = 1;
- for(;;){
- while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
- if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
- j += jsonNodeSize(&pRoot[j]);
- }
- if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pRoot->eU==2 );
- iRoot += pRoot->u.iAppend;
- pRoot = &pParse->aNode[iRoot];
- j = 1;
- }
- if( j<=pRoot->n ){
- return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
- }
- if( i==0 && pApnd ){
- u32 iStart;
- JsonNode *pNode;
- iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
- pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
- if( pParse->oom ) return 0;
- if( pNode ){
- pRoot = &pParse->aNode[iRoot];
- assert( pRoot->eU==0 );
- pRoot->u.iAppend = iStart - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
- VVA( pRoot->eU = 2 );
+ j = iRoot+n;
+ iEnd = j+sz;
+ while( j<iEnd ){
+ if( k==0 ){
+ rc = jsonLookupStep(pParse, j, &zPath[i+1], 0);
+ if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ return rc;
}
- return pNode;
+ k--;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return JSON_LOOKUP_ERROR;
+ j += n+sz;
+ }
+ if( j>iEnd ) return JSON_LOOKUP_ERROR;
+ if( k>0 ) return JSON_LOOKUP_NOTFOUND;
+ if( pParse->eEdit>=JEDIT_INS ){
+ JsonParse v;
+ testcase( pParse->eEdit==JEDIT_INS );
+ testcase( pParse->eEdit==JEDIT_SET );
+ rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]);
+ if( !JSON_LOOKUP_ISERROR(rc)
+ && jsonBlobMakeEditable(pParse, v.nBlob)
+ ){
+ assert( !pParse->oom );
+ jsonBlobEdit(pParse, j, 0, v.aBlob, v.nBlob);
+ }
+ jsonParseReset(&v);
+ if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ return rc;
}
}else{
- *pzErr = zPath;
+ return JSON_LOOKUP_PATHERROR;
}
- return 0;
+ return JSON_LOOKUP_NOTFOUND;
}
/*
-** Append content to pParse that will complete zPath. Return a pointer
-** to the inserted node, or return NULL if the append fails.
+** Convert a JSON BLOB into text and make that text the return value
+** of an SQL function.
*/
-static JsonNode *jsonLookupAppend(
- JsonParse *pParse, /* Append content to the JSON parse */
- const char *zPath, /* Description of content to append */
- int *pApnd, /* Set this flag to 1 */
- const char **pzErr /* Make this point to any syntax error */
+static void jsonReturnTextJsonFromBlob(
+ sqlcipher_sqlite3_context *ctx,
+ const u8 *aBlob,
+ u32 nBlob
){
- *pApnd = 1;
- if( zPath[0]==0 ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
- }
- if( zPath[0]=='.' ){
- jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
- }else if( strncmp(zPath,"[0]",3)==0 ){
- jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
- }else{
- return 0;
- }
- if( pParse->oom ) return 0;
- return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
+ JsonParse x;
+ JsonString s;
+
+ if( NEVER(aBlob==0) ) return;
+ memset(&x, 0, sizeof(x));
+ x.aBlob = (u8*)aBlob;
+ x.nBlob = nBlob;
+ jsonStringInit(&s, ctx);
+ jsonTranslateBlobToText(&x, 0, &s);
+ jsonReturnString(&s, 0, 0);
}
+
/*
-** Return the text of a syntax error message on a JSON path. Space is
-** obtained from sqlcipher_sqlite3_malloc().
+** Return the value of the BLOB node at index i.
+**
+** If the value is a primitive, return it as an SQL value.
+** If the value is an array or object, return it as either
+** JSON text or the BLOB encoding, depending on the JSON_B flag
+** on the userdata.
*/
-static char *jsonPathSyntaxError(const char *zErr){
- return sqlcipher_sqlite3_mprintf("JSON path error near '%q'", zErr);
+static void jsonReturnFromBlob(
+ JsonParse *pParse, /* Complete JSON parse tree */
+ u32 i, /* Index of the node */
+ sqlcipher_sqlite3_context *pCtx, /* Return value for this function */
+ int textOnly /* return text JSON. Disregard user-data */
+){
+ u32 n, sz;
+ int rc;
+ sqlcipher_sqlite3 *db = sqlcipher_sqlite3_context_db_handle(pCtx);
+
+ n = jsonbPayloadSize(pParse, i, &sz);
+ if( n==0 ){
+ sqlcipher_sqlite3_result_error(pCtx, "malformed JSON", -1);
+ return;
+ }
+ switch( pParse->aBlob[i] & 0x0f ){
+ case JSONB_NULL: {
+ if( sz ) goto returnfromblob_malformed;
+ sqlcipher_sqlite3_result_null(pCtx);
+ break;
+ }
+ case JSONB_TRUE: {
+ if( sz ) goto returnfromblob_malformed;
+ sqlcipher_sqlite3_result_int(pCtx, 1);
+ break;
+ }
+ case JSONB_FALSE: {
+ if( sz ) goto returnfromblob_malformed;
+ sqlcipher_sqlite3_result_int(pCtx, 0);
+ break;
+ }
+ case JSONB_INT5:
+ case JSONB_INT: {
+ sqlcipher_sqlite3_int64 iRes = 0;
+ char *z;
+ int bNeg = 0;
+ char x;
+ if( sz==0 ) goto returnfromblob_malformed;
+ x = (char)pParse->aBlob[i+n];
+ if( x=='-' ){
+ if( sz<2 ) goto returnfromblob_malformed;
+ n++;
+ sz--;
+ bNeg = 1;
+ }
+ z = sqlcipher_sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz);
+ if( z==0 ) goto returnfromblob_oom;
+ rc = sqlcipher_sqlite3DecOrHexToI64(z, &iRes);
+ sqlcipher_sqlite3DbFree(db, z);
+ if( rc==0 ){
+ sqlcipher_sqlite3_result_int64(pCtx, bNeg ? -iRes : iRes);
+ }else if( rc==3 && bNeg ){
+ sqlcipher_sqlite3_result_int64(pCtx, SMALLEST_INT64);
+ }else if( rc==1 ){
+ goto returnfromblob_malformed;
+ }else{
+ if( bNeg ){ n--; sz++; }
+ goto to_double;
+ }
+ break;
+ }
+ case JSONB_FLOAT5:
+ case JSONB_FLOAT: {
+ double r;
+ char *z;
+ if( sz==0 ) goto returnfromblob_malformed;
+ to_double:
+ z = sqlcipher_sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz);
+ if( z==0 ) goto returnfromblob_oom;
+ rc = sqlcipher_sqlite3AtoF(z, &r, sqlcipher_sqlite3Strlen30(z), SQLITE_UTF8);
+ sqlcipher_sqlite3DbFree(db, z);
+ if( rc<=0 ) goto returnfromblob_malformed;
+ sqlcipher_sqlite3_result_double(pCtx, r);
+ break;
+ }
+ case JSONB_TEXTRAW:
+ case JSONB_TEXT: {
+ sqlcipher_sqlite3_result_text(pCtx, (char*)&pParse->aBlob[i+n], sz,
+ SQLITE_TRANSIENT);
+ break;
+ }
+ case JSONB_TEXT5:
+ case JSONB_TEXTJ: {
+ /* Translate JSON formatted string into raw text */
+ u32 iIn, iOut;
+ const char *z;
+ char *zOut;
+ u32 nOut = sz;
+ z = (const char*)&pParse->aBlob[i+n];
+ zOut = sqlcipher_sqlite3DbMallocRaw(db, nOut+1);
+ if( zOut==0 ) goto returnfromblob_oom;
+ for(iIn=iOut=0; iIn<sz; iIn++){
+ char c = z[iIn];
+ if( c=='\\' ){
+ u32 v;
+ u32 szEscape = jsonUnescapeOneChar(&z[iIn], sz-iIn, &v);
+ if( v<=0x7f ){
+ zOut[iOut++] = (char)v;
+ }else if( v<=0x7ff ){
+ assert( szEscape>=2 );
+ zOut[iOut++] = (char)(0xc0 | (v>>6));
+ zOut[iOut++] = 0x80 | (v&0x3f);
+ }else if( v<0x10000 ){
+ assert( szEscape>=3 );
+ zOut[iOut++] = 0xe0 | (v>>12);
+ zOut[iOut++] = 0x80 | ((v>>6)&0x3f);
+ zOut[iOut++] = 0x80 | (v&0x3f);
+ }else if( v==JSON_INVALID_CHAR ){
+ /* Silently ignore illegal unicode */
+ }else{
+ assert( szEscape>=4 );
+ zOut[iOut++] = 0xf0 | (v>>18);
+ zOut[iOut++] = 0x80 | ((v>>12)&0x3f);
+ zOut[iOut++] = 0x80 | ((v>>6)&0x3f);
+ zOut[iOut++] = 0x80 | (v&0x3f);
+ }
+ iIn += szEscape - 1;
+ }else{
+ zOut[iOut++] = c;
+ }
+ } /* end for() */
+ assert( iOut<=nOut );
+ zOut[iOut] = 0;
+ sqlcipher_sqlite3_result_text(pCtx, zOut, iOut, SQLITE_DYNAMIC);
+ break;
+ }
+ case JSONB_ARRAY:
+ case JSONB_OBJECT: {
+ int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(sqlcipher_sqlite3_user_data(pCtx));
+ if( flags & JSON_BLOB ){
+ sqlcipher_sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT);
+ }else{
+ jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n);
+ }
+ break;
+ }
+ default: {
+ goto returnfromblob_malformed;
+ }
+ }
+ return;
+
+returnfromblob_oom:
+ sqlcipher_sqlite3_result_error_nomem(pCtx);
+ return;
+
+returnfromblob_malformed:
+ sqlcipher_sqlite3_result_error(pCtx, "malformed JSON", -1);
+ return;
}
/*
-** Do a node lookup using zPath. Return a pointer to the node on success.
-** Return NULL if not found or if there is an error.
+** pArg is a function argument that might be an SQL value or a JSON
+** value. Figure out what it is and encode it as a JSONB blob.
+** Return the results in pParse.
**
-** On an error, write an error message into pCtx and increment the
-** pParse->nErr counter.
+** pParse is uninitialized upon entry. This routine will handle the
+** initialization of pParse. The result will be contained in
+** pParse->aBlob and pParse->nBlob. pParse->aBlob might be dynamically
+** allocated (if pParse->nBlobAlloc is greater than zero) in which case
+** the caller is responsible for freeing the space allocated to pParse->aBlob
+** when it has finished with it. Or pParse->aBlob might be a static string
+** or a value obtained from sqlcipher_sqlite3_value_blob(pArg).
**
-** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
-** nodes are appended.
+** If the argument is a BLOB that is clearly not a JSONB, then this
+** function might set an error message in ctx and return non-zero.
+** It might also set an error message and return non-zero on an OOM error.
*/
-static JsonNode *jsonLookup(
- JsonParse *pParse, /* The JSON to search */
- const char *zPath, /* The path to search */
- int *pApnd, /* Append nodes to complete path if not NULL */
- sqlcipher_sqlite3_context *pCtx /* Report errors here, if not NULL */
-){
- const char *zErr = 0;
- JsonNode *pNode = 0;
- char *zMsg;
-
- if( zPath==0 ) return 0;
- if( zPath[0]!='$' ){
- zErr = zPath;
- goto lookup_err;
+static int jsonFunctionArgToBlob(
+ sqlcipher_sqlite3_context *ctx,
+ sqlcipher_sqlite3_value *pArg,
+ JsonParse *pParse
+){
+ int eType = sqlcipher_sqlite3_value_type(pArg);
+ static u8 aNull[] = { 0x00 };
+ memset(pParse, 0, sizeof(pParse[0]));
+ pParse->db = sqlcipher_sqlite3_context_db_handle(ctx);
+ switch( eType ){
+ default: {
+ pParse->aBlob = aNull;
+ pParse->nBlob = 1;
+ return 0;
+ }
+ case SQLITE_BLOB: {
+ if( jsonFuncArgMightBeBinary(pArg) ){
+ pParse->aBlob = (u8*)sqlcipher_sqlite3_value_blob(pArg);
+ pParse->nBlob = sqlcipher_sqlite3_value_bytes(pArg);
+ }else{
+ sqlcipher_sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1);
+ return 1;
+ }
+ break;
+ }
+ case SQLITE_TEXT: {
+ const char *zJson = (const char*)sqlcipher_sqlite3_value_text(pArg);
+ int nJson = sqlcipher_sqlite3_value_bytes(pArg);
+ if( zJson==0 ) return 1;
+ if( sqlcipher_sqlite3_value_subtype(pArg)==JSON_SUBTYPE ){
+ pParse->zJson = (char*)zJson;
+ pParse->nJson = nJson;
+ if( jsonConvertTextToBlob(pParse, ctx) ){
+ sqlcipher_sqlite3_result_error(ctx, "malformed JSON", -1);
+ sqlcipher_sqlite3DbFree(pParse->db, pParse->aBlob);
+ memset(pParse, 0, sizeof(pParse[0]));
+ return 1;
+ }
+ }else{
+ jsonBlobAppendNode(pParse, JSONB_TEXTRAW, nJson, zJson);
+ }
+ break;
+ }
+ case SQLITE_FLOAT: {
+ double r = sqlcipher_sqlite3_value_double(pArg);
+ if( NEVER(sqlcipher_sqlite3IsNaN(r)) ){
+ jsonBlobAppendNode(pParse, JSONB_NULL, 0, 0);
+ }else{
+ int n = sqlcipher_sqlite3_value_bytes(pArg);
+ const char *z = (const char*)sqlcipher_sqlite3_value_text(pArg);
+ if( z==0 ) return 1;
+ if( z[0]=='I' ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
+ }else if( z[0]=='-' && z[1]=='I' ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999");
+ }else{
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, n, z);
+ }
+ }
+ break;
+ }
+ case SQLITE_INTEGER: {
+ int n = sqlcipher_sqlite3_value_bytes(pArg);
+ const char *z = (const char*)sqlcipher_sqlite3_value_text(pArg);
+ if( z==0 ) return 1;
+ jsonBlobAppendNode(pParse, JSONB_INT, n, z);
+ break;
+ }
+ }
+ if( pParse->oom ){
+ sqlcipher_sqlite3_result_error_nomem(ctx);
+ return 1;
+ }else{
+ return 0;
}
- zPath++;
- pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
- if( zErr==0 ) return pNode;
+}
-lookup_err:
- pParse->nErr++;
- assert( zErr!=0 && pCtx!=0 );
- zMsg = jsonPathSyntaxError(zErr);
+/*
+** Generate a bad path error.
+**
+** If ctx is not NULL then push the error message into ctx and return NULL.
+** If ctx is NULL, then return the text of the error message.
+*/
+static char *jsonBadPathError(
+ sqlcipher_sqlite3_context *ctx, /* The function call containing the error */
+ const char *zPath /* The path with the problem */
+){
+ char *zMsg = sqlcipher_sqlite3_mprintf("bad JSON path: %Q", zPath);
+ if( ctx==0 ) return zMsg;
if( zMsg ){
- sqlcipher_sqlite3_result_error(pCtx, zMsg, -1);
+ sqlcipher_sqlite3_result_error(ctx, zMsg, -1);
sqlcipher_sqlite3_free(zMsg);
}else{
- sqlcipher_sqlite3_result_error_nomem(pCtx);
+ sqlcipher_sqlite3_result_error_nomem(ctx);
}
return 0;
}
+/* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent
+** arguments come in parse where each pair contains a JSON path and
+** content to insert or set at that patch. Do the updates
+** and return the result.
+**
+** The specific operation is determined by eEdit, which can be one
+** of JEDIT_INS, JEDIT_REPL, or JEDIT_SET.
+*/
+static void jsonInsertIntoBlob(
+ sqlcipher_sqlite3_context *ctx,
+ int argc,
+ sqlcipher_sqlite3_value **argv,
+ int eEdit /* JEDIT_INS, JEDIT_REPL, or JEDIT_SET */
+){
+ int i;
+ u32 rc = 0;
+ const char *zPath = 0;
+ int flgs;
+ JsonParse *p;
+ JsonParse ax;
+
+ assert( (argc&1)==1 );
+ flgs = argc==1 ? 0 : JSON_EDITABLE;
+ p = jsonParseFuncArg(ctx, argv[0], flgs);
+ if( p==0 ) return;
+ for(i=1; i<argc-1; i+=2){
+ if( sqlcipher_sqlite3_value_type(argv[i])==SQLITE_NULL ) continue;
+ zPath = (const char*)sqlcipher_sqlite3_value_text(argv[i]);
+ if( zPath==0 ){
+ sqlcipher_sqlite3_result_error_nomem(ctx);
+ jsonParseFree(p);
+ return;
+ }
+ if( zPath[0]!='$' ) goto jsonInsertIntoBlob_patherror;
+ if( jsonFunctionArgToBlob(ctx, argv[i+1], &ax) ){
+ jsonParseReset(&ax);
+ jsonParseFree(p);
+ return;
+ }
+ if( zPath[1]==0 ){
+ if( eEdit==JEDIT_REPL || eEdit==JEDIT_SET ){
+ jsonBlobEdit(p, 0, p->nBlob, ax.aBlob, ax.nBlob);
+ }
+ rc = 0;
+ }else{
+ p->eEdit = eEdit;
+ p->nIns = ax.nBlob;
+ p->aIns = ax.aBlob;
+ p->delta = 0;
+ rc = jsonLookupStep(p, 0, zPath+1, 0);
+ }
+ jsonParseReset(&ax);
+ if( rc==JSON_LOOKUP_NOTFOUND ) continue;
+ if( JSON_LOOKUP_ISERROR(rc) ) goto jsonInsertIntoBlob_patherror;
+ }
+ jsonReturnParse(ctx, p);
+ jsonParseFree(p);
+ return;
+
+jsonInsertIntoBlob_patherror:
+ jsonParseFree(p);
+ if( rc==JSON_LOOKUP_ERROR ){
+ sqlcipher_sqlite3_result_error(ctx, "malformed JSON", -1);
+ }else{
+ jsonBadPathError(ctx, zPath);
+ }
+ return;
+}
/*
-** Report the wrong number of arguments for json_insert(), json_replace()
-** or json_set().
+** If pArg is a blob that seems like a JSONB blob, then initialize
+** p to point to that JSONB and return TRUE. If pArg does not seem like
+** a JSONB blob, then return FALSE;
+**
+** This routine is only called if it is already known that pArg is a
+** blob. The only open question is whether or not the blob appears
+** to be a JSONB blob.
*/
-static void jsonWrongNumArgs(
- sqlcipher_sqlite3_context *pCtx,
- const char *zFuncName
-){
- char *zMsg = sqlcipher_sqlite3_mprintf("json_%s() needs an odd number of arguments",
- zFuncName);
- sqlcipher_sqlite3_result_error(pCtx, zMsg, -1);
- sqlcipher_sqlite3_free(zMsg);
+static int jsonArgIsJsonb(sqlcipher_sqlite3_value *pArg, JsonParse *p){
+ u32 n, sz = 0;
+ p->aBlob = (u8*)sqlcipher_sqlite3_value_blob(pArg);
+ p->nBlob = (u32)sqlcipher_sqlite3_value_bytes(pArg);
+ if( p->nBlob==0 ){
+ p->aBlob = 0;
+ return 0;
+ }
+ if( NEVER(p->aBlob==0) ){
+ return 0;
+ }
+ if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT
+ && (n = jsonbPayloadSize(p, 0, &sz))>0
+ && sz+n==p->nBlob
+ && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0)
+ ){
+ return 1;
+ }
+ p->aBlob = 0;
+ p->nBlob = 0;
+ return 0;
}
/*
-** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
+** Generate a JsonParse object, containing valid JSONB in aBlob and nBlob,
+** from the SQL function argument pArg. Return a pointer to the new
+** JsonParse object.
+**
+** Ownership of the new JsonParse object is passed to the caller. The
+** caller should invoke jsonParseFree() on the return value when it
+** has finished using it.
+**
+** If any errors are detected, an appropriate error messages is set
+** using sqlcipher_sqlite3_result_error() or the equivalent and this routine
+** returns NULL. This routine also returns NULL if the pArg argument
+** is an SQL NULL value, but no error message is set in that case. This
+** is so that SQL functions that are given NULL arguments will return
+** a NULL value.
*/
-static void jsonRemoveAllNulls(JsonNode *pNode){
- int i, n;
- assert( pNode->eType==JSON_OBJECT );
- n = pNode->n;
- for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
- switch( pNode[i].eType ){
- case JSON_NULL:
- pNode[i].jnFlags |= JNODE_REMOVE;
- break;
- case JSON_OBJECT:
- jsonRemoveAllNulls(&pNode[i]);
- break;
+static JsonParse *jsonParseFuncArg(
+ sqlcipher_sqlite3_context *ctx,
+ sqlcipher_sqlite3_value *pArg,
+ u32 flgs
+){
+ int eType; /* Datatype of pArg */
+ JsonParse *p = 0; /* Value to be returned */
+ JsonParse *pFromCache = 0; /* Value taken from cache */
+ sqlcipher_sqlite3 *db; /* The database connection */
+
+ assert( ctx!=0 );
+ eType = sqlcipher_sqlite3_value_type(pArg);
+ if( eType==SQLITE_NULL ){
+ return 0;
+ }
+ pFromCache = jsonCacheSearch(ctx, pArg);
+ if( pFromCache ){
+ pFromCache->nJPRef++;
+ if( (flgs & JSON_EDITABLE)==0 ){
+ return pFromCache;
}
}
-}
+ db = sqlcipher_sqlite3_context_db_handle(ctx);
+rebuild_from_cache:
+ p = sqlcipher_sqlite3DbMallocZero(db, sizeof(*p));
+ if( p==0 ) goto json_pfa_oom;
+ memset(p, 0, sizeof(*p));
+ p->db = db;
+ p->nJPRef = 1;
+ if( pFromCache!=0 ){
+ u32 nBlob = pFromCache->nBlob;
+ p->aBlob = sqlcipher_sqlite3DbMallocRaw(db, nBlob);
+ if( p->aBlob==0 ) goto json_pfa_oom;
+ memcpy(p->aBlob, pFromCache->aBlob, nBlob);
+ p->nBlobAlloc = p->nBlob = nBlob;
+ p->hasNonstd = pFromCache->hasNonstd;
+ jsonParseFree(pFromCache);
+ return p;
+ }
+ if( eType==SQLITE_BLOB ){
+ if( jsonArgIsJsonb(pArg,p) ){
+ if( (flgs & JSON_EDITABLE)!=0 && jsonBlobMakeEditable(p, 0)==0 ){
+ goto json_pfa_oom;
+ }
+ return p;
+ }
+ /* If the blob is not valid JSONB, fall through into trying to cast
+ ** the blob into text which is then interpreted as JSON. (tag-20240123-a)
+ **
+ ** This goes against all historical documentation about how the SQLite
+ ** JSON functions were suppose to work. From the beginning, blob was
+ ** reserved for expansion and a blob value should have raised an error.
+ ** But it did not, due to a bug. And many applications came to depend
+ ** upon this buggy behavior, espeically when using the CLI and reading
+ ** JSON text using readfile(), which returns a blob. For this reason
+ ** we will continue to support the bug moving forward.
+ ** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d
+ */
+ }
+ p->zJson = (char*)sqlcipher_sqlite3_value_text(pArg);
+ p->nJson = sqlcipher_sqlite3_value_bytes(pArg);
+ if( db->mallocFailed ) goto json_pfa_oom;
+ if( p->nJson==0 ) goto json_pfa_malformed;
+ assert( p->zJson!=0 );
+ if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){
+ if( flgs & JSON_KEEPERROR ){
+ p->nErr = 1;
+ return p;
+ }else{
+ jsonParseFree(p);
+ return 0;
+ }
+ }else{
+ int isRCStr = sqlcipher_sqlite3ValueIsOfClass(pArg, sqlcipher_sqlite3RCStrUnref);
+ int rc;
+ if( !isRCStr ){
+ char *zNew = sqlcipher_sqlite3RCStrNew( p->nJson );
+ if( zNew==0 ) goto json_pfa_oom;
+ memcpy(zNew, p->zJson, p->nJson);
+ p->zJson = zNew;
+ p->zJson[p->nJson] = 0;
+ }else{
+ sqlcipher_sqlite3RCStrRef(p->zJson);
+ }
+ p->bJsonIsRCStr = 1;
+ rc = jsonCacheInsert(ctx, p);
+ if( rc==SQLITE_NOMEM ) goto json_pfa_oom;
+ if( flgs & JSON_EDITABLE ){
+ pFromCache = p;
+ p = 0;
+ goto rebuild_from_cache;
+ }
+ }
+ return p;
+json_pfa_malformed:
+ if( flgs & JSON_KEEPERROR ){
+ p->nErr = 1;
+ return p;
+ }else{
+ jsonParseFree(p);
+ sqlcipher_sqlite3_result_error(ctx, "malformed JSON", -1);
+ return 0;
+ }
-/****************************************************************************
-** SQL functions used for testing and debugging
-****************************************************************************/
+json_pfa_oom:
+ jsonParseFree(pFromCache);
+ jsonParseFree(p);
+ sqlcipher_sqlite3_result_error_nomem(ctx);
+ return 0;
+}
-#ifdef SQLITE_DEBUG
/*
-** The json_parse(JSON) function returns a string which describes
-** a parse of the JSON provided. Or it returns NULL if JSON is not
-** well-formed.
+** Make the return value of a JSON function either the raw JSONB blob
+** or make it JSON text, depending on whether the JSON_BLOB flag is
+** set on the function.
*/
-static void jsonParseFunc(
+static void jsonReturnParse(
sqlcipher_sqlite3_context *ctx,
- int argc,
- sqlcipher_sqlite3_value **argv
+ JsonParse *p
){
- JsonString s; /* Output string - not real JSON */
- JsonParse x; /* The parse */
- u32 i;
-
- assert( argc==1 );
- if( jsonParse(&x, ctx, (const char*)sqlcipher_sqlite3_value_text(argv[0])) ) return;
- jsonParseFindParents(&x);
- jsonInit(&s, ctx);
- for(i=0; i<x.nNode; i++){
- const char *zType;
- if( x.aNode[i].jnFlags & JNODE_LABEL ){
- assert( x.aNode[i].eType==JSON_STRING );
- zType = "label";
+ int flgs;
+ if( p->oom ){
+ sqlcipher_sqlite3_result_error_nomem(ctx);
+ return;
+ }
+ flgs = SQLITE_PTR_TO_INT(sqlcipher_sqlite3_user_data(ctx));
+ if( flgs & JSON_BLOB ){
+ if( p->nBlobAlloc>0 && !p->bReadOnly ){
+ sqlcipher_sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_DYNAMIC);
+ p->nBlobAlloc = 0;
}else{
- zType = jsonType[x.aNode[i].eType];
+ sqlcipher_sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_TRANSIENT);
}
- jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d",
- i, zType, x.aNode[i].n, x.aUp[i]);
- assert( x.aNode[i].eU==0 || x.aNode[i].eU==1 );
- if( x.aNode[i].u.zJContent!=0 ){
- assert( x.aNode[i].eU==1 );
- jsonAppendRaw(&s, " ", 1);
- jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
- }else{
- assert( x.aNode[i].eU==0 );
+ }else{
+ JsonString s;
+ jsonStringInit(&s, ctx);
+ p->delta = 0;
+ jsonTranslateBlobToText(p, 0, &s);
+ jsonReturnString(&s, p, ctx);
+ sqlcipher_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
+}
+
+/****************************************************************************
+** SQL functions used for testing and debugging
+****************************************************************************/
+
+#if SQLITE_DEBUG
+/*
+** Decode JSONB bytes in aBlob[] starting at iStart through but not
+** including iEnd. Indent the
+** content by nIndent spaces.
+*/
+static void jsonDebugPrintBlob(
+ JsonParse *pParse, /* JSON content */
+ u32 iStart, /* Start rendering here */
+ u32 iEnd, /* Do not render this byte or any byte after this one */
+ int nIndent, /* Indent by this many spaces */
+ sqlcipher_sqlite3_str *pOut /* Generate output into this sqlcipher_sqlite3_str object */
+){
+ while( iStart<iEnd ){
+ u32 i, n, nn, sz = 0;
+ int showContent = 1;
+ u8 x = pParse->aBlob[iStart] & 0x0f;
+ u32 savedNBlob = pParse->nBlob;
+ sqlcipher_sqlite3_str_appendf(pOut, "%5d:%*s", iStart, nIndent, "");
+ if( pParse->nBlobAlloc>pParse->nBlob ){
+ pParse->nBlob = pParse->nBlobAlloc;
+ }
+ nn = n = jsonbPayloadSize(pParse, iStart, &sz);
+ if( nn==0 ) nn = 1;
+ if( sz>0 && x<JSONB_ARRAY ){
+ nn += sz;
+ }
+ for(i=0; i<nn; i++){
+ sqlcipher_sqlite3_str_appendf(pOut, " %02x", pParse->aBlob[iStart+i]);
}
- jsonAppendRaw(&s, "\n", 1);
+ if( n==0 ){
+ sqlcipher_sqlite3_str_appendf(pOut, " ERROR invalid node size\n");
+ iStart = n==0 ? iStart+1 : iEnd;
+ continue;
+ }
+ pParse->nBlob = savedNBlob;
+ if( iStart+n+sz>iEnd ){
+ iEnd = iStart+n+sz;
+ if( iEnd>pParse->nBlob ){
+ if( pParse->nBlobAlloc>0 && iEnd>pParse->nBlobAlloc ){
+ iEnd = pParse->nBlobAlloc;
+ }else{
+ iEnd = pParse->nBlob;
+ }
+ }
+ }
+ sqlcipher_sqlite3_str_appendall(pOut," <-- ");
+ switch( x ){
+ case JSONB_NULL: sqlcipher_sqlite3_str_appendall(pOut,"null"); break;
+ case JSONB_TRUE: sqlcipher_sqlite3_str_appendall(pOut,"true"); break;
+ case JSONB_FALSE: sqlcipher_sqlite3_str_appendall(pOut,"false"); break;
+ case JSONB_INT: sqlcipher_sqlite3_str_appendall(pOut,"int"); break;
+ case JSONB_INT5: sqlcipher_sqlite3_str_appendall(pOut,"int5"); break;
+ case JSONB_FLOAT: sqlcipher_sqlite3_str_appendall(pOut,"float"); break;
+ case JSONB_FLOAT5: sqlcipher_sqlite3_str_appendall(pOut,"float5"); break;
+ case JSONB_TEXT: sqlcipher_sqlite3_str_appendall(pOut,"text"); break;
+ case JSONB_TEXTJ: sqlcipher_sqlite3_str_appendall(pOut,"textj"); break;
+ case JSONB_TEXT5: sqlcipher_sqlite3_str_appendall(pOut,"text5"); break;
+ case JSONB_TEXTRAW: sqlcipher_sqlite3_str_appendall(pOut,"textraw"); break;
+ case JSONB_ARRAY: {
+ sqlcipher_sqlite3_str_appendf(pOut,"array, %u bytes\n", sz);
+ jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut);
+ showContent = 0;
+ break;
+ }
+ case JSONB_OBJECT: {
+ sqlcipher_sqlite3_str_appendf(pOut, "object, %u bytes\n", sz);
+ jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut);
+ showContent = 0;
+ break;
+ }
+ default: {
+ sqlcipher_sqlite3_str_appendall(pOut, "ERROR: unknown node type\n");
+ showContent = 0;
+ break;
+ }
+ }
+ if( showContent ){
+ if( sz==0 && x<=JSONB_FALSE ){
+ sqlcipher_sqlite3_str_append(pOut, "\n", 1);
+ }else{
+ u32 j;
+ sqlcipher_sqlite3_str_appendall(pOut, ": \"");
+ for(j=iStart+n; j<iStart+n+sz; j++){
+ u8 c = pParse->aBlob[j];
+ if( c<0x20 || c>=0x7f ) c = '.';
+ sqlcipher_sqlite3_str_append(pOut, (char*)&c, 1);
+ }
+ sqlcipher_sqlite3_str_append(pOut, "\"\n", 2);
+ }
+ }
+ iStart += n + sz;
+ }
+}
+static void jsonShowParse(JsonParse *pParse){
+ sqlcipher_sqlite3_str out;
+ char zBuf[1000];
+ if( pParse==0 ){
+ printf("NULL pointer\n");
+ return;
+ }else{
+ printf("nBlobAlloc = %u\n", pParse->nBlobAlloc);
+ printf("nBlob = %u\n", pParse->nBlob);
+ printf("delta = %d\n", pParse->delta);
+ if( pParse->nBlob==0 ) return;
+ printf("content (bytes 0..%u):\n", pParse->nBlob-1);
}
- jsonParseReset(&x);
- jsonResult(&s);
+ sqlcipher_sqlite3StrAccumInit(&out, 0, zBuf, sizeof(zBuf), 1000000);
+ jsonDebugPrintBlob(pParse, 0, pParse->nBlob, 0, &out);
+ printf("%s", sqlcipher_sqlite3_str_value(&out));
+ sqlcipher_sqlite3_str_reset(&out);
}
+#endif /* SQLITE_DEBUG */
+#ifdef SQLITE_DEBUG
/*
-** The json_test1(JSON) function return true (1) if the input is JSON
-** text generated by another json function. It returns (0) if the input
-** is not known to be JSON.
+** SQL function: json_parse(JSON)
+**
+** Parse JSON using jsonParseFuncArg(). Return text that is a
+** human-readable dump of the binary JSONB for the input parameter.
*/
-static void jsonTest1Func(
+static void jsonParseFunc(
sqlcipher_sqlite3_context *ctx,
int argc,
sqlcipher_sqlite3_value **argv
){
- UNUSED_PARAMETER(argc);
- sqlcipher_sqlite3_result_int(ctx, sqlcipher_sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
+ JsonParse *p; /* The parse */
+ sqlcipher_sqlite3_str out;
+
+ assert( argc>=1 );
+ sqlcipher_sqlite3StrAccumInit(&out, 0, 0, 0, 1000000);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
+ if( p==0 ) return;
+ if( argc==1 ){
+ jsonDebugPrintBlob(p, 0, p->nBlob, 0, &out);
+ sqlcipher_sqlite3_result_text64(ctx,out.zText,out.nChar,SQLITE_TRANSIENT,SQLITE_UTF8);
+ }else{
+ jsonShowParse(p);
+ }
+ jsonParseFree(p);
+ sqlcipher_sqlite3_str_reset(&out);
}
#endif /* SQLITE_DEBUG */
@@ -202288,7 +213864,7 @@ static void jsonTest1Func(
****************************************************************************/
/*
-** Implementation of the json_QUOTE(VALUE) function. Return a JSON value
+** Implementation of the json_quote(VALUE) function. Return a JSON value
** corresponding to the SQL value input. Mostly this means putting
** double-quotes around strings and returning the unquoted string "null"
** when given a NULL input.
@@ -202301,9 +213877,9 @@ static void jsonQuoteFunc(
JsonString jx;
UNUSED_PARAMETER(argc);
- jsonInit(&jx, ctx);
- jsonAppendValue(&jx, argv[0]);
- jsonResult(&jx);
+ jsonStringInit(&jx, ctx);
+ jsonAppendSqlValue(&jx, argv[0]);
+ jsonReturnString(&jx, 0, 0);
sqlcipher_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
@@ -202320,18 +213896,17 @@ static void jsonArrayFunc(
int i;
JsonString jx;
- jsonInit(&jx, ctx);
+ jsonStringInit(&jx, ctx);
jsonAppendChar(&jx, '[');
for(i=0; i<argc; i++){
jsonAppendSeparator(&jx);
- jsonAppendValue(&jx, argv[i]);
+ jsonAppendSqlValue(&jx, argv[i]);
}
jsonAppendChar(&jx, ']');
- jsonResult(&jx);
+ jsonReturnString(&jx, 0, 0);
sqlcipher_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
-
/*
** json_array_length(JSON)
** json_array_length(JSON, PATH)
@@ -202345,39 +213920,46 @@ static void jsonArrayLengthFunc(
sqlcipher_sqlite3_value **argv
){
JsonParse *p; /* The parse */
- sqlcipher_sqlite3_int64 n = 0;
+ sqlcipher_sqlite3_int64 cnt = 0;
u32 i;
- JsonNode *pNode;
+ u8 eErr = 0;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
if( p==0 ) return;
- assert( p->nNode );
if( argc==2 ){
const char *zPath = (const char*)sqlcipher_sqlite3_value_text(argv[1]);
- pNode = jsonLookup(p, zPath, 0, ctx);
+ if( zPath==0 ){
+ jsonParseFree(p);
+ return;
+ }
+ i = jsonLookupStep(p, 0, zPath[0]=='$' ? zPath+1 : "@", 0);
+ if( JSON_LOOKUP_ISERROR(i) ){
+ if( i==JSON_LOOKUP_NOTFOUND ){
+ /* no-op */
+ }else if( i==JSON_LOOKUP_PATHERROR ){
+ jsonBadPathError(ctx, zPath);
+ }else{
+ sqlcipher_sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ eErr = 1;
+ i = 0;
+ }
}else{
- pNode = p->aNode;
- }
- if( pNode==0 ){
- return;
+ i = 0;
}
- if( pNode->eType==JSON_ARRAY ){
- assert( (pNode->jnFlags & JNODE_APPEND)==0 );
- for(i=1; i<=pNode->n; n++){
- i += jsonNodeSize(&pNode[i]);
- }
+ if( (p->aBlob[i] & 0x0f)==JSONB_ARRAY ){
+ cnt = jsonbArrayCount(p, i);
}
- sqlcipher_sqlite3_result_int64(ctx, n);
+ if( !eErr ) sqlcipher_sqlite3_result_int64(ctx, cnt);
+ jsonParseFree(p);
}
-/*
-** Bit values for the flags passed into jsonExtractFunc() or
-** jsonSetFunc() via the user-data value.
-*/
-#define JSON_JSON 0x01 /* Result is always JSON */
-#define JSON_SQL 0x02 /* Result is always SQL */
-#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */
-#define JSON_ISSET 0x04 /* json_set(), not json_insert() */
+/* True if the string is all alphanumerics and underscores */
+static int jsonAllAlphanum(const char *z, int n){
+ int i;
+ for(i=0; i<n && (sqlcipher_sqlite3Isalnum(z[i]) || z[i]=='_'); i++){}
+ return i==n;
+}
/*
** json_extract(JSON, PATH, ...)
@@ -202404,161 +213986,307 @@ static void jsonExtractFunc(
int argc,
sqlcipher_sqlite3_value **argv
){
- JsonParse *p; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- int flags = SQLITE_PTR_TO_INT(sqlcipher_sqlite3_user_data(ctx));
- JsonString jx;
+ JsonParse *p = 0; /* The parse */
+ int flags; /* Flags associated with the function */
+ int i; /* Loop counter */
+ JsonString jx; /* String for array result */
if( argc<2 ) return;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
if( p==0 ) return;
- if( argc==2 ){
+ flags = SQLITE_PTR_TO_INT(sqlcipher_sqlite3_user_data(ctx));
+ jsonStringInit(&jx, ctx);
+ if( argc>2 ){
+ jsonAppendChar(&jx, '[');
+ }
+ for(i=1; i<argc; i++){
/* With a single PATH argument */
- zPath = (const char*)sqlcipher_sqlite3_value_text(argv[1]);
- if( zPath==0 ) return;
- if( flags & JSON_ABPATH ){
- if( zPath[0]!='$' ){
- /* The -> and ->> operators accept abbreviated PATH arguments. This
- ** is mostly for compatibility with PostgreSQL, but also for
- ** convenience.
- **
- ** NUMBER ==> $[NUMBER] // PG compatible
- ** LABEL ==> $.LABEL // PG compatible
- ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience
- */
- jsonInit(&jx, ctx);
- if( sqlcipher_sqlite3Isdigit(zPath[0]) ){
- jsonAppendRaw(&jx, "$[", 2);
- jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
- jsonAppendRaw(&jx, "]", 2);
- }else{
- jsonAppendRaw(&jx, "$.", 1 + (zPath[0]!='['));
- jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
- jsonAppendChar(&jx, 0);
- }
- pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx);
- jsonReset(&jx);
+ const char *zPath = (const char*)sqlcipher_sqlite3_value_text(argv[i]);
+ int nPath;
+ u32 j;
+ if( zPath==0 ) goto json_extract_error;
+ nPath = sqlcipher_sqlite3Strlen30(zPath);
+ if( zPath[0]=='$' ){
+ j = jsonLookupStep(p, 0, zPath+1, 0);
+ }else if( (flags & JSON_ABPATH) ){
+ /* The -> and ->> operators accept abbreviated PATH arguments. This
+ ** is mostly for compatibility with PostgreSQL, but also for
+ ** convenience.
+ **
+ ** NUMBER ==> $[NUMBER] // PG compatible
+ ** LABEL ==> $.LABEL // PG compatible
+ ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience
+ */
+ jsonStringInit(&jx, ctx);
+ if( sqlcipher_sqlite3_value_type(argv[i])==SQLITE_INTEGER ){
+ jsonAppendRawNZ(&jx, "[", 1);
+ jsonAppendRaw(&jx, zPath, nPath);
+ jsonAppendRawNZ(&jx, "]", 2);
+ }else if( jsonAllAlphanum(zPath, nPath) ){
+ jsonAppendRawNZ(&jx, ".", 1);
+ jsonAppendRaw(&jx, zPath, nPath);
+ }else if( zPath[0]=='[' && nPath>=3 && zPath[nPath-1]==']' ){
+ jsonAppendRaw(&jx, zPath, nPath);
}else{
- pNode = jsonLookup(p, zPath, 0, ctx);
+ jsonAppendRawNZ(&jx, ".\"", 2);
+ jsonAppendRaw(&jx, zPath, nPath);
+ jsonAppendRawNZ(&jx, "\"", 1);
}
- if( pNode ){
+ jsonStringTerminate(&jx);
+ j = jsonLookupStep(p, 0, jx.zBuf, 0);
+ jsonStringReset(&jx);
+ }else{
+ jsonBadPathError(ctx, zPath);
+ goto json_extract_error;
+ }
+ if( j<p->nBlob ){
+ if( argc==2 ){
if( flags & JSON_JSON ){
- jsonReturnJson(pNode, ctx, 0);
+ jsonStringInit(&jx, ctx);
+ jsonTranslateBlobToText(p, j, &jx);
+ jsonReturnString(&jx, 0, 0);
+ jsonStringReset(&jx);
+ assert( (flags & JSON_BLOB)==0 );
+ sqlcipher_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}else{
- jsonReturn(pNode, ctx, 0);
- sqlcipher_sqlite3_result_subtype(ctx, 0);
+ jsonReturnFromBlob(p, j, ctx, 0);
+ if( (flags & (JSON_SQL|JSON_BLOB))==0
+ && (p->aBlob[j]&0x0f)>=JSONB_ARRAY
+ ){
+ sqlcipher_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
}
+ }else{
+ jsonAppendSeparator(&jx);
+ jsonTranslateBlobToText(p, j, &jx);
}
- }else{
- pNode = jsonLookup(p, zPath, 0, ctx);
- if( p->nErr==0 && pNode ) jsonReturn(pNode, ctx, 0);
- }
- }else{
- /* Two or more PATH arguments results in a JSON array with each
- ** element of the array being the value selected by one of the PATHs */
- int i;
- jsonInit(&jx, ctx);
- jsonAppendChar(&jx, '[');
- for(i=1; i<argc; i++){
- zPath = (const char*)sqlcipher_sqlite3_value_text(argv[i]);
- pNode = jsonLookup(p, zPath, 0, ctx);
- if( p->nErr ) break;
- jsonAppendSeparator(&jx);
- if( pNode ){
- jsonRenderNode(pNode, &jx, 0);
+ }else if( j==JSON_LOOKUP_NOTFOUND ){
+ if( argc==2 ){
+ goto json_extract_error; /* Return NULL if not found */
}else{
- jsonAppendRaw(&jx, "null", 4);
+ jsonAppendSeparator(&jx);
+ jsonAppendRawNZ(&jx, "null", 4);
}
+ }else if( j==JSON_LOOKUP_ERROR ){
+ sqlcipher_sqlite3_result_error(ctx, "malformed JSON", -1);
+ goto json_extract_error;
+ }else{
+ jsonBadPathError(ctx, zPath);
+ goto json_extract_error;
}
- if( i==argc ){
- jsonAppendChar(&jx, ']');
- jsonResult(&jx);
+ }
+ if( argc>2 ){
+ jsonAppendChar(&jx, ']');
+ jsonReturnString(&jx, 0, 0);
+ if( (flags & JSON_BLOB)==0 ){
sqlcipher_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
- jsonReset(&jx);
}
+json_extract_error:
+ jsonStringReset(&jx);
+ jsonParseFree(p);
+ return;
}
-/* This is the RFC 7396 MergePatch algorithm.
-*/
-static JsonNode *jsonMergePatch(
- JsonParse *pParse, /* The JSON parser that contains the TARGET */
- u32 iTarget, /* Node of the TARGET in pParse */
- JsonNode *pPatch /* The PATCH */
-){
- u32 i, j;
- u32 iRoot;
- JsonNode *pTarget;
- if( pPatch->eType!=JSON_OBJECT ){
- return pPatch;
- }
- assert( iTarget<pParse->nNode );
- pTarget = &pParse->aNode[iTarget];
- assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
- if( pTarget->eType!=JSON_OBJECT ){
- jsonRemoveAllNulls(pPatch);
- return pPatch;
- }
- iRoot = iTarget;
- for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
- u32 nKey;
- const char *zKey;
- assert( pPatch[i].eType==JSON_STRING );
- assert( pPatch[i].jnFlags & JNODE_LABEL );
- assert( pPatch[i].eU==1 );
- nKey = pPatch[i].n;
- zKey = pPatch[i].u.zJContent;
- assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
- for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
- assert( pTarget[j].eType==JSON_STRING );
- assert( pTarget[j].jnFlags & JNODE_LABEL );
- assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
- if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
- if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
- if( pPatch[i+1].eType==JSON_NULL ){
- pTarget[j+1].jnFlags |= JNODE_REMOVE;
- }else{
- JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
- if( pNew==0 ) return 0;
- pTarget = &pParse->aNode[iTarget];
- if( pNew!=&pTarget[j+1] ){
- assert( pTarget[j+1].eU==0
- || pTarget[j+1].eU==1
- || pTarget[j+1].eU==2 );
- testcase( pTarget[j+1].eU==1 );
- testcase( pTarget[j+1].eU==2 );
- VVA( pTarget[j+1].eU = 5 );
- pTarget[j+1].u.pPatch = pNew;
- pTarget[j+1].jnFlags |= JNODE_PATCH;
- }
- }
- break;
+/*
+** Return codes for jsonMergePatch()
+*/
+#define JSON_MERGE_OK 0 /* Success */
+#define JSON_MERGE_BADTARGET 1 /* Malformed TARGET blob */
+#define JSON_MERGE_BADPATCH 2 /* Malformed PATCH blob */
+#define JSON_MERGE_OOM 3 /* Out-of-memory condition */
+
+/*
+** RFC-7396 MergePatch for two JSONB blobs.
+**
+** pTarget is the target. pPatch is the patch. The target is updated
+** in place. The patch is read-only.
+**
+** The original RFC-7396 algorithm is this:
+**
+** define MergePatch(Target, Patch):
+** if Patch is an Object:
+** if Target is not an Object:
+** Target = {} # Ignore the contents and set it to an empty Object
+** for each Name/Value pair in Patch:
+** if Value is null:
+** if Name exists in Target:
+** remove the Name/Value pair from Target
+** else:
+** Target[Name] = MergePatch(Target[Name], Value)
+** return Target
+** else:
+** return Patch
+**
+** Here is an equivalent algorithm restructured to show the actual
+** implementation:
+**
+** 01 define MergePatch(Target, Patch):
+** 02 if Patch is not an Object:
+** 03 return Patch
+** 04 else: // if Patch is an Object
+** 05 if Target is not an Object:
+** 06 Target = {}
+** 07 for each Name/Value pair in Patch:
+** 08 if Name exists in Target:
+** 09 if Value is null:
+** 10 remove the Name/Value pair from Target
+** 11 else
+** 12 Target[name] = MergePatch(Target[Name], Value)
+** 13 else if Value is not NULL:
+** 14 if Value is not an Object:
+** 15 Target[name] = Value
+** 16 else:
+** 17 Target[name] = MergePatch('{}',value)
+** 18 return Target
+** |
+** ^---- Line numbers referenced in comments in the implementation
+*/
+static int jsonMergePatch(
+ JsonParse *pTarget, /* The JSON parser that contains the TARGET */
+ u32 iTarget, /* Index of TARGET in pTarget->aBlob[] */
+ const JsonParse *pPatch, /* The PATCH */
+ u32 iPatch /* Index of PATCH in pPatch->aBlob[] */
+){
+ u8 x; /* Type of a single node */
+ u32 n, sz=0; /* Return values from jsonbPayloadSize() */
+ u32 iTCursor; /* Cursor position while scanning the target object */
+ u32 iTStart; /* First label in the target object */
+ u32 iTEndBE; /* Original first byte past end of target, before edit */
+ u32 iTEnd; /* Current first byte past end of target */
+ u8 eTLabel; /* Node type of the target label */
+ u32 iTLabel = 0; /* Index of the label */
+ u32 nTLabel = 0; /* Header size in bytes for the target label */
+ u32 szTLabel = 0; /* Size of the target label payload */
+ u32 iTValue = 0; /* Index of the target value */
+ u32 nTValue = 0; /* Header size of the target value */
+ u32 szTValue = 0; /* Payload size for the target value */
+
+ u32 iPCursor; /* Cursor position while scanning the patch */
+ u32 iPEnd; /* First byte past the end of the patch */
+ u8 ePLabel; /* Node type of the patch label */
+ u32 iPLabel; /* Start of patch label */
+ u32 nPLabel; /* Size of header on the patch label */
+ u32 szPLabel; /* Payload size of the patch label */
+ u32 iPValue; /* Start of patch value */
+ u32 nPValue; /* Header size for the patch value */
+ u32 szPValue; /* Payload size of the patch value */
+
+ assert( iTarget>=0 && iTarget<pTarget->nBlob );
+ assert( iPatch>=0 && iPatch<pPatch->nBlob );
+ x = pPatch->aBlob[iPatch] & 0x0f;
+ if( x!=JSONB_OBJECT ){ /* Algorithm line 02 */
+ u32 szPatch; /* Total size of the patch, header+payload */
+ u32 szTarget; /* Total size of the target, header+payload */
+ n = jsonbPayloadSize(pPatch, iPatch, &sz);
+ szPatch = n+sz;
+ sz = 0;
+ n = jsonbPayloadSize(pTarget, iTarget, &sz);
+ szTarget = n+sz;
+ jsonBlobEdit(pTarget, iTarget, szTarget, pPatch->aBlob+iPatch, szPatch);
+ return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK; /* Line 03 */
+ }
+ x = pTarget->aBlob[iTarget] & 0x0f;
+ if( x!=JSONB_OBJECT ){ /* Algorithm line 05 */
+ n = jsonbPayloadSize(pTarget, iTarget, &sz);
+ jsonBlobEdit(pTarget, iTarget+n, sz, 0, 0);
+ x = pTarget->aBlob[iTarget];
+ pTarget->aBlob[iTarget] = (x & 0xf0) | JSONB_OBJECT;
+ }
+ n = jsonbPayloadSize(pPatch, iPatch, &sz);
+ if( NEVER(n==0) ) return JSON_MERGE_BADPATCH;
+ iPCursor = iPatch+n;
+ iPEnd = iPCursor+sz;
+ n = jsonbPayloadSize(pTarget, iTarget, &sz);
+ if( NEVER(n==0) ) return JSON_MERGE_BADTARGET;
+ iTStart = iTarget+n;
+ iTEndBE = iTStart+sz;
+
+ while( iPCursor<iPEnd ){ /* Algorithm line 07 */
+ iPLabel = iPCursor;
+ ePLabel = pPatch->aBlob[iPCursor] & 0x0f;
+ if( ePLabel<JSONB_TEXT || ePLabel>JSONB_TEXTRAW ){
+ return JSON_MERGE_BADPATCH;
+ }
+ nPLabel = jsonbPayloadSize(pPatch, iPCursor, &szPLabel);
+ if( nPLabel==0 ) return JSON_MERGE_BADPATCH;
+ iPValue = iPCursor + nPLabel + szPLabel;
+ if( iPValue>=iPEnd ) return JSON_MERGE_BADPATCH;
+ nPValue = jsonbPayloadSize(pPatch, iPValue, &szPValue);
+ if( nPValue==0 ) return JSON_MERGE_BADPATCH;
+ iPCursor = iPValue + nPValue + szPValue;
+ if( iPCursor>iPEnd ) return JSON_MERGE_BADPATCH;
+
+ iTCursor = iTStart;
+ iTEnd = iTEndBE + pTarget->delta;
+ while( iTCursor<iTEnd ){
+ int isEqual; /* true if the patch and target labels match */
+ iTLabel = iTCursor;
+ eTLabel = pTarget->aBlob[iTCursor] & 0x0f;
+ if( eTLabel<JSONB_TEXT || eTLabel>JSONB_TEXTRAW ){
+ return JSON_MERGE_BADTARGET;
+ }
+ nTLabel = jsonbPayloadSize(pTarget, iTCursor, &szTLabel);
+ if( nTLabel==0 ) return JSON_MERGE_BADTARGET;
+ iTValue = iTLabel + nTLabel + szTLabel;
+ if( iTValue>=iTEnd ) return JSON_MERGE_BADTARGET;
+ nTValue = jsonbPayloadSize(pTarget, iTValue, &szTValue);
+ if( nTValue==0 ) return JSON_MERGE_BADTARGET;
+ if( iTValue + nTValue + szTValue > iTEnd ) return JSON_MERGE_BADTARGET;
+ isEqual = jsonLabelCompare(
+ (const char*)&pPatch->aBlob[iPLabel+nPLabel],
+ szPLabel,
+ (ePLabel==JSONB_TEXT || ePLabel==JSONB_TEXTRAW),
+ (const char*)&pTarget->aBlob[iTLabel+nTLabel],
+ szTLabel,
+ (eTLabel==JSONB_TEXT || eTLabel==JSONB_TEXTRAW));
+ if( isEqual ) break;
+ iTCursor = iTValue + nTValue + szTValue;
+ }
+ x = pPatch->aBlob[iPValue] & 0x0f;
+ if( iTCursor<iTEnd ){
+ /* A match was found. Algorithm line 08 */
+ if( x==0 ){
+ /* Patch value is NULL. Algorithm line 09 */
+ jsonBlobEdit(pTarget, iTLabel, nTLabel+szTLabel+nTValue+szTValue, 0,0);
+ /* vvvvvv----- No OOM on a delete-only edit */
+ if( NEVER(pTarget->oom) ) return JSON_MERGE_OOM;
+ }else{
+ /* Algorithm line 12 */
+ int rc, savedDelta = pTarget->delta;
+ pTarget->delta = 0;
+ rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue);
+ if( rc ) return rc;
+ pTarget->delta += savedDelta;
+ }
+ }else if( x>0 ){ /* Algorithm line 13 */
+ /* No match and patch value is not NULL */
+ u32 szNew = szPLabel+nPLabel;
+ if( (pPatch->aBlob[iPValue] & 0x0f)!=JSONB_OBJECT ){ /* Line 14 */
+ jsonBlobEdit(pTarget, iTEnd, 0, 0, szPValue+nPValue+szNew);
+ if( pTarget->oom ) return JSON_MERGE_OOM;
+ memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew);
+ memcpy(&pTarget->aBlob[iTEnd+szNew],
+ &pPatch->aBlob[iPValue], szPValue+nPValue);
+ }else{
+ int rc, savedDelta;
+ jsonBlobEdit(pTarget, iTEnd, 0, 0, szNew+1);
+ if( pTarget->oom ) return JSON_MERGE_OOM;
+ memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew);
+ pTarget->aBlob[iTEnd+szNew] = 0x00;
+ savedDelta = pTarget->delta;
+ pTarget->delta = 0;
+ rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue);
+ if( rc ) return rc;
+ pTarget->delta += savedDelta;
}
}
- if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
- int iStart, iPatch;
- iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
- jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
- iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
- if( pParse->oom ) return 0;
- jsonRemoveAllNulls(pPatch);
- pTarget = &pParse->aNode[iTarget];
- assert( pParse->aNode[iRoot].eU==0 || pParse->aNode[iRoot].eU==2 );
- testcase( pParse->aNode[iRoot].eU==2 );
- pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
- VVA( pParse->aNode[iRoot].eU = 2 );
- pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
- iRoot = iStart;
- assert( pParse->aNode[iPatch].eU==0 );
- VVA( pParse->aNode[iPatch].eU = 5 );
- pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
- pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
- }
}
- return pTarget;
+ if( pTarget->delta ) jsonAfterEditSizeAdjust(pTarget, iTarget);
+ return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK;
}
+
/*
** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON
** object that is the result of running the RFC 7396 MergePatch() algorithm
@@ -202569,25 +214297,27 @@ static void jsonPatchFunc(
int argc,
sqlcipher_sqlite3_value **argv
){
- JsonParse x; /* The JSON that is being patched */
- JsonParse y; /* The patch */
- JsonNode *pResult; /* The result of the merge */
+ JsonParse *pTarget; /* The TARGET */
+ JsonParse *pPatch; /* The PATCH */
+ int rc; /* Result code */
UNUSED_PARAMETER(argc);
- if( jsonParse(&x, ctx, (const char*)sqlcipher_sqlite3_value_text(argv[0])) ) return;
- if( jsonParse(&y, ctx, (const char*)sqlcipher_sqlite3_value_text(argv[1])) ){
- jsonParseReset(&x);
- return;
- }
- pResult = jsonMergePatch(&x, 0, y.aNode);
- assert( pResult!=0 || x.oom );
- if( pResult ){
- jsonReturnJson(pResult, ctx, 0);
- }else{
- sqlcipher_sqlite3_result_error_nomem(ctx);
+ assert( argc==2 );
+ pTarget = jsonParseFuncArg(ctx, argv[0], JSON_EDITABLE);
+ if( pTarget==0 ) return;
+ pPatch = jsonParseFuncArg(ctx, argv[1], 0);
+ if( pPatch ){
+ rc = jsonMergePatch(pTarget, 0, pPatch, 0);
+ if( rc==JSON_MERGE_OK ){
+ jsonReturnParse(ctx, pTarget);
+ }else if( rc==JSON_MERGE_OOM ){
+ sqlcipher_sqlite3_result_error_nomem(ctx);
+ }else{
+ sqlcipher_sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ jsonParseFree(pPatch);
}
- jsonParseReset(&x);
- jsonParseReset(&y);
+ jsonParseFree(pTarget);
}
@@ -202611,23 +214341,23 @@ static void jsonObjectFunc(
"of arguments", -1);
return;
}
- jsonInit(&jx, ctx);
+ jsonStringInit(&jx, ctx);
jsonAppendChar(&jx, '{');
for(i=0; i<argc; i+=2){
if( sqlcipher_sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
sqlcipher_sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
- jsonReset(&jx);
+ jsonStringReset(&jx);
return;
}
jsonAppendSeparator(&jx);
z = (const char*)sqlcipher_sqlite3_value_text(argv[i]);
- n = (u32)sqlcipher_sqlite3_value_bytes(argv[i]);
+ n = sqlcipher_sqlite3_value_bytes(argv[i]);
jsonAppendString(&jx, z, n);
jsonAppendChar(&jx, ':');
- jsonAppendValue(&jx, argv[i+1]);
+ jsonAppendSqlValue(&jx, argv[i+1]);
}
jsonAppendChar(&jx, '}');
- jsonResult(&jx);
+ jsonReturnString(&jx, 0, 0);
sqlcipher_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
@@ -202643,26 +214373,50 @@ static void jsonRemoveFunc(
int argc,
sqlcipher_sqlite3_value **argv
){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
+ JsonParse *p; /* The parse */
+ const char *zPath = 0; /* Path of element to be removed */
+ int i; /* Loop counter */
+ u32 rc; /* Subroutine return code */
if( argc<1 ) return;
- if( jsonParse(&x, ctx, (const char*)sqlcipher_sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i++){
+ p = jsonParseFuncArg(ctx, argv[0], argc>1 ? JSON_EDITABLE : 0);
+ if( p==0 ) return;
+ for(i=1; i<argc; i++){
zPath = (const char*)sqlcipher_sqlite3_value_text(argv[i]);
- if( zPath==0 ) goto remove_done;
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto remove_done;
- if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
- }
- if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
- jsonReturnJson(x.aNode, ctx, 0);
+ if( zPath==0 ){
+ goto json_remove_done;
+ }
+ if( zPath[0]!='$' ){
+ goto json_remove_patherror;
+ }
+ if( zPath[1]==0 ){
+ /* json_remove(j,'$') returns NULL */
+ goto json_remove_done;
+ }
+ p->eEdit = JEDIT_DEL;
+ p->delta = 0;
+ rc = jsonLookupStep(p, 0, zPath+1, 0);
+ if( JSON_LOOKUP_ISERROR(rc) ){
+ if( rc==JSON_LOOKUP_NOTFOUND ){
+ continue; /* No-op */
+ }else if( rc==JSON_LOOKUP_PATHERROR ){
+ jsonBadPathError(ctx, zPath);
+ }else{
+ sqlcipher_sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ goto json_remove_done;
+ }
}
-remove_done:
- jsonParseReset(&x);
+ jsonReturnParse(ctx, p);
+ jsonParseFree(p);
+ return;
+
+json_remove_patherror:
+ jsonBadPathError(ctx, zPath);
+
+json_remove_done:
+ jsonParseFree(p);
+ return;
}
/*
@@ -202676,38 +214430,12 @@ static void jsonReplaceFunc(
int argc,
sqlcipher_sqlite3_value **argv
){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
-
if( argc<1 ) return;
if( (argc&1)==0 ) {
jsonWrongNumArgs(ctx, "replace");
return;
}
- if( jsonParse(&x, ctx, (const char*)sqlcipher_sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i+=2){
- zPath = (const char*)sqlcipher_sqlite3_value_text(argv[i]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto replace_err;
- if( pNode ){
- assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 );
- testcase( pNode->eU!=0 && pNode->eU!=1 );
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- VVA( pNode->eU = 4 );
- pNode->u.iReplace = i + 1;
- }
- }
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- assert( x.aNode[0].eU==4 );
- sqlcipher_sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
- }else{
- jsonReturnJson(x.aNode, ctx, argv);
- }
-replace_err:
- jsonParseReset(&x);
+ jsonInsertIntoBlob(ctx, argc, argv, JEDIT_REPL);
}
@@ -202728,45 +214456,16 @@ static void jsonSetFunc(
int argc,
sqlcipher_sqlite3_value **argv
){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
- int bApnd;
- int bIsSet = sqlcipher_sqlite3_user_data(ctx)!=0;
+
+ int flags = SQLITE_PTR_TO_INT(sqlcipher_sqlite3_user_data(ctx));
+ int bIsSet = (flags&JSON_ISSET)!=0;
if( argc<1 ) return;
if( (argc&1)==0 ) {
jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
return;
}
- if( jsonParse(&x, ctx, (const char*)sqlcipher_sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i+=2){
- zPath = (const char*)sqlcipher_sqlite3_value_text(argv[i]);
- bApnd = 0;
- pNode = jsonLookup(&x, zPath, &bApnd, ctx);
- if( x.oom ){
- sqlcipher_sqlite3_result_error_nomem(ctx);
- goto jsonSetDone;
- }else if( x.nErr ){
- goto jsonSetDone;
- }else if( pNode && (bApnd || bIsSet) ){
- testcase( pNode->eU!=0 && pNode->eU!=1 );
- assert( pNode->eU!=3 && pNode->eU!=5 );
- VVA( pNode->eU = 4 );
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- pNode->u.iReplace = i + 1;
- }
- }
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- assert( x.aNode[0].eU==4 );
- sqlcipher_sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
- }else{
- jsonReturnJson(x.aNode, ctx, argv);
- }
-jsonSetDone:
- jsonParseReset(&x);
+ jsonInsertIntoBlob(ctx, argc, argv, bIsSet ? JEDIT_SET : JEDIT_INS);
}
/*
@@ -202782,27 +214481,127 @@ static void jsonTypeFunc(
sqlcipher_sqlite3_value **argv
){
JsonParse *p; /* The parse */
- const char *zPath;
- JsonNode *pNode;
+ const char *zPath = 0;
+ u32 i;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
if( p==0 ) return;
if( argc==2 ){
zPath = (const char*)sqlcipher_sqlite3_value_text(argv[1]);
- pNode = jsonLookup(p, zPath, 0, ctx);
+ if( zPath==0 ) goto json_type_done;
+ if( zPath[0]!='$' ){
+ jsonBadPathError(ctx, zPath);
+ goto json_type_done;
+ }
+ i = jsonLookupStep(p, 0, zPath+1, 0);
+ if( JSON_LOOKUP_ISERROR(i) ){
+ if( i==JSON_LOOKUP_NOTFOUND ){
+ /* no-op */
+ }else if( i==JSON_LOOKUP_PATHERROR ){
+ jsonBadPathError(ctx, zPath);
+ }else{
+ sqlcipher_sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ goto json_type_done;
+ }
}else{
- pNode = p->aNode;
+ i = 0;
}
- if( pNode ){
- sqlcipher_sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
+ sqlcipher_sqlite3_result_text(ctx, jsonbType[p->aBlob[i]&0x0f], -1, SQLITE_STATIC);
+json_type_done:
+ jsonParseFree(p);
+}
+
+/*
+** json_pretty(JSON)
+** json_pretty(JSON, INDENT)
+**
+** Return text that is a pretty-printed rendering of the input JSON.
+** If the argument is not valid JSON, return NULL.
+**
+** The INDENT argument is text that is used for indentation. If omitted,
+** it defaults to four spaces (the same as PostgreSQL).
+*/
+static void jsonPrettyFunc(
+ sqlcipher_sqlite3_context *ctx,
+ int argc,
+ sqlcipher_sqlite3_value **argv
+){
+ JsonString s; /* The output string */
+ JsonPretty x; /* Pretty printing context */
+
+ memset(&x, 0, sizeof(x));
+ x.pParse = jsonParseFuncArg(ctx, argv[0], 0);
+ if( x.pParse==0 ) return;
+ x.pOut = &s;
+ jsonStringInit(&s, ctx);
+ if( argc==1 || (x.zIndent = (const char*)sqlcipher_sqlite3_value_text(argv[1]))==0 ){
+ x.zIndent = " ";
+ x.szIndent = 4;
+ }else{
+ x.szIndent = (u32)strlen(x.zIndent);
}
+ jsonTranslateBlobToPrettyText(&x, 0);
+ jsonReturnString(&s, 0, 0);
+ jsonParseFree(x.pParse);
}
/*
** json_valid(JSON)
-**
-** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
-** Return 0 otherwise.
+** json_valid(JSON, FLAGS)
+**
+** Check the JSON argument to see if it is well-formed. The FLAGS argument
+** encodes the various constraints on what is meant by "well-formed":
+**
+** 0x01 Canonical RFC-8259 JSON text
+** 0x02 JSON text with optional JSON-5 extensions
+** 0x04 Superficially appears to be JSONB
+** 0x08 Strictly well-formed JSONB
+**
+** If the FLAGS argument is omitted, it defaults to 1. Useful values for
+** FLAGS include:
+**
+** 1 Strict canonical JSON text
+** 2 JSON text perhaps with JSON-5 extensions
+** 4 Superficially appears to be JSONB
+** 5 Canonical JSON text or superficial JSONB
+** 6 JSON-5 text or superficial JSONB
+** 8 Strict JSONB
+** 9 Canonical JSON text or strict JSONB
+** 10 JSON-5 text or strict JSONB
+**
+** Other flag combinations are redundant. For example, every canonical
+** JSON text is also well-formed JSON-5 text, so FLAG values 2 and 3
+** are the same. Similarly, any input that passes a strict JSONB validation
+** will also pass the superficial validation so 12 through 15 are the same
+** as 8 through 11 respectively.
+**
+** This routine runs in linear time to validate text and when doing strict
+** JSONB validation. Superficial JSONB validation is constant time,
+** assuming the BLOB is already in memory. The performance advantage
+** of superficial JSONB validation is why that option is provided.
+** Application developers can choose to do fast superficial validation or
+** slower strict validation, according to their specific needs.
+**
+** Only the lower four bits of the FLAGS argument are currently used.
+** Higher bits are reserved for future expansion. To facilitate
+** compatibility, the current implementation raises an error if any bit
+** in FLAGS is set other than the lower four bits.
+**
+** The original circa 2015 implementation of the JSON routines in
+** SQLite only supported canonical RFC-8259 JSON text and the json_valid()
+** function only accepted one argument. That is why the default value
+** for the FLAGS argument is 1, since FLAGS=1 causes this routine to only
+** recognize canonical RFC-8259 JSON text as valid. The extra FLAGS
+** argument was added when the JSON routines were extended to support
+** JSON5-like extensions and binary JSONB stored in BLOBs.
+**
+** Return Values:
+**
+** * Raise an error if FLAGS is outside the range of 1 to 15.
+** * Return NULL if the input is NULL
+** * Return 1 if the input is well-formed.
+** * Return 0 if the input is not well-formed.
*/
static void jsonValidFunc(
sqlcipher_sqlite3_context *ctx,
@@ -202810,11 +214609,127 @@ static void jsonValidFunc(
sqlcipher_sqlite3_value **argv
){
JsonParse *p; /* The parse */
- UNUSED_PARAMETER(argc);
- p = jsonParseCached(ctx, argv, 0);
- sqlcipher_sqlite3_result_int(ctx, p!=0);
+ u8 flags = 1;
+ u8 res = 0;
+ if( argc==2 ){
+ i64 f = sqlcipher_sqlite3_value_int64(argv[1]);
+ if( f<1 || f>15 ){
+ sqlcipher_sqlite3_result_error(ctx, "FLAGS parameter to json_valid() must be"
+ " between 1 and 15", -1);
+ return;
+ }
+ flags = f & 0x0f;
+ }
+ switch( sqlcipher_sqlite3_value_type(argv[0]) ){
+ case SQLITE_NULL: {
+#ifdef SQLITE_LEGACY_JSON_VALID
+ /* Incorrect legacy behavior was to return FALSE for a NULL input */
+ sqlcipher_sqlite3_result_int(ctx, 0);
+#endif
+ return;
+ }
+ case SQLITE_BLOB: {
+ if( jsonFuncArgMightBeBinary(argv[0]) ){
+ if( flags & 0x04 ){
+ /* Superficial checking only - accomplished by the
+ ** jsonFuncArgMightBeBinary() call above. */
+ res = 1;
+ }else if( flags & 0x08 ){
+ /* Strict checking. Check by translating BLOB->TEXT->BLOB. If
+ ** no errors occur, call that a "strict check". */
+ JsonParse px;
+ u32 iErr;
+ memset(&px, 0, sizeof(px));
+ px.aBlob = (u8*)sqlcipher_sqlite3_value_blob(argv[0]);
+ px.nBlob = sqlcipher_sqlite3_value_bytes(argv[0]);
+ iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1);
+ res = iErr==0;
+ }
+ break;
+ }
+ /* Fall through into interpreting the input as text. See note
+ ** above at tag-20240123-a. */
+ /* no break */ deliberate_fall_through
+ }
+ default: {
+ JsonParse px;
+ if( (flags & 0x3)==0 ) break;
+ memset(&px, 0, sizeof(px));
+
+ p = jsonParseFuncArg(ctx, argv[0], JSON_KEEPERROR);
+ if( p ){
+ if( p->oom ){
+ sqlcipher_sqlite3_result_error_nomem(ctx);
+ }else if( p->nErr ){
+ /* no-op */
+ }else if( (flags & 0x02)!=0 || p->hasNonstd==0 ){
+ res = 1;
+ }
+ jsonParseFree(p);
+ }else{
+ sqlcipher_sqlite3_result_error_nomem(ctx);
+ }
+ break;
+ }
+ }
+ sqlcipher_sqlite3_result_int(ctx, res);
}
+/*
+** json_error_position(JSON)
+**
+** If the argument is NULL, return NULL
+**
+** If the argument is BLOB, do a full validity check and return non-zero
+** if the check fails. The return value is the approximate 1-based offset
+** to the byte of the element that contains the first error.
+**
+** Otherwise interpret the argument is TEXT (even if it is numeric) and
+** return the 1-based character position for where the parser first recognized
+** that the input was not valid JSON, or return 0 if the input text looks
+** ok. JSON-5 extensions are accepted.
+*/
+static void jsonErrorFunc(
+ sqlcipher_sqlite3_context *ctx,
+ int argc,
+ sqlcipher_sqlite3_value **argv
+){
+ i64 iErrPos = 0; /* Error position to be returned */
+ JsonParse s;
+
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ memset(&s, 0, sizeof(s));
+ s.db = sqlcipher_sqlite3_context_db_handle(ctx);
+ if( jsonFuncArgMightBeBinary(argv[0]) ){
+ s.aBlob = (u8*)sqlcipher_sqlite3_value_blob(argv[0]);
+ s.nBlob = sqlcipher_sqlite3_value_bytes(argv[0]);
+ iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1);
+ }else{
+ s.zJson = (char*)sqlcipher_sqlite3_value_text(argv[0]);
+ if( s.zJson==0 ) return; /* NULL input or OOM */
+ s.nJson = sqlcipher_sqlite3_value_bytes(argv[0]);
+ if( jsonConvertTextToBlob(&s,0) ){
+ if( s.oom ){
+ iErrPos = -1;
+ }else{
+ /* Convert byte-offset s.iErr into a character offset */
+ u32 k;
+ assert( s.zJson!=0 ); /* Because s.oom is false */
+ for(k=0; k<s.iErr && ALWAYS(s.zJson[k]); k++){
+ if( (s.zJson[k] & 0xc0)!=0x80 ) iErrPos++;
+ }
+ iErrPos++;
+ }
+ }
+ }
+ jsonParseReset(&s);
+ if( iErrPos<0 ){
+ sqlcipher_sqlite3_result_error_nomem(ctx);
+ }else{
+ sqlcipher_sqlite3_result_int64(ctx, iErrPos);
+ }
+}
/****************************************************************************
** Aggregate SQL function implementations
@@ -202834,31 +214749,42 @@ static void jsonArrayStep(
pStr = (JsonString*)sqlcipher_sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
- jsonInit(pStr, ctx);
+ jsonStringInit(pStr, ctx);
jsonAppendChar(pStr, '[');
}else if( pStr->nUsed>1 ){
jsonAppendChar(pStr, ',');
}
pStr->pCtx = ctx;
- jsonAppendValue(pStr, argv[0]);
+ jsonAppendSqlValue(pStr, argv[0]);
}
}
static void jsonArrayCompute(sqlcipher_sqlite3_context *ctx, int isFinal){
JsonString *pStr;
pStr = (JsonString*)sqlcipher_sqlite3_aggregate_context(ctx, 0);
if( pStr ){
+ int flags;
pStr->pCtx = ctx;
jsonAppendChar(pStr, ']');
- if( pStr->bErr ){
- if( pStr->bErr==1 ) sqlcipher_sqlite3_result_error_nomem(ctx);
- assert( pStr->bStatic );
+ flags = SQLITE_PTR_TO_INT(sqlcipher_sqlite3_user_data(ctx));
+ if( pStr->eErr ){
+ jsonReturnString(pStr, 0, 0);
+ return;
+ }else if( flags & JSON_BLOB ){
+ jsonReturnStringAsBlob(pStr);
+ if( isFinal ){
+ if( !pStr->bStatic ) sqlcipher_sqlite3RCStrUnref(pStr->zBuf);
+ }else{
+ jsonStringTrimOneChar(pStr);
+ }
+ return;
}else if( isFinal ){
sqlcipher_sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : sqlcipher_sqlite3_free);
+ pStr->bStatic ? SQLITE_TRANSIENT :
+ sqlcipher_sqlite3RCStrUnref);
pStr->bStatic = 1;
}else{
sqlcipher_sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
- pStr->nUsed--;
+ jsonStringTrimOneChar(pStr);
}
}else{
sqlcipher_sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
@@ -202895,7 +214821,7 @@ static void jsonGroupInverse(
pStr = (JsonString*)sqlcipher_sqlite3_aggregate_context(ctx, 0);
#ifdef NEVER
/* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
- ** always have been called to initalize it */
+ ** always have been called to initialize it */
if( NEVER(!pStr) ) return;
#endif
z = pStr->zBuf;
@@ -202939,34 +214865,46 @@ static void jsonObjectStep(
pStr = (JsonString*)sqlcipher_sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
- jsonInit(pStr, ctx);
+ jsonStringInit(pStr, ctx);
jsonAppendChar(pStr, '{');
}else if( pStr->nUsed>1 ){
jsonAppendChar(pStr, ',');
}
pStr->pCtx = ctx;
z = (const char*)sqlcipher_sqlite3_value_text(argv[0]);
- n = (u32)sqlcipher_sqlite3_value_bytes(argv[0]);
+ n = sqlcipher_sqlite3Strlen30(z);
jsonAppendString(pStr, z, n);
jsonAppendChar(pStr, ':');
- jsonAppendValue(pStr, argv[1]);
+ jsonAppendSqlValue(pStr, argv[1]);
}
}
static void jsonObjectCompute(sqlcipher_sqlite3_context *ctx, int isFinal){
JsonString *pStr;
pStr = (JsonString*)sqlcipher_sqlite3_aggregate_context(ctx, 0);
if( pStr ){
+ int flags;
jsonAppendChar(pStr, '}');
- if( pStr->bErr ){
- if( pStr->bErr==1 ) sqlcipher_sqlite3_result_error_nomem(ctx);
- assert( pStr->bStatic );
+ pStr->pCtx = ctx;
+ flags = SQLITE_PTR_TO_INT(sqlcipher_sqlite3_user_data(ctx));
+ if( pStr->eErr ){
+ jsonReturnString(pStr, 0, 0);
+ return;
+ }else if( flags & JSON_BLOB ){
+ jsonReturnStringAsBlob(pStr);
+ if( isFinal ){
+ if( !pStr->bStatic ) sqlcipher_sqlite3RCStrUnref(pStr->zBuf);
+ }else{
+ jsonStringTrimOneChar(pStr);
+ }
+ return;
}else if( isFinal ){
sqlcipher_sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : sqlcipher_sqlite3_free);
+ pStr->bStatic ? SQLITE_TRANSIENT :
+ sqlcipher_sqlite3RCStrUnref);
pStr->bStatic = 1;
}else{
sqlcipher_sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
- pStr->nUsed--;
+ jsonStringTrimOneChar(pStr);
}
}else{
sqlcipher_sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
@@ -202986,19 +214924,37 @@ static void jsonObjectFinal(sqlcipher_sqlite3_context *ctx){
/****************************************************************************
** The json_each virtual table
****************************************************************************/
+typedef struct JsonParent JsonParent;
+struct JsonParent {
+ u32 iHead; /* Start of object or array */
+ u32 iValue; /* Start of the value */
+ u32 iEnd; /* First byte past the end */
+ u32 nPath; /* Length of path */
+ i64 iKey; /* Key for JSONB_ARRAY */
+};
+
typedef struct JsonEachCursor JsonEachCursor;
struct JsonEachCursor {
sqlcipher_sqlite3_vtab_cursor base; /* Base class - must be first */
u32 iRowid; /* The rowid */
- u32 iBegin; /* The first node of the scan */
- u32 i; /* Index in sParse.aNode[] of current row */
+ u32 i; /* Index in sParse.aBlob[] of current row */
u32 iEnd; /* EOF when i equals or exceeds this value */
- u8 eType; /* Type of top-level element */
+ u32 nRoot; /* Size of the root path in bytes */
+ u8 eType; /* Type of the container for element i */
u8 bRecursive; /* True for json_tree(). False for json_each() */
- char *zJson; /* Input JSON */
- char *zRoot; /* Path by which to filter zJson */
+ u32 nParent; /* Current nesting depth */
+ u32 nParentAlloc; /* Space allocated for aParent[] */
+ JsonParent *aParent; /* Parent elements of i */
+ sqlcipher_sqlite3 *db; /* Database connection */
+ JsonString path; /* Current path */
JsonParse sParse; /* Parse of the input JSON */
};
+typedef struct JsonEachConnection JsonEachConnection;
+struct JsonEachConnection {
+ sqlcipher_sqlite3_vtab base; /* Base class - must be first */
+ sqlcipher_sqlite3 *db; /* Database connection */
+};
+
/* Constructor for the json_each virtual table */
static int jsonEachConnect(
@@ -203008,7 +214964,7 @@ static int jsonEachConnect(
sqlcipher_sqlite3_vtab **ppVtab,
char **pzErr
){
- sqlcipher_sqlite3_vtab *pNew;
+ JsonEachConnection *pNew;
int rc;
/* Column numbers */
@@ -203034,28 +214990,32 @@ static int jsonEachConnect(
"CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
"json HIDDEN,root HIDDEN)");
if( rc==SQLITE_OK ){
- pNew = *ppVtab = sqlcipher_sqlite3_malloc( sizeof(*pNew) );
+ pNew = (JsonEachConnection*)sqlcipher_sqlite3DbMallocZero(db, sizeof(*pNew));
+ *ppVtab = (sqlcipher_sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
- memset(pNew, 0, sizeof(*pNew));
sqlcipher_sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
+ pNew->db = db;
}
return rc;
}
/* destructor for json_each virtual table */
static int jsonEachDisconnect(sqlcipher_sqlite3_vtab *pVtab){
- sqlcipher_sqlite3_free(pVtab);
+ JsonEachConnection *p = (JsonEachConnection*)pVtab;
+ sqlcipher_sqlite3DbFree(p->db, pVtab);
return SQLITE_OK;
}
/* constructor for a JsonEachCursor object for json_each(). */
static int jsonEachOpenEach(sqlcipher_sqlite3_vtab *p, sqlcipher_sqlite3_vtab_cursor **ppCursor){
+ JsonEachConnection *pVtab = (JsonEachConnection*)p;
JsonEachCursor *pCur;
UNUSED_PARAMETER(p);
- pCur = sqlcipher_sqlite3_malloc( sizeof(*pCur) );
+ pCur = sqlcipher_sqlite3DbMallocZero(pVtab->db, sizeof(*pCur));
if( pCur==0 ) return SQLITE_NOMEM;
- memset(pCur, 0, sizeof(*pCur));
+ pCur->db = pVtab->db;
+ jsonStringZero(&pCur->path);
*ppCursor = &pCur->base;
return SQLITE_OK;
}
@@ -203073,22 +215033,24 @@ static int jsonEachOpenTree(sqlcipher_sqlite3_vtab *p, sqlcipher_sqlite3_vtab_cu
/* Reset a JsonEachCursor back to its original state. Free any memory
** held. */
static void jsonEachCursorReset(JsonEachCursor *p){
- sqlcipher_sqlite3_free(p->zJson);
- sqlcipher_sqlite3_free(p->zRoot);
jsonParseReset(&p->sParse);
+ jsonStringReset(&p->path);
+ sqlcipher_sqlite3DbFree(p->db, p->aParent);
p->iRowid = 0;
p->i = 0;
+ p->aParent = 0;
+ p->nParent = 0;
+ p->nParentAlloc = 0;
p->iEnd = 0;
p->eType = 0;
- p->zJson = 0;
- p->zRoot = 0;
}
/* Destructor for a jsonEachCursor object */
static int jsonEachClose(sqlcipher_sqlite3_vtab_cursor *cur){
JsonEachCursor *p = (JsonEachCursor*)cur;
jsonEachCursorReset(p);
- sqlcipher_sqlite3_free(cur);
+
+ sqlcipher_sqlite3DbFree(p->db, cur);
return SQLITE_OK;
}
@@ -203099,198 +215061,233 @@ static int jsonEachEof(sqlcipher_sqlite3_vtab_cursor *cur){
return p->i >= p->iEnd;
}
-/* Advance the cursor to the next element for json_tree() */
-static int jsonEachNext(sqlcipher_sqlite3_vtab_cursor *cur){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- if( p->bRecursive ){
- if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
- p->i++;
- p->iRowid++;
- if( p->i<p->iEnd ){
- u32 iUp = p->sParse.aUp[p->i];
- JsonNode *pUp = &p->sParse.aNode[iUp];
- p->eType = pUp->eType;
- if( pUp->eType==JSON_ARRAY ){
- assert( pUp->eU==0 || pUp->eU==3 );
- testcase( pUp->eU==3 );
- VVA( pUp->eU = 3 );
- if( iUp==p->i-1 ){
- pUp->u.iKey = 0;
- }else{
- pUp->u.iKey++;
+/*
+** If the cursor is currently pointing at the label of a object entry,
+** then return the index of the value. For all other cases, return the
+** current pointer position, which is the value.
+*/
+static int jsonSkipLabel(JsonEachCursor *p){
+ if( p->eType==JSONB_OBJECT ){
+ u32 sz = 0;
+ u32 n = jsonbPayloadSize(&p->sParse, p->i, &sz);
+ return p->i + n + sz;
+ }else{
+ return p->i;
+ }
+}
+
+/*
+** Append the path name for the current element.
+*/
+static void jsonAppendPathName(JsonEachCursor *p){
+ assert( p->nParent>0 );
+ assert( p->eType==JSONB_ARRAY || p->eType==JSONB_OBJECT );
+ if( p->eType==JSONB_ARRAY ){
+ jsonPrintf(30, &p->path, "[%lld]", p->aParent[p->nParent-1].iKey);
+ }else{
+ u32 n, sz = 0, k, i;
+ const char *z;
+ int needQuote = 0;
+ n = jsonbPayloadSize(&p->sParse, p->i, &sz);
+ k = p->i + n;
+ z = (const char*)&p->sParse.aBlob[k];
+ if( sz==0 || !sqlcipher_sqlite3Isalpha(z[0]) ){
+ needQuote = 1;
+ }else{
+ for(i=0; i<sz; i++){
+ if( !sqlcipher_sqlite3Isalnum(z[i]) ){
+ needQuote = 1;
+ break;
}
}
}
- }else{
- switch( p->eType ){
- case JSON_ARRAY: {
- p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
- p->iRowid++;
- break;
- }
- case JSON_OBJECT: {
- p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
- p->iRowid++;
- break;
- }
- default: {
- p->i = p->iEnd;
- break;
- }
+ if( needQuote ){
+ jsonPrintf(sz+4,&p->path,".\"%.*s\"", sz, z);
+ }else{
+ jsonPrintf(sz+2,&p->path,".%.*s", sz, z);
}
}
- return SQLITE_OK;
}
-/* Append an object label to the JSON Path being constructed
-** in pStr.
-*/
-static void jsonAppendObjectPathElement(
- JsonString *pStr,
- JsonNode *pNode
-){
- int jj, nn;
- const char *z;
- assert( pNode->eType==JSON_STRING );
- assert( pNode->jnFlags & JNODE_LABEL );
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- nn = pNode->n;
- assert( nn>=2 );
- assert( z[0]=='"' );
- assert( z[nn-1]=='"' );
- if( nn>2 && sqlcipher_sqlite3Isalpha(z[1]) ){
- for(jj=2; jj<nn-1 && sqlcipher_sqlite3Isalnum(z[jj]); jj++){}
- if( jj==nn-1 ){
- z++;
- nn -= 2;
+/* Advance the cursor to the next element for json_tree() */
+static int jsonEachNext(sqlcipher_sqlite3_vtab_cursor *cur){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ int rc = SQLITE_OK;
+ if( p->bRecursive ){
+ u8 x;
+ u8 levelChange = 0;
+ u32 n, sz = 0;
+ u32 i = jsonSkipLabel(p);
+ x = p->sParse.aBlob[i] & 0x0f;
+ n = jsonbPayloadSize(&p->sParse, i, &sz);
+ if( x==JSONB_OBJECT || x==JSONB_ARRAY ){
+ JsonParent *pParent;
+ if( p->nParent>=p->nParentAlloc ){
+ JsonParent *pNew;
+ u64 nNew;
+ nNew = p->nParentAlloc*2 + 3;
+ pNew = sqlcipher_sqlite3DbRealloc(p->db, p->aParent, sizeof(JsonParent)*nNew);
+ if( pNew==0 ) return SQLITE_NOMEM;
+ p->nParentAlloc = (u32)nNew;
+ p->aParent = pNew;
+ }
+ levelChange = 1;
+ pParent = &p->aParent[p->nParent];
+ pParent->iHead = p->i;
+ pParent->iValue = i;
+ pParent->iEnd = i + n + sz;
+ pParent->iKey = -1;
+ pParent->nPath = (u32)p->path.nUsed;
+ if( p->eType && p->nParent ){
+ jsonAppendPathName(p);
+ if( p->path.eErr ) rc = SQLITE_NOMEM;
+ }
+ p->nParent++;
+ p->i = i + n;
+ }else{
+ p->i = i + n + sz;
+ }
+ while( p->nParent>0 && p->i >= p->aParent[p->nParent-1].iEnd ){
+ p->nParent--;
+ p->path.nUsed = p->aParent[p->nParent].nPath;
+ levelChange = 1;
+ }
+ if( levelChange ){
+ if( p->nParent>0 ){
+ JsonParent *pParent = &p->aParent[p->nParent-1];
+ u32 iVal = pParent->iValue;
+ p->eType = p->sParse.aBlob[iVal] & 0x0f;
+ }else{
+ p->eType = 0;
+ }
}
+ }else{
+ u32 n, sz = 0;
+ u32 i = jsonSkipLabel(p);
+ n = jsonbPayloadSize(&p->sParse, i, &sz);
+ p->i = i + n + sz;
+ }
+ if( p->eType==JSONB_ARRAY && p->nParent ){
+ p->aParent[p->nParent-1].iKey++;
}
- jsonPrintf(nn+2, pStr, ".%.*s", nn, z);
+ p->iRowid++;
+ return rc;
}
-/* Append the name of the path for element i to pStr
+/* Length of the path for rowid==0 in bRecursive mode.
*/
-static void jsonEachComputePath(
- JsonEachCursor *p, /* The cursor */
- JsonString *pStr, /* Write the path here */
- u32 i /* Path to this element */
-){
- JsonNode *pNode, *pUp;
- u32 iUp;
- if( i==0 ){
- jsonAppendChar(pStr, '$');
- return;
- }
- iUp = p->sParse.aUp[i];
- jsonEachComputePath(p, pStr, iUp);
- pNode = &p->sParse.aNode[i];
- pUp = &p->sParse.aNode[iUp];
- if( pUp->eType==JSON_ARRAY ){
- assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) );
- testcase( pUp->eU==0 );
- jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
- }else{
- assert( pUp->eType==JSON_OBJECT );
- if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
- jsonAppendObjectPathElement(pStr, pNode);
+static int jsonEachPathLength(JsonEachCursor *p){
+ u32 n = p->path.nUsed;
+ char *z = p->path.zBuf;
+ if( p->iRowid==0 && p->bRecursive && n>=2 ){
+ while( n>1 ){
+ n--;
+ if( z[n]=='[' || z[n]=='.' ){
+ u32 x, sz = 0;
+ char cSaved = z[n];
+ z[n] = 0;
+ assert( p->sParse.eEdit==0 );
+ x = jsonLookupStep(&p->sParse, 0, z+1, 0);
+ z[n] = cSaved;
+ if( JSON_LOOKUP_ISERROR(x) ) continue;
+ if( x + jsonbPayloadSize(&p->sParse, x, &sz) == p->i ) break;
+ }
+ }
}
+ return n;
}
/* Return the value of a column */
static int jsonEachColumn(
sqlcipher_sqlite3_vtab_cursor *cur, /* The cursor */
sqlcipher_sqlite3_context *ctx, /* First argument to sqlcipher_sqlite3_result_...() */
- int i /* Which column to return */
+ int iColumn /* Which column to return */
){
JsonEachCursor *p = (JsonEachCursor*)cur;
- JsonNode *pThis = &p->sParse.aNode[p->i];
- switch( i ){
+ switch( iColumn ){
case JEACH_KEY: {
- if( p->i==0 ) break;
- if( p->eType==JSON_OBJECT ){
- jsonReturn(pThis, ctx, 0);
- }else if( p->eType==JSON_ARRAY ){
- u32 iKey;
- if( p->bRecursive ){
- if( p->iRowid==0 ) break;
- assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 );
- iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
+ if( p->nParent==0 ){
+ u32 n, j;
+ if( p->nRoot==1 ) break;
+ j = jsonEachPathLength(p);
+ n = p->nRoot - j;
+ if( n==0 ){
+ break;
+ }else if( p->path.zBuf[j]=='[' ){
+ i64 x;
+ sqlcipher_sqlite3Atoi64(&p->path.zBuf[j+1], &x, n-1, SQLITE_UTF8);
+ sqlcipher_sqlite3_result_int64(ctx, x);
+ }else if( p->path.zBuf[j+1]=='"' ){
+ sqlcipher_sqlite3_result_text(ctx, &p->path.zBuf[j+2], n-3, SQLITE_TRANSIENT);
}else{
- iKey = p->iRowid;
+ sqlcipher_sqlite3_result_text(ctx, &p->path.zBuf[j+1], n-1, SQLITE_TRANSIENT);
}
- sqlcipher_sqlite3_result_int64(ctx, (sqlcipher_sqlite3_int64)iKey);
+ break;
+ }
+ if( p->eType==JSONB_OBJECT ){
+ jsonReturnFromBlob(&p->sParse, p->i, ctx, 1);
+ }else{
+ assert( p->eType==JSONB_ARRAY );
+ sqlcipher_sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iKey);
}
break;
}
case JEACH_VALUE: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- jsonReturn(pThis, ctx, 0);
+ u32 i = jsonSkipLabel(p);
+ jsonReturnFromBlob(&p->sParse, i, ctx, 1);
+ if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){
+ sqlcipher_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
break;
}
case JEACH_TYPE: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- sqlcipher_sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
+ u32 i = jsonSkipLabel(p);
+ u8 eType = p->sParse.aBlob[i] & 0x0f;
+ sqlcipher_sqlite3_result_text(ctx, jsonbType[eType], -1, SQLITE_STATIC);
break;
}
case JEACH_ATOM: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- if( pThis->eType>=JSON_ARRAY ) break;
- jsonReturn(pThis, ctx, 0);
+ u32 i = jsonSkipLabel(p);
+ if( (p->sParse.aBlob[i] & 0x0f)<JSONB_ARRAY ){
+ jsonReturnFromBlob(&p->sParse, i, ctx, 1);
+ }
break;
}
case JEACH_ID: {
- sqlcipher_sqlite3_result_int64(ctx,
- (sqlcipher_sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
+ sqlcipher_sqlite3_result_int64(ctx, (sqlcipher_sqlite3_int64)p->i);
break;
}
case JEACH_PARENT: {
- if( p->i>p->iBegin && p->bRecursive ){
- sqlcipher_sqlite3_result_int64(ctx, (sqlcipher_sqlite3_int64)p->sParse.aUp[p->i]);
+ if( p->nParent>0 && p->bRecursive ){
+ sqlcipher_sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iHead);
}
break;
}
case JEACH_FULLKEY: {
- JsonString x;
- jsonInit(&x, ctx);
- if( p->bRecursive ){
- jsonEachComputePath(p, &x, p->i);
- }else{
- if( p->zRoot ){
- jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
- }else{
- jsonAppendChar(&x, '$');
- }
- if( p->eType==JSON_ARRAY ){
- jsonPrintf(30, &x, "[%d]", p->iRowid);
- }else if( p->eType==JSON_OBJECT ){
- jsonAppendObjectPathElement(&x, pThis);
- }
- }
- jsonResult(&x);
+ u64 nBase = p->path.nUsed;
+ if( p->nParent ) jsonAppendPathName(p);
+ sqlcipher_sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed,
+ SQLITE_TRANSIENT, SQLITE_UTF8);
+ p->path.nUsed = nBase;
break;
}
case JEACH_PATH: {
- if( p->bRecursive ){
- JsonString x;
- jsonInit(&x, ctx);
- jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
- jsonResult(&x);
- break;
- }
- /* For json_each() path and root are the same so fall through
- ** into the root case */
- /* no break */ deliberate_fall_through
+ u32 n = jsonEachPathLength(p);
+ sqlcipher_sqlite3_result_text64(ctx, p->path.zBuf, n,
+ SQLITE_TRANSIENT, SQLITE_UTF8);
+ break;
}
default: {
- const char *zRoot = p->zRoot;
- if( zRoot==0 ) zRoot = "$";
- sqlcipher_sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
+ sqlcipher_sqlite3_result_text(ctx, p->path.zBuf, p->nRoot, SQLITE_STATIC);
break;
}
case JEACH_JSON: {
- assert( i==JEACH_JSON );
- sqlcipher_sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
+ if( p->sParse.zJson==0 ){
+ sqlcipher_sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
+ SQLITE_TRANSIENT);
+ }else{
+ sqlcipher_sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_TRANSIENT);
+ }
break;
}
}
@@ -203340,6 +215337,13 @@ static int jsonEachBestIndex(
idxMask |= iMask;
}
}
+ if( pIdxInfo->nOrderBy>0
+ && pIdxInfo->aOrderBy[0].iColumn<0
+ && pIdxInfo->aOrderBy[0].desc==0
+ ){
+ pIdxInfo->orderByConsumed = 1;
+ }
+
if( (unusableMask & ~idxMask)!=0 ){
/* If there are any unusable constraints on JSON or ROOT, then reject
** this entire plan */
@@ -203374,78 +215378,97 @@ static int jsonEachFilter(
int argc, sqlcipher_sqlite3_value **argv
){
JsonEachCursor *p = (JsonEachCursor*)cur;
- const char *z;
const char *zRoot = 0;
- sqlcipher_sqlite3_int64 n;
+ u32 i, n, sz;
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(argc);
jsonEachCursorReset(p);
if( idxNum==0 ) return SQLITE_OK;
- z = (const char*)sqlcipher_sqlite3_value_text(argv[0]);
- if( z==0 ) return SQLITE_OK;
- n = sqlcipher_sqlite3_value_bytes(argv[0]);
- p->zJson = sqlcipher_sqlite3_malloc64( n+1 );
- if( p->zJson==0 ) return SQLITE_NOMEM;
- memcpy(p->zJson, z, (size_t)n+1);
- if( jsonParse(&p->sParse, 0, p->zJson) ){
- int rc = SQLITE_NOMEM;
- if( p->sParse.oom==0 ){
- sqlcipher_sqlite3_free(cur->pVtab->zErrMsg);
- cur->pVtab->zErrMsg = sqlcipher_sqlite3_mprintf("malformed JSON");
- if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
- }
- jsonEachCursorReset(p);
- return rc;
- }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
- jsonEachCursorReset(p);
- return SQLITE_NOMEM;
+ memset(&p->sParse, 0, sizeof(p->sParse));
+ p->sParse.nJPRef = 1;
+ p->sParse.db = p->db;
+ if( jsonFuncArgMightBeBinary(argv[0]) ){
+ p->sParse.nBlob = sqlcipher_sqlite3_value_bytes(argv[0]);
+ p->sParse.aBlob = (u8*)sqlcipher_sqlite3_value_blob(argv[0]);
}else{
- JsonNode *pNode = 0;
- if( idxNum==3 ){
- const char *zErr = 0;
- zRoot = (const char*)sqlcipher_sqlite3_value_text(argv[1]);
- if( zRoot==0 ) return SQLITE_OK;
- n = sqlcipher_sqlite3_value_bytes(argv[1]);
- p->zRoot = sqlcipher_sqlite3_malloc64( n+1 );
- if( p->zRoot==0 ) return SQLITE_NOMEM;
- memcpy(p->zRoot, zRoot, (size_t)n+1);
- if( zRoot[0]!='$' ){
- zErr = zRoot;
- }else{
- pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
+ p->sParse.zJson = (char*)sqlcipher_sqlite3_value_text(argv[0]);
+ p->sParse.nJson = sqlcipher_sqlite3_value_bytes(argv[0]);
+ if( p->sParse.zJson==0 ){
+ p->i = p->iEnd = 0;
+ return SQLITE_OK;
+ }
+ if( jsonConvertTextToBlob(&p->sParse, 0) ){
+ if( p->sParse.oom ){
+ return SQLITE_NOMEM;
}
- if( zErr ){
+ goto json_each_malformed_input;
+ }
+ }
+ if( idxNum==3 ){
+ zRoot = (const char*)sqlcipher_sqlite3_value_text(argv[1]);
+ if( zRoot==0 ) return SQLITE_OK;
+ if( zRoot[0]!='$' ){
+ sqlcipher_sqlite3_free(cur->pVtab->zErrMsg);
+ cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
+ jsonEachCursorReset(p);
+ return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
+ }
+ p->nRoot = sqlcipher_sqlite3Strlen30(zRoot);
+ if( zRoot[1]==0 ){
+ i = p->i = 0;
+ p->eType = 0;
+ }else{
+ i = jsonLookupStep(&p->sParse, 0, zRoot+1, 0);
+ if( JSON_LOOKUP_ISERROR(i) ){
+ if( i==JSON_LOOKUP_NOTFOUND ){
+ p->i = 0;
+ p->eType = 0;
+ p->iEnd = 0;
+ return SQLITE_OK;
+ }
sqlcipher_sqlite3_free(cur->pVtab->zErrMsg);
- cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
+ cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
jsonEachCursorReset(p);
return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
- }else if( pNode==0 ){
- return SQLITE_OK;
}
- }else{
- pNode = p->sParse.aNode;
- }
- p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
- p->eType = pNode->eType;
- if( p->eType>=JSON_ARRAY ){
- assert( pNode->eU==0 );
- VVA( pNode->eU = 3 );
- pNode->u.iKey = 0;
- p->iEnd = p->i + pNode->n + 1;
- if( p->bRecursive ){
- p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
- if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
- p->i--;
- }
+ if( p->sParse.iLabel ){
+ p->i = p->sParse.iLabel;
+ p->eType = JSONB_OBJECT;
}else{
- p->i++;
+ p->i = i;
+ p->eType = JSONB_ARRAY;
}
- }else{
- p->iEnd = p->i+1;
}
+ jsonAppendRaw(&p->path, zRoot, p->nRoot);
+ }else{
+ i = p->i = 0;
+ p->eType = 0;
+ p->nRoot = 1;
+ jsonAppendRaw(&p->path, "$", 1);
+ }
+ p->nParent = 0;
+ n = jsonbPayloadSize(&p->sParse, i, &sz);
+ p->iEnd = i+n+sz;
+ if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY && !p->bRecursive ){
+ p->i = i + n;
+ p->eType = p->sParse.aBlob[i] & 0x0f;
+ p->aParent = sqlcipher_sqlite3DbMallocZero(p->db, sizeof(JsonParent));
+ if( p->aParent==0 ) return SQLITE_NOMEM;
+ p->nParent = 1;
+ p->nParentAlloc = 1;
+ p->aParent[0].iKey = 0;
+ p->aParent[0].iEnd = p->iEnd;
+ p->aParent[0].iHead = p->i;
+ p->aParent[0].iValue = i;
}
return SQLITE_OK;
+
+json_each_malformed_input:
+ sqlcipher_sqlite3_free(cur->pVtab->zErrMsg);
+ cur->pVtab->zErrMsg = sqlcipher_sqlite3_mprintf("malformed JSON");
+ jsonEachCursorReset(p);
+ return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
}
/* The methods of the json_each virtual table */
@@ -203473,7 +215496,8 @@ static sqlcipher_sqlite3_module jsonEachModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
/* The methods of the json_tree virtual table. */
@@ -203501,7 +215525,8 @@ static sqlcipher_sqlite3_module jsonTreeModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#endif /* !defined(SQLITE_OMIT_JSON) */
@@ -203512,33 +215537,59 @@ static sqlcipher_sqlite3_module jsonTreeModule = {
SQLITE_PRIVATE void sqlcipher_sqlite3RegisterJsonFunctions(void){
#ifndef SQLITE_OMIT_JSON
static FuncDef aJsonFunc[] = {
- JFUNCTION(json, 1, 0, jsonRemoveFunc),
- JFUNCTION(json_array, -1, 0, jsonArrayFunc),
- JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc),
- JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc),
- JFUNCTION(json_extract, -1, 0, jsonExtractFunc),
- JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc),
- JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc),
- JFUNCTION(json_insert, -1, 0, jsonSetFunc),
- JFUNCTION(json_object, -1, 0, jsonObjectFunc),
- JFUNCTION(json_patch, 2, 0, jsonPatchFunc),
- JFUNCTION(json_quote, 1, 0, jsonQuoteFunc),
- JFUNCTION(json_remove, -1, 0, jsonRemoveFunc),
- JFUNCTION(json_replace, -1, 0, jsonReplaceFunc),
- JFUNCTION(json_set, -1, JSON_ISSET, jsonSetFunc),
- JFUNCTION(json_type, 1, 0, jsonTypeFunc),
- JFUNCTION(json_type, 2, 0, jsonTypeFunc),
- JFUNCTION(json_valid, 1, 0, jsonValidFunc),
+ /* sqlcipher_sqlite3_result_subtype() ----, ,--- sqlcipher_sqlite3_value_subtype() */
+ /* | | */
+ /* Uses cache ------, | | ,---- Returns JSONB */
+ /* | | | | */
+ /* Number of arguments ---, | | | | ,--- Flags */
+ /* | | | | | | */
+ JFUNCTION(json, 1,1,1, 0,0,0, jsonRemoveFunc),
+ JFUNCTION(jsonb, 1,1,0, 0,1,0, jsonRemoveFunc),
+ JFUNCTION(json_array, -1,0,1, 1,0,0, jsonArrayFunc),
+ JFUNCTION(jsonb_array, -1,0,1, 1,1,0, jsonArrayFunc),
+ JFUNCTION(json_array_length, 1,1,0, 0,0,0, jsonArrayLengthFunc),
+ JFUNCTION(json_array_length, 2,1,0, 0,0,0, jsonArrayLengthFunc),
+ JFUNCTION(json_error_position,1,1,0, 0,0,0, jsonErrorFunc),
+ JFUNCTION(json_extract, -1,1,1, 0,0,0, jsonExtractFunc),
+ JFUNCTION(jsonb_extract, -1,1,0, 0,1,0, jsonExtractFunc),
+ JFUNCTION(->, 2,1,1, 0,0,JSON_JSON, jsonExtractFunc),
+ JFUNCTION(->>, 2,1,0, 0,0,JSON_SQL, jsonExtractFunc),
+ JFUNCTION(json_insert, -1,1,1, 1,0,0, jsonSetFunc),
+ JFUNCTION(jsonb_insert, -1,1,0, 1,1,0, jsonSetFunc),
+ JFUNCTION(json_object, -1,0,1, 1,0,0, jsonObjectFunc),
+ JFUNCTION(jsonb_object, -1,0,1, 1,1,0, jsonObjectFunc),
+ JFUNCTION(json_patch, 2,1,1, 0,0,0, jsonPatchFunc),
+ JFUNCTION(jsonb_patch, 2,1,0, 0,1,0, jsonPatchFunc),
+ JFUNCTION(json_pretty, 1,1,0, 0,0,0, jsonPrettyFunc),
+ JFUNCTION(json_pretty, 2,1,0, 0,0,0, jsonPrettyFunc),
+ JFUNCTION(json_quote, 1,0,1, 1,0,0, jsonQuoteFunc),
+ JFUNCTION(json_remove, -1,1,1, 0,0,0, jsonRemoveFunc),
+ JFUNCTION(jsonb_remove, -1,1,0, 0,1,0, jsonRemoveFunc),
+ JFUNCTION(json_replace, -1,1,1, 1,0,0, jsonReplaceFunc),
+ JFUNCTION(jsonb_replace, -1,1,0, 1,1,0, jsonReplaceFunc),
+ JFUNCTION(json_set, -1,1,1, 1,0,JSON_ISSET, jsonSetFunc),
+ JFUNCTION(jsonb_set, -1,1,0, 1,1,JSON_ISSET, jsonSetFunc),
+ JFUNCTION(json_type, 1,1,0, 0,0,0, jsonTypeFunc),
+ JFUNCTION(json_type, 2,1,0, 0,0,0, jsonTypeFunc),
+ JFUNCTION(json_valid, 1,1,0, 0,0,0, jsonValidFunc),
+ JFUNCTION(json_valid, 2,1,0, 0,0,0, jsonValidFunc),
#if SQLITE_DEBUG
- JFUNCTION(json_parse, 1, 0, jsonParseFunc),
- JFUNCTION(json_test1, 1, 0, jsonTest1Func),
+ JFUNCTION(json_parse, 1,1,0, 0,0,0, jsonParseFunc),
#endif
WAGGREGATE(json_group_array, 1, 0, 0,
jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
- SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS),
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|
+ SQLITE_DETERMINISTIC),
+ WAGGREGATE(jsonb_group_array, 1, JSON_BLOB, 0,
+ jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
WAGGREGATE(json_group_object, 2, 0, 0,
jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
- SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS)
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
+ WAGGREGATE(jsonb_group_object,2, JSON_BLOB, 0,
+ jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|
+ SQLITE_DETERMINISTIC)
};
sqlcipher_sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc));
#endif
@@ -203665,6 +215716,11 @@ typedef unsigned int u32;
#endif
#endif /* !defined(SQLITE_AMALGAMATION) */
+/* Macro to check for 4-byte alignment. Only used inside of assert() */
+#ifdef SQLITE_DEBUG
+# define FOUR_BYTE_ALIGNED(X) ((((char*)(X) - (char*)0) & 3)==0)
+#endif
+
/* #include <string.h> */
/* #include <stdio.h> */
/* #include <assert.h> */
@@ -203730,6 +215786,7 @@ struct Rtree {
int iDepth; /* Current depth of the r-tree structure */
char *zDb; /* Name of database containing r-tree table */
char *zName; /* Name of r-tree table */
+ char *zNodeName; /* Name of the %_node table */
u32 nBusy; /* Current number of users of this structure */
i64 nRowEst; /* Estimated number of rows in this table */
u32 nCursor; /* Number of open cursors */
@@ -203742,7 +215799,6 @@ struct Rtree {
** headed by the node (leaf nodes have RtreeNode.iNode==0).
*/
RtreeNode *pDeleted;
- int iReinsertHeight; /* Height of sub-trees Reinsert() has run on */
/* Blob I/O on xxx_node */
sqlcipher_sqlite3_blob *pNodeBlob;
@@ -204039,17 +216095,23 @@ struct RtreeMatchArg {
** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
** at run-time.
*/
-#ifndef SQLITE_BYTEORDER
-#if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
- defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
- defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
- defined(__arm__)
-# define SQLITE_BYTEORDER 1234
-#elif defined(sparc) || defined(__ppc__)
-# define SQLITE_BYTEORDER 4321
-#else
-# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
-#endif
+#ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */
+# if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
+# define SQLITE_BYTEORDER 4321
+# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
+# define SQLITE_BYTEORDER 1234
+# elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1
+# define SQLITE_BYTEORDER 4321
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
+ defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64)
+# define SQLITE_BYTEORDER 1234
+# elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__)
+# define SQLITE_BYTEORDER 4321
+# else
+# define SQLITE_BYTEORDER 0
+# endif
#endif
@@ -204070,7 +216132,7 @@ static int readInt16(u8 *p){
return (p[0]<<8) + p[1];
}
static void readCoord(u8 *p, RtreeCoord *pCoord){
- assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(p) );
#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
pCoord->u = _byteswap_ulong(*(u32*)p);
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
@@ -204124,7 +216186,7 @@ static void writeInt16(u8 *p, int i){
}
static int writeCoord(u8 *p, RtreeCoord *pCoord){
u32 i;
- assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(p) );
assert( sizeof(RtreeCoord)==4 );
assert( sizeof(u32)==4 );
#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
@@ -204252,11 +216314,9 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
** Clear the Rtree.pNodeBlob object
*/
static void nodeBlobReset(Rtree *pRtree){
- if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
- sqlcipher_sqlite3_blob *pBlob = pRtree->pNodeBlob;
- pRtree->pNodeBlob = 0;
- sqlcipher_sqlite3_blob_close(pBlob);
- }
+ sqlcipher_sqlite3_blob *pBlob = pRtree->pNodeBlob;
+ pRtree->pNodeBlob = 0;
+ sqlcipher_sqlite3_blob_close(pBlob);
}
/*
@@ -204275,7 +216335,7 @@ static int nodeAcquire(
** increase its reference count and return it.
*/
if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
- if( pParent && pParent!=pNode->pParent ){
+ if( pParent && ALWAYS(pParent!=pNode->pParent) ){
RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
@@ -204295,14 +216355,11 @@ static int nodeAcquire(
}
}
if( pRtree->pNodeBlob==0 ){
- char *zTab = sqlcipher_sqlite3_mprintf("%s_node", pRtree->zName);
- if( zTab==0 ) return SQLITE_NOMEM;
- rc = sqlcipher_sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0,
+ rc = sqlcipher_sqlite3_blob_open(pRtree->db, pRtree->zDb, pRtree->zNodeName,
+ "data", iNode, 0,
&pRtree->pNodeBlob);
- sqlcipher_sqlite3_free(zTab);
}
if( rc ){
- nodeBlobReset(pRtree);
*ppNode = 0;
/* If unable to open an sqlcipher_sqlite3_blob on the desired row, that can only
** be because the shadow tables hold erroneous data. */
@@ -204362,6 +216419,7 @@ static int nodeAcquire(
}
*ppNode = pNode;
}else{
+ nodeBlobReset(pRtree);
if( pNode ){
pRtree->nNodeRef--;
sqlcipher_sqlite3_free(pNode);
@@ -204506,6 +216564,7 @@ static void nodeGetCoord(
int iCoord, /* Which coordinate to extract */
RtreeCoord *pCoord /* OUT: Space to write result to */
){
+ assert( iCell<NCELL(pNode) );
readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord);
}
@@ -204695,7 +216754,9 @@ static int rtreeClose(sqlcipher_sqlite3_vtab_cursor *cur){
sqlcipher_sqlite3_finalize(pCsr->pReadAux);
sqlcipher_sqlite3_free(pCsr);
pRtree->nCursor--;
- nodeBlobReset(pRtree);
+ if( pRtree->nCursor==0 && pRtree->inWrTrans==0 ){
+ nodeBlobReset(pRtree);
+ }
return SQLITE_OK;
}
@@ -204852,7 +216913,7 @@ static void rtreeNonleafConstraint(
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|| p->op==RTREE_FALSE );
- assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(pCellData) );
switch( p->op ){
case RTREE_TRUE: return; /* Always satisfied */
case RTREE_FALSE: break; /* Never satisfied */
@@ -204905,7 +216966,7 @@ static void rtreeLeafConstraint(
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|| p->op==RTREE_FALSE );
pCellData += 8 + p->iCoord*4;
- assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(pCellData) );
RTREE_DECODE_COORD(eInt, pCellData, xN);
switch( p->op ){
case RTREE_TRUE: return; /* Always satisfied */
@@ -205280,7 +217341,11 @@ static int rtreeRowid(sqlcipher_sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *
int rc = SQLITE_OK;
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
if( rc==SQLITE_OK && ALWAYS(p) ){
- *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
+ if( p->iCell>=NCELL(pNode) ){
+ rc = SQLITE_ABORT;
+ }else{
+ *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
+ }
}
return rc;
}
@@ -205298,6 +217363,7 @@ static int rtreeColumn(sqlcipher_sqlite3_vtab_cursor *cur, sqlcipher_sqlite3_con
if( rc ) return rc;
if( NEVER(p==0) ) return SQLITE_OK;
+ if( p->iCell>=NCELL(pNode) ) return SQLITE_ABORT;
if( i==0 ){
sqlcipher_sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
}else if( i<=pRtree->nDim2 ){
@@ -205395,6 +217461,8 @@ static int deserializeGeometry(sqlcipher_sqlite3_value *pValue, RtreeConstraint
return SQLITE_OK;
}
+SQLITE_PRIVATE int sqlcipher_sqlite3IntFloatCompare(i64,double);
+
/*
** Rtree virtual table module xFilter method.
*/
@@ -205424,7 +217492,8 @@ static int rtreeFilter(
i64 iNode = 0;
int eType = sqlcipher_sqlite3_value_numeric_type(argv[0]);
if( eType==SQLITE_INTEGER
- || (eType==SQLITE_FLOAT && sqlcipher_sqlite3_value_double(argv[0])==iRowid)
+ || (eType==SQLITE_FLOAT
+ && 0==sqlcipher_sqlite3IntFloatCompare(iRowid,sqlcipher_sqlite3_value_double(argv[0])))
){
rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
}else{
@@ -205475,7 +217544,20 @@ static int rtreeFilter(
p->pInfo->nCoord = pRtree->nDim2;
p->pInfo->anQueue = pCsr->anQueue;
p->pInfo->mxLevel = pRtree->iDepth + 1;
- }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ }else if( eType==SQLITE_INTEGER ){
+ sqlcipher_sqlite3_int64 iVal = sqlcipher_sqlite3_value_int64(argv[ii]);
+#ifdef SQLITE_RTREE_INT_ONLY
+ p->u.rValue = iVal;
+#else
+ p->u.rValue = (double)iVal;
+ if( iVal>=((sqlcipher_sqlite3_int64)1)<<48
+ || iVal<=-(((sqlcipher_sqlite3_int64)1)<<48)
+ ){
+ if( p->op==RTREE_LT ) p->op = RTREE_LE;
+ if( p->op==RTREE_GT ) p->op = RTREE_GE;
+ }
+#endif
+ }else if( eType==SQLITE_FLOAT ){
#ifdef SQLITE_RTREE_INT_ONLY
p->u.rValue = sqlcipher_sqlite3_value_int64(argv[ii]);
#else
@@ -205606,11 +217688,12 @@ static int rtreeBestIndex(sqlcipher_sqlite3_vtab *tab, sqlcipher_sqlite3_index_i
|| p->op==SQLITE_INDEX_CONSTRAINT_MATCH)
){
u8 op;
+ u8 doOmit = 1;
switch( p->op ){
- case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
- case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break;
+ case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; doOmit = 0; break;
+ case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; doOmit = 0; break;
case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
- case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
+ case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; doOmit = 0; break;
case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break;
case SQLITE_INDEX_CONSTRAINT_MATCH: op = RTREE_MATCH; break;
default: op = 0; break;
@@ -205619,15 +217702,19 @@ static int rtreeBestIndex(sqlcipher_sqlite3_vtab *tab, sqlcipher_sqlite3_index_i
zIdxStr[iIdx++] = op;
zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0');
pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
- pIdxInfo->aConstraintUsage[ii].omit = 1;
+ pIdxInfo->aConstraintUsage[ii].omit = doOmit;
}
}
}
pIdxInfo->idxNum = 2;
pIdxInfo->needToFreeIdxStr = 1;
- if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlcipher_sqlite3_mprintf("%s", zIdxStr)) ){
- return SQLITE_NOMEM;
+ if( iIdx>0 ){
+ pIdxInfo->idxStr = sqlcipher_sqlite3_malloc( iIdx+1 );
+ if( pIdxInfo->idxStr==0 ){
+ return SQLITE_NOMEM;
+ }
+ memcpy(pIdxInfo->idxStr, zIdxStr, iIdx+1);
}
nRow = pRtree->nRowEst >> (iIdx/2);
@@ -205706,31 +217793,22 @@ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
*/
static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
int ii;
- int isInt = (pRtree->eCoordType==RTREE_COORD_INT32);
- for(ii=0; ii<pRtree->nDim2; ii+=2){
- RtreeCoord *a1 = &p1->aCoord[ii];
- RtreeCoord *a2 = &p2->aCoord[ii];
- if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f))
- || ( isInt && (a2[0].i<a1[0].i || a2[1].i>a1[1].i))
- ){
- return 0;
+ if( pRtree->eCoordType==RTREE_COORD_INT32 ){
+ for(ii=0; ii<pRtree->nDim2; ii+=2){
+ RtreeCoord *a1 = &p1->aCoord[ii];
+ RtreeCoord *a2 = &p2->aCoord[ii];
+ if( a2[0].i<a1[0].i || a2[1].i>a1[1].i ) return 0;
+ }
+ }else{
+ for(ii=0; ii<pRtree->nDim2; ii+=2){
+ RtreeCoord *a1 = &p1->aCoord[ii];
+ RtreeCoord *a2 = &p2->aCoord[ii];
+ if( a2[0].f<a1[0].f || a2[1].f>a1[1].f ) return 0;
}
}
return 1;
}
-/*
-** Return the amount cell p would grow by if it were unioned with pCell.
-*/
-static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
- RtreeDValue area;
- RtreeCell cell;
- memcpy(&cell, p, sizeof(RtreeCell));
- area = cellArea(pRtree, &cell);
- cellUnion(pRtree, &cell, pCell);
- return (cellArea(pRtree, &cell)-area);
-}
-
static RtreeDValue cellOverlap(
Rtree *pRtree,
RtreeCell *p,
@@ -205777,38 +217855,52 @@ static int ChooseLeaf(
for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){
int iCell;
sqlcipher_sqlite3_int64 iBest = 0;
-
+ int bFound = 0;
RtreeDValue fMinGrowth = RTREE_ZERO;
RtreeDValue fMinArea = RTREE_ZERO;
-
int nCell = NCELL(pNode);
- RtreeCell cell;
RtreeNode *pChild = 0;
- RtreeCell *aCell = 0;
-
- /* Select the child node which will be enlarged the least if pCell
- ** is inserted into it. Resolve ties by choosing the entry with
- ** the smallest area.
+ /* First check to see if there is are any cells in pNode that completely
+ ** contains pCell. If two or more cells in pNode completely contain pCell
+ ** then pick the smallest.
*/
for(iCell=0; iCell<nCell; iCell++){
- int bBest = 0;
- RtreeDValue growth;
- RtreeDValue area;
+ RtreeCell cell;
nodeGetCell(pRtree, pNode, iCell, &cell);
- growth = cellGrowth(pRtree, &cell, pCell);
- area = cellArea(pRtree, &cell);
- if( iCell==0||growth<fMinGrowth||(growth==fMinGrowth && area<fMinArea) ){
- bBest = 1;
+ if( cellContains(pRtree, &cell, pCell) ){
+ RtreeDValue area = cellArea(pRtree, &cell);
+ if( bFound==0 || area<fMinArea ){
+ iBest = cell.iRowid;
+ fMinArea = area;
+ bFound = 1;
+ }
}
- if( bBest ){
- fMinGrowth = growth;
- fMinArea = area;
- iBest = cell.iRowid;
+ }
+ if( !bFound ){
+ /* No cells of pNode will completely contain pCell. So pick the
+ ** cell of pNode that grows by the least amount when pCell is added.
+ ** Break ties by selecting the smaller cell.
+ */
+ for(iCell=0; iCell<nCell; iCell++){
+ RtreeCell cell;
+ RtreeDValue growth;
+ RtreeDValue area;
+ nodeGetCell(pRtree, pNode, iCell, &cell);
+ area = cellArea(pRtree, &cell);
+ cellUnion(pRtree, &cell, pCell);
+ growth = cellArea(pRtree, &cell)-area;
+ if( iCell==0
+ || growth<fMinGrowth
+ || (growth==fMinGrowth && area<fMinArea)
+ ){
+ fMinGrowth = growth;
+ fMinArea = area;
+ iBest = cell.iRowid;
+ }
}
}
- sqlcipher_sqlite3_free(aCell);
rc = nodeAcquire(pRtree, iBest, pNode, &pChild);
nodeRelease(pRtree, pNode);
pNode = pChild;
@@ -205881,77 +217973,6 @@ static int parentWrite(Rtree *pRtree, sqlcipher_sqlite3_int64 iNode, sqlcipher_s
static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int);
-/*
-** Arguments aIdx, aDistance and aSpare all point to arrays of size
-** nIdx. The aIdx array contains the set of integers from 0 to
-** (nIdx-1) in no particular order. This function sorts the values
-** in aIdx according to the indexed values in aDistance. For
-** example, assuming the inputs:
-**
-** aIdx = { 0, 1, 2, 3 }
-** aDistance = { 5.0, 2.0, 7.0, 6.0 }
-**
-** this function sets the aIdx array to contain:
-**
-** aIdx = { 0, 1, 2, 3 }
-**
-** The aSpare array is used as temporary working space by the
-** sorting algorithm.
-*/
-static void SortByDistance(
- int *aIdx,
- int nIdx,
- RtreeDValue *aDistance,
- int *aSpare
-){
- if( nIdx>1 ){
- int iLeft = 0;
- int iRight = 0;
-
- int nLeft = nIdx/2;
- int nRight = nIdx-nLeft;
- int *aLeft = aIdx;
- int *aRight = &aIdx[nLeft];
-
- SortByDistance(aLeft, nLeft, aDistance, aSpare);
- SortByDistance(aRight, nRight, aDistance, aSpare);
-
- memcpy(aSpare, aLeft, sizeof(int)*nLeft);
- aLeft = aSpare;
-
- while( iLeft<nLeft || iRight<nRight ){
- if( iLeft==nLeft ){
- aIdx[iLeft+iRight] = aRight[iRight];
- iRight++;
- }else if( iRight==nRight ){
- aIdx[iLeft+iRight] = aLeft[iLeft];
- iLeft++;
- }else{
- RtreeDValue fLeft = aDistance[aLeft[iLeft]];
- RtreeDValue fRight = aDistance[aRight[iRight]];
- if( fLeft<fRight ){
- aIdx[iLeft+iRight] = aLeft[iLeft];
- iLeft++;
- }else{
- aIdx[iLeft+iRight] = aRight[iRight];
- iRight++;
- }
- }
- }
-
-#if 0
- /* Check that the sort worked */
- {
- int jj;
- for(jj=1; jj<nIdx; jj++){
- RtreeDValue left = aDistance[aIdx[jj-1]];
- RtreeDValue right = aDistance[aIdx[jj]];
- assert( left<=right );
- }
- }
-#endif
- }
-}
/*
** Arguments aIdx, aCell and aSpare all point to arrays of size
@@ -206436,107 +218457,6 @@ static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){
return rc;
}
-static int Reinsert(
- Rtree *pRtree,
- RtreeNode *pNode,
- RtreeCell *pCell,
- int iHeight
-){
- int *aOrder;
- int *aSpare;
- RtreeCell *aCell;
- RtreeDValue *aDistance;
- int nCell;
- RtreeDValue aCenterCoord[RTREE_MAX_DIMENSIONS];
- int iDim;
- int ii;
- int rc = SQLITE_OK;
- int n;
-
- 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 *)sqlcipher_sqlite3_malloc64(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[n];
- aSpare = (int *)&aOrder[n];
- aDistance = (RtreeDValue *)&aSpare[n];
-
- for(ii=0; ii<nCell; ii++){
- if( ii==(nCell-1) ){
- memcpy(&aCell[ii], pCell, sizeof(RtreeCell));
- }else{
- nodeGetCell(pRtree, pNode, ii, &aCell[ii]);
- }
- aOrder[ii] = ii;
- for(iDim=0; iDim<pRtree->nDim; iDim++){
- 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] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2));
- }
-
- for(ii=0; ii<nCell; ii++){
- aDistance[ii] = RTREE_ZERO;
- for(iDim=0; iDim<pRtree->nDim; iDim++){
- RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) -
- DCOORD(aCell[ii].aCoord[iDim*2]));
- aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
- }
- }
-
- SortByDistance(aOrder, nCell, aDistance, aSpare);
- nodeZero(pRtree, pNode);
-
- for(ii=0; rc==SQLITE_OK && ii<(nCell-(RTREE_MINCELLS(pRtree)+1)); ii++){
- RtreeCell *p = &aCell[aOrder[ii]];
- nodeInsertCell(pRtree, pNode, p);
- if( p->iRowid==pCell->iRowid ){
- if( iHeight==0 ){
- rc = rowidWrite(pRtree, p->iRowid, pNode->iNode);
- }else{
- rc = parentWrite(pRtree, p->iRowid, pNode->iNode);
- }
- }
- }
- if( rc==SQLITE_OK ){
- rc = fixBoundingBox(pRtree, pNode);
- }
- for(; rc==SQLITE_OK && ii<nCell; ii++){
- /* Find a node to store this cell in. pNode->iNode currently contains
- ** the height of the sub-tree headed by the cell.
- */
- RtreeNode *pInsert;
- RtreeCell *p = &aCell[aOrder[ii]];
- rc = ChooseLeaf(pRtree, p, iHeight, &pInsert);
- if( rc==SQLITE_OK ){
- int rc2;
- rc = rtreeInsertCell(pRtree, pInsert, p, iHeight);
- rc2 = nodeRelease(pRtree, pInsert);
- if( rc==SQLITE_OK ){
- rc = rc2;
- }
- }
- }
-
- sqlcipher_sqlite3_free(aCell);
- return rc;
-}
-
/*
** Insert cell pCell into node pNode. Node pNode is the head of a
** subtree iHeight high (leaf nodes have iHeight==0).
@@ -206557,12 +218477,7 @@ static int rtreeInsertCell(
}
}
if( nodeInsertCell(pRtree, pNode, pCell) ){
- if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){
- rc = SplitNode(pRtree, pNode, pCell, iHeight);
- }else{
- pRtree->iReinsertHeight = iHeight;
- rc = Reinsert(pRtree, pNode, pCell, iHeight);
- }
+ rc = SplitNode(pRtree, pNode, pCell, iHeight);
}else{
rc = AdjustTree(pRtree, pNode, pCell);
if( ALWAYS(rc==SQLITE_OK) ){
@@ -206804,7 +218719,7 @@ static int rtreeUpdate(
rtreeReference(pRtree);
assert(nData>=1);
- cell.iRowid = 0; /* Used only to suppress a compiler warning */
+ memset(&cell, 0, sizeof(cell));
/* Constraint handling. A write operation on an r-tree table may return
** SQLITE_CONSTRAINT for two reasons:
@@ -206905,7 +218820,6 @@ static int rtreeUpdate(
}
if( rc==SQLITE_OK ){
int rc2;
- pRtree->iReinsertHeight = -1;
rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0);
rc2 = nodeRelease(pRtree, pLeaf);
if( rc==SQLITE_OK ){
@@ -206935,7 +218849,7 @@ constraint:
static int rtreeBeginTransaction(sqlcipher_sqlite3_vtab *pVtab){
Rtree *pRtree = (Rtree *)pVtab;
assert( pRtree->inWrTrans==0 );
- pRtree->inWrTrans++;
+ pRtree->inWrTrans = 1;
return SQLITE_OK;
}
@@ -206949,6 +218863,9 @@ static int rtreeEndTransaction(sqlcipher_sqlite3_vtab *pVtab){
nodeBlobReset(pRtree);
return SQLITE_OK;
}
+static int rtreeRollback(sqlcipher_sqlite3_vtab *pVtab){
+ return rtreeEndTransaction(pVtab);
+}
/*
** The xRename method for rtree module virtual tables.
@@ -207046,8 +218963,11 @@ static int rtreeShadowName(const char *zName){
return 0;
}
+/* Forward declaration */
+static int rtreeIntegrity(sqlcipher_sqlite3_vtab*, const char*, const char*, int, char**);
+
static sqlcipher_sqlite3_module rtreeModule = {
- 3, /* iVersion */
+ 4, /* iVersion */
rtreeCreate, /* xCreate - create a table */
rtreeConnect, /* xConnect - connect to an existing table */
rtreeBestIndex, /* xBestIndex - Determine search strategy */
@@ -207064,13 +218984,14 @@ static sqlcipher_sqlite3_module rtreeModule = {
rtreeBeginTransaction, /* xBegin - begin transaction */
rtreeEndTransaction, /* xSync - sync transaction */
rtreeEndTransaction, /* xCommit - commit transaction */
- rtreeEndTransaction, /* xRollback - rollback transaction */
+ rtreeRollback, /* xRollback - rollback transaction */
0, /* xFindFunction - function overloading */
rtreeRename, /* xRename - rename the table */
rtreeSavepoint, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- rtreeShadowName /* xShadowName */
+ rtreeShadowName, /* xShadowName */
+ rtreeIntegrity /* xIntegrity */
};
static int rtreeSqlInit(
@@ -207163,7 +219084,7 @@ static int rtreeSqlInit(
}
sqlcipher_sqlite3_free(zSql);
}
- if( pRtree->nAux ){
+ if( pRtree->nAux && rc!=SQLITE_NOMEM ){
pRtree->zReadAuxSql = sqlcipher_sqlite3_mprintf(
"SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1",
zDb, zPrefix);
@@ -207326,22 +219247,27 @@ static int rtreeInit(
}
sqlcipher_sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ sqlcipher_sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
+
/* Allocate the sqlcipher_sqlite3_vtab structure */
nDb = (int)strlen(argv[1]);
nName = (int)strlen(argv[2]);
- pRtree = (Rtree *)sqlcipher_sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
+ pRtree = (Rtree *)sqlcipher_sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8);
if( !pRtree ){
return SQLITE_NOMEM;
}
- memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
+ memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8);
pRtree->nBusy = 1;
pRtree->base.pModule = &rtreeModule;
pRtree->zDb = (char *)&pRtree[1];
pRtree->zName = &pRtree->zDb[nDb+1];
+ pRtree->zNodeName = &pRtree->zName[nName+1];
pRtree->eCoordType = (u8)eCoordType;
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
+ memcpy(pRtree->zNodeName, argv[2], nName);
+ memcpy(&pRtree->zNodeName[nName], "_node", 6);
/* Create/Connect to the underlying relational database schema. If
@@ -207838,7 +219764,6 @@ static int rtreeCheckTable(
){
RtreeCheck check; /* Common context for various routines */
sqlcipher_sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */
- int bEnd = 0; /* True if transaction should be closed */
int nAux = 0; /* Number of extra columns. */
/* Initialize the context object */
@@ -207847,24 +219772,14 @@ static int rtreeCheckTable(
check.zDb = zDb;
check.zTab = zTab;
- /* If there is not already an open transaction, open one now. This is
- ** to ensure that the queries run as part of this integrity-check operate
- ** on a consistent snapshot. */
- if( sqlcipher_sqlite3_get_autocommit(db) ){
- check.rc = sqlcipher_sqlite3_exec(db, "BEGIN", 0, 0, 0);
- bEnd = 1;
- }
-
/* Find the number of auxiliary columns */
- if( check.rc==SQLITE_OK ){
- pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
- if( pStmt ){
- nAux = sqlcipher_sqlite3_column_count(pStmt) - 2;
- sqlcipher_sqlite3_finalize(pStmt);
- }else
- if( check.rc!=SQLITE_NOMEM ){
- check.rc = SQLITE_OK;
- }
+ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
+ if( pStmt ){
+ nAux = sqlcipher_sqlite3_column_count(pStmt) - 2;
+ sqlcipher_sqlite3_finalize(pStmt);
+ }else
+ if( check.rc!=SQLITE_NOMEM ){
+ check.rc = SQLITE_OK;
}
/* Find number of dimensions in the rtree table. */
@@ -207895,16 +219810,36 @@ static int rtreeCheckTable(
sqlcipher_sqlite3_finalize(check.aCheckMapping[0]);
sqlcipher_sqlite3_finalize(check.aCheckMapping[1]);
- /* If one was opened, close the transaction */
- if( bEnd ){
- int rc = sqlcipher_sqlite3_exec(db, "END", 0, 0, 0);
- if( check.rc==SQLITE_OK ) check.rc = rc;
- }
*pzReport = check.zReport;
return check.rc;
}
/*
+** Implementation of the xIntegrity method for Rtree.
+*/
+static int rtreeIntegrity(
+ sqlcipher_sqlite3_vtab *pVtab, /* The virtual table to check */
+ const char *zSchema, /* Schema in which the virtual table lives */
+ const char *zName, /* Name of the virtual table */
+ int isQuick, /* True for a quick_check */
+ char **pzErr /* Write results here */
+){
+ Rtree *pRtree = (Rtree*)pVtab;
+ int rc;
+ assert( pzErr!=0 && *pzErr==0 );
+ UNUSED_PARAMETER(zSchema);
+ UNUSED_PARAMETER(zName);
+ UNUSED_PARAMETER(isQuick);
+ rc = rtreeCheckTable(pRtree->db, pRtree->zDb, pRtree->zName, pzErr);
+ if( rc==SQLITE_OK && *pzErr ){
+ *pzErr = sqlcipher_sqlite3_mprintf("In RTree %s.%s:\n%z",
+ pRtree->zDb, pRtree->zName, *pzErr);
+ if( (*pzErr)==0 ) rc = SQLITE_NOMEM;
+ }
+ return rc;
+}
+
+/*
** Usage:
**
** rtreecheck(<rtree-table>);
@@ -208277,7 +220212,7 @@ static GeoPoly *geopolyFuncParam(
int nByte;
testcase( pCtx==0 );
if( sqlcipher_sqlite3_value_type(pVal)==SQLITE_BLOB
- && (nByte = sqlcipher_sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord))
+ && (nByte = sqlcipher_sqlite3_value_bytes(pVal))>=(int)(4+6*sizeof(GeoCoord))
){
const unsigned char *a = sqlcipher_sqlite3_value_blob(pVal);
int nVertex;
@@ -208335,6 +220270,7 @@ static void geopolyBlobFunc(
sqlcipher_sqlite3_value **argv
){
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ (void)argc;
if( p ){
sqlcipher_sqlite3_result_blob(context, p->hdr,
4+8*p->nVertex, SQLITE_TRANSIENT);
@@ -208354,6 +220290,7 @@ static void geopolyJsonFunc(
sqlcipher_sqlite3_value **argv
){
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ (void)argc;
if( p ){
sqlcipher_sqlite3 *db = sqlcipher_sqlite3_context_db_handle(context);
sqlcipher_sqlite3_str *x = sqlcipher_sqlite3_str_new(db);
@@ -208435,6 +220372,7 @@ static void geopolyXformFunc(
double F = sqlcipher_sqlite3_value_double(argv[6]);
GeoCoord x1, y1, x0, y0;
int ii;
+ (void)argc;
if( p ){
for(ii=0; ii<p->nVertex; ii++){
x0 = GeoX(p,ii);
@@ -208485,6 +220423,7 @@ static void geopolyAreaFunc(
sqlcipher_sqlite3_value **argv
){
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ (void)argc;
if( p ){
sqlcipher_sqlite3_result_double(context, geopolyArea(p));
sqlcipher_sqlite3_free(p);
@@ -208510,6 +220449,7 @@ static void geopolyCcwFunc(
sqlcipher_sqlite3_value **argv
){
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ (void)argc;
if( p ){
if( geopolyArea(p)<0.0 ){
int ii, jj;
@@ -208564,6 +220504,7 @@ static void geopolyRegularFunc(
int n = sqlcipher_sqlite3_value_int(argv[3]);
int i;
GeoPoly *p;
+ (void)argc;
if( n<3 || r<=0.0 ) return;
if( n>1000 ) n = 1000;
@@ -208673,6 +220614,7 @@ static void geopolyBBoxFunc(
sqlcipher_sqlite3_value **argv
){
GeoPoly *p = geopolyBBox(context, argv[0], 0, 0);
+ (void)argc;
if( p ){
sqlcipher_sqlite3_result_blob(context, p->hdr,
4+8*p->nVertex, SQLITE_TRANSIENT);
@@ -208700,6 +220642,7 @@ static void geopolyBBoxStep(
){
RtreeCoord a[4];
int rc = SQLITE_OK;
+ (void)argc;
(void)geopolyBBox(context, argv[0], a, &rc);
if( rc==SQLITE_OK ){
GeoBBox *pBBox;
@@ -208788,6 +220731,8 @@ static void geopolyContainsPointFunc(
int v = 0;
int cnt = 0;
int ii;
+ (void)argc;
+
if( p1==0 ) return;
for(ii=0; ii<p1->nVertex-1; ii++){
v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii),
@@ -208827,6 +220772,7 @@ static void geopolyWithinFunc(
){
GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
+ (void)argc;
if( p1 && p2 ){
int x = geopolyOverlap(p1, p2);
if( x<0 ){
@@ -209157,6 +221103,7 @@ static void geopolyOverlapFunc(
){
GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
+ (void)argc;
if( p1 && p2 ){
int x = geopolyOverlap(p1, p2);
if( x<0 ){
@@ -209177,8 +221124,12 @@ static void geopolyDebugFunc(
int argc,
sqlcipher_sqlite3_value **argv
){
+ (void)context;
+ (void)argc;
#ifdef GEOPOLY_ENABLE_DEBUG
geo_debug = sqlcipher_sqlite3_value_int(argv[0]);
+#else
+ (void)argv;
#endif
}
@@ -209206,26 +221157,31 @@ static int geopolyInit(
sqlcipher_sqlite3_str *pSql;
char *zSql;
int ii;
+ (void)pAux;
sqlcipher_sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ sqlcipher_sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
/* Allocate the sqlcipher_sqlite3_vtab structure */
nDb = strlen(argv[1]);
nName = strlen(argv[2]);
- pRtree = (Rtree *)sqlcipher_sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
+ pRtree = (Rtree *)sqlcipher_sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8);
if( !pRtree ){
return SQLITE_NOMEM;
}
- memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
+ memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8);
pRtree->nBusy = 1;
pRtree->base.pModule = &rtreeModule;
pRtree->zDb = (char *)&pRtree[1];
pRtree->zName = &pRtree->zDb[nDb+1];
+ pRtree->zNodeName = &pRtree->zName[nName+1];
pRtree->eCoordType = RTREE_COORD_REAL32;
pRtree->nDim = 2;
pRtree->nDim2 = 4;
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
+ memcpy(pRtree->zNodeName, argv[2], nName);
+ memcpy(&pRtree->zNodeName[nName], "_node", 6);
/* Create/Connect to the underlying relational database schema. If
@@ -209322,6 +221278,7 @@ static int geopolyFilter(
RtreeNode *pRoot = 0;
int rc = SQLITE_OK;
int iCell = 0;
+ (void)idxStr;
rtreeReference(pRtree);
@@ -209448,6 +221405,7 @@ static int geopolyBestIndex(sqlcipher_sqlite3_vtab *tab, sqlcipher_sqlite3_index
int iRowidTerm = -1;
int iFuncTerm = -1;
int idxNum = 0;
+ (void)tab;
for(ii=0; ii<pIdxInfo->nConstraint; ii++){
struct sqlcipher_sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
@@ -209637,7 +221595,6 @@ static int geopolyUpdate(
}
if( rc==SQLITE_OK ){
int rc2;
- pRtree->iReinsertHeight = -1;
rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0);
rc2 = nodeRelease(pRtree, pLeaf);
if( rc==SQLITE_OK ){
@@ -209694,6 +221651,8 @@ static int geopolyFindFunction(
void (**pxFunc)(sqlcipher_sqlite3_context*,int,sqlcipher_sqlite3_value**),
void **ppArg
){
+ (void)pVtab;
+ (void)nArg;
if( sqlcipher_sqlite3_stricmp(zName, "geopoly_overlap")==0 ){
*pxFunc = geopolyOverlapFunc;
*ppArg = 0;
@@ -209732,7 +221691,8 @@ static sqlcipher_sqlite3_module geopolyModule = {
rtreeSavepoint, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- rtreeShadowName /* xShadowName */
+ rtreeShadowName, /* xShadowName */
+ rtreeIntegrity /* xIntegrity */
};
static int sqlcipher_sqlite3_geopoly_init(sqlcipher_sqlite3 *db){
@@ -209763,7 +221723,7 @@ static int sqlcipher_sqlite3_geopoly_init(sqlcipher_sqlite3 *db){
} aAgg[] = {
{ geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" },
};
- int i;
+ unsigned int i;
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
int enc;
if( aFunc[i].bPure ){
@@ -210443,7 +222403,7 @@ static void icuLoadCollation(
UCollator *pUCollator; /* ICU library collation object */
int rc; /* Return code from sqlcipher_sqlite3_create_collation_x() */
- assert(nArg==2);
+ assert(nArg==2 || nArg==3);
(void)nArg; /* Unused parameter */
zLocale = (const char *)sqlcipher_sqlite3_value_text(apArg[0]);
zName = (const char *)sqlcipher_sqlite3_value_text(apArg[1]);
@@ -210458,7 +222418,39 @@ static void icuLoadCollation(
return;
}
assert(p);
-
+ if(nArg==3){
+ const char *zOption = (const char*)sqlcipher_sqlite3_value_text(apArg[2]);
+ static const struct {
+ const char *zName;
+ UColAttributeValue val;
+ } aStrength[] = {
+ { "PRIMARY", UCOL_PRIMARY },
+ { "SECONDARY", UCOL_SECONDARY },
+ { "TERTIARY", UCOL_TERTIARY },
+ { "DEFAULT", UCOL_DEFAULT_STRENGTH },
+ { "QUARTERNARY", UCOL_QUATERNARY },
+ { "IDENTICAL", UCOL_IDENTICAL },
+ };
+ unsigned int i;
+ for(i=0; i<sizeof(aStrength)/sizeof(aStrength[0]); i++){
+ if( sqlcipher_sqlite3_stricmp(zOption,aStrength[i].zName)==0 ){
+ ucol_setStrength(pUCollator, aStrength[i].val);
+ break;
+ }
+ }
+ if( i>=sizeof(aStrength)/sizeof(aStrength[0]) ){
+ sqlcipher_sqlite3_str *pStr = sqlcipher_sqlite3_str_new(sqlcipher_sqlite3_context_db_handle(p));
+ sqlcipher_sqlite3_str_appendf(pStr,
+ "unknown collation strength \"%s\" - should be one of:",
+ zOption);
+ for(i=0; i<sizeof(aStrength)/sizeof(aStrength[0]); i++){
+ sqlcipher_sqlite3_str_appendf(pStr, " %s", aStrength[i].zName);
+ }
+ sqlcipher_sqlite3_result_error(p, sqlcipher_sqlite3_str_value(pStr), -1);
+ sqlcipher_sqlite3_free(sqlcipher_sqlite3_str_finish(pStr));
+ return;
+ }
+ }
rc = sqlcipher_sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
icuCollationColl, icuCollationDel
);
@@ -210481,6 +222473,7 @@ SQLITE_PRIVATE int sqlcipher_sqlite3IcuInit(sqlcipher_sqlite3 *db){
void (*xFunc)(sqlcipher_sqlite3_context*,int,sqlcipher_sqlite3_value**);
} scalars[] = {
{"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
+ {"icu_load_collation",3,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
{"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc},
{"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
@@ -210984,7 +222977,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Fts3IcuTokenizerModule(
** The order of the columns in the data_% table does not matter.
**
** Instead of a regular table, the RBU database may also contain virtual
-** tables or view named using the data_<target> naming scheme.
+** tables or views named using the data_<target> naming scheme.
**
** Instead of the plain data_<target> naming scheme, RBU database tables
** may also be named data<integer>_<target>, where <integer> is any sequence
@@ -210997,7 +222990,7 @@ SQLITE_PRIVATE void sqlcipher_sqlite3Fts3IcuTokenizerModule(
**
** If the target database table is a virtual table or a table that has no
** PRIMARY KEY declaration, the data_% table must also contain a column
-** named "rbu_rowid". This column is mapped to the tables implicit primary
+** named "rbu_rowid". This column is mapped to the table's implicit primary
** key column - "rowid". Virtual tables for which the "rowid" column does
** not function like a primary key value cannot be updated using RBU. For
** example, if the target db contains either of the following:
@@ -211431,6 +223424,34 @@ SQLITE_API void sqlcipher_sqlite3rbu_bp_progress(sqlcipher_sqlite3rbu *pRbu, int
SQLITE_API int sqlcipher_sqlite3rbu_state(sqlcipher_sqlite3rbu *pRbu);
/*
+** As part of applying an RBU update or performing an RBU vacuum operation,
+** the system must at one point move the *-oal file to the equivalent *-wal
+** path. Normally, it does this by invoking POSIX function rename(2) directly.
+** Except on WINCE platforms, where it uses win32 API MoveFileW(). This
+** function may be used to register a callback that the RBU module will invoke
+** instead of one of these APIs.
+**
+** If a callback is registered with an RBU handle, it invokes it instead
+** of rename(2) when it needs to move a file within the file-system. The
+** first argument passed to the xRename() callback is a copy of the second
+** argument (pArg) passed to this function. The second is the full path
+** to the file to move and the third the full path to which it should be
+** moved. The callback function should return SQLITE_OK to indicate
+** success. If an error occurs, it should return an SQLite error code.
+** In this case the RBU operation will be abandoned and the error returned
+** to the RBU user.
+**
+** Passing a NULL pointer in place of the xRename argument to this function
+** restores the default behaviour.
+*/
+SQLITE_API void sqlcipher_sqlite3rbu_rename_handler(
+ sqlcipher_sqlite3rbu *pRbu,
+ void *pArg,
+ int (*xRename)(void *pArg, const char *zOld, const char *zNew)
+);
+
+
+/*
** Create an RBU VFS named zName that accesses the underlying file-system
** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
** then the new RBU VFS uses the default system VFS to access the file-system.
@@ -211603,6 +223624,7 @@ typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef sqlcipher_sqlite3_int64 i64;
+typedef sqlcipher_sqlite3_uint64 u64;
#endif
/*
@@ -211797,6 +223819,8 @@ struct sqlcipher_sqlite3rbu {
int nPagePerSector; /* Pages per sector for pTargetFd */
i64 iOalSz;
i64 nPhaseOneStep;
+ void *pRenameArg;
+ int (*xRename)(void*, const char*, const char*);
/* The following state variables are used as part of the incremental
** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
@@ -212287,6 +224311,7 @@ static int rbuObjIterNext(sqlcipher_sqlite3rbu *p, RbuObjIter *pIter){
if( rc!=SQLITE_ROW ){
rc = resetAndCollectError(pIter->pTblIter, &p->zErrmsg);
pIter->zTbl = 0;
+ pIter->zDataTbl = 0;
}else{
pIter->zTbl = (const char*)sqlcipher_sqlite3_column_text(pIter->pTblIter, 0);
pIter->zDataTbl = (const char*)sqlcipher_sqlite3_column_text(pIter->pTblIter,1);
@@ -214185,7 +226210,7 @@ static void rbuOpenDatabase(sqlcipher_sqlite3rbu *p, sqlcipher_sqlite3 *dbMain,
sqlcipher_sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
if( p->zState==0 ){
const char *zFile = sqlcipher_sqlite3_db_filename(p->dbRbu, "main");
- p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile);
+ p->zState = rbuMPrintf(p, "file:///%s-vacuum?modeof=%s", zFile, zFile);
}
}
@@ -214381,7 +226406,7 @@ static i64 rbuShmChecksum(sqlcipher_sqlite3rbu *p){
u32 volatile *ptr;
p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, (void volatile**)&ptr);
if( p->rc==SQLITE_OK ){
- iRet = ((i64)ptr[10] << 32) + ptr[11];
+ iRet = (i64)(((u64)ptr[10] << 32) + ptr[11]);
}
}
return iRet;
@@ -214433,11 +226458,11 @@ static void rbuSetupCheckpoint(sqlcipher_sqlite3rbu *p, RbuState *pState){
** no-ops. These locks will not be released until the connection
** is closed.
**
- ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL
+ ** * Attempting to xSync() the database file causes an SQLITE_NOTICE
** error.
**
** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the
- ** checkpoint below fails with SQLITE_INTERNAL, and leaves the aFrame[]
+ ** checkpoint below fails with SQLITE_NOTICE, and leaves the aFrame[]
** array populated with a set of (frame -> page) mappings. Because the
** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy
** data from the wal file into the database file according to the
@@ -214447,7 +226472,7 @@ static void rbuSetupCheckpoint(sqlcipher_sqlite3rbu *p, RbuState *pState){
int rc2;
p->eStage = RBU_STAGE_CAPTURE;
rc2 = sqlcipher_sqlite3_exec(p->dbMain, "PRAGMA main.wal_checkpoint=restart", 0, 0,0);
- if( rc2!=SQLITE_INTERNAL ) p->rc = rc2;
+ if( rc2!=SQLITE_NOTICE ) p->rc = rc2;
}
if( p->rc==SQLITE_OK && p->nFrame>0 ){
@@ -214493,7 +226518,7 @@ static int rbuCaptureWalRead(sqlcipher_sqlite3rbu *pRbu, i64 iOff, int iAmt){
if( pRbu->mLock!=mReq ){
pRbu->rc = SQLITE_BUSY;
- return SQLITE_INTERNAL;
+ return SQLITE_NOTICE_RBU;
}
pRbu->pgsz = iAmt;
@@ -214543,6 +226568,11 @@ static void rbuCheckpointFrame(sqlcipher_sqlite3rbu *p, RbuFrame *pFrame){
p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
}
+/*
+** This value is copied from the definition of ZIPVFS_CTRL_FILE_POINTER
+** in zipvfs.h.
+*/
+#define RBU_ZIPVFS_CTRL_FILE_POINTER 230439
/*
** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if
@@ -214551,9 +226581,20 @@ static void rbuCheckpointFrame(sqlcipher_sqlite3rbu *p, RbuFrame *pFrame){
static int rbuLockDatabase(sqlcipher_sqlite3 *db){
int rc = SQLITE_OK;
sqlcipher_sqlite3_file *fd = 0;
- sqlcipher_sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
- if( fd->pMethods ){
+ sqlcipher_sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd);
+ if( fd ){
+ sqlcipher_sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
+ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
+ if( rc==SQLITE_OK ){
+ rc = fd->pMethods->xUnlock(fd, SQLITE_LOCK_NONE);
+ }
+ sqlcipher_sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd);
+ }else{
+ sqlcipher_sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
+ }
+
+ if( rc==SQLITE_OK && fd->pMethods ){
rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
if( rc==SQLITE_OK ){
rc = fd->pMethods->xLock(fd, SQLITE_LOCK_EXCLUSIVE);
@@ -214645,32 +226686,7 @@ static void rbuMoveOalFile(sqlcipher_sqlite3rbu *p){
}
if( p->rc==SQLITE_OK ){
-#if defined(_WIN32_WCE)
- {
- LPWSTR zWideOal;
- LPWSTR zWideWal;
-
- zWideOal = rbuWinUtf8ToUnicode(zOal);
- if( zWideOal ){
- zWideWal = rbuWinUtf8ToUnicode(zWal);
- if( zWideWal ){
- if( MoveFileW(zWideOal, zWideWal) ){
- p->rc = SQLITE_OK;
- }else{
- p->rc = SQLITE_IOERR;
- }
- sqlcipher_sqlite3_free(zWideWal);
- }else{
- p->rc = SQLITE_IOERR_NOMEM;
- }
- sqlcipher_sqlite3_free(zWideOal);
- }else{
- p->rc = SQLITE_IOERR_NOMEM;
- }
- }
-#else
- p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
-#endif
+ p->rc = p->xRename(p->pRenameArg, zOal, zWal);
}
if( p->rc!=SQLITE_OK
@@ -215257,7 +227273,8 @@ static void rbuSetupOal(sqlcipher_sqlite3rbu *p, RbuState *pState){
static void rbuDeleteOalFile(sqlcipher_sqlite3rbu *p){
char *zOal = rbuMPrintf(p, "%s-oal", p->zTarget);
if( zOal ){
- sqlcipher_sqlite3_vfs *pVfs = sqlcipher_sqlite3_vfs_find(0);
+ sqlcipher_sqlite3_vfs *pVfs = 0;
+ sqlcipher_sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_VFS_POINTER, &pVfs);
assert( pVfs && p->rc==SQLITE_OK && p->zErrmsg==0 );
pVfs->xDelete(pVfs, zOal, 0);
sqlcipher_sqlite3_free(zOal);
@@ -215409,6 +227426,7 @@ static sqlcipher_sqlite3rbu *openRbuHandle(
/* Create the custom VFS. */
memset(p, 0, sizeof(sqlcipher_sqlite3rbu));
+ sqlcipher_sqlite3rbu_rename_handler(p, 0, 0);
rbuCreateVfs(p);
/* Open the target, RBU and state databases */
@@ -215800,6 +227818,54 @@ SQLITE_API int sqlcipher_sqlite3rbu_savestate(sqlcipher_sqlite3rbu *p){
return rc;
}
+/*
+** Default xRename callback for RBU.
+*/
+static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
+ int rc = SQLITE_OK;
+#if defined(_WIN32_WCE)
+ {
+ LPWSTR zWideOld;
+ LPWSTR zWideNew;
+
+ zWideOld = rbuWinUtf8ToUnicode(zOld);
+ if( zWideOld ){
+ zWideNew = rbuWinUtf8ToUnicode(zNew);
+ if( zWideNew ){
+ if( MoveFileW(zWideOld, zWideNew) ){
+ rc = SQLITE_OK;
+ }else{
+ rc = SQLITE_IOERR;
+ }
+ sqlcipher_sqlite3_free(zWideNew);
+ }else{
+ rc = SQLITE_IOERR_NOMEM;
+ }
+ sqlcipher_sqlite3_free(zWideOld);
+ }else{
+ rc = SQLITE_IOERR_NOMEM;
+ }
+ }
+#else
+ rc = rename(zOld, zNew) ? SQLITE_IOERR : SQLITE_OK;
+#endif
+ return rc;
+}
+
+SQLITE_API void sqlcipher_sqlite3rbu_rename_handler(
+ sqlcipher_sqlite3rbu *pRbu,
+ void *pArg,
+ int (*xRename)(void *pArg, const char *zOld, const char *zNew)
+){
+ if( xRename ){
+ pRbu->xRename = xRename;
+ pRbu->pRenameArg = pArg;
+ }else{
+ pRbu->xRename = xDefaultRename;
+ pRbu->pRenameArg = 0;
+ }
+}
+
/**************************************************************************
** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour
** of a standard VFS in the following ways:
@@ -215856,7 +227922,7 @@ SQLITE_API int sqlcipher_sqlite3rbu_savestate(sqlcipher_sqlite3rbu *p){
** database file are recorded. xShmLock() calls to unlock the same
** locks are no-ops (so that once obtained, these locks are never
** relinquished). Finally, calls to xSync() on the target database
-** file fail with SQLITE_INTERNAL errors.
+** file fail with SQLITE_NOTICE errors.
*/
static void rbuUnlockShm(rbu_file *p){
@@ -215965,9 +228031,12 @@ static int rbuVfsClose(sqlcipher_sqlite3_file *pFile){
sqlcipher_sqlite3_free(p->zDel);
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
+ const sqlcipher_sqlite3_io_methods *pMeth = p->pReal->pMethods;
rbuMainlistRemove(p);
rbuUnlockShm(p);
- p->pReal->pMethods->xShmUnmap(p->pReal, 0);
+ if( pMeth->iVersion>1 && pMeth->xShmUnmap ){
+ pMeth->xShmUnmap(p->pReal, 0);
+ }
}
else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
rbuUpdateTempSize(p, 0);
@@ -216135,7 +228204,7 @@ static int rbuVfsSync(sqlcipher_sqlite3_file *pFile, int flags){
rbu_file *p = (rbu_file *)pFile;
if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
- return SQLITE_INTERNAL;
+ return SQLITE_NOTICE_RBU;
}
return SQLITE_OK;
}
@@ -216426,6 +228495,25 @@ static int rbuVfsOpen(
rbuVfsShmUnmap, /* xShmUnmap */
0, 0 /* xFetch, xUnfetch */
};
+ static sqlcipher_sqlite3_io_methods rbuvfs_io_methods1 = {
+ 1, /* iVersion */
+ rbuVfsClose, /* xClose */
+ rbuVfsRead, /* xRead */
+ rbuVfsWrite, /* xWrite */
+ rbuVfsTruncate, /* xTruncate */
+ rbuVfsSync, /* xSync */
+ rbuVfsFileSize, /* xFileSize */
+ rbuVfsLock, /* xLock */
+ rbuVfsUnlock, /* xUnlock */
+ rbuVfsCheckReservedLock, /* xCheckReservedLock */
+ rbuVfsFileControl, /* xFileControl */
+ rbuVfsSectorSize, /* xSectorSize */
+ rbuVfsDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, 0, 0, 0, 0, 0
+ };
+
+
+
rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
sqlcipher_sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
rbu_file *pFd = (rbu_file *)pFile;
@@ -216480,10 +228568,15 @@ static int rbuVfsOpen(
rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags);
}
if( pFd->pReal->pMethods ){
+ const sqlcipher_sqlite3_io_methods *pMeth = pFd->pReal->pMethods;
/* The xOpen() operation has succeeded. Set the sqlcipher_sqlite3_file.pMethods
** pointer and, if the file is a main database file, link it into the
** mutex protected linked list of all such files. */
- pFile->pMethods = &rbuvfs_io_methods;
+ if( pMeth->iVersion<2 || pMeth->xShmLock==0 ){
+ pFile->pMethods = &rbuvfs_io_methods1;
+ }else{
+ pFile->pMethods = &rbuvfs_io_methods;
+ }
if( flags & SQLITE_OPEN_MAIN_DB ){
rbuMainlistAdd(pFd);
}
@@ -216916,6 +229009,7 @@ static int statConnect(
StatTable *pTab = 0;
int rc = SQLITE_OK;
int iDb;
+ (void)pAux;
if( argc>=4 ){
Token nm;
@@ -216969,6 +229063,7 @@ static int statBestIndex(sqlcipher_sqlite3_vtab *tab, sqlcipher_sqlite3_index_in
int iSchema = -1;
int iName = -1;
int iAgg = -1;
+ (void)tab;
/* Look for a valid schema=? constraint. If found, change the idxNum to
** 1 and request the value of that constraint be sent to xFilter. And
@@ -217494,6 +229589,8 @@ static int statFilter(
int iArg = 0; /* Count of argv[] parameters used so far */
int rc = SQLITE_OK; /* Result of this operation */
const char *zName = 0; /* Only provide analysis of this table */
+ (void)argc;
+ (void)idxStr;
statResetCsr(pCsr);
sqlcipher_sqlite3_finalize(pCsr->pStmt);
@@ -217577,16 +229674,16 @@ static int statColumn(
}
break;
case 4: /* ncell */
- sqlcipher_sqlite3_result_int(ctx, pCsr->nCell);
+ sqlcipher_sqlite3_result_int64(ctx, pCsr->nCell);
break;
case 5: /* payload */
- sqlcipher_sqlite3_result_int(ctx, pCsr->nPayload);
+ sqlcipher_sqlite3_result_int64(ctx, pCsr->nPayload);
break;
case 6: /* unused */
- sqlcipher_sqlite3_result_int(ctx, pCsr->nUnused);
+ sqlcipher_sqlite3_result_int64(ctx, pCsr->nUnused);
break;
case 7: /* mx_payload */
- sqlcipher_sqlite3_result_int(ctx, pCsr->nMxPayload);
+ sqlcipher_sqlite3_result_int64(ctx, pCsr->nMxPayload);
break;
case 8: /* pgoffset */
if( !pCsr->isAgg ){
@@ -217594,7 +229691,7 @@ static int statColumn(
}
break;
case 9: /* pgsize */
- sqlcipher_sqlite3_result_int(ctx, pCsr->szPage);
+ sqlcipher_sqlite3_result_int64(ctx, pCsr->szPage);
break;
case 10: { /* schema */
sqlcipher_sqlite3 *db = sqlcipher_sqlite3_context_db_handle(ctx);
@@ -217644,7 +229741,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3DbstatRegister(sqlcipher_sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
return sqlcipher_sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
}
@@ -217728,8 +229826,13 @@ static int dbpageConnect(
){
DbpageTable *pTab = 0;
int rc = SQLITE_OK;
+ (void)pAux;
+ (void)argc;
+ (void)argv;
+ (void)pzErr;
sqlcipher_sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
+ sqlcipher_sqlite3_vtab_config(db, SQLITE_VTAB_USES_ALL_SCHEMAS);
rc = sqlcipher_sqlite3_declare_vtab(db,
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
if( rc==SQLITE_OK ){
@@ -217766,6 +229869,7 @@ static int dbpageDisconnect(sqlcipher_sqlite3_vtab *pVtab){
static int dbpageBestIndex(sqlcipher_sqlite3_vtab *tab, sqlcipher_sqlite3_index_info *pIdxInfo){
int i;
int iPlan = 0;
+ (void)tab;
/* If there is a schema= constraint, it must be honored. Report a
** ridiculously large estimated cost if the schema= constraint is
@@ -217812,7 +229916,6 @@ static int dbpageBestIndex(sqlcipher_sqlite3_vtab *tab, sqlcipher_sqlite3_index_
){
pIdxInfo->orderByConsumed = 1;
}
- sqlcipher_sqlite3VtabUsesAllSchemas(pIdxInfo);
return SQLITE_OK;
}
@@ -217881,6 +229984,8 @@ static int dbpageFilter(
sqlcipher_sqlite3 *db = pTab->db;
Btree *pBt;
+ (void)idxStr;
+
/* Default setting is no rows of result */
pCsr->pgno = 1;
pCsr->mxPgno = 0;
@@ -217895,7 +230000,7 @@ static int dbpageFilter(
pCsr->iDb = 0;
}
pBt = db->aDb[pCsr->iDb].pBt;
- if( pBt==0 ) return SQLITE_OK;
+ if( NEVER(pBt==0) ) return SQLITE_OK;
pCsr->pPager = sqlcipher_sqlite3BtreePager(pBt);
pCsr->szPage = sqlcipher_sqlite3BtreeGetPageSize(pBt);
pCsr->mxPgno = sqlcipher_sqlite3BtreeLastPage(pBt);
@@ -217930,12 +230035,18 @@ static int dbpageColumn(
}
case 1: { /* data */
DbPage *pDbPage = 0;
- rc = sqlcipher_sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
- if( rc==SQLITE_OK ){
- sqlcipher_sqlite3_result_blob(ctx, sqlcipher_sqlite3PagerGetData(pDbPage), pCsr->szPage,
- SQLITE_TRANSIENT);
+ if( pCsr->pgno==((PENDING_BYTE/pCsr->szPage)+1) ){
+ /* The pending byte page. Assume it is zeroed out. Attempting to
+ ** request this page from the page is an SQLITE_CORRUPT error. */
+ sqlcipher_sqlite3_result_zeroblob(ctx, pCsr->szPage);
+ }else{
+ rc = sqlcipher_sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
+ if( rc==SQLITE_OK ){
+ sqlcipher_sqlite3_result_blob(ctx, sqlcipher_sqlite3PagerGetData(pDbPage), pCsr->szPage,
+ SQLITE_TRANSIENT);
+ }
+ sqlcipher_sqlite3PagerUnref(pDbPage);
}
- sqlcipher_sqlite3PagerUnref(pDbPage);
break;
}
default: { /* schema */
@@ -217944,7 +230055,7 @@ static int dbpageColumn(
break;
}
}
- return SQLITE_OK;
+ return rc;
}
static int dbpageRowid(sqlcipher_sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
@@ -217970,6 +230081,7 @@ static int dbpageUpdate(
Pager *pPager;
int szPage;
+ (void)pRowid;
if( pTab->db->flags & SQLITE_Defensive ){
zErr = "read-only";
goto update_fail;
@@ -217979,18 +230091,20 @@ static int dbpageUpdate(
goto update_fail;
}
pgno = sqlcipher_sqlite3_value_int(argv[0]);
- if( (Pgno)sqlcipher_sqlite3_value_int(argv[1])!=pgno ){
+ if( sqlcipher_sqlite3_value_type(argv[0])==SQLITE_NULL
+ || (Pgno)sqlcipher_sqlite3_value_int(argv[1])!=pgno
+ ){
zErr = "cannot insert";
goto update_fail;
}
zSchema = (const char*)sqlcipher_sqlite3_value_text(argv[4]);
- iDb = zSchema ? sqlcipher_sqlite3FindDbName(pTab->db, zSchema) : -1;
- if( iDb<0 ){
+ iDb = ALWAYS(zSchema) ? sqlcipher_sqlite3FindDbName(pTab->db, zSchema) : -1;
+ if( NEVER(iDb<0) ){
zErr = "no such schema";
goto update_fail;
}
pBt = pTab->db->aDb[iDb].pBt;
- if( pgno<1 || pBt==0 || pgno>sqlcipher_sqlite3BtreeLastPage(pBt) ){
+ if( NEVER(pgno<1) || NEVER(pBt==0) || NEVER(pgno>sqlcipher_sqlite3BtreeLastPage(pBt)) ){
zErr = "bad page number";
goto update_fail;
}
@@ -218004,11 +230118,12 @@ static int dbpageUpdate(
pPager = sqlcipher_sqlite3BtreePager(pBt);
rc = sqlcipher_sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
if( rc==SQLITE_OK ){
- rc = sqlcipher_sqlite3PagerWrite(pDbPage);
- if( rc==SQLITE_OK ){
- memcpy(sqlcipher_sqlite3PagerGetData(pDbPage),
- sqlcipher_sqlite3_value_blob(argv[3]),
- szPage);
+ const void *pData = sqlcipher_sqlite3_value_blob(argv[3]);
+ assert( pData!=0 || pTab->db->mallocFailed );
+ if( pData
+ && (rc = sqlcipher_sqlite3PagerWrite(pDbPage))==SQLITE_OK
+ ){
+ memcpy(sqlcipher_sqlite3PagerGetData(pDbPage), pData, szPage);
}
}
sqlcipher_sqlite3PagerUnref(pDbPage);
@@ -218030,7 +230145,7 @@ static int dbpageBegin(sqlcipher_sqlite3_vtab *pVtab){
int i;
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
- if( pBt ) sqlcipher_sqlite3BtreeBeginTrans(pBt, 1, 0);
+ if( pBt ) (void)sqlcipher_sqlite3BtreeBeginTrans(pBt, 1, 0);
}
return SQLITE_OK;
}
@@ -218064,7 +230179,8 @@ SQLITE_PRIVATE int sqlcipher_sqlite3DbpageRegister(sqlcipher_sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
return sqlcipher_sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
}
@@ -218101,6 +230217,8 @@ typedef struct SessionInput SessionInput;
# endif
#endif
+#define SESSIONS_ROWID "_rowid_"
+
static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE;
typedef struct SessionHook SessionHook;
@@ -218122,6 +230240,7 @@ struct sqlcipher_sqlite3_session {
int bEnable; /* True if currently recording */
int bIndirect; /* True if all changes are indirect */
int bAutoAttach; /* True to auto-attach tables */
+ int bImplicitPK; /* True to handle tables with implicit PK */
int rc; /* Non-zero if an error has occurred */
void *pFilterCtx; /* First argument to pass to xTableFilter */
int (*xTableFilter)(void *pCtx, const char *zTab);
@@ -218192,17 +230311,32 @@ struct sqlcipher_sqlite3_changeset_iter {
** The data associated with each hash-table entry is a structure containing
** a subset of the initial values that the modified row contained at the
** start of the session. Or no initial values if the row was inserted.
+**
+** pDfltStmt:
+** This is only used by the sqlcipher_sqlite3changegroup_xxx() APIs, not by
+** regular sqlcipher_sqlite3_session objects. It is a SELECT statement that
+** selects the default value for each table column. For example,
+** if the table is
+**
+** CREATE TABLE xx(a DEFAULT 1, b, c DEFAULT 'abc')
+**
+** then this variable is the compiled version of:
+**
+** SELECT 1, NULL, 'abc'
*/
struct SessionTable {
SessionTable *pNext;
char *zName; /* Local name of table */
int nCol; /* Number of columns in table zName */
int bStat1; /* True if this is sqlite_stat1 */
+ int bRowid; /* True if this table uses rowid for PK */
const char **azCol; /* Column names */
+ const char **azDflt; /* Default value expressions */
u8 *abPK; /* Array of primary key flags */
int nEntry; /* Total number of entries in hash table */
int nChange; /* Size of apChange[] array */
SessionChange **apChange; /* Hash table buckets */
+ sqlcipher_sqlite3_stmt *pDfltStmt;
};
/*
@@ -218371,6 +230505,7 @@ struct SessionTable {
struct SessionChange {
u8 op; /* One of UPDATE, DELETE, INSERT */
u8 bIndirect; /* True if this change is "indirect" */
+ u16 nRecordField; /* Number of fields in aRecord[] */
int nMaxSize; /* Max size of eventual changeset record */
int nRecord; /* Number of bytes in buffer aRecord[] */
u8 *aRecord; /* Buffer containing old.* record */
@@ -218396,7 +230531,7 @@ static int sessionVarintLen(int iVal){
** Read a varint value from aBuf[] into *piVal. Return the number of
** bytes read.
*/
-static int sessionVarintGet(u8 *aBuf, int *piVal){
+static int sessionVarintGet(const u8 *aBuf, int *piVal){
return getVarint32(aBuf, *piVal);
}
@@ -218590,6 +230725,7 @@ static unsigned int sessionHashAppendType(unsigned int h, int eType){
*/
static int sessionPreupdateHash(
sqlcipher_sqlite3_session *pSession, /* Session object that owns pTab */
+ i64 iRowid,
SessionTable *pTab, /* Session table handle */
int bNew, /* True to hash the new.* PK */
int *piHash, /* OUT: Hash value */
@@ -218598,48 +230734,53 @@ static int sessionPreupdateHash(
unsigned int h = 0; /* Hash value to return */
int i; /* Used to iterate through columns */
- assert( *pbNullPK==0 );
- assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
- for(i=0; i<pTab->nCol; i++){
- if( pTab->abPK[i] ){
- int rc;
- int eType;
- sqlcipher_sqlite3_value *pVal;
-
- if( bNew ){
- rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
- }else{
- rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
- }
- if( rc!=SQLITE_OK ) return rc;
+ if( pTab->bRowid ){
+ assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) );
+ h = sessionHashAppendI64(h, iRowid);
+ }else{
+ assert( *pbNullPK==0 );
+ assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
+ for(i=0; i<pTab->nCol; i++){
+ if( pTab->abPK[i] ){
+ int rc;
+ int eType;
+ sqlcipher_sqlite3_value *pVal;
- eType = sqlcipher_sqlite3_value_type(pVal);
- h = sessionHashAppendType(h, eType);
- if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- i64 iVal;
- if( eType==SQLITE_INTEGER ){
- iVal = sqlcipher_sqlite3_value_int64(pVal);
+ if( bNew ){
+ rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
}else{
- double rVal = sqlcipher_sqlite3_value_double(pVal);
- assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
- memcpy(&iVal, &rVal, 8);
+ rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
}
- h = sessionHashAppendI64(h, iVal);
- }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
- const u8 *z;
- int n;
- if( eType==SQLITE_TEXT ){
- z = (const u8 *)sqlcipher_sqlite3_value_text(pVal);
+ if( rc!=SQLITE_OK ) return rc;
+
+ eType = sqlcipher_sqlite3_value_type(pVal);
+ h = sessionHashAppendType(h, eType);
+ if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ i64 iVal;
+ if( eType==SQLITE_INTEGER ){
+ iVal = sqlcipher_sqlite3_value_int64(pVal);
+ }else{
+ double rVal = sqlcipher_sqlite3_value_double(pVal);
+ assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
+ memcpy(&iVal, &rVal, 8);
+ }
+ h = sessionHashAppendI64(h, iVal);
+ }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+ const u8 *z;
+ int n;
+ if( eType==SQLITE_TEXT ){
+ z = (const u8 *)sqlcipher_sqlite3_value_text(pVal);
+ }else{
+ z = (const u8 *)sqlcipher_sqlite3_value_blob(pVal);
+ }
+ n = sqlcipher_sqlite3_value_bytes(pVal);
+ if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
+ h = sessionHashAppendBlob(h, n, z);
}else{
- z = (const u8 *)sqlcipher_sqlite3_value_blob(pVal);
+ assert( eType==SQLITE_NULL );
+ assert( pTab->bStat1==0 || i!=1 );
+ *pbNullPK = 1;
}
- n = sqlcipher_sqlite3_value_bytes(pVal);
- if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
- h = sessionHashAppendBlob(h, n, z);
- }else{
- assert( eType==SQLITE_NULL );
- assert( pTab->bStat1==0 || i!=1 );
- *pbNullPK = 1;
}
}
}
@@ -218653,9 +230794,11 @@ static int sessionPreupdateHash(
** Return the number of bytes of space occupied by the value (including
** the type byte).
*/
-static int sessionSerialLen(u8 *a){
- int e = *a;
+static int sessionSerialLen(const u8 *a){
+ int e;
int n;
+ assert( a!=0 );
+ e = *a;
if( e==0 || e==0xFF ) return 1;
if( e==SQLITE_NULL ) return 1;
if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
@@ -218922,6 +231065,7 @@ static int sessionMergeUpdate(
*/
static int sessionPreupdateEqual(
sqlcipher_sqlite3_session *pSession, /* Session object that owns SessionTable */
+ i64 iRowid, /* Rowid value if pTab->bRowid */
SessionTable *pTab, /* Table associated with change */
SessionChange *pChange, /* Change to compare to */
int op /* Current pre-update operation */
@@ -218929,6 +231073,11 @@ static int sessionPreupdateEqual(
int iCol; /* Used to iterate through columns */
u8 *a = pChange->aRecord; /* Cursor used to scan change record */
+ if( pTab->bRowid ){
+ if( a[0]!=SQLITE_INTEGER ) return 0;
+ return sessionGetI64(&a[1])==iRowid;
+ }
+
assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
for(iCol=0; iCol<pTab->nCol; iCol++){
if( !pTab->abPK[iCol] ){
@@ -218951,6 +231100,7 @@ static int sessionPreupdateEqual(
rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
}
assert( rc==SQLITE_OK );
+ (void)rc; /* Suppress warning about unused variable */
if( sqlcipher_sqlite3_value_type(pVal)!=eType ) return 0;
/* A SessionChange object never has a NULL value in a PK column */
@@ -219053,13 +231203,14 @@ static int sessionGrowHash(
**
** For example, if the table is declared as:
**
-** CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
+** CREATE TABLE tbl1(w, x DEFAULT 'abc', y, z, PRIMARY KEY(w, z));
**
-** Then the four output variables are populated as follows:
+** Then the five output variables are populated as follows:
**
** *pnCol = 4
** *pzTab = "tbl1"
** *pazCol = {"w", "x", "y", "z"}
+** *pazDflt = {NULL, 'abc', NULL, NULL}
** *pabPK = {1, 0, 0, 1}
**
** All returned buffers are part of the same single allocation, which must
@@ -219073,7 +231224,9 @@ static int sessionTableInfo(
int *pnCol, /* OUT: number of columns */
const char **pzTab, /* OUT: Copy of zThis */
const char ***pazCol, /* OUT: Array of column names for table */
- u8 **pabPK /* OUT: Array of booleans - true for PK col */
+ const char ***pazDflt, /* OUT: Array of default value expressions */
+ u8 **pabPK, /* OUT: Array of booleans - true for PK col */
+ int *pbRowid /* OUT: True if only PK is a rowid */
){
char *zPragma;
sqlcipher_sqlite3_stmt *pStmt;
@@ -219084,10 +231237,18 @@ static int sessionTableInfo(
int i;
u8 *pAlloc = 0;
char **azCol = 0;
+ char **azDflt = 0;
u8 *abPK = 0;
+ int bRowid = 0; /* Set to true to use rowid as PK */
assert( pazCol && pabPK );
+ *pazCol = 0;
+ *pabPK = 0;
+ *pnCol = 0;
+ if( pzTab ) *pzTab = 0;
+ if( pazDflt ) *pazDflt = 0;
+
nThis = sqlcipher_sqlite3Strlen30(zThis);
if( nThis==12 && 0==sqlcipher_sqlite3_stricmp("sqlite_stat1", zThis) ){
rc = sqlcipher_sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
@@ -219101,50 +231262,47 @@ static int sessionTableInfo(
}else if( rc==SQLITE_ERROR ){
zPragma = sqlcipher_sqlite3_mprintf("");
}else{
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return rc;
}
}else{
zPragma = sqlcipher_sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
}
if( !zPragma ){
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return SQLITE_NOMEM;
}
rc = sqlcipher_sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
sqlcipher_sqlite3_free(zPragma);
if( rc!=SQLITE_OK ){
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return rc;
}
nByte = nThis + 1;
+ bRowid = (pbRowid!=0);
while( SQLITE_ROW==sqlcipher_sqlite3_step(pStmt) ){
- nByte += sqlcipher_sqlite3_column_bytes(pStmt, 1);
+ nByte += sqlcipher_sqlite3_column_bytes(pStmt, 1); /* name */
+ nByte += sqlcipher_sqlite3_column_bytes(pStmt, 4); /* dflt_value */
nDbCol++;
+ if( sqlcipher_sqlite3_column_int(pStmt, 5) ) bRowid = 0; /* pk */
}
+ if( nDbCol==0 ) bRowid = 0;
+ nDbCol += bRowid;
+ nByte += strlen(SESSIONS_ROWID);
rc = sqlcipher_sqlite3_reset(pStmt);
if( rc==SQLITE_OK ){
- nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
+ nByte += nDbCol * (sizeof(const char *)*2 + sizeof(u8) + 1 + 1);
pAlloc = sessionMalloc64(pSession, nByte);
if( pAlloc==0 ){
rc = SQLITE_NOMEM;
+ }else{
+ memset(pAlloc, 0, nByte);
}
}
if( rc==SQLITE_OK ){
azCol = (char **)pAlloc;
- pAlloc = (u8 *)&azCol[nDbCol];
+ azDflt = (char**)&azCol[nDbCol];
+ pAlloc = (u8 *)&azDflt[nDbCol];
abPK = (u8 *)pAlloc;
pAlloc = &abPK[nDbCol];
if( pzTab ){
@@ -219154,43 +231312,57 @@ static int sessionTableInfo(
}
i = 0;
+ if( bRowid ){
+ size_t nName = strlen(SESSIONS_ROWID);
+ memcpy(pAlloc, SESSIONS_ROWID, nName+1);
+ azCol[i] = (char*)pAlloc;
+ pAlloc += nName+1;
+ abPK[i] = 1;
+ i++;
+ }
while( SQLITE_ROW==sqlcipher_sqlite3_step(pStmt) ){
int nName = sqlcipher_sqlite3_column_bytes(pStmt, 1);
+ int nDflt = sqlcipher_sqlite3_column_bytes(pStmt, 4);
const unsigned char *zName = sqlcipher_sqlite3_column_text(pStmt, 1);
+ const unsigned char *zDflt = sqlcipher_sqlite3_column_text(pStmt, 4);
+
if( zName==0 ) break;
memcpy(pAlloc, zName, nName+1);
azCol[i] = (char *)pAlloc;
pAlloc += nName+1;
+ if( zDflt ){
+ memcpy(pAlloc, zDflt, nDflt+1);
+ azDflt[i] = (char *)pAlloc;
+ pAlloc += nDflt+1;
+ }else{
+ azDflt[i] = 0;
+ }
abPK[i] = sqlcipher_sqlite3_column_int(pStmt, 5);
i++;
}
rc = sqlcipher_sqlite3_reset(pStmt);
-
}
/* If successful, populate the output variables. Otherwise, zero them and
** free any allocation made. An error code will be returned in this case.
*/
if( rc==SQLITE_OK ){
- *pazCol = (const char **)azCol;
+ *pazCol = (const char**)azCol;
+ if( pazDflt ) *pazDflt = (const char**)azDflt;
*pabPK = abPK;
*pnCol = nDbCol;
}else{
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
sessionFree(pSession, azCol);
}
+ if( pbRowid ) *pbRowid = bRowid;
sqlcipher_sqlite3_finalize(pStmt);
return rc;
}
/*
-** This function is only called from within a pre-update handler for a
-** write to table pTab, part of session pSession. If this is the first
-** write to this table, initalize the SessionTable.nCol, azCol[] and
-** abPK[] arrays accordingly.
+** This function is called to initialize the SessionTable.nCol, azCol[]
+** abPK[] and azDflt[] members of SessionTable object pTab. If these
+** fields are already initilialized, this function is a no-op.
**
** If an error occurs, an error code is stored in sqlcipher_sqlite3_session.rc and
** non-zero returned. Or, if no error occurs but the table has no primary
@@ -219198,14 +231370,22 @@ static int sessionTableInfo(
** indicate that updates on this table should be ignored. SessionTable.abPK
** is set to NULL in this case.
*/
-static int sessionInitTable(sqlcipher_sqlite3_session *pSession, SessionTable *pTab){
+static int sessionInitTable(
+ sqlcipher_sqlite3_session *pSession, /* Optional session handle */
+ SessionTable *pTab, /* Table object to initialize */
+ sqlcipher_sqlite3 *db, /* Database handle to read schema from */
+ const char *zDb /* Name of db - "main", "temp" etc. */
+){
+ int rc = SQLITE_OK;
+
if( pTab->nCol==0 ){
u8 *abPK;
assert( pTab->azCol==0 || pTab->abPK==0 );
- pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
- pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
+ rc = sessionTableInfo(pSession, db, zDb,
+ pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->azDflt, &abPK,
+ ((pSession==0 || pSession->bImplicitPK) ? &pTab->bRowid : 0)
);
- if( pSession->rc==SQLITE_OK ){
+ if( rc==SQLITE_OK ){
int i;
for(i=0; i<pTab->nCol; i++){
if( abPK[i] ){
@@ -219217,14 +231397,321 @@ static int sessionInitTable(sqlcipher_sqlite3_session *pSession, SessionTable *p
pTab->bStat1 = 1;
}
- if( pSession->bEnableSize ){
+ if( pSession && pSession->bEnableSize ){
pSession->nMaxChangesetSize += (
1 + sessionVarintLen(pTab->nCol) + pTab->nCol + strlen(pTab->zName)+1
);
}
}
}
- return (pSession->rc || pTab->abPK==0);
+
+ if( pSession ){
+ pSession->rc = rc;
+ return (rc || pTab->abPK==0);
+ }
+ return rc;
+}
+
+/*
+** Re-initialize table object pTab.
+*/
+static int sessionReinitTable(sqlcipher_sqlite3_session *pSession, SessionTable *pTab){
+ int nCol = 0;
+ const char **azCol = 0;
+ const char **azDflt = 0;
+ u8 *abPK = 0;
+ int bRowid = 0;
+
+ assert( pSession->rc==SQLITE_OK );
+
+ pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
+ pTab->zName, &nCol, 0, &azCol, &azDflt, &abPK,
+ (pSession->bImplicitPK ? &bRowid : 0)
+ );
+ if( pSession->rc==SQLITE_OK ){
+ if( pTab->nCol>nCol || pTab->bRowid!=bRowid ){
+ pSession->rc = SQLITE_SCHEMA;
+ }else{
+ int ii;
+ int nOldCol = pTab->nCol;
+ for(ii=0; ii<nCol; ii++){
+ if( ii<pTab->nCol ){
+ if( pTab->abPK[ii]!=abPK[ii] ){
+ pSession->rc = SQLITE_SCHEMA;
+ }
+ }else if( abPK[ii] ){
+ pSession->rc = SQLITE_SCHEMA;
+ }
+ }
+
+ if( pSession->rc==SQLITE_OK ){
+ const char **a = pTab->azCol;
+ pTab->azCol = azCol;
+ pTab->nCol = nCol;
+ pTab->azDflt = azDflt;
+ pTab->abPK = abPK;
+ azCol = a;
+ }
+ if( pSession->bEnableSize ){
+ pSession->nMaxChangesetSize += (nCol - nOldCol);
+ pSession->nMaxChangesetSize += sessionVarintLen(nCol);
+ pSession->nMaxChangesetSize -= sessionVarintLen(nOldCol);
+ }
+ }
+ }
+
+ sqlcipher_sqlite3_free((char*)azCol);
+ return pSession->rc;
+}
+
+/*
+** Session-change object (*pp) contains an old.* record with fewer than
+** nCol fields. This function updates it with the default values for
+** the missing fields.
+*/
+static void sessionUpdateOneChange(
+ sqlcipher_sqlite3_session *pSession, /* For memory accounting */
+ int *pRc, /* IN/OUT: Error code */
+ SessionChange **pp, /* IN/OUT: Change object to update */
+ int nCol, /* Number of columns now in table */
+ sqlcipher_sqlite3_stmt *pDflt /* SELECT <default-values...> */
+){
+ SessionChange *pOld = *pp;
+
+ while( pOld->nRecordField<nCol ){
+ SessionChange *pNew = 0;
+ int nByte = 0;
+ int nIncr = 0;
+ int iField = pOld->nRecordField;
+ int eType = sqlcipher_sqlite3_column_type(pDflt, iField);
+ switch( eType ){
+ case SQLITE_NULL:
+ nIncr = 1;
+ break;
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT:
+ nIncr = 9;
+ break;
+ default: {
+ int n = sqlcipher_sqlite3_column_bytes(pDflt, iField);
+ nIncr = 1 + sessionVarintLen(n) + n;
+ assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
+ break;
+ }
+ }
+
+ nByte = nIncr + (sizeof(SessionChange) + pOld->nRecord);
+ pNew = sessionMalloc64(pSession, nByte);
+ if( pNew==0 ){
+ *pRc = SQLITE_NOMEM;
+ return;
+ }else{
+ memcpy(pNew, pOld, sizeof(SessionChange));
+ pNew->aRecord = (u8*)&pNew[1];
+ memcpy(pNew->aRecord, pOld->aRecord, pOld->nRecord);
+ pNew->aRecord[pNew->nRecord++] = (u8)eType;
+ switch( eType ){
+ case SQLITE_INTEGER: {
+ i64 iVal = sqlcipher_sqlite3_column_int64(pDflt, iField);
+ sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal);
+ pNew->nRecord += 8;
+ break;
+ }
+
+ case SQLITE_FLOAT: {
+ double rVal = sqlcipher_sqlite3_column_double(pDflt, iField);
+ i64 iVal = 0;
+ memcpy(&iVal, &rVal, sizeof(rVal));
+ sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal);
+ pNew->nRecord += 8;
+ break;
+ }
+
+ case SQLITE_TEXT: {
+ int n = sqlcipher_sqlite3_column_bytes(pDflt, iField);
+ const char *z = (const char*)sqlcipher_sqlite3_column_text(pDflt, iField);
+ pNew->nRecord += sessionVarintPut(&pNew->aRecord[pNew->nRecord], n);
+ memcpy(&pNew->aRecord[pNew->nRecord], z, n);
+ pNew->nRecord += n;
+ break;
+ }
+
+ case SQLITE_BLOB: {
+ int n = sqlcipher_sqlite3_column_bytes(pDflt, iField);
+ const u8 *z = (const u8*)sqlcipher_sqlite3_column_blob(pDflt, iField);
+ pNew->nRecord += sessionVarintPut(&pNew->aRecord[pNew->nRecord], n);
+ memcpy(&pNew->aRecord[pNew->nRecord], z, n);
+ pNew->nRecord += n;
+ break;
+ }
+
+ default:
+ assert( eType==SQLITE_NULL );
+ break;
+ }
+
+ sessionFree(pSession, pOld);
+ *pp = pOld = pNew;
+ pNew->nRecordField++;
+ pNew->nMaxSize += nIncr;
+ if( pSession ){
+ pSession->nMaxChangesetSize += nIncr;
+ }
+ }
+ }
+}
+
+/*
+** Ensure that there is room in the buffer to append nByte bytes of data.
+** If not, use sqlcipher_sqlite3_realloc() to grow the buffer so that there is.
+**
+** If successful, return zero. Otherwise, if an OOM condition is encountered,
+** set *pRc to SQLITE_NOMEM and return non-zero.
+*/
+static int sessionBufferGrow(SessionBuffer *p, i64 nByte, int *pRc){
+#define SESSION_MAX_BUFFER_SZ (0x7FFFFF00 - 1)
+ i64 nReq = p->nBuf + nByte;
+ if( *pRc==SQLITE_OK && nReq>p->nAlloc ){
+ u8 *aNew;
+ i64 nNew = p->nAlloc ? p->nAlloc : 128;
+
+ do {
+ nNew = nNew*2;
+ }while( nNew<nReq );
+
+ /* The value of SESSION_MAX_BUFFER_SZ is copied from the implementation
+ ** of sqlcipher_sqlite3_realloc64(). Allocations greater than this size in bytes
+ ** always fail. It is used here to ensure that this routine can always
+ ** allocate up to this limit - instead of up to the largest power of
+ ** two smaller than the limit. */
+ if( nNew>SESSION_MAX_BUFFER_SZ ){
+ nNew = SESSION_MAX_BUFFER_SZ;
+ if( nNew<nReq ){
+ *pRc = SQLITE_NOMEM;
+ return 1;
+ }
+ }
+
+ aNew = (u8 *)sqlcipher_sqlite3_realloc64(p->aBuf, nNew);
+ if( 0==aNew ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ p->aBuf = aNew;
+ p->nAlloc = nNew;
+ }
+ }
+ return (*pRc!=SQLITE_OK);
+}
+
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append a string to the buffer. All bytes in the string
+** up to (but not including) the nul-terminator are written to the buffer.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
+*/
+static void sessionAppendStr(
+ SessionBuffer *p,
+ const char *zStr,
+ int *pRc
+){
+ int nStr = sqlcipher_sqlite3Strlen30(zStr);
+ if( 0==sessionBufferGrow(p, nStr+1, pRc) ){
+ memcpy(&p->aBuf[p->nBuf], zStr, nStr);
+ p->nBuf += nStr;
+ p->aBuf[p->nBuf] = 0x00;
+ }
+}
+
+/*
+** Format a string using printf() style formatting and then append it to the
+** buffer using sessionAppendString().
+*/
+static void sessionAppendPrintf(
+ SessionBuffer *p, /* Buffer to append to */
+ int *pRc,
+ const char *zFmt,
+ ...
+){
+ if( *pRc==SQLITE_OK ){
+ char *zApp = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zApp = sqlcipher_sqlite3_vmprintf(zFmt, ap);
+ if( zApp==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ sessionAppendStr(p, zApp, pRc);
+ }
+ va_end(ap);
+ sqlcipher_sqlite3_free(zApp);
+ }
+}
+
+/*
+** Prepare a statement against database handle db that SELECTs a single
+** row containing the default values for each column in table pTab. For
+** example, if pTab is declared as:
+**
+** CREATE TABLE pTab(a PRIMARY KEY, b DEFAULT 123, c DEFAULT 'abcd');
+**
+** Then this function prepares and returns the SQL statement:
+**
+** SELECT NULL, 123, 'abcd';
+*/
+static int sessionPrepareDfltStmt(
+ sqlcipher_sqlite3 *db, /* Database handle */
+ SessionTable *pTab, /* Table to prepare statement for */
+ sqlcipher_sqlite3_stmt **ppStmt /* OUT: Statement handle */
+){
+ SessionBuffer sql = {0,0,0};
+ int rc = SQLITE_OK;
+ const char *zSep = " ";
+ int ii = 0;
+
+ *ppStmt = 0;
+ sessionAppendPrintf(&sql, &rc, "SELECT");
+ for(ii=0; ii<pTab->nCol; ii++){
+ const char *zDflt = pTab->azDflt[ii] ? pTab->azDflt[ii] : "NULL";
+ sessionAppendPrintf(&sql, &rc, "%s%s", zSep, zDflt);
+ zSep = ", ";
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlcipher_sqlite3_prepare_v2(db, (const char*)sql.aBuf, -1, ppStmt, 0);
+ }
+ sqlcipher_sqlite3_free(sql.aBuf);
+
+ return rc;
+}
+
+/*
+** Table pTab has one or more existing change-records with old.* records
+** with fewer than pTab->nCol columns. This function updates all such
+** change-records with the default values for the missing columns.
+*/
+static int sessionUpdateChanges(sqlcipher_sqlite3_session *pSession, SessionTable *pTab){
+ sqlcipher_sqlite3_stmt *pStmt = 0;
+ int rc = pSession->rc;
+
+ rc = sessionPrepareDfltStmt(pSession->db, pTab, &pStmt);
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlcipher_sqlite3_step(pStmt) ){
+ int ii = 0;
+ SessionChange **pp = 0;
+ for(ii=0; ii<pTab->nChange; ii++){
+ for(pp=&pTab->apChange[ii]; *pp; pp=&((*pp)->pNext)){
+ if( (*pp)->nRecordField!=pTab->nCol ){
+ sessionUpdateOneChange(pSession, &rc, pp, pTab->nCol, pStmt);
+ }
+ }
+ }
+ }
+
+ pSession->rc = rc;
+ rc = sqlcipher_sqlite3_finalize(pStmt);
+ if( pSession->rc==SQLITE_OK ) pSession->rc = rc;
+ return pSession->rc;
}
/*
@@ -219275,6 +231762,7 @@ static int sessionUpdateMaxSize(
){
i64 nNew = 2;
if( pC->op==SQLITE_INSERT ){
+ if( pTab->bRowid ) nNew += 9;
if( op!=SQLITE_DELETE ){
int ii;
for(ii=0; ii<pTab->nCol; ii++){
@@ -219291,12 +231779,16 @@ static int sessionUpdateMaxSize(
}else{
int ii;
u8 *pCsr = pC->aRecord;
- for(ii=0; ii<pTab->nCol; ii++){
+ if( pTab->bRowid ){
+ nNew += 9 + 1;
+ pCsr += 9;
+ }
+ for(ii=pTab->bRowid; ii<pTab->nCol; ii++){
int bChanged = 1;
int nOld = 0;
int eType;
sqlcipher_sqlite3_value *p = 0;
- pSession->hook.xNew(pSession->hook.pCtx, ii, &p);
+ pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p);
if( p==0 ){
return SQLITE_NOMEM;
}
@@ -219375,22 +231867,29 @@ static int sessionUpdateMaxSize(
*/
static void sessionPreupdateOneChange(
int op, /* One of SQLITE_UPDATE, INSERT, DELETE */
+ i64 iRowid,
sqlcipher_sqlite3_session *pSession, /* Session object pTab is attached to */
SessionTable *pTab /* Table that change applies to */
){
int iHash;
int bNull = 0;
int rc = SQLITE_OK;
+ int nExpect = 0;
SessionStat1Ctx stat1 = {{0,0,0,0,0},0};
if( pSession->rc ) return;
/* Load table details if required */
- if( sessionInitTable(pSession, pTab) ) return;
+ if( sessionInitTable(pSession, pTab, pSession->db, pSession->zDb) ) return;
/* Check the number of columns in this xPreUpdate call matches the
** number of columns in the table. */
- if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
+ nExpect = pSession->hook.xCount(pSession->hook.pCtx);
+ if( (pTab->nCol-pTab->bRowid)<nExpect ){
+ if( sessionReinitTable(pSession, pTab) ) return;
+ if( sessionUpdateChanges(pSession, pTab) ) return;
+ }
+ if( (pTab->nCol-pTab->bRowid)!=nExpect ){
pSession->rc = SQLITE_SCHEMA;
return;
}
@@ -219423,14 +231922,16 @@ static void sessionPreupdateOneChange(
/* Calculate the hash-key for this change. If the primary key of the row
** includes a NULL value, exit early. Such changes are ignored by the
** session module. */
- rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
+ rc = sessionPreupdateHash(
+ pSession, iRowid, pTab, op==SQLITE_INSERT, &iHash, &bNull
+ );
if( rc!=SQLITE_OK ) goto error_out;
if( bNull==0 ){
/* Search the hash table for an existing record for this row. */
SessionChange *pC;
for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
- if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break;
+ if( sessionPreupdateEqual(pSession, iRowid, pTab, pC, op) ) break;
}
if( pC==0 ){
@@ -219445,7 +231946,7 @@ static void sessionPreupdateOneChange(
/* Figure out how large an allocation is required */
nByte = sizeof(SessionChange);
- for(i=0; i<pTab->nCol; i++){
+ for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlcipher_sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
@@ -219460,9 +231961,12 @@ static void sessionPreupdateOneChange(
rc = sessionSerializeValue(0, p, &nByte);
if( rc!=SQLITE_OK ) goto error_out;
}
+ if( pTab->bRowid ){
+ nByte += 9; /* Size of rowid field - an integer */
+ }
/* Allocate the change object */
- pC = (SessionChange *)sessionMalloc64(pSession, nByte);
+ pC = (SessionChange*)sessionMalloc64(pSession, nByte);
if( !pC ){
rc = SQLITE_NOMEM;
goto error_out;
@@ -219476,7 +231980,12 @@ static void sessionPreupdateOneChange(
** required values and encodings have already been cached in memory.
** It is not possible for an OOM to occur in this block. */
nByte = 0;
- for(i=0; i<pTab->nCol; i++){
+ if( pTab->bRowid ){
+ pC->aRecord[0] = SQLITE_INTEGER;
+ sessionPutI64(&pC->aRecord[1], iRowid);
+ nByte = 9;
+ }
+ for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlcipher_sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
pSession->hook.xOld(pSession->hook.pCtx, i, &p);
@@ -219490,6 +231999,7 @@ static void sessionPreupdateOneChange(
if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){
pC->bIndirect = 1;
}
+ pC->nRecordField = pTab->nCol;
pC->nRecord = nByte;
pC->op = op;
pC->pNext = pTab->apChange[iHash];
@@ -219575,6 +232085,8 @@ static void xPreUpdate(
int nDb = sqlcipher_sqlite3Strlen30(zDb);
assert( sqlcipher_sqlite3_mutex_held(db->mutex) );
+ (void)iKey1;
+ (void)iKey2;
for(pSession=(sqlcipher_sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
SessionTable *pTab;
@@ -219589,9 +232101,10 @@ static void xPreUpdate(
pSession->rc = sessionFindTable(pSession, zName, &pTab);
if( pTab ){
assert( pSession->rc==SQLITE_OK );
- sessionPreupdateOneChange(op, pSession, pTab);
+ assert( op==SQLITE_UPDATE || iKey1==iKey2 );
+ sessionPreupdateOneChange(op, iKey1, pSession, pTab);
if( op==SQLITE_UPDATE ){
- sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
+ sessionPreupdateOneChange(SQLITE_INSERT, iKey2, pSession, pTab);
}
}
}
@@ -219630,6 +232143,7 @@ static void sessionPreupdateHooks(
typedef struct SessionDiffCtx SessionDiffCtx;
struct SessionDiffCtx {
sqlcipher_sqlite3_stmt *pStmt;
+ int bRowid;
int nOldOff;
};
@@ -219638,19 +232152,20 @@ struct SessionDiffCtx {
*/
static int sessionDiffOld(void *pCtx, int iVal, sqlcipher_sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = sqlcipher_sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
+ *ppVal = sqlcipher_sqlite3_column_value(p->pStmt, iVal+p->nOldOff+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffNew(void *pCtx, int iVal, sqlcipher_sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = sqlcipher_sqlite3_column_value(p->pStmt, iVal);
+ *ppVal = sqlcipher_sqlite3_column_value(p->pStmt, iVal+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffCount(void *pCtx){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- return p->nOldOff ? p->nOldOff : sqlcipher_sqlite3_column_count(p->pStmt);
+ return (p->nOldOff ? p->nOldOff : sqlcipher_sqlite3_column_count(p->pStmt)) - p->bRowid;
}
static int sessionDiffDepth(void *pCtx){
+ (void)pCtx;
return 0;
}
@@ -219724,17 +232239,18 @@ static char *sessionExprCompareOther(
}
static char *sessionSelectFindNew(
- int nCol,
const char *zDb1, /* Pick rows in this db only */
const char *zDb2, /* But not in this one */
+ int bRowid,
const char *zTbl, /* Table name */
const char *zExpr
){
+ const char *zSel = (bRowid ? SESSIONS_ROWID ", *" : "*");
char *zRet = sqlcipher_sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
+ "SELECT %s FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
" SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
")",
- zDb1, zTbl, zDb2, zTbl, zExpr
+ zSel, zDb1, zTbl, zDb2, zTbl, zExpr
);
return zRet;
}
@@ -219748,7 +232264,9 @@ static int sessionDiffFindNew(
char *zExpr
){
int rc = SQLITE_OK;
- char *zStmt = sessionSelectFindNew(pTab->nCol, zDb1, zDb2, pTab->zName,zExpr);
+ char *zStmt = sessionSelectFindNew(
+ zDb1, zDb2, pTab->bRowid, pTab->zName, zExpr
+ );
if( zStmt==0 ){
rc = SQLITE_NOMEM;
@@ -219759,8 +232277,10 @@ static int sessionDiffFindNew(
SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = 0;
+ pDiffCtx->bRowid = pTab->bRowid;
while( SQLITE_ROW==sqlcipher_sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(op, pSession, pTab);
+ i64 iRowid = (pTab->bRowid ? sqlcipher_sqlite3_column_int64(pStmt, 0) : 0);
+ sessionPreupdateOneChange(op, iRowid, pSession, pTab);
}
rc = sqlcipher_sqlite3_finalize(pStmt);
}
@@ -219770,6 +232290,27 @@ static int sessionDiffFindNew(
return rc;
}
+/*
+** Return a comma-separated list of the fully-qualified (with both database
+** and table name) column names from table pTab. e.g.
+**
+** "main"."t1"."a", "main"."t1"."b", "main"."t1"."c"
+*/
+static char *sessionAllCols(
+ const char *zDb,
+ SessionTable *pTab
+){
+ int ii;
+ char *zRet = 0;
+ for(ii=0; ii<pTab->nCol; ii++){
+ zRet = sqlcipher_sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"",
+ zRet, (zRet ? ", " : ""), zDb, pTab->zName, pTab->azCol[ii]
+ );
+ if( !zRet ) break;
+ }
+ return zRet;
+}
+
static int sessionDiffFindModified(
sqlcipher_sqlite3_session *pSession,
SessionTable *pTab,
@@ -219784,11 +232325,13 @@ static int sessionDiffFindModified(
if( zExpr2==0 ){
rc = SQLITE_NOMEM;
}else{
+ char *z1 = sessionAllCols(pSession->zDb, pTab);
+ char *z2 = sessionAllCols(zFrom, pTab);
char *zStmt = sqlcipher_sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
- pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
+ "SELECT %s,%s FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
+ z1, z2, pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
);
- if( zStmt==0 ){
+ if( zStmt==0 || z1==0 || z2==0 ){
rc = SQLITE_NOMEM;
}else{
sqlcipher_sqlite3_stmt *pStmt;
@@ -219799,12 +232342,15 @@ static int sessionDiffFindModified(
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = pTab->nCol;
while( SQLITE_ROW==sqlcipher_sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
+ i64 iRowid = (pTab->bRowid ? sqlcipher_sqlite3_column_int64(pStmt, 0) : 0);
+ sessionPreupdateOneChange(SQLITE_UPDATE, iRowid, pSession, pTab);
}
rc = sqlcipher_sqlite3_finalize(pStmt);
}
- sqlcipher_sqlite3_free(zStmt);
}
+ sqlcipher_sqlite3_free(zStmt);
+ sqlcipher_sqlite3_free(z1);
+ sqlcipher_sqlite3_free(z2);
}
return rc;
@@ -219833,7 +232379,7 @@ SQLITE_API int sqlcipher_sqlite3session_diff(
/* Locate and if necessary initialize the target table object */
rc = sessionFindTable(pSession, zTbl, &pTo);
if( pTo==0 ) goto diff_out;
- if( sessionInitTable(pSession, pTo) ){
+ if( sessionInitTable(pSession, pTo, pSession->db, pSession->zDb) ){
rc = pSession->rc;
goto diff_out;
}
@@ -219843,9 +232389,12 @@ SQLITE_API int sqlcipher_sqlite3session_diff(
int bHasPk = 0;
int bMismatch = 0;
int nCol; /* Columns in zFrom.zTbl */
+ int bRowid = 0;
u8 *abPK;
const char **azCol = 0;
- rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
+ rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, 0, &abPK,
+ pSession->bImplicitPK ? &bRowid : 0
+ );
if( rc==SQLITE_OK ){
if( pTo->nCol!=nCol ){
bMismatch = 1;
@@ -219958,6 +232507,7 @@ static void sessionDeleteTable(sqlcipher_sqlite3_session *pSession, SessionTable
sessionFree(pSession, p);
}
}
+ sqlcipher_sqlite3_finalize(pTab->pDfltStmt);
sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */
sessionFree(pSession, pTab->apChange);
sessionFree(pSession, pTab);
@@ -219990,9 +232540,7 @@ SQLITE_API void sqlcipher_sqlite3session_delete(sqlcipher_sqlite3_session *pSess
** associated hash-tables. */
sessionDeleteTable(pSession, pSession->pTable);
- /* Assert that all allocations have been freed and then free the
- ** session object itself. */
- assert( pSession->nMalloc==0 );
+ /* Free the session object. */
sqlcipher_sqlite3_free(pSession);
}
@@ -220064,48 +232612,6 @@ SQLITE_API int sqlcipher_sqlite3session_attach(
}
/*
-** Ensure that there is room in the buffer to append nByte bytes of data.
-** If not, use sqlcipher_sqlite3_realloc() to grow the buffer so that there is.
-**
-** If successful, return zero. Otherwise, if an OOM condition is encountered,
-** set *pRc to SQLITE_NOMEM and return non-zero.
-*/
-static int sessionBufferGrow(SessionBuffer *p, i64 nByte, int *pRc){
-#define SESSION_MAX_BUFFER_SZ (0x7FFFFF00 - 1)
- i64 nReq = p->nBuf + nByte;
- if( *pRc==SQLITE_OK && nReq>p->nAlloc ){
- u8 *aNew;
- i64 nNew = p->nAlloc ? p->nAlloc : 128;
-
- do {
- nNew = nNew*2;
- }while( nNew<nReq );
-
- /* The value of SESSION_MAX_BUFFER_SZ is copied from the implementation
- ** of sqlcipher_sqlite3_realloc64(). Allocations greater than this size in bytes
- ** always fail. It is used here to ensure that this routine can always
- ** allocate up to this limit - instead of up to the largest power of
- ** two smaller than the limit. */
- if( nNew>SESSION_MAX_BUFFER_SZ ){
- nNew = SESSION_MAX_BUFFER_SZ;
- if( nNew<nReq ){
- *pRc = SQLITE_NOMEM;
- return 1;
- }
- }
-
- aNew = (u8 *)sqlcipher_sqlite3_realloc64(p->aBuf, nNew);
- if( 0==aNew ){
- *pRc = SQLITE_NOMEM;
- }else{
- p->aBuf = aNew;
- p->nAlloc = nNew;
- }
- }
- return (*pRc!=SQLITE_OK);
-}
-
-/*
** Append the value passed as the second argument to the buffer passed
** as the first.
**
@@ -220175,26 +232681,6 @@ static void sessionAppendBlob(
/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append a string to the buffer. All bytes in the string
-** up to (but not including) the nul-terminator are written to the buffer.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendStr(
- SessionBuffer *p,
- const char *zStr,
- int *pRc
-){
- int nStr = sqlcipher_sqlite3Strlen30(zStr);
- if( 0==sessionBufferGrow(p, nStr, pRc) ){
- memcpy(&p->aBuf[p->nBuf], zStr, nStr);
- p->nBuf += nStr;
- }
-}
-
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. Otherwise, append the string representation of integer iVal
** to the buffer. No nul-terminator is written.
**
@@ -220225,7 +232711,7 @@ static void sessionAppendIdent(
const char *zStr, /* String to quote, escape and append */
int *pRc /* IN/OUT: Error code */
){
- int nStr = sqlcipher_sqlite3Strlen30(zStr)*2 + 2 + 1;
+ int nStr = sqlcipher_sqlite3Strlen30(zStr)*2 + 2 + 2;
if( 0==sessionBufferGrow(p, nStr, pRc) ){
char *zOut = (char *)&p->aBuf[p->nBuf];
const char *zIn = zStr;
@@ -220236,6 +232722,7 @@ static void sessionAppendIdent(
}
*zOut++ = '"';
p->nBuf = (int)((u8 *)zOut - p->aBuf);
+ p->aBuf[p->nBuf] = 0x00;
}
}
@@ -220371,7 +232858,7 @@ static int sessionAppendUpdate(
/* If at least one field has been modified, this is not a no-op. */
if( bChanged ) bNoop = 0;
- /* Add a field to the old.* record. This is omitted if this modules is
+ /* Add a field to the old.* record. This is omitted if this module is
** currently generating a patchset. */
if( bPatchset==0 ){
if( bChanged || abPK[i] ){
@@ -220460,12 +232947,20 @@ static int sessionAppendDelete(
** Formulate and prepare a SELECT statement to retrieve a row from table
** zTab in database zDb based on its primary key. i.e.
**
-** SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ...
+** SELECT *, <noop-test> FROM zDb.zTab WHERE (pk1, pk2,...) IS (?1, ?2,...)
+**
+** where <noop-test> is:
+**
+** 1 AND (?A OR ?1 IS <column>) AND ...
+**
+** for each non-pk <column>.
*/
static int sessionSelectStmt(
sqlcipher_sqlite3 *db, /* Database handle */
+ int bIgnoreNoop,
const char *zDb, /* Database name */
const char *zTab, /* Table name */
+ int bRowid,
int nCol, /* Number of columns in table */
const char **azCol, /* Names of table columns */
u8 *abPK, /* PRIMARY KEY array */
@@ -220473,16 +232968,57 @@ static int sessionSelectStmt(
){
int rc = SQLITE_OK;
char *zSql = 0;
+ const char *zSep = "";
+ const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*";
int nSql = -1;
+ int i;
+
+ SessionBuffer nooptest = {0, 0, 0};
+ SessionBuffer pkfield = {0, 0, 0};
+ SessionBuffer pkvar = {0, 0, 0};
+
+ sessionAppendStr(&nooptest, ", 1", &rc);
if( 0==sqlcipher_sqlite3_stricmp("sqlite_stat1", zTab) ){
+ sessionAppendStr(&nooptest, " AND (?6 OR ?3 IS stat)", &rc);
+ sessionAppendStr(&pkfield, "tbl, idx", &rc);
+ sessionAppendStr(&pkvar,
+ "?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc
+ );
+ zCols = "tbl, ?2, stat";
+ }else{
+ for(i=0; i<nCol; i++){
+ if( abPK[i] ){
+ sessionAppendStr(&pkfield, zSep, &rc);
+ sessionAppendStr(&pkvar, zSep, &rc);
+ zSep = ", ";
+ sessionAppendIdent(&pkfield, azCol[i], &rc);
+ sessionAppendPrintf(&pkvar, &rc, "?%d", i+1);
+ }else{
+ sessionAppendPrintf(&nooptest, &rc,
+ " AND (?%d OR ?%d IS %w.%w)", i+1+nCol, i+1, zTab, azCol[i]
+ );
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ zSql = sqlcipher_sqlite3_mprintf(
+ "SELECT %s%s FROM %Q.%Q WHERE (%s) IS (%s)",
+ zCols, (bIgnoreNoop ? (char*)nooptest.aBuf : ""),
+ zDb, zTab, (char*)pkfield.aBuf, (char*)pkvar.aBuf
+ );
+ if( zSql==0 ) rc = SQLITE_NOMEM;
+ }
+
+#if 0
+ if( 0==sqlcipher_sqlite3_stricmp("sqlite_stat1", zTab) ){
zSql = sqlcipher_sqlite3_mprintf(
"SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
"idx IS (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", zDb
);
if( zSql==0 ) rc = SQLITE_NOMEM;
}else{
- int i;
const char *zSep = "";
SessionBuffer buf = {0, 0, 0};
@@ -220503,11 +233039,15 @@ static int sessionSelectStmt(
zSql = (char*)buf.aBuf;
nSql = buf.nBuf;
}
+#endif
if( rc==SQLITE_OK ){
rc = sqlcipher_sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
}
sqlcipher_sqlite3_free(zSql);
+ sqlcipher_sqlite3_free(nooptest.aBuf);
+ sqlcipher_sqlite3_free(pkfield.aBuf);
+ sqlcipher_sqlite3_free(pkvar.aBuf);
return rc;
}
@@ -220647,18 +233187,16 @@ static int sessionGenerateChangeset(
for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
if( pTab->nEntry ){
const char *zName = pTab->zName;
- int nCol = 0; /* Number of columns in table */
- u8 *abPK = 0; /* Primary key array */
- const char **azCol = 0; /* Table columns */
int i; /* Used to iterate through hash buckets */
sqlcipher_sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */
int nRewind = buf.nBuf; /* Initial size of write buffer */
int nNoop; /* Size of buffer after writing tbl header */
+ int nOldCol = pTab->nCol;
/* Check the table schema is still Ok. */
- rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK);
- if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
- rc = SQLITE_SCHEMA;
+ rc = sessionReinitTable(pSession, pTab);
+ if( rc==SQLITE_OK && pTab->nCol!=nOldCol ){
+ rc = sessionUpdateChanges(pSession, pTab);
}
/* Write a table header */
@@ -220666,8 +233204,9 @@ static int sessionGenerateChangeset(
/* Build and compile a statement to execute: */
if( rc==SQLITE_OK ){
- rc = sessionSelectStmt(
- db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
+ rc = sessionSelectStmt(db, 0, pSession->zDb,
+ zName, pTab->bRowid, pTab->nCol, pTab->azCol, pTab->abPK, &pSel
+ );
}
nNoop = buf.nBuf;
@@ -220675,22 +233214,22 @@ static int sessionGenerateChangeset(
SessionChange *p; /* Used to iterate through changes */
for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
- rc = sessionSelectBind(pSel, nCol, abPK, p);
+ rc = sessionSelectBind(pSel, pTab->nCol, pTab->abPK, p);
if( rc!=SQLITE_OK ) continue;
if( sqlcipher_sqlite3_step(pSel)==SQLITE_ROW ){
if( p->op==SQLITE_INSERT ){
int iCol;
sessionAppendByte(&buf, SQLITE_INSERT, &rc);
sessionAppendByte(&buf, p->bIndirect, &rc);
- for(iCol=0; iCol<nCol; iCol++){
+ for(iCol=0; iCol<pTab->nCol; iCol++){
sessionAppendCol(&buf, pSel, iCol, &rc);
}
}else{
- assert( abPK!=0 ); /* Because sessionSelectStmt() returned ok */
- rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
+ assert( pTab->abPK!=0 );
+ rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, pTab->abPK);
}
}else if( p->op!=SQLITE_INSERT ){
- rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
+ rc = sessionAppendDelete(&buf, bPatchset, p, pTab->nCol,pTab->abPK);
}
if( rc==SQLITE_OK ){
rc = sqlcipher_sqlite3_reset(pSel);
@@ -220715,7 +233254,6 @@ static int sessionGenerateChangeset(
if( buf.nBuf==nNoop ){
buf.nBuf = nRewind;
}
- sqlcipher_sqlite3_free((char*)azCol); /* cast works around VC++ bug */
}
}
@@ -220750,7 +233288,7 @@ SQLITE_API int sqlcipher_sqlite3session_changeset(
int rc;
if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE;
- rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset);
+ rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
assert( rc || pnChangeset==0
|| pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize
);
@@ -220868,6 +233406,19 @@ SQLITE_API int sqlcipher_sqlite3session_object_config(sqlcipher_sqlite3_session
break;
}
+ case SQLITE_SESSION_OBJCONFIG_ROWID: {
+ int iArg = *(int*)pArg;
+ if( iArg>=0 ){
+ if( pSession->pTable ){
+ rc = SQLITE_MISUSE;
+ }else{
+ pSession->bImplicitPK = (iArg!=0);
+ }
+ }
+ *(int*)pArg = pSession->bImplicitPK;
+ break;
+ }
+
default:
rc = SQLITE_MISUSE;
}
@@ -221126,15 +233677,19 @@ static int sessionReadRecord(
}
}
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- sqlcipher_sqlite3_int64 v = sessionGetI64(aVal);
- if( eType==SQLITE_INTEGER ){
- sqlcipher_sqlite3VdbeMemSetInt64(apOut[i], v);
+ if( (pIn->nData-pIn->iNext)<8 ){
+ rc = SQLITE_CORRUPT_BKPT;
}else{
- double d;
- memcpy(&d, &v, 8);
- sqlcipher_sqlite3VdbeMemSetDouble(apOut[i], d);
+ sqlcipher_sqlite3_int64 v = sessionGetI64(aVal);
+ if( eType==SQLITE_INTEGER ){
+ sqlcipher_sqlite3VdbeMemSetInt64(apOut[i], v);
+ }else{
+ double d;
+ memcpy(&d, &v, 8);
+ sqlcipher_sqlite3VdbeMemSetDouble(apOut[i], d);
+ }
+ pIn->iNext += 8;
}
- pIn->iNext += 8;
}
}
}
@@ -221322,14 +233877,14 @@ static int sessionChangesetNextOne(
p->rc = sessionInputBuffer(&p->in, 2);
if( p->rc!=SQLITE_OK ) return p->rc;
+ sessionDiscardData(&p->in);
+ p->in.iCurrent = p->in.iNext;
+
/* If the iterator is already at the end of the changeset, return DONE. */
if( p->in.iNext>=p->in.nData ){
return SQLITE_DONE;
}
- sessionDiscardData(&p->in);
- p->in.iCurrent = p->in.iNext;
-
op = p->in.aData[p->in.iNext++];
while( op=='T' || op=='P' ){
if( pbNew ) *pbNew = 1;
@@ -221403,6 +233958,22 @@ static int sessionChangesetNextOne(
if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE;
else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT;
}
+
+ /* If this is an UPDATE that is part of a changeset, then check that
+ ** there are no fields in the old.* record that are not (a) PK fields,
+ ** or (b) also present in the new.* record.
+ **
+ ** Such records are technically corrupt, but the rebaser was at one
+ ** point generating them. Under most circumstances this is benign, but
+ ** can cause spurious SQLITE_RANGE errors when applying the changeset. */
+ if( p->bPatchset==0 && p->op==SQLITE_UPDATE){
+ for(i=0; i<p->nCol; i++){
+ if( p->abPK[i]==0 && p->apValue[i+p->nCol]==0 ){
+ sqlcipher_sqlite3ValueFree(p->apValue[i]);
+ p->apValue[i] = 0;
+ }
+ }
+ }
}
return SQLITE_ROW;
@@ -221840,6 +234411,8 @@ struct SessionApplyCtx {
SessionBuffer rebase; /* Rebase information (if any) here */
u8 bRebaseStarted; /* If table header is already in rebase */
u8 bRebase; /* True to collect rebase information */
+ u8 bIgnoreNoop; /* True to ignore no-op conflicts */
+ int bRowid;
};
/* Number of prepared UPDATE statements to cache. */
@@ -222090,8 +234663,10 @@ static int sessionSelectRow(
const char *zTab, /* Table name */
SessionApplyCtx *p /* Session changeset-apply context */
){
- return sessionSelectStmt(
- db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
+ /* TODO */
+ return sessionSelectStmt(db, p->bIgnoreNoop,
+ "main", zTab, p->bRowid, p->nCol, p->azCol, p->abPK, &p->pSelect
+ );
}
/*
@@ -222249,22 +234824,34 @@ static int sessionBindRow(
** UPDATE, bind values from the old.* record.
*/
static int sessionSeekToRow(
- sqlcipher_sqlite3 *db, /* Database handle */
sqlcipher_sqlite3_changeset_iter *pIter, /* Changeset iterator */
- u8 *abPK, /* Primary key flags array */
- sqlcipher_sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */
+ SessionApplyCtx *p
){
+ sqlcipher_sqlite3_stmt *pSelect = p->pSelect;
int rc; /* Return code */
int nCol; /* Number of columns in table */
int op; /* Changset operation (SQLITE_UPDATE etc.) */
const char *zDummy; /* Unused */
+ sqlcipher_sqlite3_clear_bindings(pSelect);
sqlcipher_sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
rc = sessionBindRow(pIter,
op==SQLITE_INSERT ? sqlcipher_sqlite3changeset_new : sqlcipher_sqlite3changeset_old,
- nCol, abPK, pSelect
+ nCol, p->abPK, pSelect
);
+ if( op!=SQLITE_DELETE && p->bIgnoreNoop ){
+ int ii;
+ for(ii=0; rc==SQLITE_OK && ii<nCol; ii++){
+ if( p->abPK[ii]==0 ){
+ sqlcipher_sqlite3_value *pVal = 0;
+ sqlcipher_sqlite3changeset_new(pIter, ii, &pVal);
+ sqlcipher_sqlite3_bind_int(pSelect, ii+1+nCol, (pVal==0));
+ if( pVal ) rc = sessionBindValue(pSelect, ii+1, pVal);
+ }
+ }
+ }
+
if( rc==SQLITE_OK ){
rc = sqlcipher_sqlite3_step(pSelect);
if( rc!=SQLITE_ROW ) rc = sqlcipher_sqlite3_reset(pSelect);
@@ -222379,16 +234966,22 @@ static int sessionConflictHandler(
/* Bind the new.* PRIMARY KEY values to the SELECT statement. */
if( pbReplace ){
- rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
+ rc = sessionSeekToRow(pIter, p);
}else{
rc = SQLITE_OK;
}
if( rc==SQLITE_ROW ){
/* There exists another row with the new.* primary key. */
- pIter->pConflict = p->pSelect;
- res = xConflict(pCtx, eType, pIter);
- pIter->pConflict = 0;
+ if( p->bIgnoreNoop
+ && sqlcipher_sqlite3_column_int(p->pSelect, sqlcipher_sqlite3_column_count(p->pSelect)-1)
+ ){
+ res = SQLITE_CHANGESET_OMIT;
+ }else{
+ pIter->pConflict = p->pSelect;
+ res = xConflict(pCtx, eType, pIter);
+ pIter->pConflict = 0;
+ }
rc = sqlcipher_sqlite3_reset(p->pSelect);
}else if( rc==SQLITE_OK ){
if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){
@@ -222496,7 +235089,7 @@ static int sessionApplyOneOp(
sqlcipher_sqlite3_step(p->pDelete);
rc = sqlcipher_sqlite3_reset(p->pDelete);
- if( rc==SQLITE_OK && sqlcipher_sqlite3_changes(p->db)==0 ){
+ if( rc==SQLITE_OK && sqlcipher_sqlite3_changes(p->db)==0 && p->bIgnoreNoop==0 ){
rc = sessionConflictHandler(
SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
);
@@ -222553,7 +235146,7 @@ static int sessionApplyOneOp(
/* Check if there is a conflicting row. For sqlite_stat1, this needs
** to be done using a SELECT, as there is no PRIMARY KEY in the
** database schema to throw an exception if a duplicate is inserted. */
- rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
+ rc = sessionSeekToRow(pIter, p);
if( rc==SQLITE_ROW ){
rc = SQLITE_CONSTRAINT;
sqlcipher_sqlite3_reset(p->pSelect);
@@ -222730,6 +235323,7 @@ static int sessionChangesetApply(
memset(&sApply, 0, sizeof(sApply));
sApply.bRebase = (ppRebase && pnRebase);
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
+ sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
sqlcipher_sqlite3_mutex_enter(sqlcipher_sqlite3_db_mutex(db));
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
rc = sqlcipher_sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
@@ -222767,6 +235361,7 @@ static int sessionChangesetApply(
sApply.bStat1 = 0;
sApply.bDeferConstraints = 1;
sApply.bRebaseStarted = 0;
+ sApply.bRowid = 0;
memset(&sApply.constraints, 0, sizeof(SessionBuffer));
/* If an xFilter() callback was specified, invoke it now. If the
@@ -222786,8 +235381,8 @@ static int sessionChangesetApply(
int i;
sqlcipher_sqlite3changeset_pk(pIter, &abPK, 0);
- rc = sessionTableInfo(0,
- db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
+ rc = sessionTableInfo(0, db, "main", zNew,
+ &sApply.nCol, &zTab, &sApply.azCol, 0, &sApply.abPK, &sApply.bRowid
);
if( rc!=SQLITE_OK ) break;
for(i=0; i<sApply.nCol; i++){
@@ -222919,11 +235514,24 @@ SQLITE_API int sqlcipher_sqlite3changeset_apply_v2(
sqlcipher_sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
+ u64 savedFlag = db->flags & SQLITE_FkNoAction;
+
+ if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
+ db->flags |= ((u64)SQLITE_FkNoAction);
+ db->aDb[0].pSchema->schema_cookie -= 32;
+ }
+
if( rc==SQLITE_OK ){
rc = sessionChangesetApply(
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
);
}
+
+ if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
+ assert( db->flags & SQLITE_FkNoAction );
+ db->flags &= ~((u64)SQLITE_FkNoAction);
+ db->aDb[0].pSchema->schema_cookie -= 32;
+ }
return rc;
}
@@ -223011,6 +235619,10 @@ struct sqlcipher_sqlite3_changegroup {
int rc; /* Error code */
int bPatch; /* True to accumulate patchsets */
SessionTable *pList; /* List of tables in current patch */
+ SessionBuffer rec;
+
+ sqlcipher_sqlite3 *db; /* Configured by changegroup_schema() */
+ char *zDb; /* Configured by changegroup_schema() */
};
/*
@@ -223031,6 +235643,7 @@ static int sessionChangeMerge(
){
SessionChange *pNew = 0;
int rc = SQLITE_OK;
+ assert( aRec!=0 );
if( !pExist ){
pNew = (SessionChange *)sqlcipher_sqlite3_malloc64(sizeof(SessionChange) + nRec);
@@ -223197,84 +235810,236 @@ static int sessionChangeMerge(
}
/*
-** Add all changes in the changeset traversed by the iterator passed as
-** the first argument to the changegroup hash tables.
+** Check if a changeset entry with nCol columns and the PK array passed
+** as the final argument to this function is compatible with SessionTable
+** pTab. If so, return 1. Otherwise, if they are incompatible in some way,
+** return 0.
*/
-static int sessionChangesetToHash(
- sqlcipher_sqlite3_changeset_iter *pIter, /* Iterator to read from */
- sqlcipher_sqlite3_changegroup *pGrp, /* Changegroup object to add changeset to */
- int bRebase /* True if hash table is for rebasing */
+static int sessionChangesetCheckCompat(
+ SessionTable *pTab,
+ int nCol,
+ u8 *abPK
){
- u8 *aRec;
- int nRec;
- int rc = SQLITE_OK;
- SessionTable *pTab = 0;
-
- while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, 0) ){
- const char *zNew;
- int nCol;
- int op;
- int iHash;
- int bIndirect;
- SessionChange *pChange;
- SessionChange *pExist = 0;
- SessionChange **pp;
-
- if( pGrp->pList==0 ){
- pGrp->bPatch = pIter->bPatchset;
- }else if( pIter->bPatchset!=pGrp->bPatch ){
- rc = SQLITE_ERROR;
- break;
+ if( pTab->azCol && nCol<pTab->nCol ){
+ int ii;
+ for(ii=0; ii<pTab->nCol; ii++){
+ u8 bPK = (ii < nCol) ? abPK[ii] : 0;
+ if( pTab->abPK[ii]!=bPK ) return 0;
}
+ return 1;
+ }
+ return (pTab->nCol==nCol && 0==memcmp(abPK, pTab->abPK, nCol));
+}
- sqlcipher_sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);
- if( !pTab || sqlcipher_sqlite3_stricmp(zNew, pTab->zName) ){
- /* Search the list for a matching table */
- int nNew = (int)strlen(zNew);
- u8 *abPK;
+static int sessionChangesetExtendRecord(
+ sqlcipher_sqlite3_changegroup *pGrp,
+ SessionTable *pTab,
+ int nCol,
+ int op,
+ const u8 *aRec,
+ int nRec,
+ SessionBuffer *pOut
+){
+ int rc = SQLITE_OK;
+ int ii = 0;
- sqlcipher_sqlite3changeset_pk(pIter, &abPK, 0);
- for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
- if( 0==sqlcipher_sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
- }
- if( !pTab ){
- SessionTable **ppTab;
+ assert( pTab->azCol );
+ assert( nCol<pTab->nCol );
- pTab = sqlcipher_sqlite3_malloc64(sizeof(SessionTable) + nCol + nNew+1);
- if( !pTab ){
- rc = SQLITE_NOMEM;
+ pOut->nBuf = 0;
+ if( op==SQLITE_INSERT || (op==SQLITE_DELETE && pGrp->bPatch==0) ){
+ /* Append the missing default column values to the record. */
+ sessionAppendBlob(pOut, aRec, nRec, &rc);
+ if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){
+ rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt);
+ }
+ for(ii=nCol; rc==SQLITE_OK && ii<pTab->nCol; ii++){
+ int eType = sqlcipher_sqlite3_column_type(pTab->pDfltStmt, ii);
+ sessionAppendByte(pOut, eType, &rc);
+ switch( eType ){
+ case SQLITE_FLOAT:
+ case SQLITE_INTEGER: {
+ i64 iVal;
+ if( eType==SQLITE_INTEGER ){
+ iVal = sqlcipher_sqlite3_column_int64(pTab->pDfltStmt, ii);
+ }else{
+ double rVal = sqlcipher_sqlite3_column_int64(pTab->pDfltStmt, ii);
+ memcpy(&iVal, &rVal, sizeof(i64));
+ }
+ if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){
+ sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
+ }
break;
}
- memset(pTab, 0, sizeof(SessionTable));
- pTab->nCol = nCol;
- pTab->abPK = (u8*)&pTab[1];
- memcpy(pTab->abPK, abPK, nCol);
- pTab->zName = (char*)&pTab->abPK[nCol];
- memcpy(pTab->zName, zNew, nNew+1);
-
- /* The new object must be linked on to the end of the list, not
- ** simply added to the start of it. This is to ensure that the
- ** tables within the output of sqlcipher_sqlite3changegroup_output() are in
- ** the right order. */
- for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
- *ppTab = pTab;
- }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){
- rc = SQLITE_SCHEMA;
- break;
+
+ case SQLITE_BLOB:
+ case SQLITE_TEXT: {
+ int n = sqlcipher_sqlite3_column_bytes(pTab->pDfltStmt, ii);
+ sessionAppendVarint(pOut, n, &rc);
+ if( eType==SQLITE_TEXT ){
+ const u8 *z = (const u8*)sqlcipher_sqlite3_column_text(pTab->pDfltStmt, ii);
+ sessionAppendBlob(pOut, z, n, &rc);
+ }else{
+ const u8 *z = (const u8*)sqlcipher_sqlite3_column_blob(pTab->pDfltStmt, ii);
+ sessionAppendBlob(pOut, z, n, &rc);
+ }
+ break;
+ }
+
+ default:
+ assert( eType==SQLITE_NULL );
+ break;
+ }
+ }
+ }else if( op==SQLITE_UPDATE ){
+ /* Append missing "undefined" entries to the old.* record. And, if this
+ ** is an UPDATE, to the new.* record as well. */
+ int iOff = 0;
+ if( pGrp->bPatch==0 ){
+ for(ii=0; ii<nCol; ii++){
+ iOff += sessionSerialLen(&aRec[iOff]);
+ }
+ sessionAppendBlob(pOut, aRec, iOff, &rc);
+ for(ii=0; ii<(pTab->nCol-nCol); ii++){
+ sessionAppendByte(pOut, 0x00, &rc);
}
}
- if( sessionGrowHash(0, pIter->bPatchset, pTab) ){
- rc = SQLITE_NOMEM;
- break;
+ sessionAppendBlob(pOut, &aRec[iOff], nRec-iOff, &rc);
+ for(ii=0; ii<(pTab->nCol-nCol); ii++){
+ sessionAppendByte(pOut, 0x00, &rc);
+ }
+ }else{
+ assert( op==SQLITE_DELETE && pGrp->bPatch );
+ sessionAppendBlob(pOut, aRec, nRec, &rc);
+ }
+
+ return rc;
+}
+
+/*
+** Locate or create a SessionTable object that may be used to add the
+** change currently pointed to by iterator pIter to changegroup pGrp.
+** If successful, set output variable (*ppTab) to point to the table
+** object and return SQLITE_OK. Otherwise, if some error occurs, return
+** an SQLite error code and leave (*ppTab) set to NULL.
+*/
+static int sessionChangesetFindTable(
+ sqlcipher_sqlite3_changegroup *pGrp,
+ const char *zTab,
+ sqlcipher_sqlite3_changeset_iter *pIter,
+ SessionTable **ppTab
+){
+ int rc = SQLITE_OK;
+ SessionTable *pTab = 0;
+ int nTab = (int)strlen(zTab);
+ u8 *abPK = 0;
+ int nCol = 0;
+
+ *ppTab = 0;
+ sqlcipher_sqlite3changeset_pk(pIter, &abPK, &nCol);
+
+ /* Search the list for an existing table */
+ for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
+ if( 0==sqlcipher_sqlite3_strnicmp(pTab->zName, zTab, nTab+1) ) break;
+ }
+
+ /* If one was not found above, create a new table now */
+ if( !pTab ){
+ SessionTable **ppNew;
+
+ pTab = sqlcipher_sqlite3_malloc64(sizeof(SessionTable) + nCol + nTab+1);
+ if( !pTab ){
+ return SQLITE_NOMEM;
}
+ memset(pTab, 0, sizeof(SessionTable));
+ pTab->nCol = nCol;
+ pTab->abPK = (u8*)&pTab[1];
+ memcpy(pTab->abPK, abPK, nCol);
+ pTab->zName = (char*)&pTab->abPK[nCol];
+ memcpy(pTab->zName, zTab, nTab+1);
+
+ if( pGrp->db ){
+ pTab->nCol = 0;
+ rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb);
+ if( rc ){
+ assert( pTab->azCol==0 );
+ sqlcipher_sqlite3_free(pTab);
+ return rc;
+ }
+ }
+
+ /* The new object must be linked on to the end of the list, not
+ ** simply added to the start of it. This is to ensure that the
+ ** tables within the output of sqlcipher_sqlite3changegroup_output() are in
+ ** the right order. */
+ for(ppNew=&pGrp->pList; *ppNew; ppNew=&(*ppNew)->pNext);
+ *ppNew = pTab;
+ }
+
+ /* Check that the table is compatible. */
+ if( !sessionChangesetCheckCompat(pTab, nCol, abPK) ){
+ rc = SQLITE_SCHEMA;
+ }
+
+ *ppTab = pTab;
+ return rc;
+}
+
+/*
+** Add the change currently indicated by iterator pIter to the hash table
+** belonging to changegroup pGrp.
+*/
+static int sessionOneChangeToHash(
+ sqlcipher_sqlite3_changegroup *pGrp,
+ sqlcipher_sqlite3_changeset_iter *pIter,
+ int bRebase
+){
+ int rc = SQLITE_OK;
+ int nCol = 0;
+ int op = 0;
+ int iHash = 0;
+ int bIndirect = 0;
+ SessionChange *pChange = 0;
+ SessionChange *pExist = 0;
+ SessionChange **pp = 0;
+ SessionTable *pTab = 0;
+ u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2];
+ int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2;
+
+ /* Ensure that only changesets, or only patchsets, but not a mixture
+ ** of both, are being combined. It is an error to try to combine a
+ ** changeset and a patchset. */
+ if( pGrp->pList==0 ){
+ pGrp->bPatch = pIter->bPatchset;
+ }else if( pIter->bPatchset!=pGrp->bPatch ){
+ rc = SQLITE_ERROR;
+ }
+
+ if( rc==SQLITE_OK ){
+ const char *zTab = 0;
+ sqlcipher_sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect);
+ rc = sessionChangesetFindTable(pGrp, zTab, pIter, &pTab);
+ }
+
+ if( rc==SQLITE_OK && nCol<pTab->nCol ){
+ SessionBuffer *pBuf = &pGrp->rec;
+ rc = sessionChangesetExtendRecord(pGrp, pTab, nCol, op, aRec, nRec, pBuf);
+ aRec = pBuf->aBuf;
+ nRec = pBuf->nBuf;
+ assert( pGrp->db );
+ }
+
+ if( rc==SQLITE_OK && sessionGrowHash(0, pIter->bPatchset, pTab) ){
+ rc = SQLITE_NOMEM;
+ }
+
+ if( rc==SQLITE_OK ){
+ /* Search for existing entry. If found, remove it from the hash table.
+ ** Code below may link it back in. */
iHash = sessionChangeHash(
pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
);
-
- /* Search for existing entry. If found, remove it from the hash table.
- ** Code below may link it back in.
- */
for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
int bPkOnly1 = 0;
int bPkOnly2 = 0;
@@ -223289,16 +236054,39 @@ static int sessionChangesetToHash(
break;
}
}
+ }
+ if( rc==SQLITE_OK ){
rc = sessionChangeMerge(pTab, bRebase,
pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
);
- if( rc ) break;
- if( pChange ){
- pChange->pNext = pTab->apChange[iHash];
- pTab->apChange[iHash] = pChange;
- pTab->nEntry++;
- }
+ }
+ if( rc==SQLITE_OK && pChange ){
+ pChange->pNext = pTab->apChange[iHash];
+ pTab->apChange[iHash] = pChange;
+ pTab->nEntry++;
+ }
+
+ if( rc==SQLITE_OK ) rc = pIter->rc;
+ return rc;
+}
+
+/*
+** Add all changes in the changeset traversed by the iterator passed as
+** the first argument to the changegroup hash tables.
+*/
+static int sessionChangesetToHash(
+ sqlcipher_sqlite3_changeset_iter *pIter, /* Iterator to read from */
+ sqlcipher_sqlite3_changegroup *pGrp, /* Changegroup object to add changeset to */
+ int bRebase /* True if hash table is for rebasing */
+){
+ u8 *aRec;
+ int nRec;
+ int rc = SQLITE_OK;
+
+ while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){
+ rc = sessionOneChangeToHash(pGrp, pIter, bRebase);
+ if( rc!=SQLITE_OK ) break;
}
if( rc==SQLITE_OK ) rc = pIter->rc;
@@ -223388,6 +236176,31 @@ SQLITE_API int sqlcipher_sqlite3changegroup_new(sqlcipher_sqlite3_changegroup **
}
/*
+** Provide a database schema to the changegroup object.
+*/
+SQLITE_API int sqlcipher_sqlite3changegroup_schema(
+ sqlcipher_sqlite3_changegroup *pGrp,
+ sqlcipher_sqlite3 *db,
+ const char *zDb
+){
+ int rc = SQLITE_OK;
+
+ if( pGrp->pList || pGrp->db ){
+ /* Cannot add a schema after one or more calls to sqlcipher_sqlite3changegroup_add(),
+ ** or after sqlcipher_sqlite3changegroup_schema() has already been called. */
+ rc = SQLITE_MISUSE;
+ }else{
+ pGrp->zDb = sqlcipher_sqlite3_mprintf("%s", zDb);
+ if( pGrp->zDb==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pGrp->db = db;
+ }
+ }
+ return rc;
+}
+
+/*
** Add the changeset currently stored in buffer pData, size nData bytes,
** to changeset-group p.
*/
@@ -223404,6 +236217,23 @@ SQLITE_API int sqlcipher_sqlite3changegroup_add(sqlcipher_sqlite3_changegroup *p
}
/*
+** Add a single change to a changeset-group.
+*/
+SQLITE_API int sqlcipher_sqlite3changegroup_add_change(
+ sqlcipher_sqlite3_changegroup *pGrp,
+ sqlcipher_sqlite3_changeset_iter *pIter
+){
+ if( pIter->in.iCurrent==pIter->in.iNext
+ || pIter->rc!=SQLITE_OK
+ || pIter->bInvert
+ ){
+ /* Iterator does not point to any valid entry or is an INVERT iterator. */
+ return SQLITE_ERROR;
+ }
+ return sessionOneChangeToHash(pGrp, pIter, 0);
+}
+
+/*
** Obtain a buffer containing a changeset representing the concatenation
** of all changesets added to the group so far.
*/
@@ -223450,7 +236280,9 @@ SQLITE_API int sqlcipher_sqlite3changegroup_output_strm(
*/
SQLITE_API void sqlcipher_sqlite3changegroup_delete(sqlcipher_sqlite3_changegroup *pGrp){
if( pGrp ){
+ sqlcipher_sqlite3_free(pGrp->zDb);
sessionDeleteTable(0, pGrp->pList);
+ sqlcipher_sqlite3_free(pGrp->rec.aBuf);
sqlcipher_sqlite3_free(pGrp);
}
}
@@ -223599,7 +236431,7 @@ static void sessionAppendPartialUpdate(
if( !pIter->abPK[i] && a1[0] ) bData = 1;
memcpy(pOut, a1, n1);
pOut += n1;
- }else if( a2[0]!=0xFF ){
+ }else if( a2[0]!=0xFF && a1[0] ){
bData = 1;
memcpy(pOut, a2, n2);
pOut += n2;
@@ -223852,6 +236684,7 @@ SQLITE_API int sqlcipher_sqlite3rebaser_rebase_strm(
SQLITE_API void sqlcipher_sqlite3rebaser_delete(sqlcipher_sqlite3_rebaser *p){
if( p ){
sessionDeleteTable(0, p->grp.pList);
+ sqlcipher_sqlite3_free(p->grp.rec.aBuf);
sqlcipher_sqlite3_free(p);
}
}
@@ -223949,8 +236782,8 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
-** registered with.
+** Return a copy of the pUserData pointer passed to the xCreateFunction()
+** API when the extension function was registered.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
@@ -223982,8 +236815,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the text of column iCol of
+** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -223993,8 +236829,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of phrases in the current query, as returned by xPhraseCount,
+** 0 is returned. Otherwise, this function returns the number of tokens in
+** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -224010,12 +236848,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
+** output by xInstCount(). If iIdx is less than zero or greater than
+** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
+** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. Returns SQLITE_OK if successful, or an error
-** code (i.e. SQLITE_NOMEM) if an error occurs.
+** first token of the phrase. SQLITE_OK is returned if successful, or an
+** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -224041,6 +236880,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
+** If parameter iPhrase is less than zero, or greater than or equal to
+** the number of phrases in the query, as returned by xPhraseCount(),
+** this function returns SQLITE_RANGE.
+**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -224155,6 +236998,39 @@ struct Fts5PhraseIter {
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
+**
+** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase iPhrase of the current
+** query. Before returning, output parameter *ppToken is set to point
+** to a buffer containing the requested token, and *pnToken to the
+** size of this buffer in bytes.
+**
+** If iPhrase or iToken are less than zero, or if iPhrase is greater than
+** or equal to the number of phrases in the query as reported by
+** xPhraseCount(), or if iToken is equal to or greater than the number of
+** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
+ are both zeroed.
+**
+** The output text is not a copy of the query text that specified the
+** token. It is the output of the tokenizer module. For tokendata=1
+** tables, this includes any embedded 0x00 and trailing data.
+**
+** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase hit iIdx within the
+** current row. If iIdx is less than zero or greater than or equal to the
+** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
+** output variable (*ppToken) is set to point to a buffer containing the
+** matching document token, and (*pnToken) to the size of that buffer in
+** bytes. This API is not available if the specified token matches a
+** prefix query term. In that case both output variables are always set
+** to 0.
+**
+** The output text is not a copy of the document text that was tokenized.
+** It is the output of the tokenizer module. For tokendata=1 tables, this
+** includes any embedded 0x00 and trailing data.
+**
+** This API can be quite slow if used with an FTS5 table created with the
+** "detail=none" or "detail=column" option.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 3 */
@@ -224192,6 +237068,13 @@ struct Fts5ExtensionApi {
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
+
+ /* Below this point are iVersion>=3 only */
+ int (*xQueryToken)(Fts5Context*,
+ int iPhrase, int iToken,
+ const char **ppToken, int *pnToken
+ );
+ int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
};
/*
@@ -224386,8 +237269,8 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
@@ -224435,7 +237318,7 @@ struct fts5_api {
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -224444,7 +237327,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -224452,7 +237335,7 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
@@ -224624,6 +237507,10 @@ typedef struct Fts5Config Fts5Config;
** attempt to merge together. A value of 1 sets the object to use the
** compile time default. Zero disables auto-merge altogether.
**
+** bContentlessDelete:
+** True if the contentless_delete option was present in the CREATE
+** VIRTUAL TABLE statement.
+**
** zContent:
**
** zContentRowid:
@@ -224658,9 +237545,11 @@ struct Fts5Config {
int nPrefix; /* Number of prefix indexes */
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
int eContent; /* An FTS5_CONTENT value */
+ int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
char *zContent; /* content table */
char *zContentRowid; /* "content_rowid=" option value */
int bColumnsize; /* "columnsize=" option value (dflt==1) */
+ int bTokendata; /* "tokendata=" option value (dflt==0) */
int eDetail; /* FTS5_DETAIL_XXX value */
char *zContentExprlist;
Fts5Tokenizer *pTok;
@@ -224669,6 +237558,7 @@ struct Fts5Config {
int ePattern; /* FTS_PATTERN_XXX constant */
/* Values loaded from the %_config table */
+ int iVersion; /* fts5 file format 'version' */
int iCookie; /* Incremented when %_config is modified */
int pgsz; /* Approximate page size used in %_data */
int nAutomerge; /* 'automerge' setting */
@@ -224677,6 +237567,8 @@ struct Fts5Config {
int nHashSize; /* Bytes of memory for in-memory hash */
char *zRank; /* Name of rank function */
char *zRankArgs; /* Arguments to rank function */
+ int bSecureDelete; /* 'secure-delete' */
+ int nDeleteMerge; /* 'deletemerge' */
/* If non-NULL, points to sqlcipher_sqlite3_vtab.base.zErrmsg. Often NULL. */
char **pzErrmsg;
@@ -224686,8 +237578,11 @@ struct Fts5Config {
#endif
};
-/* Current expected value of %_config table 'version' field */
-#define FTS5_CURRENT_VERSION 4
+/* Current expected value of %_config table 'version' field. And
+** the expected version if the 'secure-delete' option has ever been
+** set on the table. */
+#define FTS5_CURRENT_VERSION 4
+#define FTS5_CURRENT_VERSION_SECUREDELETE 5
#define FTS5_CONTENT_NORMAL 0
#define FTS5_CONTENT_NONE 1
@@ -224756,7 +237651,7 @@ static void sqlcipher_sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zF
static char *sqlcipher_sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
#define fts5BufferZero(x) sqlcipher_sqlite3Fts5BufferZero(x)
-#define fts5BufferAppendVarint(a,b,c) sqlcipher_sqlite3Fts5BufferAppendVarint(a,b,c)
+#define fts5BufferAppendVarint(a,b,c) sqlcipher_sqlite3Fts5BufferAppendVarint(a,b,(i64)c)
#define fts5BufferFree(a) sqlcipher_sqlite3Fts5BufferFree(a)
#define fts5BufferAppendBlob(a,b,c,d) sqlcipher_sqlite3Fts5BufferAppendBlob(a,b,c,d)
#define fts5BufferSet(a,b,c,d) sqlcipher_sqlite3Fts5BufferSet(a,b,c,d)
@@ -224843,16 +237738,19 @@ struct Fts5IndexIter {
/*
** Values used as part of the flags argument passed to IndexQuery().
*/
-#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */
-#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */
-#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
-#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
+#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */
+#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */
+#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
+#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
/* The following are used internally by the fts5_index.c module. They are
** defined here only to make it easier to avoid clashes with the flags
** above. */
-#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
-#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
+#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
+#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
+#define FTS5INDEX_QUERY_SKIPHASH 0x0040
+#define FTS5INDEX_QUERY_NOTOKENDATA 0x0080
+#define FTS5INDEX_QUERY_SCANONETERM 0x0100
/*
** Create/destroy an Fts5Index object.
@@ -224921,6 +237819,10 @@ static void *sqlcipher_sqlite3Fts5StructureRef(Fts5Index*);
static void sqlcipher_sqlite3Fts5StructureRelease(void*);
static int sqlcipher_sqlite3Fts5StructureTest(Fts5Index*, void*);
+/*
+** Used by xInstToken():
+*/
+static int sqlcipher_sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*);
/*
** Insert or remove data to or from the index. Each time a document is
@@ -224995,6 +237897,16 @@ static int sqlcipher_sqlite3Fts5IndexReset(Fts5Index *p);
static int sqlcipher_sqlite3Fts5IndexLoadConfig(Fts5Index *p);
+static int sqlcipher_sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin);
+static int sqlcipher_sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid);
+
+static void sqlcipher_sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter*);
+
+/* Used to populate hash tables for xInstToken in detail=none/column mode. */
+static int sqlcipher_sqlite3Fts5IndexIterWriteTokendata(
+ Fts5IndexIter*, const char*, int, i64 iRowid, int iCol, int iOff
+);
+
/*
** End of interface to code in fts5_index.c.
**************************************************************************/
@@ -225007,7 +237919,7 @@ static int sqlcipher_sqlite3Fts5GetVarintLen(u32 iVal);
static u8 sqlcipher_sqlite3Fts5GetVarint(const unsigned char*, u64*);
static int sqlcipher_sqlite3Fts5PutVarint(unsigned char *p, u64 v);
-#define fts5GetVarint32(a,b) sqlcipher_sqlite3Fts5GetVarint32(a,(u32*)&b)
+#define fts5GetVarint32(a,b) sqlcipher_sqlite3Fts5GetVarint32(a,(u32*)&(b))
#define fts5GetVarint sqlcipher_sqlite3Fts5GetVarint
#define fts5FastGetVarint32(a, iOff, nVal) { \
@@ -225079,6 +237991,11 @@ static int sqlcipher_sqlite3Fts5HashWrite(
*/
static void sqlcipher_sqlite3Fts5HashClear(Fts5Hash*);
+/*
+** Return true if the hash is empty, false otherwise.
+*/
+static int sqlcipher_sqlite3Fts5HashIsEmpty(Fts5Hash*);
+
static int sqlcipher_sqlite3Fts5HashQuery(
Fts5Hash*, /* Hash table to query */
int nPre,
@@ -225095,11 +238012,13 @@ static void sqlcipher_sqlite3Fts5HashScanNext(Fts5Hash*);
static int sqlcipher_sqlite3Fts5HashScanEof(Fts5Hash*);
static void sqlcipher_sqlite3Fts5HashScanEntry(Fts5Hash *,
const char **pzTerm, /* OUT: term (nul-terminated) */
+ int *pnTerm, /* OUT: Size of term in bytes */
const u8 **ppDoclist, /* OUT: pointer to doclist */
int *pnDoclist /* OUT: size of doclist in bytes */
);
+
/*
** End of interface to code in fts5_hash.c.
**************************************************************************/
@@ -225220,6 +238139,10 @@ static int sqlcipher_sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**);
static int sqlcipher_sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
+static int sqlcipher_sqlite3Fts5ExprQueryToken(Fts5Expr*, int, int, const char**, int*);
+static int sqlcipher_sqlite3Fts5ExprInstToken(Fts5Expr*, i64, int, int, int, int, const char**, int*);
+static void sqlcipher_sqlite3Fts5ExprClearTokens(Fts5Expr*);
+
/*******************************************
** The fts5_expr.c API above this point is used by the other hand-written
** C code in this module. The interfaces below this point are called by
@@ -225343,7 +238266,8 @@ static void sqlcipher_sqlite3Fts5UnicodeAscii(u8*, u8*);
#define FTS5_STAR 15
/* This file is automatically generated by Lemon from input grammar
-** source file "fts5parse.y". */
+** source file "fts5parse.y".
+*/
/*
** 2000-05-29
**
@@ -225455,6 +238379,9 @@ static void sqlcipher_sqlite3Fts5UnicodeAscii(u8*, u8*);
** sqlcipher_sqlite3Fts5ParserARG_STORE Code to store %extra_argument into fts5yypParser
** sqlcipher_sqlite3Fts5ParserARG_FETCH Code to extract %extra_argument from fts5yypParser
** sqlcipher_sqlite3Fts5ParserCTX_* As sqlcipher_sqlite3Fts5ParserARG_ except for %extra_context
+** fts5YYREALLOC Name of the realloc() function to use
+** fts5YYFREE Name of the free() function to use
+** fts5YYDYNSTACK True if stack space should be extended on heap
** fts5YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing.
** fts5YYNSTATE the combined number of states.
@@ -225468,6 +238395,8 @@ static void sqlcipher_sqlite3Fts5UnicodeAscii(u8*, u8*);
** fts5YY_NO_ACTION The fts5yy_action[] code for no-op
** fts5YY_MIN_REDUCE Minimum value for reduce actions
** fts5YY_MAX_REDUCE Maximum value for reduce actions
+** fts5YY_MIN_DSTRCTR Minimum symbol value that has a destructor
+** fts5YY_MAX_DSTRCTR Maximum symbol value that has a destructor
*/
#ifndef INTERFACE
# define INTERFACE 1
@@ -225494,6 +238423,9 @@ typedef union {
#define sqlcipher_sqlite3Fts5ParserARG_PARAM ,pParse
#define sqlcipher_sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse=fts5yypParser->pParse;
#define sqlcipher_sqlite3Fts5ParserARG_STORE fts5yypParser->pParse=pParse;
+#define fts5YYREALLOC realloc
+#define fts5YYFREE free
+#define fts5YYDYNSTACK 0
#define sqlcipher_sqlite3Fts5ParserCTX_SDECL
#define sqlcipher_sqlite3Fts5ParserCTX_PDECL
#define sqlcipher_sqlite3Fts5ParserCTX_PARAM
@@ -225511,6 +238443,8 @@ typedef union {
#define fts5YY_NO_ACTION 82
#define fts5YY_MIN_REDUCE 83
#define fts5YY_MAX_REDUCE 110
+#define fts5YY_MIN_DSTRCTR 16
+#define fts5YY_MAX_DSTRCTR 24
/************* End control #defines *******************************************/
#define fts5YY_NLOOKAHEAD ((int)(sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0])))
@@ -225526,6 +238460,22 @@ typedef union {
# define fts5yytestcase(X)
#endif
+/* Macro to determine if stack space has the ability to grow using
+** heap memory.
+*/
+#if fts5YYSTACKDEPTH<=0 || fts5YYDYNSTACK
+# define fts5YYGROWABLESTACK 1
+#else
+# define fts5YYGROWABLESTACK 0
+#endif
+
+/* Guarantee a minimum number of initial stack slots.
+*/
+#if fts5YYSTACKDEPTH<=0
+# undef fts5YYSTACKDEPTH
+# define fts5YYSTACKDEPTH 2 /* Need a minimum stack size */
+#endif
+
/* Next are the tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
@@ -225686,14 +238636,9 @@ struct fts5yyParser {
#endif
sqlcipher_sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */
sqlcipher_sqlite3Fts5ParserCTX_SDECL /* A place to hold %extra_context */
-#if fts5YYSTACKDEPTH<=0
- int fts5yystksz; /* Current side of the stack */
- fts5yyStackEntry *fts5yystack; /* The parser's stack */
- fts5yyStackEntry fts5yystk0; /* First stack entry */
-#else
- fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH]; /* The parser's stack */
- fts5yyStackEntry *fts5yystackEnd; /* Last entry in the stack */
-#endif
+ fts5yyStackEntry *fts5yystackEnd; /* Last entry in the stack */
+ fts5yyStackEntry *fts5yystack; /* The parser stack */
+ fts5yyStackEntry fts5yystk0[fts5YYSTACKDEPTH]; /* Initial stack space */
};
typedef struct fts5yyParser fts5yyParser;
@@ -225800,37 +238745,45 @@ static const char *const fts5yyRuleName[] = {
#endif /* NDEBUG */
-#if fts5YYSTACKDEPTH<=0
+#if fts5YYGROWABLESTACK
/*
** Try to increase the size of the parser stack. Return the number
** of errors. Return 0 on success.
*/
static int fts5yyGrowStack(fts5yyParser *p){
+ int oldSize = 1 + (int)(p->fts5yystackEnd - p->fts5yystack);
int newSize;
int idx;
fts5yyStackEntry *pNew;
- newSize = p->fts5yystksz*2 + 100;
- idx = p->fts5yytos ? (int)(p->fts5yytos - p->fts5yystack) : 0;
- if( p->fts5yystack==&p->fts5yystk0 ){
- pNew = malloc(newSize*sizeof(pNew[0]));
- if( pNew ) pNew[0] = p->fts5yystk0;
+ newSize = oldSize*2 + 100;
+ idx = (int)(p->fts5yytos - p->fts5yystack);
+ if( p->fts5yystack==p->fts5yystk0 ){
+ pNew = fts5YYREALLOC(0, newSize*sizeof(pNew[0]));
+ if( pNew==0 ) return 1;
+ memcpy(pNew, p->fts5yystack, oldSize*sizeof(pNew[0]));
}else{
- pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0]));
+ pNew = fts5YYREALLOC(p->fts5yystack, newSize*sizeof(pNew[0]));
+ if( pNew==0 ) return 1;
}
- if( pNew ){
- p->fts5yystack = pNew;
- p->fts5yytos = &p->fts5yystack[idx];
+ p->fts5yystack = pNew;
+ p->fts5yytos = &p->fts5yystack[idx];
#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n",
- fts5yyTracePrompt, p->fts5yystksz, newSize);
- }
-#endif
- p->fts5yystksz = newSize;
+ if( fts5yyTraceFILE ){
+ fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n",
+ fts5yyTracePrompt, oldSize, newSize);
}
- return pNew==0;
+#endif
+ p->fts5yystackEnd = &p->fts5yystack[newSize-1];
+ return 0;
}
+#endif /* fts5YYGROWABLESTACK */
+
+#if !fts5YYGROWABLESTACK
+/* For builds that do no have a growable stack, fts5yyGrowStack always
+** returns an error.
+*/
+# define fts5yyGrowStack(X) 1
#endif
/* Datatype of the argument to the memory allocated passed as the
@@ -225850,24 +238803,14 @@ static void sqlcipher_sqlite3Fts5ParserInit(void *fts5yypRawParser sqlcipher_sql
#ifdef fts5YYTRACKMAXSTACKDEPTH
fts5yypParser->fts5yyhwm = 0;
#endif
-#if fts5YYSTACKDEPTH<=0
- fts5yypParser->fts5yytos = NULL;
- fts5yypParser->fts5yystack = NULL;
- fts5yypParser->fts5yystksz = 0;
- if( fts5yyGrowStack(fts5yypParser) ){
- fts5yypParser->fts5yystack = &fts5yypParser->fts5yystk0;
- fts5yypParser->fts5yystksz = 1;
- }
-#endif
+ fts5yypParser->fts5yystack = fts5yypParser->fts5yystk0;
+ fts5yypParser->fts5yystackEnd = &fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1];
#ifndef fts5YYNOERRORRECOVERY
fts5yypParser->fts5yyerrcnt = -1;
#endif
fts5yypParser->fts5yytos = fts5yypParser->fts5yystack;
fts5yypParser->fts5yystack[0].stateno = 0;
fts5yypParser->fts5yystack[0].major = 0;
-#if fts5YYSTACKDEPTH>0
- fts5yypParser->fts5yystackEnd = &fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1];
-#endif
}
#ifndef sqlcipher_sqlite3Fts5Parser_ENGINEALWAYSONSTACK
@@ -225981,9 +238924,26 @@ static void fts5yy_pop_parser_stack(fts5yyParser *pParser){
*/
static void sqlcipher_sqlite3Fts5ParserFinalize(void *p){
fts5yyParser *pParser = (fts5yyParser*)p;
- while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser);
-#if fts5YYSTACKDEPTH<=0
- if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack);
+
+ /* In-lined version of calling fts5yy_pop_parser_stack() for each
+ ** element left in the stack */
+ fts5yyStackEntry *fts5yytos = pParser->fts5yytos;
+ while( fts5yytos>pParser->fts5yystack ){
+#ifndef NDEBUG
+ if( fts5yyTraceFILE ){
+ fprintf(fts5yyTraceFILE,"%sPopping %s\n",
+ fts5yyTracePrompt,
+ fts5yyTokenName[fts5yytos->major]);
+ }
+#endif
+ if( fts5yytos->major>=fts5YY_MIN_DSTRCTR ){
+ fts5yy_destructor(pParser, fts5yytos->major, &fts5yytos->minor);
+ }
+ fts5yytos--;
+ }
+
+#if fts5YYGROWABLESTACK
+ if( pParser->fts5yystack!=pParser->fts5yystk0 ) fts5YYFREE(pParser->fts5yystack);
#endif
}
@@ -226210,25 +239170,19 @@ static void fts5yy_shift(
assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) );
}
#endif
-#if fts5YYSTACKDEPTH>0
- if( fts5yypParser->fts5yytos>fts5yypParser->fts5yystackEnd ){
- fts5yypParser->fts5yytos--;
- fts5yyStackOverflow(fts5yypParser);
- return;
- }
-#else
- if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz] ){
+ fts5yytos = fts5yypParser->fts5yytos;
+ if( fts5yytos>fts5yypParser->fts5yystackEnd ){
if( fts5yyGrowStack(fts5yypParser) ){
fts5yypParser->fts5yytos--;
fts5yyStackOverflow(fts5yypParser);
return;
}
+ fts5yytos = fts5yypParser->fts5yytos;
+ assert( fts5yytos <= fts5yypParser->fts5yystackEnd );
}
-#endif
if( fts5yyNewState > fts5YY_MAX_SHIFT ){
fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
}
- fts5yytos = fts5yypParser->fts5yytos;
fts5yytos->stateno = fts5yyNewState;
fts5yytos->major = fts5yyMajor;
fts5yytos->minor.fts5yy0 = fts5yyMinor;
@@ -226665,19 +239619,12 @@ static void sqlcipher_sqlite3Fts5Parser(
(int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack));
}
#endif
-#if fts5YYSTACKDEPTH>0
if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){
- fts5yyStackOverflow(fts5yypParser);
- break;
- }
-#else
- if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){
if( fts5yyGrowStack(fts5yypParser) ){
fts5yyStackOverflow(fts5yypParser);
break;
}
}
-#endif
}
fts5yyact = fts5yy_reduce(fts5yypParser,fts5yyruleno,fts5yymajor,fts5yyminor sqlcipher_sqlite3Fts5ParserCTX_PARAM);
}else if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
@@ -226933,15 +239880,19 @@ static int fts5CInstIterInit(
*/
typedef struct HighlightContext HighlightContext;
struct HighlightContext {
- CInstIter iter; /* Coalesced Instance Iterator */
- int iPos; /* Current token offset in zIn[] */
+ /* Constant parameters to fts5HighlightCb() */
int iRangeStart; /* First token to include */
int iRangeEnd; /* If non-zero, last token to include */
const char *zOpen; /* Opening highlight */
const char *zClose; /* Closing highlight */
const char *zIn; /* Input text */
int nIn; /* Size of input text in bytes */
- int iOff; /* Current offset within zIn[] */
+
+ /* Variables modified by fts5HighlightCb() */
+ CInstIter iter; /* Coalesced Instance Iterator */
+ int iPos; /* Current token offset in zIn[] */
+ int iOff; /* Have copied up to this offset in zIn[] */
+ int bOpen; /* True if highlight is open */
char *zOut; /* Output value */
};
@@ -226974,8 +239925,8 @@ static int fts5HighlightCb(
int tflags, /* Mask of FTS5_TOKEN_* flags */
const char *pToken, /* Buffer containing token */
int nToken, /* Size of token in bytes */
- int iStartOff, /* Start offset of token */
- int iEndOff /* End offset of token */
+ int iStartOff, /* Start byte offset of token */
+ int iEndOff /* End byte offset of token */
){
HighlightContext *p = (HighlightContext*)pContext;
int rc = SQLITE_OK;
@@ -226986,35 +239937,60 @@ static int fts5HighlightCb(
if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK;
iPos = p->iPos++;
- if( p->iRangeEnd>0 ){
+ if( p->iRangeEnd>=0 ){
if( iPos<p->iRangeStart || iPos>p->iRangeEnd ) return SQLITE_OK;
if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff;
}
- if( iPos==p->iter.iStart ){
+ /* If the parenthesis is open, and this token is not part of the current
+ ** phrase, and the starting byte offset of this token is past the point
+ ** that has currently been copied into the output buffer, close the
+ ** parenthesis. */
+ if( p->bOpen
+ && (iPos<=p->iter.iStart || p->iter.iStart<0)
+ && iStartOff>p->iOff
+ ){
+ fts5HighlightAppend(&rc, p, p->zClose, -1);
+ p->bOpen = 0;
+ }
+
+ /* If this is the start of a new phrase, and the highlight is not open:
+ **
+ ** * copy text from the input up to the start of the phrase, and
+ ** * open the highlight.
+ */
+ if( iPos==p->iter.iStart && p->bOpen==0 ){
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iStartOff - p->iOff);
fts5HighlightAppend(&rc, p, p->zOpen, -1);
p->iOff = iStartOff;
+ p->bOpen = 1;
}
if( iPos==p->iter.iEnd ){
- if( p->iRangeEnd && p->iter.iStart<p->iRangeStart ){
+ if( p->bOpen==0 ){
+ assert( p->iRangeEnd>=0 );
fts5HighlightAppend(&rc, p, p->zOpen, -1);
+ p->bOpen = 1;
}
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
- fts5HighlightAppend(&rc, p, p->zClose, -1);
p->iOff = iEndOff;
+
if( rc==SQLITE_OK ){
rc = fts5CInstIterNext(&p->iter);
}
}
- if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){
- fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
- p->iOff = iEndOff;
- if( iPos>=p->iter.iStart && iPos<p->iter.iEnd ){
+ if( iPos==p->iRangeEnd ){
+ if( p->bOpen ){
+ if( p->iter.iStart>=0 && iPos>=p->iter.iStart ){
+ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
+ p->iOff = iEndOff;
+ }
fts5HighlightAppend(&rc, p, p->zClose, -1);
+ p->bOpen = 0;
}
+ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
+ p->iOff = iEndOff;
}
return rc;
@@ -227044,9 +240020,12 @@ static void fts5HighlightFunction(
memset(&ctx, 0, sizeof(HighlightContext));
ctx.zOpen = (const char*)sqlcipher_sqlite3_value_text(apVal[1]);
ctx.zClose = (const char*)sqlcipher_sqlite3_value_text(apVal[2]);
+ ctx.iRangeEnd = -1;
rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
-
- if( ctx.zIn ){
+ if( rc==SQLITE_RANGE ){
+ sqlcipher_sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
+ rc = SQLITE_OK;
+ }else if( ctx.zIn ){
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
}
@@ -227054,6 +240033,9 @@ static void fts5HighlightFunction(
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
}
+ if( ctx.bOpen ){
+ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
+ }
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
if( rc==SQLITE_OK ){
@@ -227229,6 +240211,7 @@ static void fts5SnippetFunction(
iCol = sqlcipher_sqlite3_value_int(apVal[0]);
ctx.zOpen = fts5ValueToText(apVal[1]);
ctx.zClose = fts5ValueToText(apVal[2]);
+ ctx.iRangeEnd = -1;
zEllips = fts5ValueToText(apVal[3]);
nToken = sqlcipher_sqlite3_value_int(apVal[4]);
@@ -227331,6 +240314,9 @@ static void fts5SnippetFunction(
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
}
+ if( ctx.bOpen ){
+ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
+ }
if( ctx.iRangeEnd>=(nColSize-1) ){
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
}else{
@@ -227606,6 +240592,7 @@ static void sqlcipher_sqlite3Fts5BufferAppendBlob(
){
if( nData ){
if( fts5BufferGrow(pRc, pBuf, nData) ) return;
+ assert( pBuf->p!=0 );
memcpy(&pBuf->p[pBuf->n], pData, nData);
pBuf->n += nData;
}
@@ -227707,6 +240694,7 @@ static int sqlcipher_sqlite3Fts5PoslistNext64(
i64 *piOff /* IN/OUT: Current offset */
){
int i = *pi;
+ assert( a!=0 || i==0 );
if( i>=n ){
/* EOF */
*piOff = -1;
@@ -227714,6 +240702,7 @@ static int sqlcipher_sqlite3Fts5PoslistNext64(
}else{
i64 iOff = *piOff;
u32 iVal;
+ assert( a!=0 );
fts5FastGetVarint32(a, i, iVal);
if( iVal<=1 ){
if( iVal==0 ){
@@ -227969,6 +240958,8 @@ static void sqlcipher_sqlite3Fts5TermsetFree(Fts5Termset *p){
#define FTS5_DEFAULT_CRISISMERGE 16
#define FTS5_DEFAULT_HASHSIZE (1024*1024)
+#define FTS5_DEFAULT_DELETE_AUTOMERGE 10 /* default 10% */
+
/* Maximum allowed page size */
#define FTS5_MAX_PAGE_SIZE (64*1024)
@@ -228299,6 +241290,16 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( sqlcipher_sqlite3_strnicmp("contentless_delete", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = sqlcipher_sqlite3_mprintf("malformed contentless_delete=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bContentlessDelete = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
if( sqlcipher_sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
if( pConfig->zContentRowid ){
*pzErr = sqlcipher_sqlite3_mprintf("multiple content_rowid=... directives");
@@ -228333,6 +241334,16 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( sqlcipher_sqlite3_strnicmp("tokendata", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = sqlcipher_sqlite3_mprintf("malformed tokendata=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bTokendata = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
*pzErr = sqlcipher_sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
return SQLITE_ERROR;
}
@@ -228497,6 +241508,7 @@ static int sqlcipher_sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR;
}
+ assert( (pRet->abUnindexed && pRet->azCol) || rc!=SQLITE_OK );
for(i=3; rc==SQLITE_OK && i<nArg; i++){
const char *zOrig = azArg[i];
const char *z;
@@ -228542,6 +241554,28 @@ static int sqlcipher_sqlite3Fts5ConfigParse(
sqlcipher_sqlite3_free(zTwo);
}
+ /* We only allow contentless_delete=1 if the table is indeed contentless. */
+ if( rc==SQLITE_OK
+ && pRet->bContentlessDelete
+ && pRet->eContent!=FTS5_CONTENT_NONE
+ ){
+ *pzErr = sqlcipher_sqlite3_mprintf(
+ "contentless_delete=1 requires a contentless table"
+ );
+ rc = SQLITE_ERROR;
+ }
+
+ /* We only allow contentless_delete=1 if columnsize=0 is not present.
+ **
+ ** This restriction may be removed at some point.
+ */
+ if( rc==SQLITE_OK && pRet->bContentlessDelete && pRet->bColumnsize==0 ){
+ *pzErr = sqlcipher_sqlite3_mprintf(
+ "contentless_delete=1 is incompatible with columnsize=0"
+ );
+ rc = SQLITE_ERROR;
+ }
+
/* If a tokenizer= option was successfully parsed, the tokenizer has
** already been allocated. Otherwise, allocate an instance of the default
** tokenizer (unicode61) now. */
@@ -228836,6 +241870,18 @@ static int sqlcipher_sqlite3Fts5ConfigSetValue(
}
}
+ else if( 0==sqlcipher_sqlite3_stricmp(zKey, "deletemerge") ){
+ int nVal = -1;
+ if( SQLITE_INTEGER==sqlcipher_sqlite3_value_numeric_type(pVal) ){
+ nVal = sqlcipher_sqlite3_value_int(pVal);
+ }else{
+ *pbBadkey = 1;
+ }
+ if( nVal<0 ) nVal = FTS5_DEFAULT_DELETE_AUTOMERGE;
+ if( nVal>100 ) nVal = 0;
+ pConfig->nDeleteMerge = nVal;
+ }
+
else if( 0==sqlcipher_sqlite3_stricmp(zKey, "rank") ){
const char *zIn = (const char*)sqlcipher_sqlite3_value_text(pVal);
char *zRank;
@@ -228850,6 +241896,18 @@ static int sqlcipher_sqlite3Fts5ConfigSetValue(
rc = SQLITE_OK;
*pbBadkey = 1;
}
+ }
+
+ else if( 0==sqlcipher_sqlite3_stricmp(zKey, "secure-delete") ){
+ int bVal = -1;
+ if( SQLITE_INTEGER==sqlcipher_sqlite3_value_numeric_type(pVal) ){
+ bVal = sqlcipher_sqlite3_value_int(pVal);
+ }
+ if( bVal<0 ){
+ *pbBadkey = 1;
+ }else{
+ pConfig->bSecureDelete = (bVal ? 1 : 0);
+ }
}else{
*pbBadkey = 1;
}
@@ -228872,6 +241930,7 @@ static int sqlcipher_sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE;
pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE;
+ pConfig->nDeleteMerge = FTS5_DEFAULT_DELETE_AUTOMERGE;
zSql = sqlcipher_sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName);
if( zSql ){
@@ -228894,15 +241953,20 @@ static int sqlcipher_sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
rc = sqlcipher_sqlite3_finalize(p);
}
- if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){
+ if( rc==SQLITE_OK
+ && iVersion!=FTS5_CURRENT_VERSION
+ && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
+ ){
rc = SQLITE_ERROR;
if( pConfig->pzErrmsg ){
assert( 0==*pConfig->pzErrmsg );
- *pConfig->pzErrmsg = sqlcipher_sqlite3_mprintf(
- "invalid fts5 file format (found %d, expected %d) - run 'rebuild'",
- iVersion, FTS5_CURRENT_VERSION
+ *pConfig->pzErrmsg = sqlcipher_sqlite3_mprintf("invalid fts5 file format "
+ "(found %d, expected %d or %d) - run 'rebuild'",
+ iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
);
}
+ }else{
+ pConfig->iVersion = iVersion;
}
if( rc==SQLITE_OK ){
@@ -228930,6 +241994,10 @@ static int sqlcipher_sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
/* #include "fts5Int.h" */
/* #include "fts5parse.h" */
+#ifndef SQLITE_FTS5_MAX_EXPR_DEPTH
+# define SQLITE_FTS5_MAX_EXPR_DEPTH 256
+#endif
+
/*
** All token types in the generated fts5parse.h file are greater than 0.
*/
@@ -228970,11 +242038,17 @@ struct Fts5Expr {
** FTS5_NOT (nChild, apChild valid)
** FTS5_STRING (pNear valid)
** FTS5_TERM (pNear valid)
+**
+** iHeight:
+** Distance from this node to furthest leaf. This is always 0 for nodes
+** of type FTS5_STRING and FTS5_TERM. For all other nodes it is one
+** greater than the largest child value.
*/
struct Fts5ExprNode {
int eType; /* Node type */
int bEof; /* True at EOF */
int bNomatch; /* True if entry is not a match */
+ int iHeight; /* Distance to tree leaf nodes */
/* Next method for this node. */
int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64);
@@ -229003,7 +242077,9 @@ struct Fts5ExprNode {
struct Fts5ExprTerm {
u8 bPrefix; /* True for a prefix term */
u8 bFirst; /* True if token must be first in column */
- char *zTerm; /* nul-terminated term */
+ char *pTerm; /* Term data */
+ int nQueryTerm; /* Effective size of term in bytes */
+ int nFullTerm; /* Size of term in bytes incl. tokendata */
Fts5IndexIter *pIter; /* Iterator for this term */
Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */
};
@@ -229044,6 +242120,31 @@ struct Fts5Parse {
int bPhraseToAnd; /* Convert "a+b" to "a AND b" */
};
+/*
+** Check that the Fts5ExprNode.iHeight variables are set correctly in
+** the expression tree passed as the only argument.
+*/
+#ifndef NDEBUG
+static void assert_expr_depth_ok(int rc, Fts5ExprNode *p){
+ if( rc==SQLITE_OK ){
+ if( p->eType==FTS5_TERM || p->eType==FTS5_STRING || p->eType==0 ){
+ assert( p->iHeight==0 );
+ }else{
+ int ii;
+ int iMaxChild = 0;
+ for(ii=0; ii<p->nChild; ii++){
+ Fts5ExprNode *pChild = p->apChild[ii];
+ iMaxChild = MAX(iMaxChild, pChild->iHeight);
+ assert_expr_depth_ok(SQLITE_OK, pChild);
+ }
+ assert( p->iHeight==iMaxChild+1 );
+ }
+ }
+}
+#else
+# define assert_expr_depth_ok(rc, p)
+#endif
+
static void sqlcipher_sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){
va_list ap;
va_start(ap, zFmt);
@@ -229158,6 +242259,8 @@ static int sqlcipher_sqlite3Fts5ExprNew(
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
sqlcipher_sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
+ assert_expr_depth_ok(sParse.rc, sParse.pExpr);
+
/* If the LHS of the MATCH expression was a user column, apply the
** implicit column-filter. */
if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
@@ -229198,11 +242301,28 @@ static int sqlcipher_sqlite3Fts5ExprNew(
}
sqlcipher_sqlite3_free(sParse.apPhrase);
- *pzErr = sParse.zErr;
+ if( 0==*pzErr ){
+ *pzErr = sParse.zErr;
+ }else{
+ sqlcipher_sqlite3_free(sParse.zErr);
+ }
return sParse.rc;
}
/*
+** Assuming that buffer z is at least nByte bytes in size and contains a
+** valid utf-8 string, return the number of characters in the string.
+*/
+static int fts5ExprCountChar(const char *z, int nByte){
+ int nRet = 0;
+ int ii;
+ for(ii=0; ii<nByte; ii++){
+ if( (z[ii] & 0xC0)!=0x80 ) nRet++;
+ }
+ return nRet;
+}
+
+/*
** This function is only called when using the special 'trigram' tokenizer.
** Argument zText contains the text of a LIKE or GLOB pattern matched
** against column iCol. This function creates and compiles an FTS5 MATCH
@@ -229239,7 +242359,8 @@ static int sqlcipher_sqlite3Fts5ExprPattern(
if( i==nText
|| zText[i]==aSpec[0] || zText[i]==aSpec[1] || zText[i]==aSpec[2]
){
- if( i-iFirst>=3 ){
+
+ if( fts5ExprCountChar(&zText[iFirst], i-iFirst)>=3 ){
int jj;
zExpr[iOut++] = '"';
for(jj=iFirst; jj<i; jj++){
@@ -229306,7 +242427,7 @@ static int sqlcipher_sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
Fts5Parse sParse;
memset(&sParse, 0, sizeof(sParse));
- if( *pp1 ){
+ if( *pp1 && p2 ){
Fts5Expr *p1 = *pp1;
int nPhrase = p1->nPhrase + p2->nPhrase;
@@ -229331,7 +242452,7 @@ static int sqlcipher_sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
}
sqlcipher_sqlite3_free(p2->apExprPhrase);
sqlcipher_sqlite3_free(p2);
- }else{
+ }else if( p2 ){
*pp1 = p2;
}
@@ -229829,7 +242950,7 @@ static int fts5ExprNearInitAll(
p->pIter = 0;
}
rc = sqlcipher_sqlite3Fts5IndexQuery(
- pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
+ pExpr->pIndex, p->pTerm, p->nQueryTerm,
(pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
(pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
pNear->pColset,
@@ -230466,7 +243587,7 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
Fts5ExprTerm *pSyn;
Fts5ExprTerm *pNext;
Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
- sqlcipher_sqlite3_free(pTerm->zTerm);
+ sqlcipher_sqlite3_free(pTerm->pTerm);
sqlcipher_sqlite3Fts5IterClose(pTerm->pIter);
for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){
pNext = pSyn->pSynonym;
@@ -230564,6 +243685,7 @@ static Fts5ExprNearset *sqlcipher_sqlite3Fts5ParseNearset(
typedef struct TokenCtx TokenCtx;
struct TokenCtx {
Fts5ExprPhrase *pPhrase;
+ Fts5Config *pConfig;
int rc;
};
@@ -230597,8 +243719,12 @@ static int fts5ParseTokenize(
rc = SQLITE_NOMEM;
}else{
memset(pSyn, 0, (size_t)nByte);
- pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
- memcpy(pSyn->zTerm, pToken, nToken);
+ pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
+ pSyn->nFullTerm = pSyn->nQueryTerm = nToken;
+ if( pCtx->pConfig->bTokendata ){
+ pSyn->nQueryTerm = (int)strlen(pSyn->pTerm);
+ }
+ memcpy(pSyn->pTerm, pToken, nToken);
pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
}
@@ -230623,7 +243749,11 @@ static int fts5ParseTokenize(
if( rc==SQLITE_OK ){
pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
memset(pTerm, 0, sizeof(Fts5ExprTerm));
- pTerm->zTerm = sqlcipher_sqlite3Fts5Strndup(&rc, pToken, nToken);
+ pTerm->pTerm = sqlcipher_sqlite3Fts5Strndup(&rc, pToken, nToken);
+ pTerm->nFullTerm = pTerm->nQueryTerm = nToken;
+ if( pCtx->pConfig->bTokendata && rc==SQLITE_OK ){
+ pTerm->nQueryTerm = (int)strlen(pTerm->pTerm);
+ }
}
}
@@ -230690,6 +243820,7 @@ static Fts5ExprPhrase *sqlcipher_sqlite3Fts5ParseTerm(
memset(&sCtx, 0, sizeof(TokenCtx));
sCtx.pPhrase = pAppend;
+ sCtx.pConfig = pConfig;
rc = fts5ParseStringFromToken(pToken, &z);
if( rc==SQLITE_OK ){
@@ -230737,12 +243868,15 @@ static int sqlcipher_sqlite3Fts5ExprClonePhrase(
Fts5Expr **ppNew
){
int rc = SQLITE_OK; /* Return code */
- Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */
+ Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */
Fts5Expr *pNew = 0; /* Expression to return via *ppNew */
- TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */
-
- pOrig = pExpr->apExprPhrase[iPhrase];
- pNew = (Fts5Expr*)sqlcipher_sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
+ TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */
+ if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ rc = SQLITE_RANGE;
+ }else{
+ pOrig = pExpr->apExprPhrase[iPhrase];
+ pNew = (Fts5Expr*)sqlcipher_sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
+ }
if( rc==SQLITE_OK ){
pNew->apExprPhrase = (Fts5ExprPhrase**)sqlcipher_sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprPhrase*));
@@ -230755,7 +243889,7 @@ static int sqlcipher_sqlite3Fts5ExprClonePhrase(
pNew->pRoot->pNear = (Fts5ExprNearset*)sqlcipher_sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
}
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
if( pColsetOrig ){
sqlcipher_sqlite3_int64 nByte;
@@ -230769,26 +243903,27 @@ static int sqlcipher_sqlite3Fts5ExprClonePhrase(
}
}
- if( pOrig->nTerm ){
- int i; /* Used to iterate through phrase terms */
- for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
- int tflags = 0;
- Fts5ExprTerm *p;
- for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
- const char *zTerm = p->zTerm;
- rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
- 0, 0);
- tflags = FTS5_TOKEN_COLOCATED;
- }
- if( rc==SQLITE_OK ){
- sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
- sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
+ if( rc==SQLITE_OK ){
+ if( pOrig->nTerm ){
+ int i; /* Used to iterate through phrase terms */
+ sCtx.pConfig = pExpr->pConfig;
+ for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
+ int tflags = 0;
+ Fts5ExprTerm *p;
+ for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
+ rc = fts5ParseTokenize((void*)&sCtx,tflags,p->pTerm,p->nFullTerm,0,0);
+ tflags = FTS5_TOKEN_COLOCATED;
+ }
+ if( rc==SQLITE_OK ){
+ sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
+ sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
+ }
}
+ }else{
+ /* This happens when parsing a token or quoted phrase that contains
+ ** no token characters at all. (e.g ... MATCH '""'). */
+ sCtx.pPhrase = sqlcipher_sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
}
- }else{
- /* This happens when parsing a token or quoted phrase that contains
- ** no token characters at all. (e.g ... MATCH '""'). */
- sCtx.pPhrase = sqlcipher_sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
}
if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){
@@ -231105,6 +244240,7 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
}
static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
+ int ii = p->nChild;
if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
int nByte = sizeof(Fts5ExprNode*) * pSub->nChild;
memcpy(&p->apChild[p->nChild], pSub->apChild, nByte);
@@ -231113,6 +244249,9 @@ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
}else{
p->apChild[p->nChild++] = pSub;
}
+ for( ; ii<p->nChild; ii++){
+ p->iHeight = MAX(p->iHeight, p->apChild[ii]->iHeight + 1);
+ }
}
/*
@@ -231143,6 +244282,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
if( pRet ){
pRet->eType = FTS5_AND;
pRet->nChild = nTerm;
+ pRet->iHeight = 1;
fts5ExprAssignXNext(pRet);
pParse->nPhrase--;
for(ii=0; ii<nTerm; ii++){
@@ -231153,11 +244293,13 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
if( parseGrowPhraseArray(pParse) ){
fts5ExprPhraseFree(pPhrase);
}else{
+ Fts5ExprTerm *p = &pNear->apPhrase[0]->aTerm[ii];
+ Fts5ExprTerm *pTo = &pPhrase->aTerm[0];
pParse->apPhrase[pParse->nPhrase++] = pPhrase;
pPhrase->nTerm = 1;
- pPhrase->aTerm[0].zTerm = sqlcipher_sqlite3Fts5Strndup(
- &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1
- );
+ pTo->pTerm = sqlcipher_sqlite3Fts5Strndup(&pParse->rc, p->pTerm, p->nFullTerm);
+ pTo->nQueryTerm = p->nQueryTerm;
+ pTo->nFullTerm = p->nFullTerm;
pRet->apChild[ii] = sqlcipher_sqlite3Fts5ParseNode(pParse, FTS5_STRING,
0, 0, sqlcipher_sqlite3Fts5ParseNearset(pParse, 0, pPhrase)
);
@@ -231248,6 +244390,14 @@ static Fts5ExprNode *sqlcipher_sqlite3Fts5ParseNode(
}else{
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
+ if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){
+ sqlcipher_sqlite3Fts5ParseError(pParse,
+ "fts5 expression tree is too large (maximum depth %d)",
+ SQLITE_FTS5_MAX_EXPR_DEPTH
+ );
+ sqlcipher_sqlite3_free(pRet);
+ pRet = 0;
+ }
}
}
}
@@ -231283,6 +244433,7 @@ static Fts5ExprNode *sqlcipher_sqlite3Fts5ParseImplicitAnd(
assert( pRight->eType==FTS5_STRING
|| pRight->eType==FTS5_TERM
|| pRight->eType==FTS5_EOF
+ || (pRight->eType==FTS5_AND && pParse->bPhraseToAnd)
);
if( pLeft->eType==FTS5_AND ){
@@ -231326,7 +244477,7 @@ static Fts5ExprNode *sqlcipher_sqlite3Fts5ParseImplicitAnd(
return pRet;
}
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
sqlcipher_sqlite3_int64 nByte = 0;
Fts5ExprTerm *p;
@@ -231334,16 +244485,17 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
/* Determine the maximum amount of space required. */
for(p=pTerm; p; p=p->pSynonym){
- nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
+ nByte += pTerm->nQueryTerm * 2 + 3 + 2;
}
zQuoted = sqlcipher_sqlite3_malloc64(nByte);
if( zQuoted ){
int i = 0;
for(p=pTerm; p; p=p->pSynonym){
- char *zIn = p->zTerm;
+ char *zIn = p->pTerm;
+ char *zEnd = &zIn[p->nQueryTerm];
zQuoted[i++] = '"';
- while( *zIn ){
+ while( zIn<zEnd ){
if( *zIn=='"' ) zQuoted[i++] = '"';
zQuoted[i++] = *zIn++;
}
@@ -231421,8 +244573,10 @@ static char *fts5ExprPrintTcl(
zRet = fts5PrintfAppend(zRet, " {");
for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
- char *zTerm = pPhrase->aTerm[iTerm].zTerm;
- zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
+ Fts5ExprTerm *p = &pPhrase->aTerm[iTerm];
+ zRet = fts5PrintfAppend(zRet, "%s%.*s", iTerm==0?"":" ",
+ p->nQueryTerm, p->pTerm
+ );
if( pPhrase->aTerm[iTerm].bPrefix ){
zRet = fts5PrintfAppend(zRet, "*");
}
@@ -231432,6 +244586,8 @@ static char *fts5ExprPrintTcl(
if( zRet==0 ) return 0;
}
+ }else if( pExpr->eType==0 ){
+ zRet = sqlcipher_sqlite3_mprintf("{}");
}else{
char const *zOp = 0;
int i;
@@ -231693,14 +244849,14 @@ static void fts5ExprFold(
sqlcipher_sqlite3_result_int(pCtx, sqlcipher_sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics));
}
}
-#endif /* ifdef SQLITE_TEST */
+#endif /* if SQLITE_TEST || SQLITE_FTS5_DEBUG */
/*
** This is called during initialization to register the fts5_expr() scalar
** UDF with the SQLite handle passed as the only argument.
*/
static int sqlcipher_sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlcipher_sqlite3 *db){
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
struct Fts5ExprFunc {
const char *z;
void (*x)(sqlcipher_sqlite3_context*,int,sqlcipher_sqlite3_value**);
@@ -231821,6 +244977,17 @@ static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){
return 0;
}
+/*
+** pToken is a buffer nToken bytes in size that may or may not contain
+** an embedded 0x00 byte. If it does, return the number of bytes in
+** the buffer before the 0x00. If it does not, return nToken.
+*/
+static int fts5QueryTerm(const char *pToken, int nToken){
+ int ii;
+ for(ii=0; ii<nToken && pToken[ii]; ii++){}
+ return ii;
+}
+
static int fts5ExprPopulatePoslistsCb(
void *pCtx, /* Copy of 2nd argument to xTokenize() */
int tflags, /* Mask of FTS5_TOKEN_* flags */
@@ -231832,22 +244999,33 @@ static int fts5ExprPopulatePoslistsCb(
Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx;
Fts5Expr *pExpr = p->pExpr;
int i;
+ int nQuery = nToken;
+ i64 iRowid = pExpr->pRoot->iRowid;
UNUSED_PARAM2(iUnused1, iUnused2);
- if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
+ if( nQuery>FTS5_MAX_TOKEN_SIZE ) nQuery = FTS5_MAX_TOKEN_SIZE;
+ if( pExpr->pConfig->bTokendata ){
+ nQuery = fts5QueryTerm(pToken, nQuery);
+ }
if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
for(i=0; i<pExpr->nPhrase; i++){
- Fts5ExprTerm *pTerm;
+ Fts5ExprTerm *pT;
if( p->aPopulator[i].bOk==0 ) continue;
- for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
- int nTerm = (int)strlen(pTerm->zTerm);
- if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
- && memcmp(pTerm->zTerm, pToken, nTerm)==0
+ for(pT=&pExpr->apExprPhrase[i]->aTerm[0]; pT; pT=pT->pSynonym){
+ if( (pT->nQueryTerm==nQuery || (pT->nQueryTerm<nQuery && pT->bPrefix))
+ && memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0
){
int rc = sqlcipher_sqlite3Fts5PoslistWriterAppend(
&pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
);
+ if( rc==SQLITE_OK && pExpr->pConfig->bTokendata && !pT->bPrefix ){
+ int iCol = p->iOff>>32;
+ int iTokOff = p->iOff & 0x7FFFFFFF;
+ rc = sqlcipher_sqlite3Fts5IndexIterWriteTokendata(
+ pT->pIter, pToken, nToken, iRowid, iCol, iTokOff
+ );
+ }
if( rc ) return rc;
break;
}
@@ -231984,6 +245162,83 @@ static int sqlcipher_sqlite3Fts5ExprPhraseCollist(
}
/*
+** Does the work of the fts5_api.xQueryToken() API method.
+*/
+static int sqlcipher_sqlite3Fts5ExprQueryToken(
+ Fts5Expr *pExpr,
+ int iPhrase,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5ExprPhrase *pPhrase = 0;
+
+ if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ return SQLITE_RANGE;
+ }
+ pPhrase = pExpr->apExprPhrase[iPhrase];
+ if( iToken<0 || iToken>=pPhrase->nTerm ){
+ return SQLITE_RANGE;
+ }
+
+ *ppOut = pPhrase->aTerm[iToken].pTerm;
+ *pnOut = pPhrase->aTerm[iToken].nFullTerm;
+ return SQLITE_OK;
+}
+
+/*
+** Does the work of the fts5_api.xInstToken() API method.
+*/
+static int sqlcipher_sqlite3Fts5ExprInstToken(
+ Fts5Expr *pExpr,
+ i64 iRowid,
+ int iPhrase,
+ int iCol,
+ int iOff,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5ExprPhrase *pPhrase = 0;
+ Fts5ExprTerm *pTerm = 0;
+ int rc = SQLITE_OK;
+
+ if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ return SQLITE_RANGE;
+ }
+ pPhrase = pExpr->apExprPhrase[iPhrase];
+ if( iToken<0 || iToken>=pPhrase->nTerm ){
+ return SQLITE_RANGE;
+ }
+ pTerm = &pPhrase->aTerm[iToken];
+ if( pTerm->bPrefix==0 ){
+ if( pExpr->pConfig->bTokendata ){
+ rc = sqlcipher_sqlite3Fts5IterToken(
+ pTerm->pIter, iRowid, iCol, iOff+iToken, ppOut, pnOut
+ );
+ }else{
+ *ppOut = pTerm->pTerm;
+ *pnOut = pTerm->nFullTerm;
+ }
+ }
+ return rc;
+}
+
+/*
+** Clear the token mappings for all Fts5IndexIter objects mannaged by
+** the expression passed as the only argument.
+*/
+static void sqlcipher_sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){
+ int ii;
+ for(ii=0; ii<pExpr->nPhrase; ii++){
+ Fts5ExprTerm *pT;
+ for(pT=&pExpr->apExprPhrase[ii]->aTerm[0]; pT; pT=pT->pSynonym){
+ sqlcipher_sqlite3Fts5IndexIterClearTokendata(pT->pIter);
+ }
+ }
+}
+
+/*
** 2014 August 11
**
** The author disclaims copyright to this source code. In place of
@@ -232021,10 +245276,15 @@ struct Fts5Hash {
/*
** Each entry in the hash table is represented by an object of the
-** following type. Each object, its key (a nul-terminated string) and
-** its current data are stored in a single memory allocation. The
-** key immediately follows the object in memory. The position list
-** data immediately follows the key data in memory.
+** following type. Each object, its key, and its current data are stored
+** in a single memory allocation. The key immediately follows the object
+** in memory. The position list data immediately follows the key data
+** in memory.
+**
+** The key is Fts5HashEntry.nKey bytes in size. It consists of a single
+** byte identifying the index (either the main term index or a prefix-index),
+** followed by the term data. For example: "0token". There is no
+** nul-terminator - in this case nKey=6.
**
** The data that follows the key is in a similar, but not identical format
** to the doclist data stored in the database. It is:
@@ -232159,8 +245419,7 @@ static int fts5HashResize(Fts5Hash *pHash){
unsigned int iHash;
Fts5HashEntry *p = apOld[i];
apOld[i] = p->pHashNext;
- iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p),
- (int)strlen(fts5EntryKey(p)));
+ iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), p->nKey);
p->pHashNext = apNew[iHash];
apNew[iHash] = p;
}
@@ -232244,7 +245503,7 @@ static int sqlcipher_sqlite3Fts5HashWrite(
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
char *zKey = fts5EntryKey(p);
if( zKey[0]==bByte
- && p->nKey==nToken
+ && p->nKey==nToken+1
&& memcmp(&zKey[1], pToken, nToken)==0
){
break;
@@ -232274,9 +245533,9 @@ static int sqlcipher_sqlite3Fts5HashWrite(
zKey[0] = bByte;
memcpy(&zKey[1], pToken, nToken);
assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) );
- p->nKey = nToken;
+ p->nKey = nToken+1;
zKey[nToken+1] = '\0';
- p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry);
+ p->nData = nToken+1 + sizeof(Fts5HashEntry);
p->pHashNext = pHash->aSlot[iHash];
pHash->aSlot[iHash] = p;
pHash->nEntry++;
@@ -232393,12 +245652,17 @@ static Fts5HashEntry *fts5HashEntryMerge(
*ppOut = p1;
p1 = 0;
}else{
- int i = 0;
char *zKey1 = fts5EntryKey(p1);
char *zKey2 = fts5EntryKey(p2);
- while( zKey1[i]==zKey2[i] ) i++;
+ int nMin = MIN(p1->nKey, p2->nKey);
+
+ int cmp = memcmp(zKey1, zKey2, nMin);
+ if( cmp==0 ){
+ cmp = p1->nKey - p2->nKey;
+ }
+ assert( cmp!=0 );
- if( ((u8)zKey1[i])>((u8)zKey2[i]) ){
+ if( cmp>0 ){
/* p2 is smaller */
*ppOut = p2;
ppOut = &p2->pScanNext;
@@ -232417,10 +245681,8 @@ static Fts5HashEntry *fts5HashEntryMerge(
}
/*
-** Extract all tokens from hash table iHash and link them into a list
-** in sorted order. The hash table is cleared before returning. It is
-** the responsibility of the caller to free the elements of the returned
-** list.
+** Link all tokens from hash table iHash into a list in sorted order. The
+** tokens are not removed from the hash table.
*/
static int fts5HashEntrySort(
Fts5Hash *pHash,
@@ -232442,7 +245704,7 @@ static int fts5HashEntrySort(
Fts5HashEntry *pIter;
for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
if( pTerm==0
- || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
+ || (pIter->nKey>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
){
Fts5HashEntry *pEntry = pIter;
pEntry->pScanNext = 0;
@@ -232460,7 +245722,6 @@ static int fts5HashEntrySort(
pList = fts5HashEntryMerge(pList, ap[i]);
}
- pHash->nEntry = 0;
sqlcipher_sqlite3_free(ap);
*ppSorted = pList;
return SQLITE_OK;
@@ -232482,12 +245743,11 @@ static int sqlcipher_sqlite3Fts5HashQuery(
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
zKey = fts5EntryKey(p);
- assert( p->nKey+1==(int)strlen(zKey) );
- if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break;
+ if( nTerm==p->nKey && memcmp(zKey, pTerm, nTerm)==0 ) break;
}
if( p ){
- int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1;
+ int nHashPre = sizeof(Fts5HashEntry) + nTerm;
int nList = p->nData - nHashPre;
u8 *pRet = (u8*)(*ppOut = sqlcipher_sqlite3_malloc64(nPre + nList + 10));
if( pRet ){
@@ -232514,6 +245774,28 @@ static int sqlcipher_sqlite3Fts5HashScanInit(
return fts5HashEntrySort(p, pTerm, nTerm, &p->pScan);
}
+#ifdef SQLITE_DEBUG
+static int fts5HashCount(Fts5Hash *pHash){
+ int nEntry = 0;
+ int ii;
+ for(ii=0; ii<pHash->nSlot; ii++){
+ Fts5HashEntry *p = 0;
+ for(p=pHash->aSlot[ii]; p; p=p->pHashNext){
+ nEntry++;
+ }
+ }
+ return nEntry;
+}
+#endif
+
+/*
+** Return true if the hash table is empty, false otherwise.
+*/
+static int sqlcipher_sqlite3Fts5HashIsEmpty(Fts5Hash *pHash){
+ assert( pHash->nEntry==fts5HashCount(pHash) );
+ return pHash->nEntry==0;
+}
+
static void sqlcipher_sqlite3Fts5HashScanNext(Fts5Hash *p){
assert( !sqlcipher_sqlite3Fts5HashScanEof(p) );
p->pScan = p->pScan->pScanNext;
@@ -232526,19 +245808,22 @@ static int sqlcipher_sqlite3Fts5HashScanEof(Fts5Hash *p){
static void sqlcipher_sqlite3Fts5HashScanEntry(
Fts5Hash *pHash,
const char **pzTerm, /* OUT: term (nul-terminated) */
+ int *pnTerm, /* OUT: Size of term in bytes */
const u8 **ppDoclist, /* OUT: pointer to doclist */
int *pnDoclist /* OUT: size of doclist in bytes */
){
Fts5HashEntry *p;
if( (p = pHash->pScan) ){
char *zKey = fts5EntryKey(p);
- int nTerm = (int)strlen(zKey);
+ int nTerm = p->nKey;
fts5HashAddPoslistSize(pHash, p, 0);
*pzTerm = zKey;
- *ppDoclist = (const u8*)&zKey[nTerm+1];
- *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
+ *pnTerm = nTerm;
+ *ppDoclist = (const u8*)&zKey[nTerm];
+ *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm);
}else{
*pzTerm = 0;
+ *pnTerm = 0;
*ppDoclist = 0;
*pnDoclist = 0;
}
@@ -232600,6 +245885,26 @@ static void sqlcipher_sqlite3Fts5HashScanEntry(
# error "FTS5_MAX_PREFIX_INDEXES is too large"
#endif
+#define FTS5_MAX_LEVEL 64
+
+/*
+** There are two versions of the format used for the structure record:
+**
+** 1. the legacy format, that may be read by all fts5 versions, and
+**
+** 2. the V2 format, which is used by contentless_delete=1 databases.
+**
+** Both begin with a 4-byte "configuration cookie" value. Then, a legacy
+** format structure record contains a varint - the number of levels in
+** the structure. Whereas a V2 structure record contains the constant
+** 4 bytes [0xff 0x00 0x00 0x01]. This is unambiguous as the value of a
+** varint has to be at least 16256 to begin with "0xFF". And the default
+** maximum number of levels is 64.
+**
+** See below for more on structure record formats.
+*/
+#define FTS5_STRUCTURE_V2 "\xFF\x00\x00\x01"
+
/*
** Details:
**
@@ -232607,7 +245912,7 @@ static void sqlcipher_sqlite3Fts5HashScanEntry(
**
** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB);
**
-** , contains the following 5 types of records. See the comments surrounding
+** , contains the following 6 types of records. See the comments surrounding
** the FTS5_*_ROWID macros below for a description of how %_data rowids are
** assigned to each fo them.
**
@@ -232616,12 +245921,12 @@ static void sqlcipher_sqlite3Fts5HashScanEntry(
** The set of segments that make up an index - the index structure - are
** recorded in a single record within the %_data table. The record consists
** of a single 32-bit configuration cookie value followed by a list of
-** SQLite varints. If the FTS table features more than one index (because
-** there are one or more prefix indexes), it is guaranteed that all share
-** the same cookie value.
+** SQLite varints.
+**
+** If the structure record is a V2 record, the configuration cookie is
+** followed by the following 4 bytes: [0xFF 0x00 0x00 0x01].
**
-** Immediately following the configuration cookie, the record begins with
-** three varints:
+** Next, the record continues with three varints:
**
** + number of levels,
** + total number of segments on all levels,
@@ -232636,6 +245941,12 @@ static void sqlcipher_sqlite3Fts5HashScanEntry(
** + first leaf page number (often 1, always greater than 0)
** + final leaf page number
**
+** Then, for V2 structures only:
+**
+** + lower origin counter value,
+** + upper origin counter value,
+** + the number of tombstone hash pages.
+**
** 2. The Averages Record:
**
** A single record within the %_data table. The data is a list of varints.
@@ -232751,6 +246062,38 @@ static void sqlcipher_sqlite3Fts5HashScanEntry(
** * A list of delta-encoded varints - the first rowid on each subsequent
** child page.
**
+** 6. Tombstone Hash Page
+**
+** These records are only ever present in contentless_delete=1 tables.
+** There are zero or more of these associated with each segment. They
+** are used to store the tombstone rowids for rows contained in the
+** associated segments.
+**
+** The set of nHashPg tombstone hash pages associated with a single
+** segment together form a single hash table containing tombstone rowids.
+** To find the page of the hash on which a key might be stored:
+**
+** iPg = (rowid % nHashPg)
+**
+** Then, within page iPg, which has nSlot slots:
+**
+** iSlot = (rowid / nHashPg) % nSlot
+**
+** Each tombstone hash page begins with an 8 byte header:
+**
+** 1-byte: Key-size (the size in bytes of each slot). Either 4 or 8.
+** 1-byte: rowid-0-tombstone flag. This flag is only valid on the
+** first tombstone hash page for each segment (iPg=0). If set,
+** the hash table contains rowid 0. If clear, it does not.
+** Rowid 0 is handled specially.
+** 2-bytes: unused.
+** 4-bytes: Big-endian integer containing number of entries on page.
+**
+** Following this are nSlot 4 or 8 byte slots (depending on the key-size
+** in the first byte of the page header). The number of slots may be
+** determined based on the size of the page record and the key-size:
+**
+** nSlot = (nByte - 8) / key-size
*/
/*
@@ -232784,6 +246127,7 @@ static void sqlcipher_sqlite3Fts5HashScanEntry(
#define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno)
#define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno)
+#define FTS5_TOMBSTONE_ROWID(segid,ipg) fts5_dri(segid+(1<<16), 0, 0, ipg)
#ifdef SQLITE_DEBUG
static int sqlcipher_sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; }
@@ -232810,6 +246154,9 @@ typedef struct Fts5SegWriter Fts5SegWriter;
typedef struct Fts5Structure Fts5Structure;
typedef struct Fts5StructureLevel Fts5StructureLevel;
typedef struct Fts5StructureSegment Fts5StructureSegment;
+typedef struct Fts5TokenDataIter Fts5TokenDataIter;
+typedef struct Fts5TokenDataMap Fts5TokenDataMap;
+typedef struct Fts5TombstoneArray Fts5TombstoneArray;
struct Fts5Data {
u8 *p; /* Pointer to buffer containing record */
@@ -232819,6 +246166,12 @@ struct Fts5Data {
/*
** One object per %_data table.
+**
+** nContentlessDelete:
+** The number of contentless delete operations since the most recent
+** call to fts5IndexFlush() or fts5IndexDiscardData(). This is tracked
+** so that extra auto-merge work can be done by fts5IndexFlush() to
+** account for the delete operations.
*/
struct Fts5Index {
Fts5Config *pConfig; /* Virtual table configuration */
@@ -232833,9 +246186,12 @@ struct Fts5Index {
int nPendingData; /* Current bytes of pending data */
i64 iWriteRowid; /* Rowid for current doc being written */
int bDelete; /* Current write is a delete */
+ int nContentlessDelete; /* Number of contentless delete ops */
+ int nPendingRow; /* Number of INSERT in hash table */
/* Error state. */
int rc; /* Current error code */
+ int flushRc;
/* State used by the fts5DataXXX() functions. */
sqlcipher_sqlite3_blob *pReader; /* RO incr-blob open on %_data table */
@@ -232844,8 +246200,11 @@ struct Fts5Index {
sqlcipher_sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */
sqlcipher_sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=?" */
sqlcipher_sqlite3_stmt *pIdxSelect;
+ sqlcipher_sqlite3_stmt *pIdxNextSelect;
int nRead; /* Total number of blocks read */
+ sqlcipher_sqlite3_stmt *pDeleteFromIdx;
+
sqlcipher_sqlite3_stmt *pDataVersion;
i64 iStructVersion; /* data_version when pStruct read */
Fts5Structure *pStruct; /* Current db structure (or NULL) */
@@ -232865,11 +246224,23 @@ struct Fts5DoclistIter {
** The contents of the "structure" record for each index are represented
** using an Fts5Structure record in memory. Which uses instances of the
** other Fts5StructureXXX types as components.
+**
+** nOriginCntr:
+** This value is set to non-zero for structure records created for
+** contentlessdelete=1 tables only. In that case it represents the
+** origin value to apply to the next top-level segment created.
*/
struct Fts5StructureSegment {
int iSegid; /* Segment id */
int pgnoFirst; /* First leaf page number in segment */
int pgnoLast; /* Last leaf page number in segment */
+
+ /* contentlessdelete=1 tables only: */
+ u64 iOrigin1;
+ u64 iOrigin2;
+ int nPgTombstone; /* Number of tombstone hash table pages */
+ u64 nEntryTombstone; /* Number of tombstone entries that "count" */
+ u64 nEntry; /* Number of rows in this segment */
};
struct Fts5StructureLevel {
int nMerge; /* Number of segments in incr-merge */
@@ -232879,6 +246250,7 @@ struct Fts5StructureLevel {
struct Fts5Structure {
int nRef; /* Object reference count */
u64 nWriteCounter; /* Total leaves written to level 0 */
+ u64 nOriginCntr; /* Origin value for next top-level segment */
int nSegment; /* Total segments in this structure */
int nLevel; /* Number of levels in this index */
Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */
@@ -232938,9 +246310,6 @@ struct Fts5CResult {
** iLeafOffset:
** Byte offset within the current leaf that is the first byte of the
** position list data (one byte passed the position-list size field).
-** rowid field of the current entry. Usually this is the size field of the
-** position list data. The exception is if the rowid for the current entry
-** is the last thing on the leaf page.
**
** pLeaf:
** Buffer containing current leaf page data. Set to NULL at EOF.
@@ -232970,6 +246339,13 @@ struct Fts5CResult {
**
** iTermIdx:
** Index of current term on iTermLeafPgno.
+**
+** apTombstone/nTombstone:
+** These are used for contentless_delete=1 tables only. When the cursor
+** is first allocated, the apTombstone[] array is allocated so that it
+** is large enough for all tombstones hash pages associated with the
+** segment. The pages themselves are loaded lazily from the database as
+** they are required.
*/
struct Fts5SegIter {
Fts5StructureSegment *pSeg; /* Segment to iterate through */
@@ -232978,6 +246354,7 @@ struct Fts5SegIter {
Fts5Data *pLeaf; /* Current leaf data */
Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */
i64 iLeafOffset; /* Byte offset within current leaf */
+ Fts5TombstoneArray *pTombArray; /* Array of tombstone pages */
/* Next method */
void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
@@ -233005,6 +246382,15 @@ struct Fts5SegIter {
};
/*
+** Array of tombstone pages. Reference counted.
+*/
+struct Fts5TombstoneArray {
+ int nRef; /* Number of pointers to this object */
+ int nTombstone;
+ Fts5Data *apTombstone[1]; /* Array of tombstone pages */
+};
+
+/*
** Argument is a pointer to an Fts5Data structure that contains a
** leaf page.
*/
@@ -233048,9 +246434,16 @@ struct Fts5SegIter {
** poslist:
** Used by sqlcipher_sqlite3Fts5IterPoslist() when the poslist needs to be buffered.
** There is no way to tell if this is populated or not.
+**
+** pColset:
+** If not NULL, points to an object containing a set of column indices.
+** Only matches that occur in one of these columns will be returned.
+** The Fts5Iter does not own the Fts5Colset object, and so it is not
+** freed when the iterator is closed - it is owned by the upper layer.
*/
struct Fts5Iter {
Fts5IndexIter base; /* Base class containing output vars */
+ Fts5TokenDataIter *pTokenDataIter;
Fts5Index *pIndex; /* Index that owns this iterator */
Fts5Buffer poslist; /* Buffer containing current poslist */
@@ -233068,7 +246461,6 @@ struct Fts5Iter {
Fts5SegIter aSeg[1]; /* Array of segment iterators */
};
-
/*
** An instance of the following type is used to iterate through the contents
** of a doclist-index record.
@@ -233108,6 +246500,60 @@ static u16 fts5GetU16(const u8 *aIn){
}
/*
+** The only argument points to a buffer at least 8 bytes in size. This
+** function interprets the first 8 bytes of the buffer as a 64-bit big-endian
+** unsigned integer and returns the result.
+*/
+static u64 fts5GetU64(u8 *a){
+ return ((u64)a[0] << 56)
+ + ((u64)a[1] << 48)
+ + ((u64)a[2] << 40)
+ + ((u64)a[3] << 32)
+ + ((u64)a[4] << 24)
+ + ((u64)a[5] << 16)
+ + ((u64)a[6] << 8)
+ + ((u64)a[7] << 0);
+}
+
+/*
+** The only argument points to a buffer at least 4 bytes in size. This
+** function interprets the first 4 bytes of the buffer as a 32-bit big-endian
+** unsigned integer and returns the result.
+*/
+static u32 fts5GetU32(const u8 *a){
+ return ((u32)a[0] << 24)
+ + ((u32)a[1] << 16)
+ + ((u32)a[2] << 8)
+ + ((u32)a[3] << 0);
+}
+
+/*
+** Write iVal, formated as a 64-bit big-endian unsigned integer, to the
+** buffer indicated by the first argument.
+*/
+static void fts5PutU64(u8 *a, u64 iVal){
+ a[0] = ((iVal >> 56) & 0xFF);
+ a[1] = ((iVal >> 48) & 0xFF);
+ a[2] = ((iVal >> 40) & 0xFF);
+ a[3] = ((iVal >> 32) & 0xFF);
+ a[4] = ((iVal >> 24) & 0xFF);
+ a[5] = ((iVal >> 16) & 0xFF);
+ a[6] = ((iVal >> 8) & 0xFF);
+ a[7] = ((iVal >> 0) & 0xFF);
+}
+
+/*
+** Write iVal, formated as a 32-bit big-endian unsigned integer, to the
+** buffer indicated by the first argument.
+*/
+static void fts5PutU32(u8 *a, u32 iVal){
+ a[0] = ((iVal >> 24) & 0xFF);
+ a[1] = ((iVal >> 16) & 0xFF);
+ a[2] = ((iVal >> 8) & 0xFF);
+ a[3] = ((iVal >> 0) & 0xFF);
+}
+
+/*
** Allocate and return a buffer at least nByte bytes in size.
**
** If an OOM error is encountered, return NULL and set the error code in
@@ -233334,10 +246780,17 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
/*
** Remove all records associated with segment iSegid.
*/
-static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){
+static void fts5DataRemoveSegment(Fts5Index *p, Fts5StructureSegment *pSeg){
+ int iSegid = pSeg->iSegid;
i64 iFirst = FTS5_SEGMENT_ROWID(iSegid, 0);
i64 iLast = FTS5_SEGMENT_ROWID(iSegid+1, 0)-1;
fts5DataDelete(p, iFirst, iLast);
+
+ if( pSeg->nPgTombstone ){
+ i64 iTomb1 = FTS5_TOMBSTONE_ROWID(iSegid, 0);
+ i64 iTomb2 = FTS5_TOMBSTONE_ROWID(iSegid, pSeg->nPgTombstone-1);
+ fts5DataDelete(p, iTomb1, iTomb2);
+ }
if( p->pIdxDeleter==0 ){
Fts5Config *pConfig = p->pConfig;
fts5IndexPrepareStmt(p, &p->pIdxDeleter, sqlcipher_sqlite3_mprintf(
@@ -233448,11 +246901,19 @@ static int fts5StructureDecode(
int nSegment = 0;
sqlcipher_sqlite3_int64 nByte; /* Bytes of space to allocate at pRet */
Fts5Structure *pRet = 0; /* Structure object to return */
+ int bStructureV2 = 0; /* True for FTS5_STRUCTURE_V2 */
+ u64 nOriginCntr = 0; /* Largest origin value seen so far */
/* Grab the cookie value */
if( piCookie ) *piCookie = sqlcipher_sqlite3Fts5Get32(pData);
i = 4;
+ /* Check if this is a V2 structure record. Set bStructureV2 if it is. */
+ if( 0==memcmp(&pData[i], FTS5_STRUCTURE_V2, 4) ){
+ i += 4;
+ bStructureV2 = 1;
+ }
+
/* Read the total number of levels and segments from the start of the
** structure record. */
i += fts5GetVarint32(&pData[i], nLevel);
@@ -233499,9 +246960,18 @@ static int fts5StructureDecode(
rc = FTS5_CORRUPT;
break;
}
+ assert( pSeg!=0 );
i += fts5GetVarint32(&pData[i], pSeg->iSegid);
i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst);
i += fts5GetVarint32(&pData[i], pSeg->pgnoLast);
+ if( bStructureV2 ){
+ i += fts5GetVarint(&pData[i], &pSeg->iOrigin1);
+ i += fts5GetVarint(&pData[i], &pSeg->iOrigin2);
+ i += fts5GetVarint32(&pData[i], pSeg->nPgTombstone);
+ i += fts5GetVarint(&pData[i], &pSeg->nEntryTombstone);
+ i += fts5GetVarint(&pData[i], &pSeg->nEntry);
+ nOriginCntr = MAX(nOriginCntr, pSeg->iOrigin2);
+ }
if( pSeg->pgnoLast<pSeg->pgnoFirst ){
rc = FTS5_CORRUPT;
break;
@@ -233512,6 +246982,9 @@ static int fts5StructureDecode(
}
}
if( nSegment!=0 && rc==SQLITE_OK ) rc = FTS5_CORRUPT;
+ if( bStructureV2 ){
+ pRet->nOriginCntr = nOriginCntr+1;
+ }
if( rc!=SQLITE_OK ){
fts5StructureRelease(pRet);
@@ -233529,6 +247002,7 @@ static int fts5StructureDecode(
*/
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
fts5StructureMakeWritable(pRc, ppStruct);
+ assert( (ppStruct!=0 && (*ppStruct)!=0) || (*pRc)!=SQLITE_OK );
if( *pRc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
int nLevel = pStruct->nLevel;
@@ -233723,6 +247197,7 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
Fts5Buffer buf; /* Buffer to serialize record into */
int iLvl; /* Used to iterate through levels */
int iCookie; /* Cookie value to store */
+ int nHdr = (pStruct->nOriginCntr>0 ? (4+4+9+9+9) : (4+9+9));
assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
memset(&buf, 0, sizeof(Fts5Buffer));
@@ -233731,9 +247206,12 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
iCookie = p->pConfig->iCookie;
if( iCookie<0 ) iCookie = 0;
- if( 0==sqlcipher_sqlite3Fts5BufferSize(&p->rc, &buf, 4+9+9+9) ){
+ if( 0==sqlcipher_sqlite3Fts5BufferSize(&p->rc, &buf, nHdr) ){
sqlcipher_sqlite3Fts5Put32(buf.p, iCookie);
buf.n = 4;
+ if( pStruct->nOriginCntr>0 ){
+ fts5BufferSafeAppendBlob(&buf, FTS5_STRUCTURE_V2, 4);
+ }
fts5BufferSafeAppendVarint(&buf, pStruct->nLevel);
fts5BufferSafeAppendVarint(&buf, pStruct->nSegment);
fts5BufferSafeAppendVarint(&buf, (i64)pStruct->nWriteCounter);
@@ -233747,9 +247225,17 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
assert( pLvl->nMerge<=pLvl->nSeg );
for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].iSegid);
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoFirst);
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoLast);
+ Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iSegid);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->pgnoFirst);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->pgnoLast);
+ if( pStruct->nOriginCntr>0 ){
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iOrigin1);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iOrigin2);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nPgTombstone);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nEntryTombstone);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nEntry);
+ }
}
}
@@ -233892,9 +247378,9 @@ static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){
}
if( iOff<pData->nn ){
- i64 iVal;
+ u64 iVal;
pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1;
- iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal);
+ iOff += fts5GetVarint(&pData->p[iOff], &iVal);
pLvl->iRowid += iVal;
pLvl->iOff = iOff;
}else{
@@ -233987,42 +247473,25 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
pLvl->bEof = 1;
}else{
u8 *a = pLvl->pData->p;
- i64 iVal;
- int iLimit;
- int ii;
- int nZero = 0;
-
- /* Currently iOff points to the first byte of a varint. This block
- ** decrements iOff until it points to the first byte of the previous
- ** varint. Taking care not to read any memory locations that occur
- ** before the buffer in memory. */
- iLimit = (iOff>9 ? iOff-9 : 0);
- for(iOff--; iOff>iLimit; iOff--){
- if( (a[iOff-1] & 0x80)==0 ) break;
- }
-
- fts5GetVarint(&a[iOff], (u64*)&iVal);
- pLvl->iRowid -= iVal;
- pLvl->iLeafPgno--;
-
- /* Skip backwards past any 0x00 varints. */
- for(ii=iOff-1; ii>=pLvl->iFirstOff && a[ii]==0x00; ii--){
- nZero++;
- }
- if( ii>=pLvl->iFirstOff && (a[ii] & 0x80) ){
- /* The byte immediately before the last 0x00 byte has the 0x80 bit
- ** set. So the last 0x00 is only a varint 0 if there are 8 more 0x80
- ** bytes before a[ii]. */
- int bZero = 0; /* True if last 0x00 counts */
- if( (ii-8)>=pLvl->iFirstOff ){
- int j;
- for(j=1; j<=8 && (a[ii-j] & 0x80); j++);
- bZero = (j>8);
+
+ pLvl->iOff = 0;
+ fts5DlidxLvlNext(pLvl);
+ while( 1 ){
+ int nZero = 0;
+ int ii = pLvl->iOff;
+ u64 delta = 0;
+
+ while( a[ii]==0 ){
+ nZero++;
+ ii++;
}
- if( bZero==0 ) nZero--;
+ ii += sqlcipher_sqlite3Fts5GetVarint(&a[ii], &delta);
+
+ if( ii>=iOff ) break;
+ pLvl->iLeafPgno += nZero+1;
+ pLvl->iRowid += delta;
+ pLvl->iOff = ii;
}
- pLvl->iLeafPgno -= nZero;
- pLvl->iOff = iOff - nZero;
}
return pLvl->bEof;
@@ -234218,7 +247687,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
i64 iOff = pIter->iLeafOffset;
ASSERT_SZLEAF_OK(pIter->pLeaf);
- if( iOff>=pIter->pLeaf->szLeaf ){
+ while( iOff>=pIter->pLeaf->szLeaf ){
fts5SegIterNextPage(p, pIter);
if( pIter->pLeaf==0 ){
if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
@@ -234290,6 +247759,25 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
}
/*
+** Allocate a tombstone hash page array object (pIter->pTombArray) for
+** the iterator passed as the second argument. If an OOM error occurs,
+** leave an error in the Fts5Index object.
+*/
+static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
+ const int nTomb = pIter->pSeg->nPgTombstone;
+ if( nTomb>0 ){
+ int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray);
+ Fts5TombstoneArray *pNew;
+ pNew = (Fts5TombstoneArray*)sqlcipher_sqlite3Fts5MallocZero(&p->rc, nByte);
+ if( pNew ){
+ pNew->nTombstone = nTomb;
+ pNew->nRef = 1;
+ pIter->pTombArray = pNew;
+ }
+ }
+}
+
+/*
** Initialize the iterator object pIter to iterate through the entries in
** segment pSeg. The iterator is left pointing to the first entry when
** this function returns.
@@ -234317,10 +247805,12 @@ static void fts5SegIterInit(
fts5SegIterSetNext(p, pIter);
pIter->pSeg = pSeg;
pIter->iLeafPgno = pSeg->pgnoFirst-1;
- fts5SegIterNextPage(p, pIter);
+ do {
+ fts5SegIterNextPage(p, pIter);
+ }while( p->rc==SQLITE_OK && pIter->pLeaf && pIter->pLeaf->nn==4 );
}
- if( p->rc==SQLITE_OK ){
+ if( p->rc==SQLITE_OK && pIter->pLeaf ){
pIter->iLeafOffset = 4;
assert( pIter->pLeaf!=0 );
assert_nc( pIter->pLeaf->nn>4 );
@@ -234328,6 +247818,7 @@ static void fts5SegIterInit(
pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
fts5SegIterLoadTerm(p, pIter, 0);
fts5SegIterLoadNPos(p, pIter);
+ fts5SegIterAllocTombstone(p, pIter);
}
}
@@ -234514,7 +248005,7 @@ static void fts5SegIterNext_None(
iOff = pIter->iLeafOffset;
/* Next entry is on the next page */
- if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
+ while( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
fts5SegIterNextPage(p, pIter);
if( p->rc || pIter->pLeaf==0 ) return;
pIter->iRowid = 0;
@@ -234538,15 +248029,16 @@ static void fts5SegIterNext_None(
}else{
const u8 *pList = 0;
const char *zTerm = 0;
+ int nTerm = 0;
int nList;
sqlcipher_sqlite3Fts5HashScanNext(p->pHash);
- sqlcipher_sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
+ sqlcipher_sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList);
if( pList==0 ) goto next_none_eof;
pIter->pLeaf->p = (u8*)pList;
pIter->pLeaf->nn = nList;
pIter->pLeaf->szLeaf = nList;
pIter->iEndofDoclist = nList;
- sqlcipher_sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm);
+ sqlcipher_sqlite3Fts5BufferSet(&p->rc,&pIter->term, nTerm, (u8*)zTerm);
pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
}
@@ -234612,11 +248104,12 @@ static void fts5SegIterNext(
}else if( pIter->pSeg==0 ){
const u8 *pList = 0;
const char *zTerm = 0;
+ int nTerm = 0;
int nList = 0;
assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
sqlcipher_sqlite3Fts5HashScanNext(p->pHash);
- sqlcipher_sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
+ sqlcipher_sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList);
}
if( pList==0 ){
fts5DataRelease(pIter->pLeaf);
@@ -234626,8 +248119,7 @@ static void fts5SegIterNext(
pIter->pLeaf->nn = nList;
pIter->pLeaf->szLeaf = nList;
pIter->iEndofDoclist = nList+1;
- sqlcipher_sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
- (u8*)zTerm);
+ sqlcipher_sqlite3Fts5BufferSet(&p->rc, &pIter->term, nTerm, (u8*)zTerm);
pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
*pbNewTerm = 1;
}
@@ -234707,7 +248199,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
Fts5Data *pLast = 0;
int pgnoLast = 0;
- if( pDlidx ){
+ if( pDlidx && p->pConfig->iVersion==FTS5_CURRENT_VERSION ){
int iSegid = pIter->pSeg->iSegid;
pgnoLast = fts5DlidxIterPgno(pDlidx);
pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
@@ -235013,7 +248505,7 @@ static void fts5SegIterSeekInit(
fts5LeafSeek(p, bGe, pIter, pTerm, nTerm);
}
- if( p->rc==SQLITE_OK && bGe==0 ){
+ if( p->rc==SQLITE_OK && (bGe==0 || (flags & FTS5INDEX_QUERY_SCANONETERM)) ){
pIter->flags |= FTS5_SEGITER_ONETERM;
if( pIter->pLeaf ){
if( flags & FTS5INDEX_QUERY_DESC ){
@@ -235029,6 +248521,9 @@ static void fts5SegIterSeekInit(
}
fts5SegIterSetNext(p, pIter);
+ if( 0==(flags & FTS5INDEX_QUERY_SCANONETERM) ){
+ fts5SegIterAllocTombstone(p, pIter);
+ }
/* Either:
**
@@ -235045,6 +248540,79 @@ static void fts5SegIterSeekInit(
);
}
+
+/*
+** SQL used by fts5SegIterNextInit() to find the page to open.
+*/
+static sqlcipher_sqlite3_stmt *fts5IdxNextStmt(Fts5Index *p){
+ if( p->pIdxNextSelect==0 ){
+ Fts5Config *pConfig = p->pConfig;
+ fts5IndexPrepareStmt(p, &p->pIdxNextSelect, sqlcipher_sqlite3_mprintf(
+ "SELECT pgno FROM '%q'.'%q_idx' WHERE "
+ "segid=? AND term>? ORDER BY term ASC LIMIT 1",
+ pConfig->zDb, pConfig->zName
+ ));
+
+ }
+ return p->pIdxNextSelect;
+}
+
+/*
+** This is similar to fts5SegIterSeekInit(), except that it initializes
+** the segment iterator to point to the first term following the page
+** with pToken/nToken on it.
+*/
+static void fts5SegIterNextInit(
+ Fts5Index *p,
+ const char *pTerm, int nTerm,
+ Fts5StructureSegment *pSeg, /* Description of segment */
+ Fts5SegIter *pIter /* Object to populate */
+){
+ int iPg = -1; /* Page of segment to open */
+ int bDlidx = 0;
+ sqlcipher_sqlite3_stmt *pSel = 0; /* SELECT to find iPg */
+
+ pSel = fts5IdxNextStmt(p);
+ if( pSel ){
+ assert( p->rc==SQLITE_OK );
+ sqlcipher_sqlite3_bind_int(pSel, 1, pSeg->iSegid);
+ sqlcipher_sqlite3_bind_blob(pSel, 2, pTerm, nTerm, SQLITE_STATIC);
+
+ if( sqlcipher_sqlite3_step(pSel)==SQLITE_ROW ){
+ i64 val = sqlcipher_sqlite3_column_int64(pSel, 0);
+ iPg = (int)(val>>1);
+ bDlidx = (val & 0x0001);
+ }
+ p->rc = sqlcipher_sqlite3_reset(pSel);
+ sqlcipher_sqlite3_bind_null(pSel, 2);
+ if( p->rc ) return;
+ }
+
+ memset(pIter, 0, sizeof(*pIter));
+ pIter->pSeg = pSeg;
+ pIter->flags |= FTS5_SEGITER_ONETERM;
+ if( iPg>=0 ){
+ pIter->iLeafPgno = iPg - 1;
+ fts5SegIterNextPage(p, pIter);
+ fts5SegIterSetNext(p, pIter);
+ }
+ if( pIter->pLeaf ){
+ const u8 *a = pIter->pLeaf->p;
+ int iTermOff = 0;
+
+ pIter->iPgidxOff = pIter->pLeaf->szLeaf;
+ pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], iTermOff);
+ pIter->iLeafOffset = iTermOff;
+ fts5SegIterLoadTerm(p, pIter, 0);
+ fts5SegIterLoadNPos(p, pIter);
+ if( bDlidx ) fts5SegIterLoadDlidx(p, pIter);
+
+ assert( p->rc!=SQLITE_OK ||
+ fts5BufferCompareBlob(&pIter->term, (const u8*)pTerm, nTerm)>0
+ );
+ }
+}
+
/*
** Initialize the object pIter to point to term pTerm/nTerm within the
** in-memory hash table. If there is no such term in the hash-table, the
@@ -235071,14 +248639,21 @@ static void fts5SegIterHashInit(
const u8 *pList = 0;
p->rc = sqlcipher_sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm);
- sqlcipher_sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList);
- n = (z ? (int)strlen((const char*)z) : 0);
+ sqlcipher_sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &n, &pList, &nList);
if( pList ){
pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
if( pLeaf ){
pLeaf->p = (u8*)pList;
}
}
+
+ /* The call to sqlcipher_sqlite3Fts5HashScanInit() causes the hash table to
+ ** fill the size field of all existing position lists. This means they
+ ** can no longer be appended to. Since the only scenario in which they
+ ** can be appended to is if the previous operation on this table was
+ ** a DELETE, by clearing the Fts5Index.bDelete flag we can avoid this
+ ** possibility altogether. */
+ p->bDelete = 0;
}else{
p->rc = sqlcipher_sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data),
(const char*)pTerm, nTerm, (void**)&pLeaf, &nList
@@ -235110,12 +248685,44 @@ static void fts5SegIterHashInit(
}
/*
+** Array ap[] contains n elements. Release each of these elements using
+** fts5DataRelease(). Then free the array itself using sqlcipher_sqlite3_free().
+*/
+static void fts5IndexFreeArray(Fts5Data **ap, int n){
+ if( ap ){
+ int ii;
+ for(ii=0; ii<n; ii++){
+ fts5DataRelease(ap[ii]);
+ }
+ sqlcipher_sqlite3_free(ap);
+ }
+}
+
+/*
+** Decrement the ref-count of the object passed as the only argument. If it
+** reaches 0, free it and its contents.
+*/
+static void fts5TombstoneArrayDelete(Fts5TombstoneArray *p){
+ if( p ){
+ p->nRef--;
+ if( p->nRef<=0 ){
+ int ii;
+ for(ii=0; ii<p->nTombstone; ii++){
+ fts5DataRelease(p->apTombstone[ii]);
+ }
+ sqlcipher_sqlite3_free(p);
+ }
+ }
+}
+
+/*
** Zero the iterator passed as the only argument.
*/
static void fts5SegIterClear(Fts5SegIter *pIter){
fts5BufferFree(&pIter->term);
fts5DataRelease(pIter->pLeaf);
fts5DataRelease(pIter->pNextLeaf);
+ fts5TombstoneArrayDelete(pIter->pTombArray);
fts5DlidxIterFree(pIter->pDlidx);
sqlcipher_sqlite3_free(pIter->aRowidOffset);
memset(pIter, 0, sizeof(Fts5SegIter));
@@ -235249,7 +248856,6 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
assert_nc( i2!=0 );
pRes->bTermEq = 1;
if( p1->iRowid==p2->iRowid ){
- p1->bDel = p2->bDel;
return i2;
}
res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1;
@@ -235268,7 +248874,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
/*
** Move the seg-iter so that it points to the first rowid on page iLeafPgno.
-** It is an error if leaf iLeafPgno does not exist or contains no rowids.
+** It is an error if leaf iLeafPgno does not exist. Unless the db is
+** a 'secure-delete' db, if it contains no rowids then this is also an error.
*/
static void fts5SegIterGotoPage(
Fts5Index *p, /* FTS5 backend object */
@@ -235283,21 +248890,23 @@ static void fts5SegIterGotoPage(
fts5DataRelease(pIter->pNextLeaf);
pIter->pNextLeaf = 0;
pIter->iLeafPgno = iLeafPgno-1;
- fts5SegIterNextPage(p, pIter);
- assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno );
- if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){
+ while( p->rc==SQLITE_OK ){
int iOff;
- u8 *a = pIter->pLeaf->p;
- int n = pIter->pLeaf->szLeaf;
-
+ fts5SegIterNextPage(p, pIter);
+ if( pIter->pLeaf==0 ) break;
iOff = fts5LeafFirstRowidOff(pIter->pLeaf);
- if( iOff<4 || iOff>=n ){
- p->rc = FTS5_CORRUPT;
- }else{
- iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
- pIter->iLeafOffset = iOff;
- fts5SegIterLoadNPos(p, pIter);
+ if( iOff>0 ){
+ u8 *a = pIter->pLeaf->p;
+ int n = pIter->pLeaf->szLeaf;
+ if( iOff<4 || iOff>=n ){
+ p->rc = FTS5_CORRUPT;
+ }else{
+ iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
+ pIter->iLeafOffset = iOff;
+ fts5SegIterLoadNPos(p, pIter);
+ }
+ break;
}
}
}
@@ -235358,7 +248967,6 @@ static void fts5SegIterNextFrom(
}while( p->rc==SQLITE_OK );
}
-
/*
** Free the iterator object passed as the second argument.
*/
@@ -235451,6 +249059,85 @@ static void fts5MultiIterSetEof(Fts5Iter *pIter){
}
/*
+** The argument to this macro must be an Fts5Data structure containing a
+** tombstone hash page. This macro returns the key-size of the hash-page.
+*/
+#define TOMBSTONE_KEYSIZE(pPg) (pPg->p[0]==4 ? 4 : 8)
+
+#define TOMBSTONE_NSLOT(pPg) \
+ ((pPg->nn > 16) ? ((pPg->nn-8) / TOMBSTONE_KEYSIZE(pPg)) : 1)
+
+/*
+** Query a single tombstone hash table for rowid iRowid. Return true if
+** it is found or false otherwise. The tombstone hash table is one of
+** nHashTable tables.
+*/
+static int fts5IndexTombstoneQuery(
+ Fts5Data *pHash, /* Hash table page to query */
+ int nHashTable, /* Number of pages attached to segment */
+ u64 iRowid /* Rowid to query hash for */
+){
+ const int szKey = TOMBSTONE_KEYSIZE(pHash);
+ const int nSlot = TOMBSTONE_NSLOT(pHash);
+ int iSlot = (iRowid / nHashTable) % nSlot;
+ int nCollide = nSlot;
+
+ if( iRowid==0 ){
+ return pHash->p[1];
+ }else if( szKey==4 ){
+ u32 *aSlot = (u32*)&pHash->p[8];
+ while( aSlot[iSlot] ){
+ if( fts5GetU32((u8*)&aSlot[iSlot])==iRowid ) return 1;
+ if( nCollide--==0 ) break;
+ iSlot = (iSlot+1)%nSlot;
+ }
+ }else{
+ u64 *aSlot = (u64*)&pHash->p[8];
+ while( aSlot[iSlot] ){
+ if( fts5GetU64((u8*)&aSlot[iSlot])==iRowid ) return 1;
+ if( nCollide--==0 ) break;
+ iSlot = (iSlot+1)%nSlot;
+ }
+ }
+
+ return 0;
+}
+
+/*
+** Return true if the iterator passed as the only argument points
+** to an segment entry for which there is a tombstone. Return false
+** if there is no tombstone or if the iterator is already at EOF.
+*/
+static int fts5MultiIterIsDeleted(Fts5Iter *pIter){
+ int iFirst = pIter->aFirst[1].iFirst;
+ Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
+ Fts5TombstoneArray *pArray = pSeg->pTombArray;
+
+ if( pSeg->pLeaf && pArray ){
+ /* Figure out which page the rowid might be present on. */
+ int iPg = ((u64)pSeg->iRowid) % pArray->nTombstone;
+ assert( iPg>=0 );
+
+ /* If tombstone hash page iPg has not yet been loaded from the
+ ** database, load it now. */
+ if( pArray->apTombstone[iPg]==0 ){
+ pArray->apTombstone[iPg] = fts5DataRead(pIter->pIndex,
+ FTS5_TOMBSTONE_ROWID(pSeg->pSeg->iSegid, iPg)
+ );
+ if( pArray->apTombstone[iPg]==0 ) return 0;
+ }
+
+ return fts5IndexTombstoneQuery(
+ pArray->apTombstone[iPg],
+ pArray->nTombstone,
+ pSeg->iRowid
+ );
+ }
+
+ return 0;
+}
+
+/*
** Move the iterator to the next entry.
**
** If an error occurs, an error code is left in Fts5Index.rc. It is not
@@ -235487,7 +249174,9 @@ static void fts5MultiIterNext(
fts5AssertMultiIterSetup(p, pIter);
assert( pSeg==&pIter->aSeg[pIter->aFirst[1].iFirst] && pSeg->pLeaf );
- if( pIter->bSkipEmpty==0 || pSeg->nPos ){
+ if( (pIter->bSkipEmpty==0 || pSeg->nPos)
+ && 0==fts5MultiIterIsDeleted(pIter)
+ ){
pIter->xSetOutputs(pIter, pSeg);
return;
}
@@ -235519,7 +249208,9 @@ static void fts5MultiIterNext2(
}
fts5AssertMultiIterSetup(p, pIter);
- }while( fts5MultiIterIsEmpty(p, pIter) );
+ }while( (fts5MultiIterIsEmpty(p, pIter) || fts5MultiIterIsDeleted(pIter))
+ && (p->rc==SQLITE_OK)
+ );
}
}
@@ -235532,7 +249223,7 @@ static Fts5Iter *fts5MultiIterAlloc(
int nSeg
){
Fts5Iter *pNew;
- int nSlot; /* Power of two >= nSeg */
+ i64 nSlot; /* Power of two >= nSeg */
for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
pNew = fts5IdxMalloc(p,
@@ -235977,6 +249668,32 @@ static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
}
}
+/*
+** All the component segment-iterators of pIter have been set up. This
+** functions finishes setup for iterator pIter itself.
+*/
+static void fts5MultiIterFinishSetup(Fts5Index *p, Fts5Iter *pIter){
+ int iIter;
+ for(iIter=pIter->nSeg-1; iIter>0; iIter--){
+ int iEq;
+ if( (iEq = fts5MultiIterDoCompare(pIter, iIter)) ){
+ Fts5SegIter *pSeg = &pIter->aSeg[iEq];
+ if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
+ fts5MultiIterAdvanced(p, pIter, iEq, iIter);
+ }
+ }
+ fts5MultiIterSetEof(pIter);
+ fts5AssertMultiIterSetup(p, pIter);
+
+ if( (pIter->bSkipEmpty && fts5MultiIterIsEmpty(p, pIter))
+ || fts5MultiIterIsDeleted(pIter)
+ ){
+ fts5MultiIterNext(p, pIter, 0, 0);
+ }else if( pIter->base.bEof==0 ){
+ Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
+ pIter->xSetOutputs(pIter, pSeg);
+ }
+}
/*
** Allocate a new Fts5Iter object.
@@ -236012,7 +249729,7 @@ static void fts5MultiIterNew(
if( iLevel<0 ){
assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
nSeg = pStruct->nSegment;
- nSeg += (p->pHash ? 1 : 0);
+ nSeg += (p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH));
}else{
nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment);
}
@@ -236033,7 +249750,7 @@ static void fts5MultiIterNew(
if( p->rc==SQLITE_OK ){
if( iLevel<0 ){
Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
- if( p->pHash ){
+ if( p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH) ){
/* Add a segment iterator for the current contents of the hash table. */
Fts5SegIter *pIter = &pNew->aSeg[iIter++];
fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
@@ -236058,29 +249775,12 @@ static void fts5MultiIterNew(
assert( iIter==nSeg );
}
- /* If the above was successful, each component iterators now points
+ /* If the above was successful, each component iterator now points
** to the first entry in its segment. In this case initialize the
** aFirst[] array. Or, if an error has occurred, free the iterator
** object and set the output variable to NULL. */
if( p->rc==SQLITE_OK ){
- for(iIter=pNew->nSeg-1; iIter>0; iIter--){
- int iEq;
- if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
- Fts5SegIter *pSeg = &pNew->aSeg[iEq];
- if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
- fts5MultiIterAdvanced(p, pNew, iEq, iIter);
- }
- }
- fts5MultiIterSetEof(pNew);
- fts5AssertMultiIterSetup(p, pNew);
-
- if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){
- fts5MultiIterNext(p, pNew, 0, 0);
- }else if( pNew->base.bEof==0 ){
- Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst];
- pNew->xSetOutputs(pNew, pSeg);
- }
-
+ fts5MultiIterFinishSetup(p, pNew);
}else{
fts5MultiIterFree(pNew);
*ppOut = 0;
@@ -236105,7 +249805,6 @@ static void fts5MultiIterNew2(
pNew = fts5MultiIterAlloc(p, 2);
if( pNew ){
Fts5SegIter *pIter = &pNew->aSeg[1];
-
pIter->flags = FTS5_SEGITER_ONETERM;
if( pData->szLeaf>0 ){
pIter->pLeaf = pData;
@@ -236252,7 +249951,10 @@ static void fts5IndexDiscardData(Fts5Index *p){
if( p->pHash ){
sqlcipher_sqlite3Fts5HashClear(p->pHash);
p->nPendingData = 0;
+ p->nPendingRow = 0;
+ p->flushRc = SQLITE_OK;
}
+ p->nContentlessDelete = 0;
}
/*
@@ -236466,7 +250168,7 @@ static void fts5WriteDlidxAppend(
}
if( pDlidx->bPrevValid ){
- iVal = iRowid - pDlidx->iPrev;
+ iVal = (u64)iRowid - (u64)pDlidx->iPrev;
}else{
i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno);
assert( pDlidx->buf.n==0 );
@@ -236633,7 +250335,9 @@ static void fts5WriteAppendRowid(
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
}else{
assert_nc( p->rc || iRowid>pWriter->iPrevRowid );
- fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
+ fts5BufferAppendVarint(&p->rc, &pPage->buf,
+ (u64)iRowid - (u64)pWriter->iPrevRowid
+ );
}
pWriter->iPrevRowid = iRowid;
pWriter->bFirstRowidInDoclist = 0;
@@ -236651,7 +250355,7 @@ static void fts5WriteAppendPoslistData(
const u8 *a = aData;
int n = nData;
- assert( p->pConfig->pgsz>0 );
+ assert( p->pConfig->pgsz>0 || p->rc!=SQLITE_OK );
while( p->rc==SQLITE_OK
&& (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz
){
@@ -236786,7 +250490,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
- fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]);
+ fts5BufferAppendBlob(&p->rc, &buf,pData->szLeaf-iOff,&pData->p[iOff]);
if( p->rc==SQLITE_OK ){
/* Set the szLeaf field */
fts5PutU16(&buf.p[2], (u16)buf.n);
@@ -236887,6 +250591,12 @@ static void fts5IndexMergeLevel(
/* Read input from all segments in the input level */
nInput = pLvl->nSeg;
+
+ /* Set the range of origins that will go into the output segment. */
+ if( pStruct->nOriginCntr>0 ){
+ pSeg->iOrigin1 = pLvl->aSeg[0].iOrigin1;
+ pSeg->iOrigin2 = pLvl->aSeg[pLvl->nSeg-1].iOrigin2;
+ }
}
bOldest = (pLvlOut->nSeg==1 && pStruct->nLevel==iLvl+2);
@@ -236946,8 +250656,11 @@ static void fts5IndexMergeLevel(
int i;
/* Remove the redundant segments from the %_data table */
+ assert( pSeg->nEntry==0 );
for(i=0; i<nInput; i++){
- fts5DataRemoveSegment(p, pLvl->aSeg[i].iSegid);
+ Fts5StructureSegment *pOld = &pLvl->aSeg[i];
+ pSeg->nEntry += (pOld->nEntry - pOld->nEntryTombstone);
+ fts5DataRemoveSegment(p, pOld);
}
/* Remove the redundant segments from the input level */
@@ -236974,6 +250687,43 @@ static void fts5IndexMergeLevel(
}
/*
+** If this is not a contentless_delete=1 table, or if the 'deletemerge'
+** configuration option is set to 0, then this function always returns -1.
+** Otherwise, it searches the structure object passed as the second argument
+** for a level suitable for merging due to having a large number of
+** tombstones in the tombstone hash. If one is found, its index is returned.
+** Otherwise, if there is no suitable level, -1.
+*/
+static int fts5IndexFindDeleteMerge(Fts5Index *p, Fts5Structure *pStruct){
+ Fts5Config *pConfig = p->pConfig;
+ int iRet = -1;
+ if( pConfig->bContentlessDelete && pConfig->nDeleteMerge>0 ){
+ int ii;
+ int nBest = 0;
+
+ for(ii=0; ii<pStruct->nLevel; ii++){
+ Fts5StructureLevel *pLvl = &pStruct->aLevel[ii];
+ i64 nEntry = 0;
+ i64 nTomb = 0;
+ int iSeg;
+ for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
+ nEntry += pLvl->aSeg[iSeg].nEntry;
+ nTomb += pLvl->aSeg[iSeg].nEntryTombstone;
+ }
+ assert_nc( nEntry>0 || pLvl->nSeg==0 );
+ if( nEntry>0 ){
+ int nPercent = (nTomb * 100) / nEntry;
+ if( nPercent>=pConfig->nDeleteMerge && nPercent>nBest ){
+ iRet = ii;
+ nBest = nPercent;
+ }
+ }
+ }
+ }
+ return iRet;
+}
+
+/*
** Do up to nPg pages of automerge work on the index.
**
** Return true if any changes were actually made, or false otherwise.
@@ -236992,14 +250742,15 @@ static int fts5IndexMerge(
int iBestLvl = 0; /* Level offering the most input segments */
int nBest = 0; /* Number of input segments on best level */
- /* Set iBestLvl to the level to read input segments from. */
+ /* Set iBestLvl to the level to read input segments from. Or to -1 if
+ ** there is no level suitable to merge segments from. */
assert( pStruct->nLevel>0 );
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
if( pLvl->nMerge ){
if( pLvl->nMerge>nBest ){
iBestLvl = iLvl;
- nBest = pLvl->nMerge;
+ nBest = nMin;
}
break;
}
@@ -237008,22 +250759,18 @@ static int fts5IndexMerge(
iBestLvl = iLvl;
}
}
-
- /* If nBest is still 0, then the index must be empty. */
-#ifdef SQLITE_DEBUG
- for(iLvl=0; nBest==0 && iLvl<pStruct->nLevel; iLvl++){
- assert( pStruct->aLevel[iLvl].nSeg==0 );
+ if( nBest<nMin ){
+ iBestLvl = fts5IndexFindDeleteMerge(p, pStruct);
}
-#endif
- if( nBest<nMin && pStruct->aLevel[iBestLvl].nMerge==0 ){
- break;
- }
+ if( iBestLvl<0 ) break;
bRet = 1;
fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem);
if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
fts5StructurePromote(p, iBestLvl+1, pStruct);
}
+
+ if( nMin==1 ) nMin = 2;
}
*ppStruct = pStruct;
return bRet;
@@ -237064,16 +250811,16 @@ static void fts5IndexCrisismerge(
){
const int nCrisis = p->pConfig->nCrisisMerge;
Fts5Structure *pStruct = *ppStruct;
- int iLvl = 0;
-
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 );
- while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
- fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
- fts5StructurePromote(p, iLvl+1, pStruct);
- iLvl++;
+ if( pStruct && pStruct->nLevel>0 ){
+ int iLvl = 0;
+ while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
+ fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
+ assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
+ fts5StructurePromote(p, iLvl+1, pStruct);
+ iLvl++;
+ }
+ *ppStruct = pStruct;
}
- *ppStruct = pStruct;
}
static int fts5IndexReturn(Fts5Index *p){
@@ -237108,6 +250855,469 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
}
/*
+** Execute the SQL statement:
+**
+** DELETE FROM %_idx WHERE (segid, (pgno/2)) = ($iSegid, $iPgno);
+**
+** This is used when a secure-delete operation removes the last term
+** from a segment leaf page. In that case the %_idx entry is removed
+** too. This is done to ensure that if all instances of a token are
+** removed from an fts5 database in secure-delete mode, no trace of
+** the token itself remains in the database.
+*/
+static void fts5SecureDeleteIdxEntry(
+ Fts5Index *p, /* FTS5 backend object */
+ int iSegid, /* Id of segment to delete entry for */
+ int iPgno /* Page number within segment */
+){
+ if( iPgno!=1 ){
+ assert( p->pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE );
+ if( p->pDeleteFromIdx==0 ){
+ fts5IndexPrepareStmt(p, &p->pDeleteFromIdx, sqlcipher_sqlite3_mprintf(
+ "DELETE FROM '%q'.'%q_idx' WHERE (segid, (pgno/2)) = (?1, ?2)",
+ p->pConfig->zDb, p->pConfig->zName
+ ));
+ }
+ if( p->rc==SQLITE_OK ){
+ sqlcipher_sqlite3_bind_int(p->pDeleteFromIdx, 1, iSegid);
+ sqlcipher_sqlite3_bind_int(p->pDeleteFromIdx, 2, iPgno);
+ sqlcipher_sqlite3_step(p->pDeleteFromIdx);
+ p->rc = sqlcipher_sqlite3_reset(p->pDeleteFromIdx);
+ }
+ }
+}
+
+/*
+** This is called when a secure-delete operation removes a position-list
+** that overflows onto segment page iPgno of segment pSeg. This function
+** rewrites node iPgno, and possibly one or more of its right-hand peers,
+** to remove this portion of the position list.
+**
+** Output variable (*pbLastInDoclist) is set to true if the position-list
+** removed is followed by a new term or the end-of-segment, or false if
+** it is followed by another rowid/position list.
+*/
+static void fts5SecureDeleteOverflow(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg,
+ int iPgno,
+ int *pbLastInDoclist
+){
+ const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
+ int pgno;
+ Fts5Data *pLeaf = 0;
+ assert( iPgno!=1 );
+
+ *pbLastInDoclist = 1;
+ for(pgno=iPgno; p->rc==SQLITE_OK && pgno<=pSeg->pgnoLast; pgno++){
+ i64 iRowid = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno);
+ int iNext = 0;
+ u8 *aPg = 0;
+
+ pLeaf = fts5DataRead(p, iRowid);
+ if( pLeaf==0 ) break;
+ aPg = pLeaf->p;
+
+ iNext = fts5GetU16(&aPg[0]);
+ if( iNext!=0 ){
+ *pbLastInDoclist = 0;
+ }
+ if( iNext==0 && pLeaf->szLeaf!=pLeaf->nn ){
+ fts5GetVarint32(&aPg[pLeaf->szLeaf], iNext);
+ }
+
+ if( iNext==0 ){
+ /* The page contains no terms or rowids. Replace it with an empty
+ ** page and move on to the right-hand peer. */
+ const u8 aEmpty[] = {0x00, 0x00, 0x00, 0x04};
+ assert_nc( bDetailNone==0 || pLeaf->nn==4 );
+ if( bDetailNone==0 ) fts5DataWrite(p, iRowid, aEmpty, sizeof(aEmpty));
+ fts5DataRelease(pLeaf);
+ pLeaf = 0;
+ }else if( bDetailNone ){
+ break;
+ }else if( iNext>=pLeaf->szLeaf || pLeaf->nn<pLeaf->szLeaf || iNext<4 ){
+ p->rc = FTS5_CORRUPT;
+ break;
+ }else{
+ int nShift = iNext - 4;
+ int nPg;
+
+ int nIdx = 0;
+ u8 *aIdx = 0;
+
+ /* Unless the current page footer is 0 bytes in size (in which case
+ ** the new page footer will be as well), allocate and populate a
+ ** buffer containing the new page footer. Set stack variables aIdx
+ ** and nIdx accordingly. */
+ if( pLeaf->nn>pLeaf->szLeaf ){
+ int iFirst = 0;
+ int i1 = pLeaf->szLeaf;
+ int i2 = 0;
+
+ i1 += fts5GetVarint32(&aPg[i1], iFirst);
+ if( iFirst<iNext ){
+ p->rc = FTS5_CORRUPT;
+ break;
+ }
+ aIdx = sqlcipher_sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2);
+ if( aIdx==0 ) break;
+ i2 = sqlcipher_sqlite3Fts5PutVarint(aIdx, iFirst-nShift);
+ if( i1<pLeaf->nn ){
+ memcpy(&aIdx[i2], &aPg[i1], pLeaf->nn-i1);
+ i2 += (pLeaf->nn-i1);
+ }
+ nIdx = i2;
+ }
+
+ /* Modify the contents of buffer aPg[]. Set nPg to the new size
+ ** in bytes. The new page is always smaller than the old. */
+ nPg = pLeaf->szLeaf - nShift;
+ memmove(&aPg[4], &aPg[4+nShift], nPg-4);
+ fts5PutU16(&aPg[2], nPg);
+ if( fts5GetU16(&aPg[0]) ) fts5PutU16(&aPg[0], 4);
+ if( nIdx>0 ){
+ memcpy(&aPg[nPg], aIdx, nIdx);
+ nPg += nIdx;
+ }
+ sqlcipher_sqlite3_free(aIdx);
+
+ /* Write the new page to disk and exit the loop */
+ assert( nPg>4 || fts5GetU16(aPg)==0 );
+ fts5DataWrite(p, iRowid, aPg, nPg);
+ break;
+ }
+ }
+ fts5DataRelease(pLeaf);
+}
+
+/*
+** Completely remove the entry that pSeg currently points to from
+** the database.
+*/
+static void fts5DoSecureDelete(
+ Fts5Index *p,
+ Fts5SegIter *pSeg
+){
+ const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
+ int iSegid = pSeg->pSeg->iSegid;
+ u8 *aPg = pSeg->pLeaf->p;
+ int nPg = pSeg->pLeaf->nn;
+ int iPgIdx = pSeg->pLeaf->szLeaf;
+
+ u64 iDelta = 0;
+ int iNextOff = 0;
+ int iOff = 0;
+ int nIdx = 0;
+ u8 *aIdx = 0;
+ int bLastInDoclist = 0;
+ int iIdx = 0;
+ int iStart = 0;
+ int iDelKeyOff = 0; /* Offset of deleted key, if any */
+
+ nIdx = nPg-iPgIdx;
+ aIdx = sqlcipher_sqlite3Fts5MallocZero(&p->rc, nIdx+16);
+ if( p->rc ) return;
+ memcpy(aIdx, &aPg[iPgIdx], nIdx);
+
+ /* At this point segment iterator pSeg points to the entry
+ ** this function should remove from the b-tree segment.
+ **
+ ** In detail=full or detail=column mode, pSeg->iLeafOffset is the
+ ** offset of the first byte in the position-list for the entry to
+ ** remove. Immediately before this comes two varints that will also
+ ** need to be removed:
+ **
+ ** + the rowid or delta rowid value for the entry, and
+ ** + the size of the position list in bytes.
+ **
+ ** Or, in detail=none mode, there is a single varint prior to
+ ** pSeg->iLeafOffset - the rowid or delta rowid value.
+ **
+ ** This block sets the following variables:
+ **
+ ** iStart:
+ ** The offset of the first byte of the rowid or delta-rowid
+ ** value for the doclist entry being removed.
+ **
+ ** iDelta:
+ ** The value of the rowid or delta-rowid value for the doclist
+ ** entry being removed.
+ **
+ ** iNextOff:
+ ** The offset of the next entry following the position list
+ ** for the one being removed. If the position list for this
+ ** entry overflows onto the next leaf page, this value will be
+ ** greater than pLeaf->szLeaf.
+ */
+ {
+ int iSOP; /* Start-Of-Position-list */
+ if( pSeg->iLeafPgno==pSeg->iTermLeafPgno ){
+ iStart = pSeg->iTermLeafOffset;
+ }else{
+ iStart = fts5GetU16(&aPg[0]);
+ }
+
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ assert_nc( iSOP<=pSeg->iLeafOffset );
+
+ if( bDetailNone ){
+ while( iSOP<pSeg->iLeafOffset ){
+ if( aPg[iSOP]==0x00 ) iSOP++;
+ if( aPg[iSOP]==0x00 ) iSOP++;
+ iStart = iSOP;
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ }
+
+ iNextOff = iSOP;
+ if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
+ if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
+
+ }else{
+ int nPos = 0;
+ iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
+ while( iSOP<pSeg->iLeafOffset ){
+ iStart = iSOP + (nPos/2);
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
+ }
+ assert_nc( iSOP==pSeg->iLeafOffset );
+ iNextOff = pSeg->iLeafOffset + pSeg->nPos;
+ }
+ }
+
+ iOff = iStart;
+
+ /* If the position-list for the entry being removed flows over past
+ ** the end of this page, delete the portion of the position-list on the
+ ** next page and beyond.
+ **
+ ** Set variable bLastInDoclist to true if this entry happens
+ ** to be the last rowid in the doclist for its term. */
+ if( iNextOff>=iPgIdx ){
+ int pgno = pSeg->iLeafPgno+1;
+ fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
+ iNextOff = iPgIdx;
+ }
+
+ if( pSeg->bDel==0 ){
+ if( iNextOff!=iPgIdx ){
+ /* Loop through the page-footer. If iNextOff (offset of the
+ ** entry following the one we are removing) is equal to the
+ ** offset of a key on this page, then the entry is the last
+ ** in its doclist. */
+ int iKeyOff = 0;
+ for(iIdx=0; iIdx<nIdx; /* no-op */){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ iKeyOff += iVal;
+ if( iKeyOff==iNextOff ){
+ bLastInDoclist = 1;
+ }
+ }
+ }
+
+ /* If this is (a) the first rowid on a page and (b) is not followed by
+ ** another position list on the same page, set the "first-rowid" field
+ ** of the header to 0. */
+ if( fts5GetU16(&aPg[0])==iStart && (bLastInDoclist || iNextOff==iPgIdx) ){
+ fts5PutU16(&aPg[0], 0);
+ }
+ }
+
+ if( pSeg->bDel ){
+ iOff += sqlcipher_sqlite3Fts5PutVarint(&aPg[iOff], iDelta);
+ aPg[iOff++] = 0x01;
+ }else if( bLastInDoclist==0 ){
+ if( iNextOff!=iPgIdx ){
+ u64 iNextDelta = 0;
+ iNextOff += fts5GetVarint(&aPg[iNextOff], &iNextDelta);
+ iOff += sqlcipher_sqlite3Fts5PutVarint(&aPg[iOff], iDelta + iNextDelta);
+ }
+ }else if(
+ pSeg->iLeafPgno==pSeg->iTermLeafPgno
+ && iStart==pSeg->iTermLeafOffset
+ ){
+ /* The entry being removed was the only position list in its
+ ** doclist. Therefore the term needs to be removed as well. */
+ int iKey = 0;
+ int iKeyOff = 0;
+
+ /* Set iKeyOff to the offset of the term that will be removed - the
+ ** last offset in the footer that is not greater than iStart. */
+ for(iIdx=0; iIdx<nIdx; iKey++){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ if( (iKeyOff+iVal)>(u32)iStart ) break;
+ iKeyOff += iVal;
+ }
+ assert_nc( iKey>=1 );
+
+ /* Set iDelKeyOff to the value of the footer entry to remove from
+ ** the page. */
+ iDelKeyOff = iOff = iKeyOff;
+
+ if( iNextOff!=iPgIdx ){
+ /* This is the only position-list associated with the term, and there
+ ** is another term following it on this page. So the subsequent term
+ ** needs to be moved to replace the term associated with the entry
+ ** being removed. */
+ int nPrefix = 0;
+ int nSuffix = 0;
+ int nPrefix2 = 0;
+ int nSuffix2 = 0;
+
+ iDelKeyOff = iNextOff;
+ iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2);
+ iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2);
+
+ if( iKey!=1 ){
+ iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix);
+ }
+ iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix);
+
+ nPrefix = MIN(nPrefix, nPrefix2);
+ nSuffix = (nPrefix2 + nSuffix2) - nPrefix;
+
+ if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){
+ p->rc = FTS5_CORRUPT;
+ }else{
+ if( iKey!=1 ){
+ iOff += sqlcipher_sqlite3Fts5PutVarint(&aPg[iOff], nPrefix);
+ }
+ iOff += sqlcipher_sqlite3Fts5PutVarint(&aPg[iOff], nSuffix);
+ if( nPrefix2>pSeg->term.n ){
+ p->rc = FTS5_CORRUPT;
+ }else if( nPrefix2>nPrefix ){
+ memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix);
+ iOff += (nPrefix2-nPrefix);
+ }
+ memmove(&aPg[iOff], &aPg[iNextOff], nSuffix2);
+ iOff += nSuffix2;
+ iNextOff += nSuffix2;
+ }
+ }
+ }else if( iStart==4 ){
+ int iPgno;
+
+ assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno );
+ /* The entry being removed may be the only position list in
+ ** its doclist. */
+ for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){
+ Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno));
+ int bEmpty = (pPg && pPg->nn==4);
+ fts5DataRelease(pPg);
+ if( bEmpty==0 ) break;
+ }
+
+ if( iPgno==pSeg->iTermLeafPgno ){
+ i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno);
+ Fts5Data *pTerm = fts5DataRead(p, iId);
+ if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){
+ u8 *aTermIdx = &pTerm->p[pTerm->szLeaf];
+ int nTermIdx = pTerm->nn - pTerm->szLeaf;
+ int iTermIdx = 0;
+ int iTermOff = 0;
+
+ while( 1 ){
+ u32 iVal = 0;
+ int nByte = fts5GetVarint32(&aTermIdx[iTermIdx], iVal);
+ iTermOff += iVal;
+ if( (iTermIdx+nByte)>=nTermIdx ) break;
+ iTermIdx += nByte;
+ }
+ nTermIdx = iTermIdx;
+
+ memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
+ fts5PutU16(&pTerm->p[2], iTermOff);
+
+ fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
+ if( nTermIdx==0 ){
+ fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
+ }
+ }
+ fts5DataRelease(pTerm);
+ }
+ }
+
+ /* Assuming no error has occurred, this block does final edits to the
+ ** leaf page before writing it back to disk. Input variables are:
+ **
+ ** nPg: Total initial size of leaf page.
+ ** iPgIdx: Initial offset of page footer.
+ **
+ ** iOff: Offset to move data to
+ ** iNextOff: Offset to move data from
+ */
+ if( p->rc==SQLITE_OK ){
+ const int nMove = nPg - iNextOff; /* Number of bytes to move */
+ int nShift = iNextOff - iOff; /* Distance to move them */
+
+ int iPrevKeyOut = 0;
+ int iKeyIn = 0;
+
+ memmove(&aPg[iOff], &aPg[iNextOff], nMove);
+ iPgIdx -= nShift;
+ nPg = iPgIdx;
+ fts5PutU16(&aPg[2], iPgIdx);
+
+ for(iIdx=0; iIdx<nIdx; /* no-op */){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ iKeyIn += iVal;
+ if( iKeyIn!=iDelKeyOff ){
+ int iKeyOut = (iKeyIn - (iKeyIn>iOff ? nShift : 0));
+ nPg += sqlcipher_sqlite3Fts5PutVarint(&aPg[nPg], iKeyOut - iPrevKeyOut);
+ iPrevKeyOut = iKeyOut;
+ }
+ }
+
+ if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){
+ fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iLeafPgno);
+ }
+
+ assert_nc( nPg>4 || fts5GetU16(aPg)==0 );
+ fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg, nPg);
+ }
+ sqlcipher_sqlite3_free(aIdx);
+}
+
+/*
+** This is called as part of flushing a delete to disk in 'secure-delete'
+** mode. It edits the segments within the database described by argument
+** pStruct to remove the entries for term zTerm, rowid iRowid.
+*/
+static void fts5FlushSecureDelete(
+ Fts5Index *p,
+ Fts5Structure *pStruct,
+ const char *zTerm,
+ int nTerm,
+ i64 iRowid
+){
+ const int f = FTS5INDEX_QUERY_SKIPHASH;
+ Fts5Iter *pIter = 0; /* Used to find term instance */
+
+ fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter);
+ if( fts5MultiIterEof(p, pIter)==0 ){
+ i64 iThis = fts5MultiIterRowid(pIter);
+ if( iThis<iRowid ){
+ fts5MultiIterNextFrom(p, pIter, iRowid);
+ }
+
+ if( p->rc==SQLITE_OK
+ && fts5MultiIterEof(p, pIter)==0
+ && iRowid==fts5MultiIterRowid(pIter)
+ ){
+ Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
+ fts5DoSecureDelete(p, pSeg);
+ }
+ }
+
+ fts5MultiIterFree(pIter);
+}
+
+
+/*
** Flush the contents of in-memory hash table iHash to a new level-0
** segment on disk. Also update the corresponding structure record.
**
@@ -237123,143 +251333,197 @@ static void fts5FlushOneHash(Fts5Index *p){
/* Obtain a reference to the index structure and allocate a new segment-id
** for the new level-0 segment. */
pStruct = fts5StructureRead(p);
- iSegid = fts5AllocateSegid(p, pStruct);
fts5StructureInvalidate(p);
- if( iSegid ){
- const int pgsz = p->pConfig->pgsz;
- int eDetail = p->pConfig->eDetail;
- Fts5StructureSegment *pSeg; /* New segment within pStruct */
- Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
- Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
+ if( sqlcipher_sqlite3Fts5HashIsEmpty(pHash)==0 ){
+ iSegid = fts5AllocateSegid(p, pStruct);
+ if( iSegid ){
+ const int pgsz = p->pConfig->pgsz;
+ int eDetail = p->pConfig->eDetail;
+ int bSecureDelete = p->pConfig->bSecureDelete;
+ Fts5StructureSegment *pSeg; /* New segment within pStruct */
+ Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
+ Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
+
+ Fts5SegWriter writer;
+ fts5WriteInit(p, &writer, iSegid);
+
+ pBuf = &writer.writer.buf;
+ pPgidx = &writer.writer.pgidx;
+
+ /* fts5WriteInit() should have initialized the buffers to (most likely)
+ ** the maximum space required. */
+ assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+ assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+
+ /* Begin scanning through hash table entries. This loop runs once for each
+ ** term/doclist currently stored within the hash table. */
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlcipher_sqlite3Fts5HashScanInit(pHash, 0, 0);
+ }
+ while( p->rc==SQLITE_OK && 0==sqlcipher_sqlite3Fts5HashScanEof(pHash) ){
+ const char *zTerm; /* Buffer containing term */
+ int nTerm; /* Size of zTerm in bytes */
+ const u8 *pDoclist; /* Pointer to doclist for this term */
+ int nDoclist; /* Size of doclist in bytes */
- Fts5SegWriter writer;
- fts5WriteInit(p, &writer, iSegid);
+ /* Get the term and doclist for this entry. */
+ sqlcipher_sqlite3Fts5HashScanEntry(pHash, &zTerm, &nTerm, &pDoclist, &nDoclist);
+ if( bSecureDelete==0 ){
+ fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
+ if( p->rc!=SQLITE_OK ) break;
+ assert( writer.bFirstRowidInPage==0 );
+ }
- pBuf = &writer.writer.buf;
- pPgidx = &writer.writer.pgidx;
+ if( !bSecureDelete && pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
+ /* The entire doclist will fit on the current leaf. */
+ fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
+ }else{
+ int bTermWritten = !bSecureDelete;
+ i64 iRowid = 0;
+ i64 iPrev = 0;
+ int iOff = 0;
+
+ /* The entire doclist will not fit on this leaf. The following
+ ** loop iterates through the poslists that make up the current
+ ** doclist. */
+ while( p->rc==SQLITE_OK && iOff<nDoclist ){
+ u64 iDelta = 0;
+ iOff += fts5GetVarint(&pDoclist[iOff], &iDelta);
+ iRowid += iDelta;
+
+ /* If in secure delete mode, and if this entry in the poslist is
+ ** in fact a delete, then edit the existing segments directly
+ ** using fts5FlushSecureDelete(). */
+ if( bSecureDelete ){
+ if( eDetail==FTS5_DETAIL_NONE ){
+ if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
+ fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
+ iOff++;
+ if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
+ iOff++;
+ nDoclist = 0;
+ }else{
+ continue;
+ }
+ }
+ }else if( (pDoclist[iOff] & 0x01) ){
+ fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
+ if( p->rc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
+ iOff++;
+ continue;
+ }
+ }
+ }
- /* fts5WriteInit() should have initialized the buffers to (most likely)
- ** the maximum space required. */
- assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) );
- assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+ if( p->rc==SQLITE_OK && bTermWritten==0 ){
+ fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
+ bTermWritten = 1;
+ assert( p->rc!=SQLITE_OK || writer.bFirstRowidInPage==0 );
+ }
- /* Begin scanning through hash table entries. This loop runs once for each
- ** term/doclist currently stored within the hash table. */
- if( p->rc==SQLITE_OK ){
- p->rc = sqlcipher_sqlite3Fts5HashScanInit(pHash, 0, 0);
- }
- while( p->rc==SQLITE_OK && 0==sqlcipher_sqlite3Fts5HashScanEof(pHash) ){
- const char *zTerm; /* Buffer containing term */
- const u8 *pDoclist; /* Pointer to doclist for this term */
- int nDoclist; /* Size of doclist in bytes */
-
- /* Write the term for this entry to disk. */
- sqlcipher_sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
- fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
- if( p->rc!=SQLITE_OK ) break;
-
- assert( writer.bFirstRowidInPage==0 );
- if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
- /* The entire doclist will fit on the current leaf. */
- fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
- }else{
- i64 iRowid = 0;
- u64 iDelta = 0;
- int iOff = 0;
-
- /* The entire doclist will not fit on this leaf. The following
- ** loop iterates through the poslists that make up the current
- ** doclist. */
- while( p->rc==SQLITE_OK && iOff<nDoclist ){
- iOff += fts5GetVarint(&pDoclist[iOff], &iDelta);
- iRowid += iDelta;
-
- if( writer.bFirstRowidInPage ){
- fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
- pBuf->n += sqlcipher_sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
- writer.bFirstRowidInPage = 0;
- fts5WriteDlidxAppend(p, &writer, iRowid);
+ if( writer.bFirstRowidInPage ){
+ fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
+ pBuf->n += sqlcipher_sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
+ writer.bFirstRowidInPage = 0;
+ fts5WriteDlidxAppend(p, &writer, iRowid);
+ }else{
+ u64 iRowidDelta = (u64)iRowid - (u64)iPrev;
+ pBuf->n += sqlcipher_sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowidDelta);
+ }
if( p->rc!=SQLITE_OK ) break;
- }else{
- pBuf->n += sqlcipher_sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
- }
- assert( pBuf->n<=pBuf->nSpace );
+ assert( pBuf->n<=pBuf->nSpace );
+ iPrev = iRowid;
- if( eDetail==FTS5_DETAIL_NONE ){
- if( iOff<nDoclist && pDoclist[iOff]==0 ){
- pBuf->p[pBuf->n++] = 0;
- iOff++;
+ if( eDetail==FTS5_DETAIL_NONE ){
if( iOff<nDoclist && pDoclist[iOff]==0 ){
pBuf->p[pBuf->n++] = 0;
iOff++;
+ if( iOff<nDoclist && pDoclist[iOff]==0 ){
+ pBuf->p[pBuf->n++] = 0;
+ iOff++;
+ }
+ }
+ if( (pBuf->n + pPgidx->n)>=pgsz ){
+ fts5WriteFlushLeaf(p, &writer);
}
- }
- if( (pBuf->n + pPgidx->n)>=pgsz ){
- fts5WriteFlushLeaf(p, &writer);
- }
- }else{
- int bDummy;
- int nPos;
- int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
- nCopy += nPos;
- if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
- /* The entire poslist will fit on the current leaf. So copy
- ** it in one go. */
- fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
}else{
- /* The entire poslist will not fit on this leaf. So it needs
- ** to be broken into sections. The only qualification being
- ** that each varint must be stored contiguously. */
- const u8 *pPoslist = &pDoclist[iOff];
- int iPos = 0;
- while( p->rc==SQLITE_OK ){
- int nSpace = pgsz - pBuf->n - pPgidx->n;
- int n = 0;
- if( (nCopy - iPos)<=nSpace ){
- n = nCopy - iPos;
- }else{
- n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
- }
- assert( n>0 );
- fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
- iPos += n;
- if( (pBuf->n + pPgidx->n)>=pgsz ){
- fts5WriteFlushLeaf(p, &writer);
+ int bDel = 0;
+ int nPos = 0;
+ int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDel);
+ if( bDel && bSecureDelete ){
+ fts5BufferAppendVarint(&p->rc, pBuf, nPos*2);
+ iOff += nCopy;
+ nCopy = nPos;
+ }else{
+ nCopy += nPos;
+ }
+ if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
+ /* The entire poslist will fit on the current leaf. So copy
+ ** it in one go. */
+ fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
+ }else{
+ /* The entire poslist will not fit on this leaf. So it needs
+ ** to be broken into sections. The only qualification being
+ ** that each varint must be stored contiguously. */
+ const u8 *pPoslist = &pDoclist[iOff];
+ int iPos = 0;
+ while( p->rc==SQLITE_OK ){
+ int nSpace = pgsz - pBuf->n - pPgidx->n;
+ int n = 0;
+ if( (nCopy - iPos)<=nSpace ){
+ n = nCopy - iPos;
+ }else{
+ n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
+ }
+ assert( n>0 );
+ fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
+ iPos += n;
+ if( (pBuf->n + pPgidx->n)>=pgsz ){
+ fts5WriteFlushLeaf(p, &writer);
+ }
+ if( iPos>=nCopy ) break;
}
- if( iPos>=nCopy ) break;
}
+ iOff += nCopy;
}
- iOff += nCopy;
}
}
- }
- /* TODO2: Doclist terminator written here. */
- /* pBuf->p[pBuf->n++] = '\0'; */
- assert( pBuf->n<=pBuf->nSpace );
- if( p->rc==SQLITE_OK ) sqlcipher_sqlite3Fts5HashScanNext(pHash);
- }
- sqlcipher_sqlite3Fts5HashClear(pHash);
- fts5WriteFinish(p, &writer, &pgnoLast);
+ /* TODO2: Doclist terminator written here. */
+ /* pBuf->p[pBuf->n++] = '\0'; */
+ assert( pBuf->n<=pBuf->nSpace );
+ if( p->rc==SQLITE_OK ) sqlcipher_sqlite3Fts5HashScanNext(pHash);
+ }
+ fts5WriteFinish(p, &writer, &pgnoLast);
- /* Update the Fts5Structure. It is written back to the database by the
- ** fts5StructureRelease() call below. */
- if( pStruct->nLevel==0 ){
- fts5StructureAddLevel(&p->rc, &pStruct);
- }
- fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
- if( p->rc==SQLITE_OK ){
- pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
- pSeg->iSegid = iSegid;
- pSeg->pgnoFirst = 1;
- pSeg->pgnoLast = pgnoLast;
- pStruct->nSegment++;
+ assert( p->rc!=SQLITE_OK || bSecureDelete || pgnoLast>0 );
+ if( pgnoLast>0 ){
+ /* Update the Fts5Structure. It is written back to the database by the
+ ** fts5StructureRelease() call below. */
+ if( pStruct->nLevel==0 ){
+ fts5StructureAddLevel(&p->rc, &pStruct);
+ }
+ fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
+ if( p->rc==SQLITE_OK ){
+ pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
+ pSeg->iSegid = iSegid;
+ pSeg->pgnoFirst = 1;
+ pSeg->pgnoLast = pgnoLast;
+ if( pStruct->nOriginCntr>0 ){
+ pSeg->iOrigin1 = pStruct->nOriginCntr;
+ pSeg->iOrigin2 = pStruct->nOriginCntr;
+ pSeg->nEntry = p->nPendingRow;
+ pStruct->nOriginCntr++;
+ }
+ pStruct->nSegment++;
+ }
+ fts5StructurePromote(p, 0, pStruct);
+ }
}
- fts5StructurePromote(p, 0, pStruct);
}
- fts5IndexAutomerge(p, &pStruct, pgnoLast);
+ fts5IndexAutomerge(p, &pStruct, pgnoLast + p->nContentlessDelete);
fts5IndexCrisismerge(p, &pStruct);
fts5StructureWrite(p, pStruct);
fts5StructureRelease(pStruct);
@@ -237270,10 +251534,21 @@ static void fts5FlushOneHash(Fts5Index *p){
*/
static void fts5IndexFlush(Fts5Index *p){
/* Unless it is empty, flush the hash table to disk */
- if( p->nPendingData ){
+ if( p->flushRc ){
+ p->rc = p->flushRc;
+ return;
+ }
+ if( p->nPendingData || p->nContentlessDelete ){
assert( p->pHash );
- p->nPendingData = 0;
fts5FlushOneHash(p);
+ if( p->rc==SQLITE_OK ){
+ sqlcipher_sqlite3Fts5HashClear(p->pHash);
+ p->nPendingData = 0;
+ p->nPendingRow = 0;
+ p->nContentlessDelete = 0;
+ }else if( p->nPendingData || p->nContentlessDelete ){
+ p->flushRc = p->rc;
+ }
}
}
@@ -237289,17 +251564,22 @@ static Fts5Structure *fts5IndexOptimizeStruct(
/* Figure out if this structure requires optimization. A structure does
** not require optimization if either:
**
- ** + it consists of fewer than two segments, or
- ** + all segments are on the same level, or
- ** + all segments except one are currently inputs to a merge operation.
+ ** 1. it consists of fewer than two segments, or
+ ** 2. all segments are on the same level, or
+ ** 3. all segments except one are currently inputs to a merge operation.
**
- ** In the first case, return NULL. In the second, increment the ref-count
- ** on *pStruct and return a copy of the pointer to it.
+ ** In the first case, if there are no tombstone hash pages, return NULL. In
+ ** the second, increment the ref-count on *pStruct and return a copy of the
+ ** pointer to it.
*/
- if( nSeg<2 ) return 0;
+ if( nSeg==0 ) return 0;
for(i=0; i<pStruct->nLevel; i++){
int nThis = pStruct->aLevel[i].nSeg;
- if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){
+ int nMerge = pStruct->aLevel[i].nMerge;
+ if( nThis>0 && (nThis==nSeg || (nThis==nSeg-1 && nMerge==nThis)) ){
+ if( nSeg==1 && nThis==1 && pStruct->aLevel[i].aSeg[0].nPgTombstone==0 ){
+ return 0;
+ }
fts5StructureRef(pStruct);
return pStruct;
}
@@ -237312,10 +251592,11 @@ static Fts5Structure *fts5IndexOptimizeStruct(
if( pNew ){
Fts5StructureLevel *pLvl;
nByte = nSeg * sizeof(Fts5StructureSegment);
- pNew->nLevel = pStruct->nLevel+1;
+ pNew->nLevel = MIN(pStruct->nLevel+1, FTS5_MAX_LEVEL);
pNew->nRef = 1;
pNew->nWriteCounter = pStruct->nWriteCounter;
- pLvl = &pNew->aLevel[pStruct->nLevel];
+ pNew->nOriginCntr = pStruct->nOriginCntr;
+ pLvl = &pNew->aLevel[pNew->nLevel-1];
pLvl->aSeg = (Fts5StructureSegment*)sqlcipher_sqlite3Fts5MallocZero(&p->rc, nByte);
if( pLvl->aSeg ){
int iLvl, iSeg;
@@ -237345,7 +251626,9 @@ static int sqlcipher_sqlite3Fts5IndexOptimize(Fts5Index *p){
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
+ assert( p->rc!=SQLITE_OK || p->nContentlessDelete==0 );
pStruct = fts5StructureRead(p);
+ assert( p->rc!=SQLITE_OK || pStruct!=0 );
fts5StructureInvalidate(p);
if( pStruct ){
@@ -237374,7 +251657,10 @@ static int sqlcipher_sqlite3Fts5IndexOptimize(Fts5Index *p){
** INSERT command.
*/
static int sqlcipher_sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
- Fts5Structure *pStruct = fts5StructureRead(p);
+ Fts5Structure *pStruct = 0;
+
+ fts5IndexFlush(p);
+ pStruct = fts5StructureRead(p);
if( pStruct ){
int nMin = p->pConfig->nUsermerge;
fts5StructureInvalidate(p);
@@ -237382,7 +251668,7 @@ static int sqlcipher_sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct);
fts5StructureRelease(pStruct);
pStruct = pNew;
- nMin = 2;
+ nMin = 1;
nMerge = nMerge*-1;
}
if( pStruct && pStruct->nLevel ){
@@ -237397,7 +251683,7 @@ static int sqlcipher_sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
static void fts5AppendRowid(
Fts5Index *p,
- i64 iDelta,
+ u64 iDelta,
Fts5Iter *pUnused,
Fts5Buffer *pBuf
){
@@ -237407,7 +251693,7 @@ static void fts5AppendRowid(
static void fts5AppendPoslist(
Fts5Index *p,
- i64 iDelta,
+ u64 iDelta,
Fts5Iter *pMulti,
Fts5Buffer *pBuf
){
@@ -237482,10 +251768,10 @@ static void fts5MergeAppendDocid(
}
#endif
-#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
- assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
- fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \
- (iLastRowid) = (iRowid); \
+#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
+ assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
+ fts5BufferSafeAppendVarint((pBuf), (u64)(iRowid) - (u64)(iLastRowid)); \
+ (iLastRowid) = (iRowid); \
}
/*
@@ -237617,7 +251903,7 @@ static void fts5MergePrefixLists(
/* Initialize a doclist-iterator for each input buffer. Arrange them in
** a linked-list starting at pHead in ascending order of rowid. Avoid
** linking any iterators already at EOF into the linked list at all. */
- assert( nBuf+1<=sizeof(aMerger)/sizeof(aMerger[0]) );
+ assert( nBuf+1<=(int)(sizeof(aMerger)/sizeof(aMerger[0])) );
memset(aMerger, 0, sizeof(PrefixMerger)*(nBuf+1));
pHead = &aMerger[nBuf];
fts5DoclistIterInit(p1, &pHead->iter);
@@ -237748,7 +252034,7 @@ static void fts5SetupPrefixIter(
u8 *pToken, /* Buffer containing prefix to match */
int nToken, /* Size of buffer pToken in bytes */
Fts5Colset *pColset, /* Restrict matches to these columns */
- Fts5Iter **ppIter /* OUT: New iterator */
+ Fts5Iter **ppIter /* OUT: New iterator */
){
Fts5Structure *pStruct;
Fts5Buffer *aBuf;
@@ -237756,7 +252042,7 @@ static void fts5SetupPrefixIter(
int nMerge = 1;
void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
- void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*);
+ void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
xMerge = fts5MergeRowidLists;
xAppend = fts5AppendRowid;
@@ -237769,8 +252055,9 @@ static void fts5SetupPrefixIter(
aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
pStruct = fts5StructureRead(p);
+ assert( p->rc!=SQLITE_OK || (aBuf && pStruct) );
- if( aBuf && pStruct ){
+ if( p->rc==SQLITE_OK ){
const int flags = FTS5INDEX_QUERY_SCAN
| FTS5INDEX_QUERY_SKIPEMPTY
| FTS5INDEX_QUERY_NOOUTPUT;
@@ -237782,6 +252069,12 @@ static void fts5SetupPrefixIter(
int bNewTerm = 1;
memset(&doclist, 0, sizeof(doclist));
+
+ /* If iIdx is non-zero, then it is the number of a prefix-index for
+ ** prefixes 1 character longer than the prefix being queried for. That
+ ** index contains all the doclists required, except for the one
+ ** corresponding to the prefix itself. That one is extracted from the
+ ** main term index here. */
if( iIdx!=0 ){
int dummy = 0;
const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT;
@@ -237795,7 +252088,7 @@ static void fts5SetupPrefixIter(
Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
p1->xSetOutputs(p1, pSeg);
if( p1->base.nData ){
- xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
+ xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
iLastRowid = p1->base.iRowid;
}
}
@@ -237805,6 +252098,7 @@ static void fts5SetupPrefixIter(
pToken[0] = FTS5_MAIN_PREFIX + iIdx;
fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
fts5IterSetOutputCb(&p->rc, p1);
+
for( /* no-op */ ;
fts5MultiIterEof(p, p1)==0;
fts5MultiIterNext2(p, p1, &bNewTerm)
@@ -237820,7 +252114,6 @@ static void fts5SetupPrefixIter(
}
if( p1->base.nData==0 ) continue;
-
if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
int i1 = i*nMerge;
@@ -237843,7 +252136,7 @@ static void fts5SetupPrefixIter(
iLastRowid = 0;
}
- xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
+ xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
iLastRowid = p1->base.iRowid;
}
@@ -237859,7 +252152,7 @@ static void fts5SetupPrefixIter(
}
fts5MultiIterFree(p1);
- pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING);
+ pData = fts5IdxMalloc(p, sizeof(*pData)+doclist.n+FTS5_DATA_ZERO_PADDING);
if( pData ){
pData->p = (u8*)&pData[1];
pData->nn = pData->szLeaf = doclist.n;
@@ -237896,6 +252189,9 @@ static int sqlcipher_sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 i
p->iWriteRowid = iRowid;
p->bDelete = bDelete;
+ if( bDelete==0 ){
+ p->nPendingRow++;
+ }
return fts5IndexReturn(p);
}
@@ -237933,6 +252229,9 @@ static int sqlcipher_sqlite3Fts5IndexReinit(Fts5Index *p){
fts5StructureInvalidate(p);
fts5IndexDiscardData(p);
memset(&s, 0, sizeof(Fts5Structure));
+ if( p->pConfig->bContentlessDelete ){
+ s.nOriginCntr = 1;
+ }
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
fts5StructureWrite(p, &s);
return fts5IndexReturn(p);
@@ -237996,7 +252295,9 @@ static int sqlcipher_sqlite3Fts5IndexClose(Fts5Index *p){
sqlcipher_sqlite3_finalize(p->pIdxWriter);
sqlcipher_sqlite3_finalize(p->pIdxDeleter);
sqlcipher_sqlite3_finalize(p->pIdxSelect);
+ sqlcipher_sqlite3_finalize(p->pIdxNextSelect);
sqlcipher_sqlite3_finalize(p->pDataVersion);
+ sqlcipher_sqlite3_finalize(p->pDeleteFromIdx);
sqlcipher_sqlite3Fts5HashFree(p->pHash);
sqlcipher_sqlite3_free(p->zDataTbl);
sqlcipher_sqlite3_free(p);
@@ -238091,6 +252392,457 @@ static int sqlcipher_sqlite3Fts5IndexWrite(
}
/*
+** pToken points to a buffer of size nToken bytes containing a search
+** term, including the index number at the start, used on a tokendata=1
+** table. This function returns true if the term in buffer pBuf matches
+** token pToken/nToken.
+*/
+static int fts5IsTokendataPrefix(
+ Fts5Buffer *pBuf,
+ const u8 *pToken,
+ int nToken
+){
+ return (
+ pBuf->n>=nToken
+ && 0==memcmp(pBuf->p, pToken, nToken)
+ && (pBuf->n==nToken || pBuf->p[nToken]==0x00)
+ );
+}
+
+/*
+** Ensure the segment-iterator passed as the only argument points to EOF.
+*/
+static void fts5SegIterSetEOF(Fts5SegIter *pSeg){
+ fts5DataRelease(pSeg->pLeaf);
+ pSeg->pLeaf = 0;
+}
+
+/*
+** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
+** array of these for each row it visits. Or, for an iterator used by an
+** "ORDER BY rank" query, it accumulates an array of these for the entire
+** query.
+**
+** Each instance in the array indicates the iterator (and therefore term)
+** associated with position iPos of rowid iRowid. This is used by the
+** xInstToken() API.
+*/
+struct Fts5TokenDataMap {
+ i64 iRowid; /* Row this token is located in */
+ i64 iPos; /* Position of token */
+ int iIter; /* Iterator token was read from */
+};
+
+/*
+** An object used to supplement Fts5Iter for tokendata=1 iterators.
+*/
+struct Fts5TokenDataIter {
+ int nIter;
+ int nIterAlloc;
+
+ int nMap;
+ int nMapAlloc;
+ Fts5TokenDataMap *aMap;
+
+ Fts5PoslistReader *aPoslistReader;
+ int *aPoslistToIter;
+ Fts5Iter *apIter[1];
+};
+
+/*
+** This function appends iterator pAppend to Fts5TokenDataIter pIn and
+** returns the result.
+*/
+static Fts5TokenDataIter *fts5AppendTokendataIter(
+ Fts5Index *p, /* Index object (for error code) */
+ Fts5TokenDataIter *pIn, /* Current Fts5TokenDataIter struct */
+ Fts5Iter *pAppend /* Append this iterator */
+){
+ Fts5TokenDataIter *pRet = pIn;
+
+ if( p->rc==SQLITE_OK ){
+ if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
+ int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
+ int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter);
+ Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlcipher_sqlite3_realloc(pIn, nByte);
+
+ if( pNew==0 ){
+ p->rc = SQLITE_NOMEM;
+ }else{
+ if( pIn==0 ) memset(pNew, 0, nByte);
+ pRet = pNew;
+ pNew->nIterAlloc = nAlloc;
+ }
+ }
+ }
+ if( p->rc ){
+ sqlcipher_sqlite3Fts5IterClose((Fts5IndexIter*)pAppend);
+ }else{
+ pRet->apIter[pRet->nIter++] = pAppend;
+ }
+ assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc );
+
+ return pRet;
+}
+
+/*
+** Delete an Fts5TokenDataIter structure and its contents.
+*/
+static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
+ if( pSet ){
+ int ii;
+ for(ii=0; ii<pSet->nIter; ii++){
+ fts5MultiIterFree(pSet->apIter[ii]);
+ }
+ sqlcipher_sqlite3_free(pSet->aPoslistReader);
+ sqlcipher_sqlite3_free(pSet->aMap);
+ sqlcipher_sqlite3_free(pSet);
+ }
+}
+
+/*
+** Append a mapping to the token-map belonging to object pT.
+*/
+static void fts5TokendataIterAppendMap(
+ Fts5Index *p,
+ Fts5TokenDataIter *pT,
+ int iIter,
+ i64 iRowid,
+ i64 iPos
+){
+ if( p->rc==SQLITE_OK ){
+ if( pT->nMap==pT->nMapAlloc ){
+ int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
+ int nByte = nNew * sizeof(Fts5TokenDataMap);
+ Fts5TokenDataMap *aNew;
+
+ aNew = (Fts5TokenDataMap*)sqlcipher_sqlite3_realloc(pT->aMap, nByte);
+ if( aNew==0 ){
+ p->rc = SQLITE_NOMEM;
+ return;
+ }
+
+ pT->aMap = aNew;
+ pT->nMapAlloc = nNew;
+ }
+
+ pT->aMap[pT->nMap].iRowid = iRowid;
+ pT->aMap[pT->nMap].iPos = iPos;
+ pT->aMap[pT->nMap].iIter = iIter;
+ pT->nMap++;
+ }
+}
+
+/*
+** The iterator passed as the only argument must be a tokendata=1 iterator
+** (pIter->pTokenDataIter!=0). This function sets the iterator output
+** variables (pIter->base.*) according to the contents of the current
+** row.
+*/
+static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){
+ int ii;
+ int nHit = 0;
+ i64 iRowid = SMALLEST_INT64;
+ int iMin = 0;
+
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+
+ pIter->base.nData = 0;
+ pIter->base.pData = 0;
+
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( p->base.bEof==0 ){
+ if( nHit==0 || p->base.iRowid<iRowid ){
+ iRowid = p->base.iRowid;
+ nHit = 1;
+ pIter->base.pData = p->base.pData;
+ pIter->base.nData = p->base.nData;
+ iMin = ii;
+ }else if( p->base.iRowid==iRowid ){
+ nHit++;
+ }
+ }
+ }
+
+ if( nHit==0 ){
+ pIter->base.bEof = 1;
+ }else{
+ int eDetail = pIter->pIndex->pConfig->eDetail;
+ pIter->base.bEof = 0;
+ pIter->base.iRowid = iRowid;
+
+ if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){
+ fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, iRowid, -1);
+ }else
+ if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){
+ int nReader = 0;
+ int nByte = 0;
+ i64 iPrev = 0;
+
+ /* Allocate array of iterators if they are not already allocated. */
+ if( pT->aPoslistReader==0 ){
+ pT->aPoslistReader = (Fts5PoslistReader*)sqlcipher_sqlite3Fts5MallocZero(
+ &pIter->pIndex->rc,
+ pT->nIter * (sizeof(Fts5PoslistReader) + sizeof(int))
+ );
+ if( pT->aPoslistReader==0 ) return;
+ pT->aPoslistToIter = (int*)&pT->aPoslistReader[pT->nIter];
+ }
+
+ /* Populate an iterator for each poslist that will be merged */
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( iRowid==p->base.iRowid ){
+ pT->aPoslistToIter[nReader] = ii;
+ sqlcipher_sqlite3Fts5PoslistReaderInit(
+ p->base.pData, p->base.nData, &pT->aPoslistReader[nReader++]
+ );
+ nByte += p->base.nData;
+ }
+ }
+
+ /* Ensure the output buffer is large enough */
+ if( fts5BufferGrow(&pIter->pIndex->rc, &pIter->poslist, nByte+nHit*10) ){
+ return;
+ }
+
+ /* Ensure the token-mapping is large enough */
+ if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){
+ int nNew = (pT->nMapAlloc + nByte) * 2;
+ Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlcipher_sqlite3_realloc(
+ pT->aMap, nNew*sizeof(Fts5TokenDataMap)
+ );
+ if( aNew==0 ){
+ pIter->pIndex->rc = SQLITE_NOMEM;
+ return;
+ }
+ pT->aMap = aNew;
+ pT->nMapAlloc = nNew;
+ }
+
+ pIter->poslist.n = 0;
+
+ while( 1 ){
+ i64 iMinPos = LARGEST_INT64;
+
+ /* Find smallest position */
+ iMin = 0;
+ for(ii=0; ii<nReader; ii++){
+ Fts5PoslistReader *pReader = &pT->aPoslistReader[ii];
+ if( pReader->bEof==0 ){
+ if( pReader->iPos<iMinPos ){
+ iMinPos = pReader->iPos;
+ iMin = ii;
+ }
+ }
+ }
+
+ /* If all readers were at EOF, break out of the loop. */
+ if( iMinPos==LARGEST_INT64 ) break;
+
+ sqlcipher_sqlite3Fts5PoslistSafeAppend(&pIter->poslist, &iPrev, iMinPos);
+ sqlcipher_sqlite3Fts5PoslistReaderNext(&pT->aPoslistReader[iMin]);
+
+ if( eDetail==FTS5_DETAIL_FULL ){
+ pT->aMap[pT->nMap].iPos = iMinPos;
+ pT->aMap[pT->nMap].iIter = pT->aPoslistToIter[iMin];
+ pT->aMap[pT->nMap].iRowid = iRowid;
+ pT->nMap++;
+ }
+ }
+
+ pIter->base.pData = pIter->poslist.p;
+ pIter->base.nData = pIter->poslist.n;
+ }
+ }
+}
+
+/*
+** The iterator passed as the only argument must be a tokendata=1 iterator
+** (pIter->pTokenDataIter!=0). This function advances the iterator. If
+** argument bFrom is false, then the iterator is advanced to the next
+** entry. Or, if bFrom is true, it is advanced to the first entry with
+** a rowid of iFrom or greater.
+*/
+static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){
+ int ii;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ Fts5Index *pIndex = pIter->pIndex;
+
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( p->base.bEof==0
+ && (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowid<iFrom))
+ ){
+ fts5MultiIterNext(pIndex, p, bFrom, iFrom);
+ while( bFrom && p->base.bEof==0
+ && p->base.iRowid<iFrom
+ && pIndex->rc==SQLITE_OK
+ ){
+ fts5MultiIterNext(pIndex, p, 0, 0);
+ }
+ }
+ }
+
+ if( pIndex->rc==SQLITE_OK ){
+ fts5IterSetOutputsTokendata(pIter);
+ }
+}
+
+/*
+** If the segment-iterator passed as the first argument is at EOF, then
+** set pIter->term to a copy of buffer pTerm.
+*/
+static void fts5TokendataSetTermIfEof(Fts5Iter *pIter, Fts5Buffer *pTerm){
+ if( pIter && pIter->aSeg[0].pLeaf==0 ){
+ fts5BufferSet(&pIter->pIndex->rc, &pIter->aSeg[0].term, pTerm->n, pTerm->p);
+ }
+}
+
+/*
+** This function sets up an iterator to use for a non-prefix query on a
+** tokendata=1 table.
+*/
+static Fts5Iter *fts5SetupTokendataIter(
+ Fts5Index *p, /* FTS index to query */
+ const u8 *pToken, /* Buffer containing query term */
+ int nToken, /* Size of buffer pToken in bytes */
+ Fts5Colset *pColset /* Colset to filter on */
+){
+ Fts5Iter *pRet = 0;
+ Fts5TokenDataIter *pSet = 0;
+ Fts5Structure *pStruct = 0;
+ const int flags = FTS5INDEX_QUERY_SCANONETERM | FTS5INDEX_QUERY_SCAN;
+
+ Fts5Buffer bSeek = {0, 0, 0};
+ Fts5Buffer *pSmall = 0;
+
+ fts5IndexFlush(p);
+ pStruct = fts5StructureRead(p);
+
+ while( p->rc==SQLITE_OK ){
+ Fts5Iter *pPrev = pSet ? pSet->apIter[pSet->nIter-1] : 0;
+ Fts5Iter *pNew = 0;
+ Fts5SegIter *pNewIter = 0;
+ Fts5SegIter *pPrevIter = 0;
+
+ int iLvl, iSeg, ii;
+
+ pNew = fts5MultiIterAlloc(p, pStruct->nSegment);
+ if( pSmall ){
+ fts5BufferSet(&p->rc, &bSeek, pSmall->n, pSmall->p);
+ fts5BufferAppendBlob(&p->rc, &bSeek, 1, (const u8*)"\0");
+ }else{
+ fts5BufferSet(&p->rc, &bSeek, nToken, pToken);
+ }
+ if( p->rc ){
+ sqlcipher_sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
+ break;
+ }
+
+ pNewIter = &pNew->aSeg[0];
+ pPrevIter = (pPrev ? &pPrev->aSeg[0] : 0);
+ for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+ for(iSeg=pStruct->aLevel[iLvl].nSeg-1; iSeg>=0; iSeg--){
+ Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
+ int bDone = 0;
+
+ if( pPrevIter ){
+ if( fts5BufferCompare(pSmall, &pPrevIter->term) ){
+ memcpy(pNewIter, pPrevIter, sizeof(Fts5SegIter));
+ memset(pPrevIter, 0, sizeof(Fts5SegIter));
+ bDone = 1;
+ }else if( pPrevIter->iEndofDoclist>pPrevIter->pLeaf->szLeaf ){
+ fts5SegIterNextInit(p,(const char*)bSeek.p,bSeek.n-1,pSeg,pNewIter);
+ bDone = 1;
+ }
+ }
+
+ if( bDone==0 ){
+ fts5SegIterSeekInit(p, bSeek.p, bSeek.n, flags, pSeg, pNewIter);
+ }
+
+ if( pPrevIter ){
+ if( pPrevIter->pTombArray ){
+ pNewIter->pTombArray = pPrevIter->pTombArray;
+ pNewIter->pTombArray->nRef++;
+ }
+ }else{
+ fts5SegIterAllocTombstone(p, pNewIter);
+ }
+
+ pNewIter++;
+ if( pPrevIter ) pPrevIter++;
+ if( p->rc ) break;
+ }
+ }
+ fts5TokendataSetTermIfEof(pPrev, pSmall);
+
+ pNew->bSkipEmpty = 1;
+ pNew->pColset = pColset;
+ fts5IterSetOutputCb(&p->rc, pNew);
+
+ /* Loop through all segments in the new iterator. Find the smallest
+ ** term that any segment-iterator points to. Iterator pNew will be
+ ** used for this term. Also, set any iterator that points to a term that
+ ** does not match pToken/nToken to point to EOF */
+ pSmall = 0;
+ for(ii=0; ii<pNew->nSeg; ii++){
+ Fts5SegIter *pII = &pNew->aSeg[ii];
+ if( 0==fts5IsTokendataPrefix(&pII->term, pToken, nToken) ){
+ fts5SegIterSetEOF(pII);
+ }
+ if( pII->pLeaf && (!pSmall || fts5BufferCompare(pSmall, &pII->term)>0) ){
+ pSmall = &pII->term;
+ }
+ }
+
+ /* If pSmall is still NULL at this point, then the new iterator does
+ ** not point to any terms that match the query. So delete it and break
+ ** out of the loop - all required iterators have been collected. */
+ if( pSmall==0 ){
+ sqlcipher_sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
+ break;
+ }
+
+ /* Append this iterator to the set and continue. */
+ pSet = fts5AppendTokendataIter(p, pSet, pNew);
+ }
+
+ if( p->rc==SQLITE_OK && pSet ){
+ int ii;
+ for(ii=0; ii<pSet->nIter; ii++){
+ Fts5Iter *pIter = pSet->apIter[ii];
+ int iSeg;
+ for(iSeg=0; iSeg<pIter->nSeg; iSeg++){
+ pIter->aSeg[iSeg].flags |= FTS5_SEGITER_ONETERM;
+ }
+ fts5MultiIterFinishSetup(p, pIter);
+ }
+ }
+
+ if( p->rc==SQLITE_OK ){
+ pRet = fts5MultiIterAlloc(p, 0);
+ }
+ if( pRet ){
+ pRet->pTokenDataIter = pSet;
+ if( pSet ){
+ fts5IterSetOutputsTokendata(pRet);
+ }else{
+ pRet->base.bEof = 1;
+ }
+ }else{
+ fts5TokendataIterDelete(pSet);
+ }
+
+ fts5StructureRelease(pStruct);
+ fts5BufferFree(&bSeek);
+ return pRet;
+}
+
+
+/*
** Open a new iterator to iterate though all rowid that match the
** specified token or token prefix.
*/
@@ -238111,8 +252863,13 @@ static int sqlcipher_sqlite3Fts5IndexQuery(
if( sqlcipher_sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
int iIdx = 0; /* Index to search */
int iPrefixIdx = 0; /* +1 prefix index */
+ int bTokendata = pConfig->bTokendata;
if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
+ if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){
+ bTokendata = 0;
+ }
+
/* Figure out which index to search and set iIdx accordingly. If this
** is a prefix query for which there is no prefix index, set iIdx to
** greater than pConfig->nPrefix to indicate that the query will be
@@ -238138,7 +252895,10 @@ static int sqlcipher_sqlite3Fts5IndexQuery(
}
}
- if( iIdx<=pConfig->nPrefix ){
+ if( bTokendata && iIdx==0 ){
+ buf.p[0] = '0';
+ pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset);
+ }else if( iIdx<=pConfig->nPrefix ){
/* Straight index lookup */
Fts5Structure *pStruct = fts5StructureRead(p);
buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
@@ -238185,7 +252945,11 @@ static int sqlcipher_sqlite3Fts5IndexQuery(
static int sqlcipher_sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
assert( pIter->pIndex->rc==SQLITE_OK );
- fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
+ if( pIter->pTokenDataIter ){
+ fts5TokendataIterNext(pIter, 0, 0);
+ }else{
+ fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
+ }
return fts5IndexReturn(pIter->pIndex);
}
@@ -238218,7 +252982,11 @@ static int sqlcipher_sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){
*/
static int sqlcipher_sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
+ if( pIter->pTokenDataIter ){
+ fts5TokendataIterNext(pIter, 1, iMatch);
+ }else{
+ fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
+ }
return fts5IndexReturn(pIter->pIndex);
}
@@ -238234,12 +253002,106 @@ static const char *sqlcipher_sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int
}
/*
+** This is used by xInstToken() to access the token at offset iOff, column
+** iCol of row iRowid. The token is returned via output variables *ppOut
+** and *pnOut. The iterator passed as the first argument must be a tokendata=1
+** iterator (pIter->pTokenDataIter!=0).
+*/
+static int sqlcipher_sqlite3Fts5IterToken(
+ Fts5IndexIter *pIndexIter,
+ i64 iRowid,
+ int iCol,
+ int iOff,
+ const char **ppOut, int *pnOut
+){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ Fts5TokenDataMap *aMap = pT->aMap;
+ i64 iPos = (((i64)iCol)<<32) + iOff;
+
+ int i1 = 0;
+ int i2 = pT->nMap;
+ int iTest = 0;
+
+ while( i2>i1 ){
+ iTest = (i1 + i2) / 2;
+
+ if( aMap[iTest].iRowid<iRowid ){
+ i1 = iTest+1;
+ }else if( aMap[iTest].iRowid>iRowid ){
+ i2 = iTest;
+ }else{
+ if( aMap[iTest].iPos<iPos ){
+ if( aMap[iTest].iPos<0 ){
+ break;
+ }
+ i1 = iTest+1;
+ }else if( aMap[iTest].iPos>iPos ){
+ i2 = iTest;
+ }else{
+ break;
+ }
+ }
+ }
+
+ if( i2>i1 ){
+ Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
+ *ppOut = (const char*)pMap->aSeg[0].term.p+1;
+ *pnOut = pMap->aSeg[0].term.n-1;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Clear any existing entries from the token-map associated with the
+** iterator passed as the only argument.
+*/
+static void sqlcipher_sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ if( pIter && pIter->pTokenDataIter ){
+ pIter->pTokenDataIter->nMap = 0;
+ }
+}
+
+/*
+** Set a token-mapping for the iterator passed as the first argument. This
+** is used in detail=column or detail=none mode when a token is requested
+** using the xInstToken() API. In this case the caller tokenizers the
+** current row and configures the token-mapping via multiple calls to this
+** function.
+*/
+static int sqlcipher_sqlite3Fts5IndexIterWriteTokendata(
+ Fts5IndexIter *pIndexIter,
+ const char *pToken, int nToken,
+ i64 iRowid, int iCol, int iOff
+){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ Fts5Index *p = pIter->pIndex;
+ int ii;
+
+ assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL );
+ assert( pIter->pTokenDataIter );
+
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
+ if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
+ }
+ if( ii<pT->nIter ){
+ fts5TokendataIterAppendMap(p, pT, ii, iRowid, (((i64)iCol)<<32) + iOff);
+ }
+ return fts5IndexReturn(p);
+}
+
+/*
** Close an iterator opened by an earlier call to sqlcipher_sqlite3Fts5IndexQuery().
*/
static void sqlcipher_sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
if( pIndexIter ){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
Fts5Index *pIndex = pIter->pIndex;
+ fts5TokendataIterDelete(pIter->pTokenDataIter);
fts5MultiIterFree(pIter);
sqlcipher_sqlite3Fts5IndexCloseReader(pIndex);
}
@@ -238323,6 +253185,347 @@ static int sqlcipher_sqlite3Fts5IndexLoadConfig(Fts5Index *p){
return fts5IndexReturn(p);
}
+/*
+** Retrieve the origin value that will be used for the segment currently
+** being accumulated in the in-memory hash table when it is flushed to
+** disk. If successful, SQLITE_OK is returned and (*piOrigin) set to
+** the queried value. Or, if an error occurs, an error code is returned
+** and the final value of (*piOrigin) is undefined.
+*/
+static int sqlcipher_sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin){
+ Fts5Structure *pStruct;
+ pStruct = fts5StructureRead(p);
+ if( pStruct ){
+ *piOrigin = pStruct->nOriginCntr;
+ fts5StructureRelease(pStruct);
+ }
+ return fts5IndexReturn(p);
+}
+
+/*
+** Buffer pPg contains a page of a tombstone hash table - one of nPg pages
+** associated with the same segment. This function adds rowid iRowid to
+** the hash table. The caller is required to guarantee that there is at
+** least one free slot on the page.
+**
+** If parameter bForce is false and the hash table is deemed to be full
+** (more than half of the slots are occupied), then non-zero is returned
+** and iRowid not inserted. Or, if bForce is true or if the hash table page
+** is not full, iRowid is inserted and zero returned.
+*/
+static int fts5IndexTombstoneAddToPage(
+ Fts5Data *pPg,
+ int bForce,
+ int nPg,
+ u64 iRowid
+){
+ const int szKey = TOMBSTONE_KEYSIZE(pPg);
+ const int nSlot = TOMBSTONE_NSLOT(pPg);
+ const int nElem = fts5GetU32(&pPg->p[4]);
+ int iSlot = (iRowid / nPg) % nSlot;
+ int nCollide = nSlot;
+
+ if( szKey==4 && iRowid>0xFFFFFFFF ) return 2;
+ if( iRowid==0 ){
+ pPg->p[1] = 0x01;
+ return 0;
+ }
+
+ if( bForce==0 && nElem>=(nSlot/2) ){
+ return 1;
+ }
+
+ fts5PutU32(&pPg->p[4], nElem+1);
+ if( szKey==4 ){
+ u32 *aSlot = (u32*)&pPg->p[8];
+ while( aSlot[iSlot] ){
+ iSlot = (iSlot + 1) % nSlot;
+ if( nCollide--==0 ) return 0;
+ }
+ fts5PutU32((u8*)&aSlot[iSlot], (u32)iRowid);
+ }else{
+ u64 *aSlot = (u64*)&pPg->p[8];
+ while( aSlot[iSlot] ){
+ iSlot = (iSlot + 1) % nSlot;
+ if( nCollide--==0 ) return 0;
+ }
+ fts5PutU64((u8*)&aSlot[iSlot], iRowid);
+ }
+
+ return 0;
+}
+
+/*
+** This function attempts to build a new hash containing all the keys
+** currently in the tombstone hash table for segment pSeg. The new
+** hash will be stored in the nOut buffers passed in array apOut[].
+** All pages of the new hash use key-size szKey (4 or 8).
+**
+** Return 0 if the hash is successfully rebuilt into the nOut pages.
+** Or non-zero if it is not (because one page became overfull). In this
+** case the caller should retry with a larger nOut parameter.
+**
+** Parameter pData1 is page iPg1 of the hash table being rebuilt.
+*/
+static int fts5IndexTombstoneRehash(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg, /* Segment to rebuild hash of */
+ Fts5Data *pData1, /* One page of current hash - or NULL */
+ int iPg1, /* Which page of the current hash is pData1 */
+ int szKey, /* 4 or 8, the keysize */
+ int nOut, /* Number of output pages */
+ Fts5Data **apOut /* Array of output hash pages */
+){
+ int ii;
+ int res = 0;
+
+ /* Initialize the headers of all the output pages */
+ for(ii=0; ii<nOut; ii++){
+ apOut[ii]->p[0] = szKey;
+ fts5PutU32(&apOut[ii]->p[4], 0);
+ }
+
+ /* Loop through the current pages of the hash table. */
+ for(ii=0; res==0 && ii<pSeg->nPgTombstone; ii++){
+ Fts5Data *pData = 0; /* Page ii of the current hash table */
+ Fts5Data *pFree = 0; /* Free this at the end of the loop */
+
+ if( iPg1==ii ){
+ pData = pData1;
+ }else{
+ pFree = pData = fts5DataRead(p, FTS5_TOMBSTONE_ROWID(pSeg->iSegid, ii));
+ }
+
+ if( pData ){
+ int szKeyIn = TOMBSTONE_KEYSIZE(pData);
+ int nSlotIn = (pData->nn - 8) / szKeyIn;
+ int iIn;
+ for(iIn=0; iIn<nSlotIn; iIn++){
+ u64 iVal = 0;
+
+ /* Read the value from slot iIn of the input page into iVal. */
+ if( szKeyIn==4 ){
+ u32 *aSlot = (u32*)&pData->p[8];
+ if( aSlot[iIn] ) iVal = fts5GetU32((u8*)&aSlot[iIn]);
+ }else{
+ u64 *aSlot = (u64*)&pData->p[8];
+ if( aSlot[iIn] ) iVal = fts5GetU64((u8*)&aSlot[iIn]);
+ }
+
+ /* If iVal is not 0 at this point, insert it into the new hash table */
+ if( iVal ){
+ Fts5Data *pPg = apOut[(iVal % nOut)];
+ res = fts5IndexTombstoneAddToPage(pPg, 0, nOut, iVal);
+ if( res ) break;
+ }
+ }
+
+ /* If this is page 0 of the old hash, copy the rowid-0-flag from the
+ ** old hash to the new. */
+ if( ii==0 ){
+ apOut[0]->p[1] = pData->p[1];
+ }
+ }
+ fts5DataRelease(pFree);
+ }
+
+ return res;
+}
+
+/*
+** This is called to rebuild the hash table belonging to segment pSeg.
+** If parameter pData1 is not NULL, then one page of the existing hash table
+** has already been loaded - pData1, which is page iPg1. The key-size for
+** the new hash table is szKey (4 or 8).
+**
+** If successful, the new hash table is not written to disk. Instead,
+** output parameter (*pnOut) is set to the number of pages in the new
+** hash table, and (*papOut) to point to an array of buffers containing
+** the new page data.
+**
+** If an error occurs, an error code is left in the Fts5Index object and
+** both output parameters set to 0 before returning.
+*/
+static void fts5IndexTombstoneRebuild(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg, /* Segment to rebuild hash of */
+ Fts5Data *pData1, /* One page of current hash - or NULL */
+ int iPg1, /* Which page of the current hash is pData1 */
+ int szKey, /* 4 or 8, the keysize */
+ int *pnOut, /* OUT: Number of output pages */
+ Fts5Data ***papOut /* OUT: Output hash pages */
+){
+ const int MINSLOT = 32;
+ int nSlotPerPage = MAX(MINSLOT, (p->pConfig->pgsz - 8) / szKey);
+ int nSlot = 0; /* Number of slots in each output page */
+ int nOut = 0;
+
+ /* Figure out how many output pages (nOut) and how many slots per
+ ** page (nSlot). There are three possibilities:
+ **
+ ** 1. The hash table does not yet exist. In this case the new hash
+ ** table will consist of a single page with MINSLOT slots.
+ **
+ ** 2. The hash table exists but is currently a single page. In this
+ ** case an attempt is made to grow the page to accommodate the new
+ ** entry. The page is allowed to grow up to nSlotPerPage (see above)
+ ** slots.
+ **
+ ** 3. The hash table already consists of more than one page, or of
+ ** a single page already so large that it cannot be grown. In this
+ ** case the new hash consists of (nPg*2+1) pages of nSlotPerPage
+ ** slots each, where nPg is the current number of pages in the
+ ** hash table.
+ */
+ if( pSeg->nPgTombstone==0 ){
+ /* Case 1. */
+ nOut = 1;
+ nSlot = MINSLOT;
+ }else if( pSeg->nPgTombstone==1 ){
+ /* Case 2. */
+ int nElem = (int)fts5GetU32(&pData1->p[4]);
+ assert( pData1 && iPg1==0 );
+ nOut = 1;
+ nSlot = MAX(nElem*4, MINSLOT);
+ if( nSlot>nSlotPerPage ) nOut = 0;
+ }
+ if( nOut==0 ){
+ /* Case 3. */
+ nOut = (pSeg->nPgTombstone * 2 + 1);
+ nSlot = nSlotPerPage;
+ }
+
+ /* Allocate the required array and output pages */
+ while( 1 ){
+ int res = 0;
+ int ii = 0;
+ int szPage = 0;
+ Fts5Data **apOut = 0;
+
+ /* Allocate space for the new hash table */
+ assert( nSlot>=MINSLOT );
+ apOut = (Fts5Data**)sqlcipher_sqlite3Fts5MallocZero(&p->rc, sizeof(Fts5Data*) * nOut);
+ szPage = 8 + nSlot*szKey;
+ for(ii=0; ii<nOut; ii++){
+ Fts5Data *pNew = (Fts5Data*)sqlcipher_sqlite3Fts5MallocZero(&p->rc,
+ sizeof(Fts5Data)+szPage
+ );
+ if( pNew ){
+ pNew->nn = szPage;
+ pNew->p = (u8*)&pNew[1];
+ apOut[ii] = pNew;
+ }
+ }
+
+ /* Rebuild the hash table. */
+ if( p->rc==SQLITE_OK ){
+ res = fts5IndexTombstoneRehash(p, pSeg, pData1, iPg1, szKey, nOut, apOut);
+ }
+ if( res==0 ){
+ if( p->rc ){
+ fts5IndexFreeArray(apOut, nOut);
+ apOut = 0;
+ nOut = 0;
+ }
+ *pnOut = nOut;
+ *papOut = apOut;
+ break;
+ }
+
+ /* If control flows to here, it was not possible to rebuild the hash
+ ** table. Free all buffers and then try again with more pages. */
+ assert( p->rc==SQLITE_OK );
+ fts5IndexFreeArray(apOut, nOut);
+ nSlot = nSlotPerPage;
+ nOut = nOut*2 + 1;
+ }
+}
+
+
+/*
+** Add a tombstone for rowid iRowid to segment pSeg.
+*/
+static void fts5IndexTombstoneAdd(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg,
+ u64 iRowid
+){
+ Fts5Data *pPg = 0;
+ int iPg = -1;
+ int szKey = 0;
+ int nHash = 0;
+ Fts5Data **apHash = 0;
+
+ p->nContentlessDelete++;
+
+ if( pSeg->nPgTombstone>0 ){
+ iPg = iRowid % pSeg->nPgTombstone;
+ pPg = fts5DataRead(p, FTS5_TOMBSTONE_ROWID(pSeg->iSegid,iPg));
+ if( pPg==0 ){
+ assert( p->rc!=SQLITE_OK );
+ return;
+ }
+
+ if( 0==fts5IndexTombstoneAddToPage(pPg, 0, pSeg->nPgTombstone, iRowid) ){
+ fts5DataWrite(p, FTS5_TOMBSTONE_ROWID(pSeg->iSegid,iPg), pPg->p, pPg->nn);
+ fts5DataRelease(pPg);
+ return;
+ }
+ }
+
+ /* Have to rebuild the hash table. First figure out the key-size (4 or 8). */
+ szKey = pPg ? TOMBSTONE_KEYSIZE(pPg) : 4;
+ if( iRowid>0xFFFFFFFF ) szKey = 8;
+
+ /* Rebuild the hash table */
+ fts5IndexTombstoneRebuild(p, pSeg, pPg, iPg, szKey, &nHash, &apHash);
+ assert( p->rc==SQLITE_OK || (nHash==0 && apHash==0) );
+
+ /* If all has succeeded, write the new rowid into one of the new hash
+ ** table pages, then write them all out to disk. */
+ if( nHash ){
+ int ii = 0;
+ fts5IndexTombstoneAddToPage(apHash[iRowid % nHash], 1, nHash, iRowid);
+ for(ii=0; ii<nHash; ii++){
+ i64 iTombstoneRowid = FTS5_TOMBSTONE_ROWID(pSeg->iSegid, ii);
+ fts5DataWrite(p, iTombstoneRowid, apHash[ii]->p, apHash[ii]->nn);
+ }
+ pSeg->nPgTombstone = nHash;
+ fts5StructureWrite(p, p->pStruct);
+ }
+
+ fts5DataRelease(pPg);
+ fts5IndexFreeArray(apHash, nHash);
+}
+
+/*
+** Add iRowid to the tombstone list of the segment or segments that contain
+** rows from origin iOrigin. Return SQLITE_OK if successful, or an SQLite
+** error code otherwise.
+*/
+static int sqlcipher_sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid){
+ Fts5Structure *pStruct;
+ pStruct = fts5StructureRead(p);
+ if( pStruct ){
+ int bFound = 0; /* True after pSeg->nEntryTombstone incr. */
+ int iLvl;
+ for(iLvl=pStruct->nLevel-1; iLvl>=0; iLvl--){
+ int iSeg;
+ for(iSeg=pStruct->aLevel[iLvl].nSeg-1; iSeg>=0; iSeg--){
+ Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
+ if( pSeg->iOrigin1<=(u64)iOrigin && pSeg->iOrigin2>=(u64)iOrigin ){
+ if( bFound==0 ){
+ pSeg->nEntryTombstone++;
+ bFound = 1;
+ }
+ fts5IndexTombstoneAdd(p, pSeg, iRowid);
+ }
+ }
+ }
+ fts5StructureRelease(pStruct);
+ }
+ return fts5IndexReturn(p);
+}
/*************************************************************************
**************************************************************************
@@ -238406,7 +253609,9 @@ static int fts5QueryCksum(
int eDetail = p->pConfig->eDetail;
u64 cksum = *pCksum;
Fts5IndexIter *pIter = 0;
- int rc = sqlcipher_sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter);
+ int rc = sqlcipher_sqlite3Fts5IndexQuery(
+ p, z, n, (flags | FTS5INDEX_QUERY_NOTOKENDATA), 0, &pIter
+ );
while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlcipher_sqlite3Fts5IterEof(pIter) ){
i64 rowid = pIter->iRowid;
@@ -238573,7 +253778,7 @@ static void fts5IndexIntegrityCheckEmpty(
}
static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
- int iTermOff = 0;
+ i64 iTermOff = 0;
int ii;
Fts5Buffer buf1 = {0,0,0};
@@ -238582,7 +253787,7 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
ii = pLeaf->szLeaf;
while( ii<pLeaf->nn && p->rc==SQLITE_OK ){
int res;
- int iOff;
+ i64 iOff;
int nIncr;
ii += fts5GetVarint32(&pLeaf->p[ii], nIncr);
@@ -238627,6 +253832,7 @@ static void fts5IndexIntegrityCheckSegment(
Fts5StructureSegment *pSeg /* Segment to check internal consistency */
){
Fts5Config *pConfig = p->pConfig;
+ int bSecureDelete = (pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE);
sqlcipher_sqlite3_stmt *pStmt = 0;
int rc2;
int iIdxPrevLeaf = pSeg->pgnoFirst-1;
@@ -238662,7 +253868,19 @@ static void fts5IndexIntegrityCheckSegment(
** is also a rowid pointer within the leaf page header, it points to a
** location before the term. */
if( pLeaf->nn<=pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
+
+ if( nIdxTerm==0
+ && pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE
+ && pLeaf->nn==pLeaf->szLeaf
+ && pLeaf->nn==4
+ ){
+ /* special case - the very first page in a segment keeps its %_idx
+ ** entry even if all the terms are removed from it by secure-delete
+ ** operations. */
+ }else{
+ p->rc = FTS5_CORRUPT;
+ }
+
}else{
int iOff; /* Offset of first term on leaf */
int iRowidOff; /* Offset of first rowid on leaf */
@@ -238726,9 +253944,12 @@ static void fts5IndexIntegrityCheckSegment(
ASSERT_SZLEAF_OK(pLeaf);
if( iRowidOff>=pLeaf->szLeaf ){
p->rc = FTS5_CORRUPT;
- }else{
+ }else if( bSecureDelete==0 || iRowidOff>0 ){
+ i64 iDlRowid = fts5DlidxIterRowid(pDlidx);
fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid);
- if( iRowid!=fts5DlidxIterRowid(pDlidx) ) p->rc = FTS5_CORRUPT;
+ if( iRowid<iDlRowid || (bSecureDelete==0 && iRowid!=iDlRowid) ){
+ p->rc = FTS5_CORRUPT;
+ }
}
fts5DataRelease(pLeaf);
}
@@ -238822,6 +254043,7 @@ static int sqlcipher_sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int
/* If this is a new term, query for it. Update cksum3 with the results. */
fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
+ if( p->rc ) break;
if( eDetail==FTS5_DETAIL_NONE ){
if( 0==fts5MultiIterIsEmpty(p, pIter) ){
@@ -238857,13 +254079,14 @@ static int sqlcipher_sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int
** function only.
*/
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** Decode a segment-data rowid from the %_data table. This function is
** the opposite of macro FTS5_SEGMENT_ROWID().
*/
static void fts5DecodeRowid(
i64 iRowid, /* Rowid from %_data table */
+ int *pbTombstone, /* OUT: Tombstone hash flag */
int *piSegid, /* OUT: Segment id */
int *pbDlidx, /* OUT: Dlidx flag */
int *piHeight, /* OUT: Height */
@@ -238879,13 +254102,16 @@ static void fts5DecodeRowid(
iRowid >>= FTS5_DATA_DLI_B;
*piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1));
+ iRowid >>= FTS5_DATA_ID_B;
+
+ *pbTombstone = (int)(iRowid & 0x0001);
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
- int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */
- fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno);
+ int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid compenents */
+ fts5DecodeRowid(iKey, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno);
if( iSegid==0 ){
if( iKey==FTS5_AVERAGES_ROWID ){
@@ -238895,14 +254121,16 @@ static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
}
}
else{
- sqlcipher_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%ssegid=%d h=%d pgno=%d}",
- bDlidx ? "dlidx " : "", iSegid, iHeight, iPgno
+ sqlcipher_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%s%ssegid=%d h=%d pgno=%d}",
+ bDlidx ? "dlidx " : "",
+ bTomb ? "tombstone " : "",
+ iSegid, iHeight, iPgno
);
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static void fts5DebugStructure(
int *pRc, /* IN/OUT: error code */
Fts5Buffer *pBuf,
@@ -238917,16 +254145,22 @@ static void fts5DebugStructure(
);
for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
- sqlcipher_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}",
+ sqlcipher_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d",
pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast
);
+ if( pSeg->iOrigin1>0 ){
+ sqlcipher_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " origin=%lld..%lld",
+ pSeg->iOrigin1, pSeg->iOrigin2
+ );
+ }
+ sqlcipher_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}");
}
sqlcipher_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}");
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** This is part of the fts5_decode() debugging aid.
**
@@ -238951,9 +254185,9 @@ static void fts5DecodeStructure(
fts5DebugStructure(pRc, pBuf, p);
fts5StructureRelease(p);
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** This is part of the fts5_decode() debugging aid.
**
@@ -238976,9 +254210,9 @@ static void fts5DecodeAverages(
zSpace = " ";
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** Buffer (a/n) is assumed to contain a list of serialized varints. Read
** each varint and append its string representation to buffer pBuf. Return
@@ -238995,9 +254229,9 @@ static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
}
return iOff;
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** The start of buffer (a/n) contains the start of a doclist. The doclist
** may or may not finish within the buffer. This function appends a text
@@ -239030,9 +254264,9 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
return iOff;
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** This function is part of the fts5_decode() debugging function. It is
** only ever used with detail=none tables.
@@ -239073,9 +254307,27 @@ static void fts5DecodeRowidList(
sqlcipher_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp);
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
+static void fts5BufferAppendTerm(int *pRc, Fts5Buffer *pBuf, Fts5Buffer *pTerm){
+ int ii;
+ fts5BufferGrow(pRc, pBuf, pTerm->n*2 + 1);
+ if( *pRc==SQLITE_OK ){
+ for(ii=0; ii<pTerm->n; ii++){
+ if( pTerm->p[ii]==0x00 ){
+ pBuf->p[pBuf->n++] = '\\';
+ pBuf->p[pBuf->n++] = '0';
+ }else{
+ pBuf->p[pBuf->n++] = pTerm->p[ii];
+ }
+ }
+ pBuf->p[pBuf->n] = 0x00;
+ }
+}
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
+
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** The implementation of user-defined scalar function fts5_decode().
*/
@@ -239086,6 +254338,7 @@ static void fts5DecodeFunction(
){
i64 iRowid; /* Rowid for record being decoded */
int iSegid,iHeight,iPgno,bDlidx;/* Rowid components */
+ int bTomb;
const u8 *aBlob; int n; /* Record to decode */
u8 *a = 0;
Fts5Buffer s; /* Build up text to return here */
@@ -239108,7 +254361,7 @@ static void fts5DecodeFunction(
if( a==0 ) goto decode_out;
if( n>0 ) memcpy(a, aBlob, n);
- fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno);
+ fts5DecodeRowid(iRowid, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno);
fts5DebugRowid(&rc, &s, iRowid);
if( bDlidx ){
@@ -239127,6 +254380,28 @@ static void fts5DecodeFunction(
" %d(%lld)", lvl.iLeafPgno, lvl.iRowid
);
}
+ }else if( bTomb ){
+ u32 nElem = fts5GetU32(&a[4]);
+ int szKey = (aBlob[0]==4 || aBlob[0]==8) ? aBlob[0] : 8;
+ int nSlot = (n - 8) / szKey;
+ int ii;
+ sqlcipher_sqlite3Fts5BufferAppendPrintf(&rc, &s, " nElem=%d", (int)nElem);
+ if( aBlob[1] ){
+ sqlcipher_sqlite3Fts5BufferAppendPrintf(&rc, &s, " 0");
+ }
+ for(ii=0; ii<nSlot; ii++){
+ u64 iVal = 0;
+ if( szKey==4 ){
+ u32 *aSlot = (u32*)&aBlob[8];
+ if( aSlot[ii] ) iVal = fts5GetU32((u8*)&aSlot[ii]);
+ }else{
+ u64 *aSlot = (u64*)&aBlob[8];
+ if( aSlot[ii] ) iVal = fts5GetU64((u8*)&aSlot[ii]);
+ }
+ if( iVal!=0 ){
+ sqlcipher_sqlite3Fts5BufferAppendPrintf(&rc, &s, " %lld", (i64)iVal);
+ }
+ }
}else if( iSegid==0 ){
if( iRowid==FTS5_AVERAGES_ROWID ){
fts5DecodeAverages(&rc, &s, a, n);
@@ -239152,16 +254427,15 @@ static void fts5DecodeFunction(
fts5DecodeRowidList(&rc, &s, &a[4], iTermOff-4);
iOff = iTermOff;
- while( iOff<szLeaf ){
+ while( iOff<szLeaf && rc==SQLITE_OK ){
int nAppend;
/* Read the term data for the next term*/
iOff += fts5GetVarint32(&a[iOff], nAppend);
term.n = nKeep;
fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]);
- sqlcipher_sqlite3Fts5BufferAppendPrintf(
- &rc, &s, " term=%.*s", term.n, (const char*)term.p
- );
+ sqlcipher_sqlite3Fts5BufferAppendPrintf(&rc, &s, " term=");
+ fts5BufferAppendTerm(&rc, &s, &term);
iOff += nAppend;
/* Figure out where the doclist for this term ends */
@@ -239172,8 +254446,11 @@ static void fts5DecodeFunction(
}else{
iTermOff = szLeaf;
}
-
- fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff);
+ if( iTermOff>szLeaf ){
+ rc = FTS5_CORRUPT;
+ }else{
+ fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff);
+ }
iOff = iTermOff;
if( iOff<szLeaf ){
iOff += fts5GetVarint32(&a[iOff], nKeep);
@@ -239266,9 +254543,8 @@ static void fts5DecodeFunction(
fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]);
iOff += nByte;
- sqlcipher_sqlite3Fts5BufferAppendPrintf(
- &rc, &s, " term=%.*s", term.n, (const char*)term.p
- );
+ sqlcipher_sqlite3Fts5BufferAppendPrintf(&rc, &s, " term=");
+ fts5BufferAppendTerm(&rc, &s, &term);
iOff += fts5DecodeDoclist(&rc, &s, &a[iOff], iEnd-iOff);
}
@@ -239284,9 +254560,9 @@ static void fts5DecodeFunction(
}
fts5BufferFree(&s);
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** The implementation of user-defined scalar function fts5_rowid().
*/
@@ -239320,7 +254596,235 @@ static void fts5RowidFunction(
}
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
+
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
+
+typedef struct Fts5StructVtab Fts5StructVtab;
+struct Fts5StructVtab {
+ sqlcipher_sqlite3_vtab base;
+};
+
+typedef struct Fts5StructVcsr Fts5StructVcsr;
+struct Fts5StructVcsr {
+ sqlcipher_sqlite3_vtab_cursor base;
+ Fts5Structure *pStruct;
+ int iLevel;
+ int iSeg;
+ int iRowid;
+};
+
+/*
+** Create a new fts5_structure() table-valued function.
+*/
+static int fts5structConnectMethod(
+ sqlcipher_sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlcipher_sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ Fts5StructVtab *pNew = 0;
+ int rc = SQLITE_OK;
+
+ rc = sqlcipher_sqlite3_declare_vtab(db,
+ "CREATE TABLE xyz("
+ "level, segment, merge, segid, leaf1, leaf2, loc1, loc2, "
+ "npgtombstone, nentrytombstone, nentry, struct HIDDEN);"
+ );
+ if( rc==SQLITE_OK ){
+ pNew = sqlcipher_sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
+ }
+
+ *ppVtab = (sqlcipher_sqlite3_vtab*)pNew;
+ return rc;
+}
+
+/*
+** We must have a single struct=? constraint that will be passed through
+** into the xFilter method. If there is no valid stmt=? constraint,
+** then return an SQLITE_CONSTRAINT error.
+*/
+static int fts5structBestIndexMethod(
+ sqlcipher_sqlite3_vtab *tab,
+ sqlcipher_sqlite3_index_info *pIdxInfo
+){
+ int i;
+ int rc = SQLITE_CONSTRAINT;
+ struct sqlcipher_sqlite3_index_constraint *p;
+ pIdxInfo->estimatedCost = (double)100;
+ pIdxInfo->estimatedRows = 100;
+ pIdxInfo->idxNum = 0;
+ for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
+ if( p->usable==0 ) continue;
+ if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==11 ){
+ rc = SQLITE_OK;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ break;
+ }
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for bytecodevtab objects.
+*/
+static int fts5structDisconnectMethod(sqlcipher_sqlite3_vtab *pVtab){
+ Fts5StructVtab *p = (Fts5StructVtab*)pVtab;
+ sqlcipher_sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new bytecodevtab_cursor object.
+*/
+static int fts5structOpenMethod(sqlcipher_sqlite3_vtab *p, sqlcipher_sqlite3_vtab_cursor **ppCsr){
+ int rc = SQLITE_OK;
+ Fts5StructVcsr *pNew = 0;
+
+ pNew = sqlcipher_sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
+ *ppCsr = (sqlcipher_sqlite3_vtab_cursor*)pNew;
+
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a bytecodevtab_cursor.
+*/
+static int fts5structCloseMethod(sqlcipher_sqlite3_vtab_cursor *cur){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ fts5StructureRelease(pCsr->pStruct);
+ sqlcipher_sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a bytecodevtab_cursor to its next row of output.
+*/
+static int fts5structNextMethod(sqlcipher_sqlite3_vtab_cursor *cur){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ Fts5Structure *p = pCsr->pStruct;
+
+ assert( pCsr->pStruct );
+ pCsr->iSeg++;
+ pCsr->iRowid++;
+ while( pCsr->iLevel<p->nLevel && pCsr->iSeg>=p->aLevel[pCsr->iLevel].nSeg ){
+ pCsr->iLevel++;
+ pCsr->iSeg = 0;
+ }
+ if( pCsr->iLevel>=p->nLevel ){
+ fts5StructureRelease(pCsr->pStruct);
+ pCsr->pStruct = 0;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int fts5structEofMethod(sqlcipher_sqlite3_vtab_cursor *cur){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ return pCsr->pStruct==0;
+}
+
+static int fts5structRowidMethod(
+ sqlcipher_sqlite3_vtab_cursor *cur,
+ sqlite_int64 *piRowid
+){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ *piRowid = pCsr->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the bytecodevtab_cursor
+** is currently pointing.
+*/
+static int fts5structColumnMethod(
+ sqlcipher_sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlcipher_sqlite3_context *ctx, /* First argument to sqlcipher_sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ Fts5Structure *p = pCsr->pStruct;
+ Fts5StructureSegment *pSeg = &p->aLevel[pCsr->iLevel].aSeg[pCsr->iSeg];
+
+ switch( i ){
+ case 0: /* level */
+ sqlcipher_sqlite3_result_int(ctx, pCsr->iLevel);
+ break;
+ case 1: /* segment */
+ sqlcipher_sqlite3_result_int(ctx, pCsr->iSeg);
+ break;
+ case 2: /* merge */
+ sqlcipher_sqlite3_result_int(ctx, pCsr->iSeg < p->aLevel[pCsr->iLevel].nMerge);
+ break;
+ case 3: /* segid */
+ sqlcipher_sqlite3_result_int(ctx, pSeg->iSegid);
+ break;
+ case 4: /* leaf1 */
+ sqlcipher_sqlite3_result_int(ctx, pSeg->pgnoFirst);
+ break;
+ case 5: /* leaf2 */
+ sqlcipher_sqlite3_result_int(ctx, pSeg->pgnoLast);
+ break;
+ case 6: /* origin1 */
+ sqlcipher_sqlite3_result_int64(ctx, pSeg->iOrigin1);
+ break;
+ case 7: /* origin2 */
+ sqlcipher_sqlite3_result_int64(ctx, pSeg->iOrigin2);
+ break;
+ case 8: /* npgtombstone */
+ sqlcipher_sqlite3_result_int(ctx, pSeg->nPgTombstone);
+ break;
+ case 9: /* nentrytombstone */
+ sqlcipher_sqlite3_result_int64(ctx, pSeg->nEntryTombstone);
+ break;
+ case 10: /* nentry */
+ sqlcipher_sqlite3_result_int64(ctx, pSeg->nEntry);
+ break;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Initialize a cursor.
+**
+** idxNum==0 means show all subprograms
+** idxNum==1 means show only the main bytecode and omit subprograms.
+*/
+static int fts5structFilterMethod(
+ sqlcipher_sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlcipher_sqlite3_value **argv
+){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr *)pVtabCursor;
+ int rc = SQLITE_OK;
+
+ const u8 *aBlob = 0;
+ int nBlob = 0;
+
+ assert( argc==1 );
+ fts5StructureRelease(pCsr->pStruct);
+ pCsr->pStruct = 0;
+
+ nBlob = sqlcipher_sqlite3_value_bytes(argv[0]);
+ aBlob = (const u8*)sqlcipher_sqlite3_value_blob(argv[0]);
+ rc = fts5StructureDecode(aBlob, nBlob, 0, &pCsr->pStruct);
+ if( rc==SQLITE_OK ){
+ pCsr->iLevel = 0;
+ pCsr->iRowid = 0;
+ pCsr->iSeg = -1;
+ rc = fts5structNextMethod(pVtabCursor);
+ }
+
+ return rc;
+}
+
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
/*
** This is called as part of registering the FTS5 module with database
@@ -239331,7 +254835,7 @@ static void fts5RowidFunction(
** SQLite error code is returned instead.
*/
static int sqlcipher_sqlite3Fts5IndexInit(sqlcipher_sqlite3 *db){
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
int rc = sqlcipher_sqlite3_create_function(
db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
);
@@ -239348,6 +254852,37 @@ static int sqlcipher_sqlite3Fts5IndexInit(sqlcipher_sqlite3 *db){
db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0
);
}
+
+ if( rc==SQLITE_OK ){
+ static const sqlcipher_sqlite3_module fts5structure_module = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ fts5structConnectMethod, /* xConnect */
+ fts5structBestIndexMethod, /* xBestIndex */
+ fts5structDisconnectMethod, /* xDisconnect */
+ 0, /* xDestroy */
+ fts5structOpenMethod, /* xOpen */
+ fts5structCloseMethod, /* xClose */
+ fts5structFilterMethod, /* xFilter */
+ fts5structNextMethod, /* xNext */
+ fts5structEofMethod, /* xEof */
+ fts5structColumnMethod, /* xColumn */
+ fts5structRowidMethod, /* xRowid */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindFunction */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
+ };
+ rc = sqlcipher_sqlite3_create_module(db, "fts5_structure", &fts5structure_module, 0);
+ }
return rc;
#else
return SQLITE_OK;
@@ -239483,6 +255018,8 @@ struct Fts5FullTable {
Fts5Storage *pStorage; /* Document store */
Fts5Global *pGlobal; /* Global (connection wide) data */
Fts5Cursor *pSortCsr; /* Sort data from this cursor */
+ int iSavepoint; /* Successful xSavepoint()+1 */
+
#ifdef SQLITE_DEBUG
struct Fts5TransactionState ts;
#endif
@@ -239626,7 +255163,7 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
break;
case FTS5_SYNC:
- assert( p->ts.eState==1 );
+ assert( p->ts.eState==1 || p->ts.eState==2 );
p->ts.eState = 2;
break;
@@ -239641,21 +255178,21 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
break;
case FTS5_SAVEPOINT:
- assert( p->ts.eState==1 );
+ assert( p->ts.eState>=1 );
assert( iSavepoint>=0 );
assert( iSavepoint>=p->ts.iSavepoint );
p->ts.iSavepoint = iSavepoint;
break;
case FTS5_RELEASE:
- assert( p->ts.eState==1 );
+ assert( p->ts.eState>=1 );
assert( iSavepoint>=0 );
assert( iSavepoint<=p->ts.iSavepoint );
p->ts.iSavepoint = iSavepoint-1;
break;
case FTS5_ROLLBACKTO:
- assert( p->ts.eState==1 );
+ assert( p->ts.eState>=1 );
assert( iSavepoint>=-1 );
/* The following assert() can fail if another vtab strikes an error
** within an xSavepoint() call then SQLite calls xRollbackTo() - without
@@ -239771,6 +255308,13 @@ static int fts5InitVtab(
pConfig->pzErrmsg = 0;
}
+ if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ rc = sqlcipher_sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, (int)1);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlcipher_sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
+ }
+
if( rc!=SQLITE_OK ){
fts5FreeVtab(pTab);
pTab = 0;
@@ -240013,12 +255557,15 @@ static int fts5BestIndexMethod(sqlcipher_sqlite3_vtab *pVTab, sqlcipher_sqlite3_
}
idxStr[iIdxStr] = '\0';
- /* Set idxFlags flags for the ORDER BY clause */
+ /* Set idxFlags flags for the ORDER BY clause
+ **
+ ** Note that tokendata=1 tables cannot currently handle "ORDER BY rowid DESC".
+ */
if( pInfo->nOrderBy==1 ){
int iSort = pInfo->aOrderBy[0].iColumn;
if( iSort==(pConfig->nCol+1) && bSeenMatch ){
idxFlags |= FTS5_BI_ORDER_RANK;
- }else if( iSort==-1 ){
+ }else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){
idxFlags |= FTS5_BI_ORDER_ROWID;
}
if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
@@ -240270,6 +255817,16 @@ static int fts5NextMethod(sqlcipher_sqlite3_vtab_cursor *pCursor){
);
assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
+ /* If this cursor uses FTS5_PLAN_MATCH and this is a tokendata=1 table,
+ ** clear any token mappings accumulated at the fts5_index.c level. In
+ ** other cases, specifically FTS5_PLAN_SOURCE and FTS5_PLAN_SORTED_MATCH,
+ ** we need to retain the mappings for the entire query. */
+ if( pCsr->ePlan==FTS5_PLAN_MATCH
+ && ((Fts5Table*)pCursor->pVtab)->pConfig->bTokendata
+ ){
+ sqlcipher_sqlite3Fts5ExprClearTokens(pCsr->pExpr);
+ }
+
if( pCsr->ePlan<3 ){
int bSkip = 0;
if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
@@ -240695,6 +256252,9 @@ static int fts5FilterMethod(
pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
}
+ rc = sqlcipher_sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ if( rc!=SQLITE_OK ) goto filter_out;
+
if( pTab->pSortCsr ){
/* If pSortCsr is non-NULL, then this call is being made as part of
** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
@@ -240717,6 +256277,7 @@ static int fts5FilterMethod(
pCsr->pExpr = pTab->pSortCsr->pExpr;
rc = fts5CursorFirst(pTab, pCsr, bDesc);
}else if( pCsr->pExpr ){
+ assert( rc==SQLITE_OK );
rc = fts5CursorParseRank(pConfig, pCsr, pRank);
if( rc==SQLITE_OK ){
if( bOrderByRank ){
@@ -240888,6 +256449,7 @@ static int fts5SpecialInsert(
Fts5Config *pConfig = pTab->p.pConfig;
int rc = SQLITE_OK;
int bError = 0;
+ int bLoadConfig = 0;
if( 0==sqlcipher_sqlite3_stricmp("delete-all", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
@@ -240899,6 +256461,7 @@ static int fts5SpecialInsert(
}else{
rc = sqlcipher_sqlite3Fts5StorageDeleteAll(pTab->pStorage);
}
+ bLoadConfig = 1;
}else if( 0==sqlcipher_sqlite3_stricmp("rebuild", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NONE ){
fts5SetVtabError(pTab,
@@ -240908,6 +256471,7 @@ static int fts5SpecialInsert(
}else{
rc = sqlcipher_sqlite3Fts5StorageRebuild(pTab->pStorage);
}
+ bLoadConfig = 1;
}else if( 0==sqlcipher_sqlite3_stricmp("optimize", zCmd) ){
rc = sqlcipher_sqlite3Fts5StorageOptimize(pTab->pStorage);
}else if( 0==sqlcipher_sqlite3_stricmp("merge", zCmd) ){
@@ -240920,8 +256484,13 @@ static int fts5SpecialInsert(
}else if( 0==sqlcipher_sqlite3_stricmp("prefix-index", zCmd) ){
pConfig->bPrefixIndex = sqlcipher_sqlite3_value_int(pVal);
#endif
+ }else if( 0==sqlcipher_sqlite3_stricmp("flush", zCmd) ){
+ rc = sqlcipher_sqlite3Fts5FlushToDisk(&pTab->p);
}else{
- rc = sqlcipher_sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ rc = sqlcipher_sqlite3Fts5FlushToDisk(&pTab->p);
+ if( rc==SQLITE_OK ){
+ rc = sqlcipher_sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ }
if( rc==SQLITE_OK ){
rc = sqlcipher_sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError);
}
@@ -240933,6 +256502,12 @@ static int fts5SpecialInsert(
}
}
}
+
+ if( rc==SQLITE_OK && bLoadConfig ){
+ pTab->p.pConfig->iCookie--;
+ rc = sqlcipher_sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ }
+
return rc;
}
@@ -240989,9 +256564,10 @@ static int fts5UpdateMethod(
Fts5Config *pConfig = pTab->p.pConfig;
int eType0; /* value_type() of apVal[0] */
int rc = SQLITE_OK; /* Return code */
+ int bUpdateOrDelete = 0;
/* A transaction must be open when this is called. */
- assert( pTab->ts.eState==1 );
+ assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
assert( pVtab->zErrMsg==0 );
assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
@@ -240999,6 +256575,11 @@ static int fts5UpdateMethod(
|| sqlcipher_sqlite3_value_type(apVal[0])==SQLITE_NULL
);
assert( pTab->p.pConfig->pzErrmsg==0 );
+ if( pConfig->pgsz==0 ){
+ rc = sqlcipher_sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
/* Put any active cursors into REQUIRE_SEEK state. */
@@ -241013,7 +256594,15 @@ static int fts5UpdateMethod(
if( pConfig->eContent!=FTS5_CONTENT_NORMAL
&& 0==sqlcipher_sqlite3_stricmp("delete", z)
){
- rc = fts5SpecialDelete(pTab, apVal);
+ if( pConfig->bContentlessDelete ){
+ fts5SetVtabError(pTab,
+ "'delete' may not be used with a contentless_delete=1 table"
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ rc = fts5SpecialDelete(pTab, apVal);
+ bUpdateOrDelete = 1;
+ }
}else{
rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
}
@@ -241030,7 +256619,7 @@ static int fts5UpdateMethod(
** Cases 3 and 4 may violate the rowid constraint.
*/
int eConflict = SQLITE_ABORT;
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->bContentlessDelete ){
eConflict = sqlcipher_sqlite3_vtab_on_conflict(pConfig->db);
}
@@ -241038,8 +256627,12 @@ static int fts5UpdateMethod(
assert( nArg!=1 || eType0==SQLITE_INTEGER );
/* Filter out attempts to run UPDATE or DELETE on contentless tables.
- ** This is not suported. */
- if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
+ ** This is not suported. Except - they are both supported if the CREATE
+ ** VIRTUAL TABLE statement contained "contentless_delete=1". */
+ if( eType0==SQLITE_INTEGER
+ && pConfig->eContent==FTS5_CONTENT_NONE
+ && pConfig->bContentlessDelete==0
+ ){
pTab->p.base.zErrMsg = sqlcipher_sqlite3_mprintf(
"cannot %s contentless fts5 table: %s",
(nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
@@ -241051,6 +256644,7 @@ static int fts5UpdateMethod(
else if( nArg==1 ){
i64 iDel = sqlcipher_sqlite3_value_int64(apVal[0]); /* Rowid to delete */
rc = sqlcipher_sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
+ bUpdateOrDelete = 1;
}
/* INSERT or UPDATE */
@@ -241062,10 +256656,12 @@ static int fts5UpdateMethod(
}
else if( eType0!=SQLITE_INTEGER ){
- /* If this is a REPLACE, first remove the current entry (if any) */
+ /* An INSERT statement. If the conflict-mode is REPLACE, first remove
+ ** the current entry (if any). */
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
i64 iNew = sqlcipher_sqlite3_value_int64(apVal[1]); /* Rowid to delete */
rc = sqlcipher_sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
+ bUpdateOrDelete = 1;
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
@@ -241094,10 +256690,24 @@ static int fts5UpdateMethod(
rc = sqlcipher_sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
+ bUpdateOrDelete = 1;
}
}
}
+ if( rc==SQLITE_OK
+ && bUpdateOrDelete
+ && pConfig->bSecureDelete
+ && pConfig->iVersion==FTS5_CURRENT_VERSION
+ ){
+ rc = sqlcipher_sqlite3Fts5StorageConfigValue(
+ pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE
+ );
+ if( rc==SQLITE_OK ){
+ pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
+ }
+ }
+
pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
@@ -241110,8 +256720,7 @@ static int fts5SyncMethod(sqlcipher_sqlite3_vtab *pVtab){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
- fts5TripCursors(pTab);
- rc = sqlcipher_sqlite3Fts5StorageSync(pTab->pStorage);
+ rc = sqlcipher_sqlite3Fts5FlushToDisk(&pTab->p);
pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
@@ -241207,7 +256816,10 @@ static int fts5ApiColumnText(
){
int rc = SQLITE_OK;
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
+ Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+ if( iCol<0 || iCol>=pTab->pConfig->nCol ){
+ rc = SQLITE_RANGE;
+ }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
|| pCsr->ePlan==FTS5_PLAN_SPECIAL
){
*pz = 0;
@@ -241232,8 +256844,9 @@ static int fts5CsrPoslist(
int rc = SQLITE_OK;
int bLive = (pCsr->pSorter==0);
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
-
+ if( iPhrase<0 || iPhrase>=sqlcipher_sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
+ rc = SQLITE_RANGE;
+ }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
Fts5PoslistPopulator *aPopulator;
int i;
@@ -241257,15 +256870,21 @@ static int fts5CsrPoslist(
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
}
- if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
- Fts5Sorter *pSorter = pCsr->pSorter;
- int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
- *pn = pSorter->aIdx[iPhrase] - i1;
- *pa = &pSorter->aPoslist[i1];
+ if( rc==SQLITE_OK ){
+ if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
+ Fts5Sorter *pSorter = pCsr->pSorter;
+ int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
+ *pn = pSorter->aIdx[iPhrase] - i1;
+ *pa = &pSorter->aPoslist[i1];
+ }else{
+ *pn = sqlcipher_sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
+ }
}else{
- *pn = sqlcipher_sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
+ *pa = 0;
+ *pn = 0;
}
+
return rc;
}
@@ -241372,12 +256991,6 @@ static int fts5ApiInst(
){
if( iIdx<0 || iIdx>=pCsr->nInstCount ){
rc = SQLITE_RANGE;
-#if 0
- }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
- *piPhrase = pCsr->aInst[iIdx*3];
- *piCol = pCsr->aInst[iIdx*3 + 2];
- *piOff = -1;
-#endif
}else{
*piPhrase = pCsr->aInst[iIdx*3];
*piCol = pCsr->aInst[iIdx*3 + 1];
@@ -241632,13 +257245,56 @@ static int fts5ApiPhraseFirstColumn(
return rc;
}
+/*
+** xQueryToken() API implemenetation.
+*/
+static int fts5ApiQueryToken(
+ Fts5Context* pCtx,
+ int iPhrase,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ return sqlcipher_sqlite3Fts5ExprQueryToken(pCsr->pExpr, iPhrase, iToken, ppOut, pnOut);
+}
+
+/*
+** xInstToken() API implemenetation.
+*/
+static int fts5ApiInstToken(
+ Fts5Context *pCtx,
+ int iIdx,
+ int iToken,
+ const char **ppOut, int *pnOut
+){
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ int rc = SQLITE_OK;
+ if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
+ || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
+ ){
+ if( iIdx<0 || iIdx>=pCsr->nInstCount ){
+ rc = SQLITE_RANGE;
+ }else{
+ int iPhrase = pCsr->aInst[iIdx*3];
+ int iCol = pCsr->aInst[iIdx*3 + 1];
+ int iOff = pCsr->aInst[iIdx*3 + 2];
+ i64 iRowid = fts5CursorRowid(pCsr);
+ rc = sqlcipher_sqlite3Fts5ExprInstToken(
+ pCsr->pExpr, iRowid, iPhrase, iCol, iOff, iToken, ppOut, pnOut
+ );
+ }
+ }
+ return rc;
+}
+
static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
);
static const Fts5ExtensionApi sFts5Api = {
- 2, /* iVersion */
+ 3, /* iVersion */
fts5ApiUserData,
fts5ApiColumnCount,
fts5ApiRowCount,
@@ -241658,6 +257314,8 @@ static const Fts5ExtensionApi sFts5Api = {
fts5ApiPhraseNext,
fts5ApiPhraseFirstColumn,
fts5ApiPhraseNextColumn,
+ fts5ApiQueryToken,
+ fts5ApiInstToken
};
/*
@@ -241878,6 +257536,12 @@ static int fts5ColumnMethod(
sqlcipher_sqlite3_result_value(pCtx, sqlcipher_sqlite3_column_value(pCsr->pStmt, iCol+1));
}
pConfig->pzErrmsg = 0;
+ }else if( pConfig->bContentlessDelete && sqlcipher_sqlite3_vtab_nochange(pCtx) ){
+ char *zErr = sqlcipher_sqlite3_mprintf("cannot UPDATE a subset of "
+ "columns on fts5 contentless-delete table: %s", pConfig->zName
+ );
+ sqlcipher_sqlite3_result_error(pCtx, zErr, -1);
+ sqlcipher_sqlite3_free(zErr);
}
return rc;
}
@@ -241916,8 +257580,10 @@ static int fts5RenameMethod(
sqlcipher_sqlite3_vtab *pVtab, /* Virtual table handle */
const char *zName /* New name of table */
){
+ int rc;
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
- return sqlcipher_sqlite3Fts5StorageRename(pTab->pStorage, zName);
+ rc = sqlcipher_sqlite3Fts5StorageRename(pTab->pStorage, zName);
+ return rc;
}
static int sqlcipher_sqlite3Fts5FlushToDisk(Fts5Table *pTab){
@@ -241931,9 +257597,15 @@ static int sqlcipher_sqlite3Fts5FlushToDisk(Fts5Table *pTab){
** Flush the contents of the pending-terms table to disk.
*/
static int fts5SavepointMethod(sqlcipher_sqlite3_vtab *pVtab, int iSavepoint){
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint);
- return sqlcipher_sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
+ int rc = SQLITE_OK;
+
+ fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
+ rc = sqlcipher_sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint+1;
+ }
+ return rc;
}
/*
@@ -241942,9 +257614,16 @@ static int fts5SavepointMethod(sqlcipher_sqlite3_vtab *pVtab, int iSavepoint){
** This is a no-op.
*/
static int fts5ReleaseMethod(sqlcipher_sqlite3_vtab *pVtab, int iSavepoint){
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint);
- return sqlcipher_sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
+ int rc = SQLITE_OK;
+ fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
+ if( (iSavepoint+1)<pTab->iSavepoint ){
+ rc = sqlcipher_sqlite3Fts5FlushToDisk(&pTab->p);
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint;
+ }
+ }
+ return rc;
}
/*
@@ -241954,10 +257633,14 @@ static int fts5ReleaseMethod(sqlcipher_sqlite3_vtab *pVtab, int iSavepoint){
*/
static int fts5RollbackToMethod(sqlcipher_sqlite3_vtab *pVtab, int iSavepoint){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
+ int rc = SQLITE_OK;
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
fts5TripCursors(pTab);
- return sqlcipher_sqlite3Fts5StorageRollback(pTab->pStorage);
+ if( (iSavepoint+1)<=pTab->iSavepoint ){
+ pTab->p.pConfig->pgsz = 0;
+ rc = sqlcipher_sqlite3Fts5StorageRollback(pTab->pStorage);
+ }
+ return rc;
}
/*
@@ -242093,14 +257776,16 @@ static int sqlcipher_sqlite3Fts5GetTokenizer(
if( pMod==0 ){
assert( nArg>0 );
rc = SQLITE_ERROR;
- *pzErr = sqlcipher_sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
+ if( pzErr ) *pzErr = sqlcipher_sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
}else{
rc = pMod->x.xCreate(
pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok
);
pConfig->pTokApi = &pMod->x;
if( rc!=SQLITE_OK ){
- if( pzErr ) *pzErr = sqlcipher_sqlite3_mprintf("error in tokenizer constructor");
+ if( pzErr && rc!=SQLITE_NOMEM ){
+ *pzErr = sqlcipher_sqlite3_mprintf("error in tokenizer constructor");
+ }
}else{
pConfig->ePattern = sqlcipher_sqlite3Fts5TokenizerPattern(
pMod->x.xCreate, pConfig->pTok
@@ -242159,7 +257844,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlcipher_sqlite3_result_text(pCtx, "fts5: 2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26b309", -1, SQLITE_TRANSIENT);
+ sqlcipher_sqlite3_result_text(pCtx, "fts5: 2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33", -1, SQLITE_TRANSIENT);
}
/*
@@ -242177,9 +257862,47 @@ static int fts5ShadowName(const char *zName){
return 0;
}
+/*
+** Run an integrity check on the FTS5 data structures. Return a string
+** if anything is found amiss. Return a NULL pointer if everything is
+** OK.
+*/
+static int fts5IntegrityMethod(
+ sqlcipher_sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */
+ const char *zSchema, /* Name of schema in which this table lives */
+ const char *zTabname, /* Name of the table itself */
+ int isQuick, /* True if this is a quick-check */
+ char **pzErr /* Write error message here */
+){
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
+ int rc;
+
+ assert( pzErr!=0 && *pzErr==0 );
+ UNUSED_PARAM(isQuick);
+ assert( pTab->p.pConfig->pzErrmsg==0 );
+ pTab->p.pConfig->pzErrmsg = pzErr;
+ rc = sqlcipher_sqlite3Fts5StorageIntegrity(pTab->pStorage, 0);
+ if( *pzErr==0 && rc!=SQLITE_OK ){
+ if( (rc&0xff)==SQLITE_CORRUPT ){
+ *pzErr = sqlcipher_sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
+ zSchema, zTabname);
+ rc = (*pzErr) ? SQLITE_OK : SQLITE_NOMEM;
+ }else{
+ *pzErr = sqlcipher_sqlite3_mprintf("unable to validate the inverted index for"
+ " FTS5 table %s.%s: %s",
+ zSchema, zTabname, sqlcipher_sqlite3_errstr(rc));
+ }
+ }
+
+ sqlcipher_sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
+ pTab->p.pConfig->pzErrmsg = 0;
+
+ return rc;
+}
+
static int fts5Init(sqlcipher_sqlite3 *db){
static const sqlcipher_sqlite3_module fts5Mod = {
- /* iVersion */ 3,
+ /* iVersion */ 4,
/* xCreate */ fts5CreateMethod,
/* xConnect */ fts5ConnectMethod,
/* xBestIndex */ fts5BestIndexMethod,
@@ -242202,7 +257925,8 @@ static int fts5Init(sqlcipher_sqlite3 *db){
/* xSavepoint */ fts5SavepointMethod,
/* xRelease */ fts5ReleaseMethod,
/* xRollbackTo */ fts5RollbackToMethod,
- /* xShadowName */ fts5ShadowName
+ /* xShadowName */ fts5ShadowName,
+ /* xIntegrity */ fts5IntegrityMethod
};
int rc;
@@ -242232,7 +257956,9 @@ static int fts5Init(sqlcipher_sqlite3 *db){
}
if( rc==SQLITE_OK ){
rc = sqlcipher_sqlite3_create_function(
- db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0
+ db, "fts5_source_id", 0,
+ SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS,
+ p, fts5SourceIdFunc, 0, 0
);
}
}
@@ -242370,10 +258096,10 @@ static int fts5StorageGetStmt(
"INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
"REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
"DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */
- "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", /* REPLACE_DOCSIZE */
+ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?%s)", /* REPLACE_DOCSIZE */
"DELETE FROM %Q.'%q_docsize' WHERE id=?", /* DELETE_DOCSIZE */
- "SELECT sz FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */
+ "SELECT sz%s FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */
"REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */
"SELECT %s FROM %s AS T", /* SCAN */
@@ -242421,6 +258147,19 @@ static int fts5StorageGetStmt(
break;
}
+ case FTS5_STMT_REPLACE_DOCSIZE:
+ zSql = sqlcipher_sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName,
+ (pC->bContentlessDelete ? ",?" : "")
+ );
+ break;
+
+ case FTS5_STMT_LOOKUP_DOCSIZE:
+ zSql = sqlcipher_sqlite3_mprintf(azStmt[eStmt],
+ (pC->bContentlessDelete ? ",origin" : ""),
+ pC->zDb, pC->zName
+ );
+ break;
+
default:
zSql = sqlcipher_sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName);
break;
@@ -242610,9 +258349,11 @@ static int sqlcipher_sqlite3Fts5StorageOpen(
}
if( rc==SQLITE_OK && pConfig->bColumnsize ){
- rc = sqlcipher_sqlite3Fts5CreateTable(
- pConfig, "docsize", "id INTEGER PRIMARY KEY, sz BLOB", 0, pzErr
- );
+ const char *zCols = "id INTEGER PRIMARY KEY, sz BLOB";
+ if( pConfig->bContentlessDelete ){
+ zCols = "id INTEGER PRIMARY KEY, sz BLOB, origin INTEGER";
+ }
+ rc = sqlcipher_sqlite3Fts5CreateTable(pConfig, "docsize", zCols, 0, pzErr);
}
if( rc==SQLITE_OK ){
rc = sqlcipher_sqlite3Fts5CreateTable(
@@ -242689,7 +258430,7 @@ static int fts5StorageDeleteFromIndex(
){
Fts5Config *pConfig = p->pConfig;
sqlcipher_sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
int rc2; /* sqlcipher_sqlite3_reset() return code */
int iCol;
Fts5InsertCtx ctx;
@@ -242705,7 +258446,6 @@ static int fts5StorageDeleteFromIndex(
ctx.pStorage = p;
ctx.iCol = -1;
- rc = sqlcipher_sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
if( pConfig->abUnindexed[iCol-1]==0 ){
const char *zText;
@@ -242742,6 +258482,37 @@ static int fts5StorageDeleteFromIndex(
return rc;
}
+/*
+** This function is called to process a DELETE on a contentless_delete=1
+** table. It adds the tombstone required to delete the entry with rowid
+** iDel. If successful, SQLITE_OK is returned. Or, if an error occurs,
+** an SQLite error code.
+*/
+static int fts5StorageContentlessDelete(Fts5Storage *p, i64 iDel){
+ i64 iOrigin = 0;
+ sqlcipher_sqlite3_stmt *pLookup = 0;
+ int rc = SQLITE_OK;
+
+ assert( p->pConfig->bContentlessDelete );
+ assert( p->pConfig->eContent==FTS5_CONTENT_NONE );
+
+ /* Look up the origin of the document in the %_docsize table. Store
+ ** this in stack variable iOrigin. */
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
+ if( rc==SQLITE_OK ){
+ sqlcipher_sqlite3_bind_int64(pLookup, 1, iDel);
+ if( SQLITE_ROW==sqlcipher_sqlite3_step(pLookup) ){
+ iOrigin = sqlcipher_sqlite3_column_int64(pLookup, 1);
+ }
+ rc = sqlcipher_sqlite3_reset(pLookup);
+ }
+
+ if( rc==SQLITE_OK && iOrigin!=0 ){
+ rc = sqlcipher_sqlite3Fts5IndexContentlessDelete(p->pIndex, iOrigin, iDel);
+ }
+
+ return rc;
+}
/*
** Insert a record into the %_docsize table. Specifically, do:
@@ -242762,10 +258533,17 @@ static int fts5StorageInsertDocsize(
rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
if( rc==SQLITE_OK ){
sqlcipher_sqlite3_bind_int64(pReplace, 1, iRowid);
- sqlcipher_sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
- sqlcipher_sqlite3_step(pReplace);
- rc = sqlcipher_sqlite3_reset(pReplace);
- sqlcipher_sqlite3_bind_null(pReplace, 2);
+ if( p->pConfig->bContentlessDelete ){
+ i64 iOrigin = 0;
+ rc = sqlcipher_sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin);
+ sqlcipher_sqlite3_bind_int64(pReplace, 3, iOrigin);
+ }
+ if( rc==SQLITE_OK ){
+ sqlcipher_sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
+ sqlcipher_sqlite3_step(pReplace);
+ rc = sqlcipher_sqlite3_reset(pReplace);
+ sqlcipher_sqlite3_bind_null(pReplace, 2);
+ }
}
}
return rc;
@@ -242829,7 +258607,15 @@ static int sqlcipher_sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlciphe
/* Delete the index records */
if( rc==SQLITE_OK ){
- rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
+ rc = sqlcipher_sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
+ }
+
+ if( rc==SQLITE_OK ){
+ if( p->pConfig->bContentlessDelete ){
+ rc = fts5StorageContentlessDelete(p, iDel);
+ }else{
+ rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
+ }
}
/* Delete the %_docsize record */
@@ -242906,7 +258692,7 @@ static int sqlcipher_sqlite3Fts5StorageRebuild(Fts5Storage *p){
}
if( rc==SQLITE_OK ){
- rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
+ rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, pConfig->pzErrmsg);
}
while( rc==SQLITE_OK && SQLITE_ROW==sqlcipher_sqlite3_step(pScan) ){
@@ -243417,7 +259203,9 @@ static int sqlcipher_sqlite3Fts5StorageSync(Fts5Storage *p){
i64 iLastRowid = sqlcipher_sqlite3_last_insert_rowid(p->pConfig->db);
if( p->bTotalsValid ){
rc = fts5StorageSaveTotals(p);
- p->bTotalsValid = 0;
+ if( rc==SQLITE_OK ){
+ p->bTotalsValid = 0;
+ }
}
if( rc==SQLITE_OK ){
rc = sqlcipher_sqlite3Fts5IndexSync(p->pIndex);
@@ -243541,7 +259329,7 @@ static int fts5AsciiCreate(
int i;
memset(p, 0, sizeof(AsciiTokenizer));
memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
- for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
+ for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
const char *zArg = azArg[i+1];
if( 0==sqlcipher_sqlite3_stricmp(azArg[i], "tokenchars") ){
fts5AsciiAddExceptions(p, zArg, 1);
@@ -243552,6 +259340,7 @@ static int fts5AsciiCreate(
rc = SQLITE_ERROR;
}
}
+ if( rc==SQLITE_OK && i<nArg ) rc = SQLITE_ERROR;
if( rc!=SQLITE_OK ){
fts5AsciiDelete((Fts5Tokenizer*)p);
p = 0;
@@ -243691,6 +259480,12 @@ static const unsigned char sqlcipher_sqlite3Utf8Trans1[] = {
#endif /* ifndef SQLITE_AMALGAMATION */
+#define FTS5_SKIP_UTF8(zIn) { \
+ if( ((unsigned char)(*(zIn++)))>=0xc0 ){ \
+ while( (((unsigned char)*zIn) & 0xc0)==0x80 ){ zIn++; } \
+ } \
+}
+
typedef struct Unicode61Tokenizer Unicode61Tokenizer;
struct Unicode61Tokenizer {
unsigned char aTokenChar[128]; /* ASCII range token characters */
@@ -243837,17 +259632,16 @@ static int fts5UnicodeCreate(
}
/* Search for a "categories" argument */
- for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
+ for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
if( 0==sqlcipher_sqlite3_stricmp(azArg[i], "categories") ){
zCat = azArg[i+1];
}
}
-
if( rc==SQLITE_OK ){
rc = unicodeSetCategories(p, zCat);
}
- for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
+ for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
const char *zArg = azArg[i+1];
if( 0==sqlcipher_sqlite3_stricmp(azArg[i], "remove_diacritics") ){
if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
@@ -243872,6 +259666,7 @@ static int fts5UnicodeCreate(
rc = SQLITE_ERROR;
}
}
+ if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
}else{
rc = SQLITE_NOMEM;
@@ -244726,6 +260521,7 @@ static int fts5PorterTokenize(
typedef struct TrigramTokenizer TrigramTokenizer;
struct TrigramTokenizer {
int bFold; /* True to fold to lower-case */
+ int iFoldParam; /* Parameter to pass to Fts5UnicodeFold() */
};
/*
@@ -244752,7 +260548,8 @@ static int fts5TriCreate(
}else{
int i;
pNew->bFold = 1;
- for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
+ pNew->iFoldParam = 0;
+ for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
const char *zArg = azArg[i+1];
if( 0==sqlcipher_sqlite3_stricmp(azArg[i], "case_sensitive") ){
if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
@@ -244760,10 +260557,22 @@ static int fts5TriCreate(
}else{
pNew->bFold = (zArg[0]=='0');
}
+ }else if( 0==sqlcipher_sqlite3_stricmp(azArg[i], "remove_diacritics") ){
+ if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
+ rc = SQLITE_ERROR;
+ }else{
+ pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
+ }
}else{
rc = SQLITE_ERROR;
}
}
+ if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
+
+ if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
+ rc = SQLITE_ERROR;
+ }
+
if( rc!=SQLITE_OK ){
fts5TriDelete((Fts5Tokenizer*)pNew);
pNew = 0;
@@ -244786,40 +260595,62 @@ static int fts5TriTokenize(
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
int rc = SQLITE_OK;
char aBuf[32];
+ char *zOut = aBuf;
+ int ii;
const unsigned char *zIn = (const unsigned char*)pText;
const unsigned char *zEof = &zIn[nText];
u32 iCode;
+ int aStart[3]; /* Input offset of each character in aBuf[] */
UNUSED_PARAM(unusedFlags);
- while( 1 ){
- char *zOut = aBuf;
- int iStart = zIn - (const unsigned char*)pText;
- const unsigned char *zNext;
-
- READ_UTF8(zIn, zEof, iCode);
- if( iCode==0 ) break;
- zNext = zIn;
- if( zIn<zEof ){
- if( p->bFold ) iCode = sqlcipher_sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
+
+ /* Populate aBuf[] with the characters for the first trigram. */
+ for(ii=0; ii<3; ii++){
+ do {
+ aStart[ii] = zIn - (const unsigned char*)pText;
READ_UTF8(zIn, zEof, iCode);
- if( iCode==0 ) break;
- }else{
- break;
- }
- if( zIn<zEof ){
- if( p->bFold ) iCode = sqlcipher_sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
+ if( iCode==0 ) return SQLITE_OK;
+ if( p->bFold ) iCode = sqlcipher_sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
+ }while( iCode==0 );
+ WRITE_UTF8(zOut, iCode);
+ }
+
+ /* At the start of each iteration of this loop:
+ **
+ ** aBuf: Contains 3 characters. The 3 characters of the next trigram.
+ ** zOut: Points to the byte following the last character in aBuf.
+ ** aStart[3]: Contains the byte offset in the input text corresponding
+ ** to the start of each of the three characters in the buffer.
+ */
+ assert( zIn<=zEof );
+ while( 1 ){
+ int iNext; /* Start of character following current tri */
+ const char *z1;
+
+ /* Read characters from the input up until the first non-diacritic */
+ do {
+ iNext = zIn - (const unsigned char*)pText;
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
- if( p->bFold ) iCode = sqlcipher_sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
- }else{
- break;
- }
- rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf);
- if( rc!=SQLITE_OK ) break;
- zIn = zNext;
+ if( p->bFold ) iCode = sqlcipher_sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
+ }while( iCode==0 );
+
+ /* Pass the current trigram back to fts5 */
+ rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext);
+ if( iCode==0 || rc!=SQLITE_OK ) break;
+
+ /* Remove the first character from buffer aBuf[]. Append the character
+ ** with codepoint iCode. */
+ z1 = aBuf;
+ FTS5_SKIP_UTF8(z1);
+ memmove(aBuf, z1, zOut - z1);
+ zOut -= (z1 - aBuf);
+ WRITE_UTF8(zOut, iCode);
+
+ /* Update the aStart[] array */
+ aStart[0] = aStart[1];
+ aStart[1] = aStart[2];
+ aStart[2] = iNext;
}
return rc;
@@ -244842,7 +260673,9 @@ static int sqlcipher_sqlite3Fts5TokenizerPattern(
){
if( xCreate==fts5TriCreate ){
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
- return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
+ if( p->iFoldParam==0 ){
+ return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
+ }
}
return FTS5_PATTERN_NONE;
}
@@ -246631,7 +262464,7 @@ static int fts5VocabFilterMethod(
if( pEq ){
zTerm = (const char *)sqlcipher_sqlite3_value_text(pEq);
nTerm = sqlcipher_sqlite3_value_bytes(pEq);
- f = 0;
+ f = FTS5INDEX_QUERY_NOTOKENDATA;
}else{
if( pGe ){
zTerm = (const char *)sqlcipher_sqlite3_value_text(pGe);
@@ -246785,7 +262618,8 @@ static int sqlcipher_sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlcipher_sqlite3
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
- /* xShadowName */ 0
+ /* xShadowName */ 0,
+ /* xIntegrity */ 0
};
void *p = (void*)pGlobal;
@@ -246897,6 +262731,10 @@ static int stmtConnect(
#define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */
+ (void)pAux;
+ (void)argc;
+ (void)argv;
+ (void)pzErr;
rc = sqlcipher_sqlite3_declare_vtab(db,
"CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep,"
"reprep,run,mem)");
@@ -247016,6 +262854,10 @@ static int stmtFilter(
sqlcipher_sqlite3_int64 iRowid = 1;
StmtRow **ppRow = 0;
+ (void)idxNum;
+ (void)idxStr;
+ (void)argc;
+ (void)argv;
stmtCsrReset(pCur);
ppRow = &pCur->pRow;
for(p=sqlcipher_sqlite3_next_stmt(pCur->db, 0); p; p=sqlcipher_sqlite3_next_stmt(pCur->db, p)){
@@ -247071,6 +262913,7 @@ static int stmtBestIndex(
sqlcipher_sqlite3_vtab *tab,
sqlcipher_sqlite3_index_info *pIdxInfo
){
+ (void)tab;
pIdxInfo->estimatedCost = (double)500;
pIdxInfo->estimatedRows = 500;
return SQLITE_OK;
@@ -247105,6 +262948,7 @@ static sqlcipher_sqlite3_module stmtModule = {
0, /* xRelease */
0, /* xRollbackTo */
0, /* xShadowName */
+ 0 /* xIntegrity */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
diff --git a/Plugins/DbSqliteCipher/sqlcipher.h b/Plugins/DbSqliteCipher/sqlcipher.h
index 0cda434..2181550 100644
--- a/Plugins/DbSqliteCipher/sqlcipher.h
+++ b/Plugins/DbSqliteCipher/sqlcipher.h
@@ -146,9 +146,9 @@ extern "C" {
** [sqlcipher_sqlite3_libversion_number()], [sqlcipher_sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.39.4"
-#define SQLITE_VERSION_NUMBER 3039004
-#define SQLITE_SOURCE_ID "2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26alt1"
+#define SQLITE_VERSION "3.46.1"
+#define SQLITE_VERSION_NUMBER 3046001
+#define SQLITE_SOURCE_ID "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69aalt1"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -420,6 +420,8 @@ typedef int (*sqlcipher_sqlite3_callback)(void*,int,char**, char**);
** the 1st parameter to sqlcipher_sqlite3_exec() while sqlcipher_sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into
** the 2nd parameter of sqlcipher_sqlite3_exec() while sqlcipher_sqlite3_exec() is running.
+** <li> The application must not dereference the arrays or string pointers
+** passed as the 3rd and 4th callback parameters after it returns.
** </ul>
*/
SQLITE_API int sqlcipher_sqlite3_exec(
@@ -528,6 +530,7 @@ SQLITE_API int sqlcipher_sqlite3_exec(
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
+#define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
@@ -563,6 +566,7 @@ SQLITE_API int sqlcipher_sqlite3_exec(
#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8))
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
+#define SQLITE_NOTICE_RBU (SQLITE_NOTICE | (3<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
@@ -670,13 +674,17 @@ SQLITE_API int sqlcipher_sqlite3_exec(
**
** SQLite uses one of these integer values as the second
** argument to calls it makes to the xLock() and xUnlock() methods
-** of an [sqlcipher_sqlite3_io_methods] object.
+** of an [sqlcipher_sqlite3_io_methods] object. These values are ordered from
+** lest restrictive to most restrictive.
+**
+** The argument to xLock() is always SHARED or higher. The argument to
+** xUnlock is either SHARED or NONE.
*/
-#define SQLITE_LOCK_NONE 0
-#define SQLITE_LOCK_SHARED 1
-#define SQLITE_LOCK_RESERVED 2
-#define SQLITE_LOCK_PENDING 3
-#define SQLITE_LOCK_EXCLUSIVE 4
+#define SQLITE_LOCK_NONE 0 /* xUnlock() only */
+#define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */
+#define SQLITE_LOCK_RESERVED 2 /* xLock() only */
+#define SQLITE_LOCK_PENDING 3 /* xLock() only */
+#define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */
/*
** CAPI3REF: Synchronization Type Flags
@@ -754,7 +762,14 @@ struct sqlcipher_sqlite3_file {
** <li> [SQLITE_LOCK_PENDING], or
** <li> [SQLITE_LOCK_EXCLUSIVE].
** </ul>
-** xLock() increases the lock. xUnlock() decreases the lock.
+** xLock() upgrades the database file lock. In other words, xLock() moves the
+** database file lock in the direction NONE toward EXCLUSIVE. The argument to
+** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
+** SQLITE_LOCK_NONE. If the database file lock is already at or above the
+** requested lock, then the call to xLock() is a no-op.
+** xUnlock() downgrades the database file lock to either SHARED or NONE.
+** If the lock is already at or below the requested lock state, then the call
+** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
** PENDING, or EXCLUSIVE lock on the file. It returns true
@@ -859,9 +874,8 @@ struct sqlcipher_sqlite3_io_methods {
** opcode causes the xFileControl method to write the current state of
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
-** into an integer that the pArg argument points to. This capability
-** is used during testing and is only available when the SQLITE_TEST
-** compile-time option is used.
+** into an integer that the pArg argument points to.
+** This capability is only available if SQLite is compiled with [SQLITE_DEBUG].
**
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
@@ -1165,7 +1179,6 @@ struct sqlcipher_sqlite3_io_methods {
** in wal mode after the client has finished copying pages from the wal
** file to the database file, but before the *-shm file is updated to
** record the fact that the pages have been checkpointed.
-** </ul>
**
** <li>[[SQLITE_FCNTL_EXTERNAL_READER]]
** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect
@@ -1178,10 +1191,16 @@ struct sqlcipher_sqlite3_io_methods {
** the database is not a wal-mode db, or if there is no such connection in any
** other process. This opcode cannot be used to detect transactions opened
** by clients within the current process, only within other processes.
-** </ul>
**
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
-** Used by the cksmvfs VFS module only.
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the
+** [checksum VFS shim] only.
+**
+** <li>[[SQLITE_FCNTL_RESET_CACHE]]
+** If there is currently no transaction open on the database, and the
+** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control
+** purges the contents of the in-memory page cache. If there is an open
+** transaction, or if the db is a temp-db, this opcode is a no-op, not an error.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1224,6 +1243,7 @@ struct sqlcipher_sqlite3_io_methods {
#define SQLITE_FCNTL_CKPT_START 39
#define SQLITE_FCNTL_EXTERNAL_READER 40
#define SQLITE_FCNTL_CKSM_FILE 41
+#define SQLITE_FCNTL_RESET_CACHE 42
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1254,6 +1274,26 @@ typedef struct sqlcipher_sqlite3_mutex sqlcipher_sqlite3_mutex;
typedef struct sqlcipher_sqlite3_api_routines sqlcipher_sqlite3_api_routines;
/*
+** CAPI3REF: File Name
+**
+** Type [sqlcipher_sqlite3_filename] is used by SQLite to pass filenames to the
+** xOpen method of a [VFS]. It may be cast to (const char*) and treated
+** as a normal, nul-terminated, UTF-8 buffer containing the filename, but
+** may also be passed to special APIs such as:
+**
+** <ul>
+** <li> sqlcipher_sqlite3_filename_database()
+** <li> sqlcipher_sqlite3_filename_journal()
+** <li> sqlcipher_sqlite3_filename_wal()
+** <li> sqlcipher_sqlite3_uri_parameter()
+** <li> sqlcipher_sqlite3_uri_boolean()
+** <li> sqlcipher_sqlite3_uri_int64()
+** <li> sqlcipher_sqlite3_uri_key()
+** </ul>
+*/
+typedef const char *sqlcipher_sqlite3_filename;
+
+/*
** CAPI3REF: OS Interface Object
**
** An instance of the sqlcipher_sqlite3_vfs object defines the interface between
@@ -1431,7 +1471,7 @@ struct sqlcipher_sqlite3_vfs {
sqlcipher_sqlite3_vfs *pNext; /* Next registered VFS */
const char *zName; /* Name of this virtual file system */
void *pAppData; /* Pointer to application-specific data */
- int (*xOpen)(sqlcipher_sqlite3_vfs*, const char *zName, sqlcipher_sqlite3_file*,
+ int (*xOpen)(sqlcipher_sqlite3_vfs*, sqlcipher_sqlite3_filename zName, sqlcipher_sqlite3_file*,
int flags, int *pOutFlags);
int (*xDelete)(sqlcipher_sqlite3_vfs*, const char *zName, int syncDir);
int (*xAccess)(sqlcipher_sqlite3_vfs*, const char *zName, int flags, int *pResOut);
@@ -1618,20 +1658,23 @@ SQLITE_API int sqlcipher_sqlite3_os_end(void);
** must ensure that no other SQLite interfaces are invoked by other
** threads while sqlcipher_sqlite3_config() is running.</b>
**
-** The sqlcipher_sqlite3_config() interface
-** may only be invoked prior to library initialization using
-** [sqlcipher_sqlite3_initialize()] or after shutdown by [sqlcipher_sqlite3_shutdown()].
-** ^If sqlcipher_sqlite3_config() is called after [sqlcipher_sqlite3_initialize()] and before
-** [sqlcipher_sqlite3_shutdown()] then it will return SQLITE_MISUSE.
-** Note, however, that ^sqlcipher_sqlite3_config() can be called as part of the
-** implementation of an application-defined [sqlcipher_sqlite3_os_init()].
-**
** The first argument to sqlcipher_sqlite3_config() is an integer
** [configuration option] that determines
** what property of SQLite is to be configured. Subsequent arguments
** vary depending on the [configuration option]
** in the first argument.
**
+** For most configuration options, the sqlcipher_sqlite3_config() interface
+** may only be invoked prior to library initialization using
+** [sqlcipher_sqlite3_initialize()] or after shutdown by [sqlcipher_sqlite3_shutdown()].
+** The exceptional configuration options that may be invoked at any time
+** are called "anytime configuration options".
+** ^If sqlcipher_sqlite3_config() is called after [sqlcipher_sqlite3_initialize()] and before
+** [sqlcipher_sqlite3_shutdown()] with a first argument that is not an anytime
+** configuration option, then the sqlcipher_sqlite3_config() call will return SQLITE_MISUSE.
+** Note, however, that ^sqlcipher_sqlite3_config() can be called as part of the
+** implementation of an application-defined [sqlcipher_sqlite3_os_init()].
+**
** ^When a configuration option is set, sqlcipher_sqlite3_config() returns [SQLITE_OK].
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
@@ -1739,6 +1782,23 @@ struct sqlcipher_sqlite3_mem_methods {
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlcipher_sqlite3_config()] interface.
**
+** Most of the configuration options for sqlcipher_sqlite3_config()
+** will only work if invoked prior to [sqlcipher_sqlite3_initialize()] or after
+** [sqlcipher_sqlite3_shutdown()]. The few exceptions to this rule are called
+** "anytime configuration options".
+** ^Calling [sqlcipher_sqlite3_config()] with a first argument that is not an
+** anytime configuration option in between calls to [sqlcipher_sqlite3_initialize()] and
+** [sqlcipher_sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE.
+**
+** The set of anytime configuration options can change (by insertions
+** and/or deletions) from one release of SQLite to the next.
+** As of SQLite version 3.42.0, the complete set of anytime configuration
+** options is:
+** <ul>
+** <li> SQLITE_CONFIG_LOG
+** <li> SQLITE_CONFIG_PCACHE_HDRSZ
+** </ul>
+**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
** should check the return code from [sqlcipher_sqlite3_config()] to make sure that
@@ -2069,7 +2129,7 @@ struct sqlcipher_sqlite3_mem_methods {
** is stored in each sorted record and the required column values loaded
** from the database as records are returned in sorted order. The default
** value for this option is to never use this optimization. Specifying a
-** negative value for this option restores the default behaviour.
+** negative value for this option restores the default behavior.
** This option is only available if SQLite is compiled with the
** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
**
@@ -2083,30 +2143,46 @@ struct sqlcipher_sqlite3_mem_methods {
** configuration setting is never used, then the default maximum is determined
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
** compile-time option is not set, then the default maximum is 1073741824.
+**
+** [[SQLITE_CONFIG_ROWID_IN_VIEW]]
+** <dt>SQLITE_CONFIG_ROWID_IN_VIEW
+** <dd>The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability
+** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is
+** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability
+** defaults to on. This configuration option queries the current setting or
+** changes the setting to off or on. The argument is a pointer to an integer.
+** If that integer initially holds a value of 1, then the ability for VIEWs to
+** have ROWIDs is activated. If the integer initially holds zero, then the
+** ability is deactivated. Any other initial value for the integer leaves the
+** setting unchanged. After changes, if any, the integer is written with
+** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite
+** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and
+** recommended case) then the integer is always filled with zero, regardless
+** if its initial value.
** </dl>
*/
-#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
-#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
-#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* sqlcipher_sqlite3_mem_methods* */
-#define SQLITE_CONFIG_GETMALLOC 5 /* sqlcipher_sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
-#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
-#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
-#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
-#define SQLITE_CONFIG_MUTEX 10 /* sqlcipher_sqlite3_mutex_methods* */
-#define SQLITE_CONFIG_GETMUTEX 11 /* sqlcipher_sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
-#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#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 /* sqlcipher_sqlite3_pcache_methods2* */
-#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlcipher_sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
+#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
+#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
+#define SQLITE_CONFIG_MALLOC 4 /* sqlcipher_sqlite3_mem_methods* */
+#define SQLITE_CONFIG_GETMALLOC 5 /* sqlcipher_sqlite3_mem_methods* */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
+#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
+#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
+#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
+#define SQLITE_CONFIG_MUTEX 10 /* sqlcipher_sqlite3_mutex_methods* */
+#define SQLITE_CONFIG_GETMUTEX 11 /* sqlcipher_sqlite3_mutex_methods* */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
+#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 /* sqlcipher_sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlcipher_sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
-#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
-#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlcipher_sqlite3_int64, sqlcipher_sqlite3_int64 */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlcipher_sqlite3_int64, sqlcipher_sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
@@ -2114,6 +2190,7 @@ struct sqlcipher_sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlcipher_sqlite3_int64 */
+#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2147,7 +2224,7 @@ struct sqlcipher_sqlite3_mem_methods {
** configuration for a database connection can only be changed when that
** connection is not currently using lookaside memory, or in other words
** when the "current value" returned by
-** [sqlcipher_sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
+** [sqlcipher_sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
** Any attempt to change the lookaside memory configuration when lookaside
** memory is in use leaves the configuration unchanged and returns
** [SQLITE_BUSY].)^</dd>
@@ -2244,7 +2321,7 @@ struct sqlcipher_sqlite3_mem_methods {
** database handle, SQLite checks if this will mean that there are now no
** connections at all to the database. If so, it performs a checkpoint
** operation before closing the connection. This option may be used to
-** override this behaviour. The first parameter passed to this operation
+** override this behavior. The first parameter passed to this operation
** is an integer - positive to disable checkpoints-on-close, or zero (the
** default) to enable them, and negative to leave the setting unchanged.
** The second parameter is a pointer to an integer
@@ -2297,8 +2374,12 @@ struct sqlcipher_sqlite3_mem_methods {
** <li> sqlcipher_sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
** </ol>
** Because resetting a database is destructive and irreversible, the
-** process requires the use of this obscure API and multiple steps to help
-** ensure that it does not happen by accident.
+** process requires the use of this obscure API and multiple steps to
+** help ensure that it does not happen by accident. Because this
+** feature must be capable of resetting corrupt databases, and
+** shutting down virtual tables may require access to that corrupt
+** storage, the library must abandon any installed virtual tables
+** without calling their xDestroy() methods.
**
** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the
@@ -2309,6 +2390,7 @@ struct sqlcipher_sqlite3_mem_methods {
** <ul>
** <li> The [PRAGMA writable_schema=ON] statement.
** <li> The [PRAGMA journal_mode=OFF] statement.
+** <li> The [PRAGMA schema_version=N] statement.
** <li> Writes to the [sqlite_dbpage] virtual table.
** <li> Direct writes to [shadow tables].
** </ul>
@@ -2336,7 +2418,7 @@ struct sqlcipher_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
-** <dt>SQLITE_DBCONFIG_DQS_DML</td>
+** <dt>SQLITE_DBCONFIG_DQS_DML</dt>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@@ -2345,7 +2427,7 @@ struct sqlcipher_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
-** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
+** <dt>SQLITE_DBCONFIG_DQS_DDL</dt>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
@@ -2354,7 +2436,7 @@ struct sqlcipher_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
-** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
+** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@@ -2374,7 +2456,7 @@ struct sqlcipher_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
-** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
+** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
@@ -2383,7 +2465,7 @@ struct sqlcipher_sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
-** is now scarcely any need to generated database files that are compatible
+** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version
@@ -2392,8 +2474,40 @@ struct sqlcipher_sqlite3_mem_methods {
** the [VACUUM] command will fail with an obscure error when attempting to
** process a table with generated columns and a descending index. This is
** not considered a bug since SQLite versions 3.3.0 and earlier do not support
-** either generated columns or decending indexes.
+** either generated columns or descending indexes.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
+** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
+** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
+** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
+** a flag that enables collection of the sqlcipher_sqlite3_stmt_scanstatus_v2()
+** statistics. For statistics to be collected, the flag must be set on
+** the database handle both when the SQL statement is prepared and when it
+** is stepped. The flag is set (collection of statistics is enabled)
+** by default. This option takes two arguments: an integer and a pointer to
+** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the statement scanstatus option. If the second argument
+** is not NULL, then the value of the statement scanstatus setting after
+** processing the first argument is written into the integer that the second
+** argument points to.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
+** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
+** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
+** in which tables and indexes are scanned so that the scans start at the end
+** and work toward the beginning rather than starting at the beginning and
+** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
+** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** two arguments which are an integer and a pointer to an integer. The first
+** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
+** reverse scan order flag, respectively. If the second argument is not NULL,
+** then 0 or 1 is written into the integer that the second argument points to
+** depending on if the reverse scan order flag is set after processing the
+** first argument.
** </dd>
+**
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2414,7 +2528,9 @@ struct sqlcipher_sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
+#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -2636,8 +2752,13 @@ SQLITE_API sqlcipher_sqlite3_int64 sqlcipher_sqlite3_total_changes64(sqlcipher_s
** ^A call to sqlcipher_sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlcipher_sqlite3_interrupt() call returns.
+**
+** ^The [sqlcipher_sqlite3_is_interrupted(D)] interface can be used to determine whether
+** or not an interrupt is currently in effect for [database connection] D.
+** It returns 1 if an interrupt is currently in effect, or 0 otherwise.
*/
SQLITE_API void sqlcipher_sqlite3_interrupt(sqlcipher_sqlite3*);
+SQLITE_API int sqlcipher_sqlite3_is_interrupted(sqlcipher_sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -3184,8 +3305,8 @@ SQLITE_API int sqlcipher_sqlite3_set_authorizer(
#define SQLITE_RECURSIVE 33 /* NULL NULL */
/*
-** CAPI3REF: Tracing And Profiling Functions
-** METHOD: sqlcipher_sqlite3
+** CAPI3REF: Deprecated Tracing And Profiling Functions
+** DEPRECATED
**
** These routines are deprecated. Use the [sqlcipher_sqlite3_trace_v2()] interface
** instead of the routines described here.
@@ -3255,8 +3376,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlcipher_sqlite3_profile(sqlcipher_sqlite3*,
** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
** information as is provided by the [sqlcipher_sqlite3_profile()] callback.
** ^The P argument is a pointer to the [prepared statement] and the
-** X argument points to a 64-bit integer which is the estimated of
-** the number of nanosecond that the prepared statement took to run.
+** X argument points to a 64-bit integer which is approximately
+** the number of nanoseconds that the prepared statement took to run.
** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
**
** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
@@ -3288,8 +3409,10 @@ SQLITE_API SQLITE_DEPRECATED void *sqlcipher_sqlite3_profile(sqlcipher_sqlite3*,
** M argument should be the bitwise OR-ed combination of
** zero or more [SQLITE_TRACE] constants.
**
-** ^Each call to either sqlcipher_sqlite3_trace() or sqlcipher_sqlite3_trace_v2() overrides
-** (cancels) any prior calls to sqlcipher_sqlite3_trace() or sqlcipher_sqlite3_trace_v2().
+** ^Each call to either sqlcipher_sqlite3_trace(D,X,P) or sqlcipher_sqlite3_trace_v2(D,M,X,P)
+** overrides (cancels) all prior calls to sqlcipher_sqlite3_trace(D,X,P) or
+** sqlcipher_sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each
+** database connection may have at most one trace callback.
**
** ^The X callback is invoked whenever any of the events identified by
** mask M occur. ^The integer return value from the callback is currently
@@ -3319,7 +3442,7 @@ SQLITE_API int sqlcipher_sqlite3_trace_v2(
**
** ^The sqlcipher_sqlite3_progress_handler(D,N,X,P) interface causes the callback
** function X to be invoked periodically during long running calls to
-** [sqlcipher_sqlite3_exec()], [sqlcipher_sqlite3_step()] and [sqlcipher_sqlite3_get_table()] for
+** [sqlcipher_sqlite3_step()] and [sqlcipher_sqlite3_prepare()] and similar for
** database connection D. An example use for this
** interface is to keep a GUI updated during a large query.
**
@@ -3344,6 +3467,13 @@ SQLITE_API int sqlcipher_sqlite3_trace_v2(
** Note that [sqlcipher_sqlite3_prepare_v2()] and [sqlcipher_sqlite3_step()] both modify their
** database connections for the meaning of "modify" in this paragraph.
**
+** The progress handler callback would originally only be invoked from the
+** bytecode engine. It still might be invoked during [sqlcipher_sqlite3_prepare()]
+** and similar because those routines might force a reparse of the schema
+** which involves running the bytecode engine. However, beginning with
+** SQLite version 3.41.0, the progress handler callback might also be
+** invoked directly from [sqlcipher_sqlite3_prepare()] while analyzing and generating
+** code for complex queries.
*/
SQLITE_API void sqlcipher_sqlite3_progress_handler(sqlcipher_sqlite3*, int, int(*)(void*), void*);
@@ -3380,13 +3510,18 @@ SQLITE_API void sqlcipher_sqlite3_progress_handler(sqlcipher_sqlite3*, int, int(
**
** <dl>
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
-** <dd>The database is opened in read-only mode. If the database does not
-** already exist, an error is returned.</dd>)^
+** <dd>The database is opened in read-only mode. If the database does
+** not already exist, an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
-** <dd>The database is opened for reading and writing if possible, or reading
-** only if the file is write protected by the operating system. In either
-** case the database must already exist, otherwise an error is returned.</dd>)^
+** <dd>The database is opened for reading and writing if possible, or
+** reading only if the file is write protected by the operating
+** system. In either case the database must already exist, otherwise
+** an error is returned. For historical reasons, if opening in
+** read-write mode fails due to OS-level permissions, an attempt is
+** made to open it in read-only mode. [sqlcipher_sqlite3_db_readonly()] can be
+** used to determine whether the database is actually
+** read-write.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
** <dd>The database is opened for reading and writing, and is created if
@@ -3424,6 +3559,9 @@ SQLITE_API void sqlcipher_sqlite3_progress_handler(sqlcipher_sqlite3*, int, int(
** <dd>The database is opened [shared cache] enabled, overriding
** the default shared cache setting provided by
** [sqlcipher_sqlite3_enable_shared_cache()].)^
+** The [use of shared cache mode is discouraged] and hence shared cache
+** capabilities may be omitted from many builds of SQLite. In such cases,
+** this option is a no-op.
**
** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
** <dd>The database is opened [shared cache] disabled, overriding
@@ -3439,7 +3577,7 @@ SQLITE_API void sqlcipher_sqlite3_progress_handler(sqlcipher_sqlite3*, int, int(
** to return an extended result code.</dd>
**
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
-** <dd>The database filename is not allowed to be a symbolic link</dd>
+** <dd>The database filename is not allowed to contain a symbolic link</dd>
** </dl>)^
**
** If the 3rd parameter to sqlcipher_sqlite3_open_v2() is not one of the
@@ -3643,7 +3781,7 @@ SQLITE_API int sqlcipher_sqlite3_open_v2(
** as F) must be one of:
** <ul>
** <li> A database filename pointer created by the SQLite core and
-** passed into the xOpen() method of a VFS implemention, or
+** passed into the xOpen() method of a VFS implementation, or
** <li> A filename obtained from [sqlcipher_sqlite3_db_filename()], or
** <li> A new filename constructed using [sqlcipher_sqlite3_create_filename()].
** </ul>
@@ -3698,10 +3836,10 @@ SQLITE_API int sqlcipher_sqlite3_open_v2(
**
** See the [URI filename] documentation for additional information.
*/
-SQLITE_API const char *sqlcipher_sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int sqlcipher_sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlcipher_sqlite3_int64 sqlcipher_sqlite3_uri_int64(const char*, const char*, sqlcipher_sqlite3_int64);
-SQLITE_API const char *sqlcipher_sqlite3_uri_key(const char *zFilename, int N);
+SQLITE_API const char *sqlcipher_sqlite3_uri_parameter(sqlcipher_sqlite3_filename z, const char *zParam);
+SQLITE_API int sqlcipher_sqlite3_uri_boolean(sqlcipher_sqlite3_filename z, const char *zParam, int bDefault);
+SQLITE_API sqlcipher_sqlite3_int64 sqlcipher_sqlite3_uri_int64(sqlcipher_sqlite3_filename, const char*, sqlcipher_sqlite3_int64);
+SQLITE_API const char *sqlcipher_sqlite3_uri_key(sqlcipher_sqlite3_filename z, int N);
/*
** CAPI3REF: Translate filenames
@@ -3730,9 +3868,9 @@ SQLITE_API const char *sqlcipher_sqlite3_uri_key(const char *zFilename, int N);
** return value from [sqlcipher_sqlite3_db_filename()], then the result is
** undefined and is likely a memory access violation.
*/
-SQLITE_API const char *sqlcipher_sqlite3_filename_database(const char*);
-SQLITE_API const char *sqlcipher_sqlite3_filename_journal(const char*);
-SQLITE_API const char *sqlcipher_sqlite3_filename_wal(const char*);
+SQLITE_API const char *sqlcipher_sqlite3_filename_database(sqlcipher_sqlite3_filename);
+SQLITE_API const char *sqlcipher_sqlite3_filename_journal(sqlcipher_sqlite3_filename);
+SQLITE_API const char *sqlcipher_sqlite3_filename_wal(sqlcipher_sqlite3_filename);
/*
** CAPI3REF: Database File Corresponding To A Journal
@@ -3756,7 +3894,7 @@ SQLITE_API sqlcipher_sqlite3_file *sqlcipher_sqlite3_database_file_object(const
/*
** CAPI3REF: Create and Destroy VFS Filenames
**
-** These interfces are provided for use by [VFS shim] implementations and
+** These interfaces are provided for use by [VFS shim] implementations and
** are not useful outside of that context.
**
** The sqlcipher_sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
@@ -3798,14 +3936,14 @@ SQLITE_API sqlcipher_sqlite3_file *sqlcipher_sqlite3_database_file_object(const
** then the corresponding [sqlcipher_sqlite3_module.xClose() method should also be
** invoked prior to calling sqlcipher_sqlite3_free_filename(Y).
*/
-SQLITE_API char *sqlcipher_sqlite3_create_filename(
+SQLITE_API sqlcipher_sqlite3_filename sqlcipher_sqlite3_create_filename(
const char *zDatabase,
const char *zJournal,
const char *zWal,
int nParam,
const char **azParam
);
-SQLITE_API void sqlcipher_sqlite3_free_filename(char*);
+SQLITE_API void sqlcipher_sqlite3_free_filename(sqlcipher_sqlite3_filename);
/*
** CAPI3REF: Error Codes And Messages
@@ -3835,14 +3973,17 @@ SQLITE_API void sqlcipher_sqlite3_free_filename(char*);
** </ul>
**
** ^The sqlcipher_sqlite3_errmsg() and sqlcipher_sqlite3_errmsg16() return English-language
-** text that describes the error, as either UTF-8 or UTF-16 respectively.
+** text that describes the error, as either UTF-8 or UTF-16 respectively,
+** or NULL if no error message is available.
+** (See how SQLite handles [invalid UTF] for exceptions to this rule.)
** ^(Memory to hold the error message string is managed internally.
** The application does not need to worry about freeing the result.
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
-** ^The sqlcipher_sqlite3_errstr() interface returns the English-language text
-** that describes the [result code], as UTF-8.
+** ^The sqlcipher_sqlite3_errstr(E) interface returns the English-language text
+** that describes the [result code] E, as UTF-8, or NULL if E is not an
+** result code for which a text error message is available.
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
@@ -4304,6 +4445,41 @@ SQLITE_API int sqlcipher_sqlite3_stmt_readonly(sqlcipher_sqlite3_stmt *pStmt);
SQLITE_API int sqlcipher_sqlite3_stmt_isexplain(sqlcipher_sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement
+** METHOD: sqlcipher_sqlite3_stmt
+**
+** The sqlcipher_sqlite3_stmt_explain(S,E) interface changes the EXPLAIN
+** setting for [prepared statement] S. If E is zero, then S becomes
+** a normal prepared statement. If E is 1, then S behaves as if
+** its SQL text began with "[EXPLAIN]". If E is 2, then S behaves as if
+** its SQL text began with "[EXPLAIN QUERY PLAN]".
+**
+** Calling sqlcipher_sqlite3_stmt_explain(S,E) might cause S to be reprepared.
+** SQLite tries to avoid a reprepare, but a reprepare might be necessary
+** on the first transition into EXPLAIN or EXPLAIN QUERY PLAN mode.
+**
+** Because of the potential need to reprepare, a call to
+** sqlcipher_sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be
+** reprepared because it was created using [sqlcipher_sqlite3_prepare()] instead of
+** the newer [sqlcipher_sqlite3_prepare_v2()] or [sqlcipher_sqlite3_prepare_v3()] interfaces and
+** hence has no saved SQL text with which to reprepare.
+**
+** Changing the explain setting for a prepared statement does not change
+** the original SQL text for the statement. Hence, if the SQL text originally
+** began with EXPLAIN or EXPLAIN QUERY PLAN, but sqlcipher_sqlite3_stmt_explain(S,0)
+** is called to convert the statement into an ordinary statement, the EXPLAIN
+** or EXPLAIN QUERY PLAN keywords will still appear in the sqlcipher_sqlite3_sql(S)
+** output, even though the statement now acts like a normal SQL statement.
+**
+** This routine returns SQLITE_OK if the explain mode is successfully
+** changed, or an error code if the explain mode could not be changed.
+** The explain mode cannot be changed while a statement is active.
+** Hence, it is good practice to call [sqlcipher_sqlite3_reset(S)]
+** immediately prior to calling sqlcipher_sqlite3_stmt_explain(S,E).
+*/
+SQLITE_API int sqlcipher_sqlite3_stmt_explain(sqlcipher_sqlite3_stmt *pStmt, int eMode);
+
+/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: sqlcipher_sqlite3_stmt
**
@@ -4466,7 +4642,7 @@ typedef struct sqlcipher_sqlite3_context sqlcipher_sqlite3_context;
** with it may be passed. ^It is called to dispose of the BLOB or string even
** if the call to the bind API fails, except the destructor is not called if
** the third parameter is a NULL pointer or the fourth parameter is negative.
-** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that
+** ^ (2) The special constant, [SQLITE_STATIC], may be passed to indicate that
** the application remains responsible for disposing of the object. ^In this
** case, the object and the provided pointer to it must remain valid until
** either the prepared statement is finalized or the same SQL parameter is
@@ -5145,20 +5321,33 @@ SQLITE_API int sqlcipher_sqlite3_finalize(sqlcipher_sqlite3_stmt *pStmt);
** ^The [sqlcipher_sqlite3_reset(S)] interface resets the [prepared statement] S
** back to the beginning of its program.
**
-** ^If the most recent call to [sqlcipher_sqlite3_step(S)] for the
-** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
-** or if [sqlcipher_sqlite3_step(S)] has never before been called on S,
-** then [sqlcipher_sqlite3_reset(S)] returns [SQLITE_OK].
+** ^The return code from [sqlcipher_sqlite3_reset(S)] indicates whether or not
+** the previous evaluation of prepared statement S completed successfully.
+** ^If [sqlcipher_sqlite3_step(S)] has never before been called on S or if
+** [sqlcipher_sqlite3_step(S)] has not been called since the previous call
+** to [sqlcipher_sqlite3_reset(S)], then [sqlcipher_sqlite3_reset(S)] will return
+** [SQLITE_OK].
**
** ^If the most recent call to [sqlcipher_sqlite3_step(S)] for the
** [prepared statement] S indicated an error, then
** [sqlcipher_sqlite3_reset(S)] returns an appropriate [error code].
+** ^The [sqlcipher_sqlite3_reset(S)] interface might also return an [error code]
+** if there were no prior errors but the process of resetting
+** the prepared statement caused a new error. ^For example, if an
+** [INSERT] statement with a [RETURNING] clause is only stepped one time,
+** that one call to [sqlcipher_sqlite3_step(S)] might return SQLITE_ROW but
+** the overall statement might still fail and the [sqlcipher_sqlite3_reset(S)] call
+** might return SQLITE_BUSY if locking constraints prevent the
+** database change from committing. Therefore, it is important that
+** applications check the return code from [sqlcipher_sqlite3_reset(S)] even if
+** no prior call to [sqlcipher_sqlite3_step(S)] indicated a problem.
**
** ^The [sqlcipher_sqlite3_reset(S)] interface does not change the values
** of any [sqlcipher_sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int sqlcipher_sqlite3_reset(sqlcipher_sqlite3_stmt *pStmt);
+
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
@@ -5364,10 +5553,21 @@ SQLITE_API int sqlcipher_sqlite3_create_window_function(
** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
** schema structures such as [CHECK constraints], [DEFAULT clauses],
** [expression indexes], [partial indexes], or [generated columns].
-** The SQLITE_DIRECTONLY flags is a security feature which is recommended
-** for all [application-defined SQL functions], and especially for functions
-** that have side-effects or that could potentially leak sensitive
-** information.
+** <p>
+** The SQLITE_DIRECTONLY flag is recommended for any
+** [application-defined SQL function]
+** that has side-effects or that could potentially leak sensitive information.
+** This will prevent attacks in which an application is tricked
+** into using a database file that has had its schema surreptitiously
+** modified to invoke the application-defined function in ways that are
+** harmful.
+** <p>
+** Some people say it is good practice to set SQLITE_DIRECTONLY on all
+** [application-defined SQL functions], regardless of whether or not they
+** are security sensitive, as doing so prevents those functions from being used
+** inside of the database schema, and thus ensures that the database
+** can be inspected and modified using generic tools (such as the [CLI])
+** that do not have access to the application-defined functions.
** </dd>
**
** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd>
@@ -5394,13 +5594,27 @@ SQLITE_API int sqlcipher_sqlite3_create_window_function(
** </dd>
**
** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd>
-** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
+** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
** [sqlcipher_sqlite3_value_subtype()] to inspect the sub-types of its arguments.
-** Specifying this flag makes no difference for scalar or aggregate user
-** functions. However, if it is not specified for a user-defined window
-** function, then any sub-types belonging to arguments passed to the window
-** function may be discarded before the window function is called (i.e.
-** sqlcipher_sqlite3_value_subtype() will always return 0).
+** This flag instructs SQLite to omit some corner-case optimizations that
+** might disrupt the operation of the [sqlcipher_sqlite3_value_subtype()] function,
+** causing it to return zero rather than the correct subtype().
+** SQL functions that invokes [sqlcipher_sqlite3_value_subtype()] should have this
+** property. If the SQLITE_SUBTYPE property is omitted, then the return
+** value from [sqlcipher_sqlite3_value_subtype()] might sometimes be zero even though
+** a non-zero subtype was specified by the function argument expression.
+**
+** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
+** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call
+** [sqlcipher_sqlite3_result_subtype()] to cause a sub-type to be associated with its
+** result.
+** Every function that invokes [sqlcipher_sqlite3_result_subtype()] should have this
+** property. If it does not, then the call to [sqlcipher_sqlite3_result_subtype()]
+** might become a no-op if the function is used as term in an
+** [expression index]. On the other hand, SQL functions that never invoke
+** [sqlcipher_sqlite3_result_subtype()] should avoid setting this property, as the
+** purpose of this property is to disable certain optimizations that are
+** incompatible with subtypes.
** </dd>
** </dl>
*/
@@ -5408,6 +5622,7 @@ SQLITE_API int sqlcipher_sqlite3_create_window_function(
#define SQLITE_DIRECTONLY 0x000080000
#define SQLITE_SUBTYPE 0x000100000
#define SQLITE_INNOCUOUS 0x000200000
+#define SQLITE_RESULT_SUBTYPE 0x001000000
/*
** CAPI3REF: Deprecated Functions
@@ -5574,6 +5789,28 @@ SQLITE_API int sqlcipher_sqlite3_value_nochange(sqlcipher_sqlite3_value*);
SQLITE_API int sqlcipher_sqlite3_value_frombind(sqlcipher_sqlite3_value*);
/*
+** CAPI3REF: Report the internal text encoding state of an sqlcipher_sqlite3_value object
+** METHOD: sqlcipher_sqlite3_value
+**
+** ^(The sqlcipher_sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8],
+** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current text encoding
+** of the value X, assuming that X has type TEXT.)^ If sqlcipher_sqlite3_value_type(X)
+** returns something other than SQLITE_TEXT, then the return value from
+** sqlcipher_sqlite3_value_encoding(X) is meaningless. ^Calls to
+** [sqlcipher_sqlite3_value_text(X)], [sqlcipher_sqlite3_value_text16(X)], [sqlcipher_sqlite3_value_text16be(X)],
+** [sqlcipher_sqlite3_value_text16le(X)], [sqlcipher_sqlite3_value_bytes(X)], or
+** [sqlcipher_sqlite3_value_bytes16(X)] might change the encoding of the value X and
+** thus change the return from subsequent calls to sqlcipher_sqlite3_value_encoding(X).
+**
+** This routine is intended for used by applications that test and validate
+** the SQLite implementation. This routine is inquiring about the opaque
+** internal state of an [sqlcipher_sqlite3_value] object. Ordinary applications should
+** not need to know what the internal state of an sqlcipher_sqlite3_value object is and
+** hence should not need to use this interface.
+*/
+SQLITE_API int sqlcipher_sqlite3_value_encoding(sqlcipher_sqlite3_value*);
+
+/*
** CAPI3REF: Finding The Subtype Of SQL Values
** METHOD: sqlcipher_sqlite3_value
**
@@ -5582,6 +5819,12 @@ SQLITE_API int sqlcipher_sqlite3_value_frombind(sqlcipher_sqlite3_value*);
** information can be used to pass a limited amount of context from
** one SQL function to another. Use the [sqlcipher_sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
+**
+** Every [application-defined SQL function] that invoke this interface
+** should include the [SQLITE_SUBTYPE] property in the text
+** encoding argument when the function is [sqlcipher_sqlite3_create_function|registered].
+** If the [SQLITE_SUBTYPE] property is omitted, then sqlcipher_sqlite3_value_subtype()
+** might return zero instead of the upstream subtype in some corner cases.
*/
SQLITE_API unsigned int sqlcipher_sqlite3_value_subtype(sqlcipher_sqlite3_value*);
@@ -5625,7 +5868,7 @@ SQLITE_API void sqlcipher_sqlite3_value_free(sqlcipher_sqlite3_value*);
**
** ^The sqlcipher_sqlite3_aggregate_context(C,N) routine returns a NULL pointer
** when first called if N is less than or equal to zero or if a memory
-** allocate error occurs.
+** allocation error occurs.
**
** ^(The amount of space allocated by sqlcipher_sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call. Changing the
@@ -5680,48 +5923,56 @@ SQLITE_API sqlcipher_sqlite3 *sqlcipher_sqlite3_context_db_handle(sqlcipher_sqli
** METHOD: sqlcipher_sqlite3_context
**
** These functions may be used by (non-aggregate) SQL functions to
-** associate metadata with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated metadata may be preserved. An example
-** of where this might be useful is in a regular-expression matching
-** function. The compiled version of the regular expression can be stored as
-** metadata associated with the pattern string.
+** associate auxiliary data with argument values. If the same argument
+** value is passed to multiple invocations of the same SQL function during
+** query execution, under some circumstances the associated auxiliary data
+** might be preserved. An example of where this might be useful is in a
+** regular-expression matching function. The compiled version of the regular
+** expression can be stored as auxiliary data associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The sqlcipher_sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** ^The sqlcipher_sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
** associated by the sqlcipher_sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
** value to the application-defined function. ^N is zero for the left-most
-** function argument. ^If there is no metadata
+** function argument. ^If there is no auxiliary data
** associated with the function argument, the sqlcipher_sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
-** ^The sqlcipher_sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
-** argument of the application-defined function. ^Subsequent
+** ^The sqlcipher_sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
+** N-th argument of the application-defined function. ^Subsequent
** calls to sqlcipher_sqlite3_get_auxdata(C,N) return P from the most recent
-** sqlcipher_sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or
-** NULL if the metadata has been discarded.
+** sqlcipher_sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or
+** NULL if the auxiliary data has been discarded.
** ^After each call to sqlcipher_sqlite3_set_auxdata(C,N,P,X) where X is not NULL,
** SQLite will invoke the destructor function X with parameter P exactly
-** once, when the metadata is discarded.
-** SQLite is free to discard the metadata at any time, including: <ul>
+** once, when the auxiliary data is discarded.
+** SQLite is free to discard the auxiliary data at any time, including: <ul>
** <li> ^(when the corresponding function parameter changes)^, or
** <li> ^(when [sqlcipher_sqlite3_reset()] or [sqlcipher_sqlite3_finalize()] is called for the
** SQL statement)^, or
** <li> ^(when sqlcipher_sqlite3_set_auxdata() is invoked again on the same
** parameter)^, or
** <li> ^(during the original sqlcipher_sqlite3_set_auxdata() call when a memory
-** allocation error occurs.)^ </ul>
+** allocation error occurs.)^
+** <li> ^(during the original sqlcipher_sqlite3_set_auxdata() call if the function
+** is evaluated during query planning instead of during query execution,
+** as sometimes happens with [SQLITE_ENABLE_STAT4].)^ </ul>
**
-** Note the last bullet in particular. The destructor X in
+** Note the last two bullets in particular. The destructor X in
** sqlcipher_sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
** sqlcipher_sqlite3_set_auxdata() interface even returns. Hence sqlcipher_sqlite3_set_auxdata()
** should be called near the end of the function implementation and the
** function implementation should not make any use of P after
-** sqlcipher_sqlite3_set_auxdata() has been called.
-**
-** ^(In practice, metadata is preserved between function calls for
+** sqlcipher_sqlite3_set_auxdata() has been called. Furthermore, a call to
+** sqlcipher_sqlite3_get_auxdata() that occurs immediately after a corresponding call
+** to sqlcipher_sqlite3_set_auxdata() might still return NULL if an out-of-memory
+** condition occurred during the sqlcipher_sqlite3_set_auxdata() call or if the
+** function is being evaluated during query planning rather than during
+** query execution.
+**
+** ^(In practice, auxiliary data is preserved between function calls for
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
**
@@ -5731,10 +5982,67 @@ SQLITE_API sqlcipher_sqlite3 *sqlcipher_sqlite3_context_db_handle(sqlcipher_sqli
**
** These routines must be called from the same thread in which
** the SQL function is running.
+**
+** See also: [sqlcipher_sqlite3_get_clientdata()] and [sqlcipher_sqlite3_set_clientdata()].
*/
SQLITE_API void *sqlcipher_sqlite3_get_auxdata(sqlcipher_sqlite3_context*, int N);
SQLITE_API void sqlcipher_sqlite3_set_auxdata(sqlcipher_sqlite3_context*, int N, void*, void (*)(void*));
+/*
+** CAPI3REF: Database Connection Client Data
+** METHOD: sqlcipher_sqlite3
+**
+** These functions are used to associate one or more named pointers
+** with a [database connection].
+** A call to sqlcipher_sqlite3_set_clientdata(D,N,P,X) causes the pointer P
+** to be attached to [database connection] D using name N. Subsequent
+** calls to sqlcipher_sqlite3_get_clientdata(D,N) will return a copy of pointer P
+** or a NULL pointer if there were no prior calls to
+** sqlcipher_sqlite3_set_clientdata() with the same values of D and N.
+** Names are compared using strcmp() and are thus case sensitive.
+**
+** If P and X are both non-NULL, then the destructor X is invoked with
+** argument P on the first of the following occurrences:
+** <ul>
+** <li> An out-of-memory error occurs during the call to
+** sqlcipher_sqlite3_set_clientdata() which attempts to register pointer P.
+** <li> A subsequent call to sqlcipher_sqlite3_set_clientdata(D,N,P,X) is made
+** with the same D and N parameters.
+** <li> The database connection closes. SQLite does not make any guarantees
+** about the order in which destructors are called, only that all
+** destructors will be called exactly once at some point during the
+** database connection closing process.
+** </ul>
+**
+** SQLite does not do anything with client data other than invoke
+** destructors on the client data at the appropriate time. The intended
+** use for client data is to provide a mechanism for wrapper libraries
+** to store additional information about an SQLite database connection.
+**
+** There is no limit (other than available memory) on the number of different
+** client data pointers (with different names) that can be attached to a
+** single database connection. However, the implementation is optimized
+** for the case of having only one or two different client data names.
+** Applications and wrapper libraries are discouraged from using more than
+** one client data name each.
+**
+** There is no way to enumerate the client data pointers
+** associated with a database connection. The N parameter can be thought
+** of as a secret key such that only code that knows the secret key is able
+** to access the associated data.
+**
+** Security Warning: These interfaces should not be exposed in scripting
+** languages or in other circumstances where it might be possible for an
+** an attacker to invoke them. Any agent that can invoke these interfaces
+** can probably also take control of the process.
+**
+** Database connection client data is only available for SQLite
+** version 3.44.0 ([dateof:3.44.0]) and later.
+**
+** See also: [sqlcipher_sqlite3_set_auxdata()] and [sqlcipher_sqlite3_get_auxdata()].
+*/
+SQLITE_API void *sqlcipher_sqlite3_get_clientdata(sqlcipher_sqlite3*,const char*);
+SQLITE_API int sqlcipher_sqlite3_set_clientdata(sqlcipher_sqlite3*, const char*, void*, void(*)(void*));
/*
** CAPI3REF: Constants Defining Special Destructor Behavior
@@ -5830,9 +6138,10 @@ typedef void (*sqlcipher_sqlite3_destructor_type)(void*);
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
** ^SQLite takes the text result from the application from
** the 2nd parameter of the sqlcipher_sqlite3_result_text* interfaces.
-** ^If the 3rd parameter to the sqlcipher_sqlite3_result_text* interfaces
-** is negative, then SQLite takes result text from the 2nd parameter
-** through the first zero character.
+** ^If the 3rd parameter to any of the sqlcipher_sqlite3_result_text* interfaces
+** other than sqlcipher_sqlite3_result_text64() is negative, then SQLite computes
+** the string length itself by searching the 2nd parameter for the first
+** zero character.
** ^If the 3rd parameter to the sqlcipher_sqlite3_result_text* interfaces
** is non-negative, then as many bytes (not characters) of the text
** pointed to by the 2nd parameter are taken as the application-defined
@@ -5935,6 +6244,20 @@ SQLITE_API int sqlcipher_sqlite3_result_zeroblob64(sqlcipher_sqlite3_context*, s
** higher order bits are discarded.
** The number of subtype bytes preserved by SQLite might increase
** in future releases of SQLite.
+**
+** Every [application-defined SQL function] that invokes this interface
+** should include the [SQLITE_RESULT_SUBTYPE] property in its
+** text encoding argument when the SQL function is
+** [sqlcipher_sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE]
+** property is omitted from the function that invokes sqlcipher_sqlite3_result_subtype(),
+** then in some cases the sqlcipher_sqlite3_result_subtype() might fail to set
+** the result subtype.
+**
+** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any
+** SQL function that invokes the sqlcipher_sqlite3_result_subtype() interface
+** and that does not have the SQLITE_RESULT_SUBTYPE property will raise
+** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1
+** by default.
*/
SQLITE_API void sqlcipher_sqlite3_result_subtype(sqlcipher_sqlite3_context*,unsigned int);
@@ -6166,6 +6489,13 @@ SQLITE_API void sqlcipher_sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of sqlcipher_sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
+**
+** If a negative argument is passed to sqlcipher_sqlite3_sleep() the results vary by
+** VFS and operating system. Some system treat a negative argument as an
+** instruction to sleep forever. Others understand it to mean do not sleep
+** at all. ^In SQLite version 3.42.0 and later, a negative
+** argument passed into sqlcipher_sqlite3_sleep() is changed to zero before it is relayed
+** down into the xSleep method of the VFS.
*/
SQLITE_API int sqlcipher_sqlite3_sleep(int);
@@ -6388,7 +6718,7 @@ SQLITE_API const char *sqlcipher_sqlite3_db_name(sqlcipher_sqlite3 *db, int N);
** <li> [sqlcipher_sqlite3_filename_wal()]
** </ul>
*/
-SQLITE_API const char *sqlcipher_sqlite3_db_filename(sqlcipher_sqlite3 *db, const char *zDbName);
+SQLITE_API sqlcipher_sqlite3_filename sqlcipher_sqlite3_db_filename(sqlcipher_sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
@@ -6419,7 +6749,7 @@ SQLITE_API int sqlcipher_sqlite3_db_readonly(sqlcipher_sqlite3 *db, const char *
SQLITE_API int sqlcipher_sqlite3_txn_state(sqlcipher_sqlite3*,const char *zSchema);
/*
-** CAPI3REF: Allowed return values from [sqlcipher_sqlite3_txn_state()]
+** CAPI3REF: Allowed return values from sqlcipher_sqlite3_txn_state()
** KEYWORDS: {transaction state}
**
** These constants define the current transaction state of a database file.
@@ -6525,7 +6855,7 @@ SQLITE_API void *sqlcipher_sqlite3_rollback_hook(sqlcipher_sqlite3*, void(*)(voi
** function C that is invoked prior to each autovacuum of the database
** file. ^The callback is passed a copy of the generic data pointer (P),
** the schema-name of the attached database that is being autovacuumed,
-** the the size of the database file in pages, the number of free pages,
+** the size of the database file in pages, the number of free pages,
** and the number of bytes per page, respectively. The callback should
** return the number of free pages that should be removed by the
** autovacuum. ^If the callback returns zero, then no autovacuum happens.
@@ -6551,7 +6881,7 @@ SQLITE_API void *sqlcipher_sqlite3_rollback_hook(sqlcipher_sqlite3*, void(*)(voi
** ^Each call to the sqlcipher_sqlite3_autovacuum_pages() interface overrides all
** previous invocations for that database connection. ^If the callback
** argument (C) to sqlcipher_sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer,
-** then the autovacuum steps callback is cancelled. The return value
+** then the autovacuum steps callback is canceled. The return value
** from sqlcipher_sqlite3_autovacuum_pages() is normally SQLITE_OK, but might
** be some other error code if something goes wrong. The current
** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other
@@ -6617,6 +6947,12 @@ SQLITE_API int sqlcipher_sqlite3_autovacuum_pages(
** The exceptions defined in this paragraph might change in a future
** release of SQLite.
**
+** Whether the update hook is invoked before or after the
+** corresponding change is currently unspecified and may differ
+** depending on the type of change. Do not rely on the order of the
+** hook call with regards to the final result of the operation which
+** triggers the hook.
+**
** The update hook implementation must not do anything that will modify
** the database connection that invoked the update hook. Any actions
** to modify the database connection must be deferred until after the
@@ -6646,6 +6982,11 @@ SQLITE_API void *sqlcipher_sqlite3_update_hook(
** to the same database. Sharing is enabled if the argument is true
** and disabled if the argument is false.)^
**
+** This interface is omitted if SQLite is compiled with
+** [-DSQLITE_OMIT_SHARED_CACHE]. The [-DSQLITE_OMIT_SHARED_CACHE]
+** compile-time option is recommended because the
+** [use of shared cache mode is discouraged].
+**
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
** In prior versions of SQLite,
@@ -6744,7 +7085,7 @@ SQLITE_API int sqlcipher_sqlite3_db_release_memory(sqlcipher_sqlite3*);
** ^The soft heap limit may not be greater than the hard heap limit.
** ^If the hard heap limit is enabled and if sqlcipher_sqlite3_soft_heap_limit(N)
** is invoked with a value of N that is greater than the hard heap limit,
-** the the soft heap limit is set to the value of the hard heap limit.
+** the soft heap limit is set to the value of the hard heap limit.
** ^The soft heap limit is automatically enabled whenever the hard heap
** limit is enabled. ^When sqlcipher_sqlite3_hard_heap_limit64(N) is invoked and
** the soft heap limit is outside the range of 1..N, then the soft heap
@@ -7006,15 +7347,6 @@ SQLITE_API int sqlcipher_sqlite3_cancel_auto_extension(void(*xEntryPoint)(void))
SQLITE_API void sqlcipher_sqlite3_reset_auto_extension(void);
/*
-** The interface to the virtual-table mechanism is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-*/
-
-/*
** Structures used by the virtual table interface
*/
typedef struct sqlcipher_sqlite3_vtab sqlcipher_sqlite3_vtab;
@@ -7074,6 +7406,10 @@ struct sqlcipher_sqlite3_module {
/* The methods above are in versions 1 and 2 of the sqlite_module object.
** Those below are for version 3 and greater. */
int (*xShadowName)(const char*);
+ /* The methods above are in versions 1 through 3 of the sqlite_module object.
+ ** Those below are for version 4 and greater. */
+ int (*xIntegrity)(sqlcipher_sqlite3_vtab *pVTab, const char *zSchema,
+ const char *zTabName, int mFlags, char **pzErr);
};
/*
@@ -7132,10 +7468,10 @@ struct sqlcipher_sqlite3_module {
** when the omit flag is true there is no guarantee that the constraint will
** not be checked again using byte code.)^
**
-** ^The idxNum and idxPtr values are recorded and passed into the
+** ^The idxNum and idxStr values are recorded and passed into the
** [xFilter] method.
-** ^[sqlcipher_sqlite3_free()] is used to free idxPtr if and only if
-** needToFreeIdxPtr is true.
+** ^[sqlcipher_sqlite3_free()] is used to free idxStr if and only if
+** needToFreeIdxStr is true.
**
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
** the correct order to satisfy the ORDER BY clause so that no separate
@@ -7255,7 +7591,7 @@ struct sqlcipher_sqlite3_index_info {
** the [sqlcipher_sqlite3_vtab_collation()] interface. For most real-world virtual
** tables, the collating sequence of constraints does not matter (for example
** because the constraints are numeric) and so the sqlcipher_sqlite3_vtab_collation()
-** interface is no commonly needed.
+** interface is not commonly needed.
*/
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
@@ -7415,16 +7751,6 @@ SQLITE_API int sqlcipher_sqlite3_declare_vtab(sqlcipher_sqlite3*, const char *zS
SQLITE_API int sqlcipher_sqlite3_overload_function(sqlcipher_sqlite3*, const char *zFuncName, int nArg);
/*
-** The interface to the virtual-table mechanism defined above (back up
-** to a comment remarkably similar to this one) is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-*/
-
-/*
** CAPI3REF: A Handle To An Open BLOB
** KEYWORDS: {BLOB handle} {BLOB handles}
**
@@ -7571,7 +7897,7 @@ SQLITE_API int sqlcipher_sqlite3_blob_reopen(sqlcipher_sqlite3_blob *, sqlcipher
** code is returned and the transaction rolled back.
**
** Calling this function with an argument that is not a NULL pointer or an
-** open blob handle results in undefined behaviour. ^Calling this routine
+** open blob handle results in undefined behavior. ^Calling this routine
** with a null pointer (such as would be returned by a failed call to
** [sqlcipher_sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
** is passed a valid open blob handle, the values returned by the
@@ -7798,18 +8124,20 @@ SQLITE_API int sqlcipher_sqlite3_vfs_unregister(sqlcipher_sqlite3_vfs*);
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by sqlcipher_sqlite3_mutex_try(). On those systems, sqlcipher_sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** sqlcipher_sqlite3_mutex_try() as an optimization so this is acceptable
-** behavior.)^
+** will always return SQLITE_BUSY. In most cases the SQLite core only uses
+** sqlcipher_sqlite3_mutex_try() as an optimization, so this is acceptable
+** behavior. The exceptions are unix builds that set the
+** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working
+** sqlcipher_sqlite3_mutex_try() is required.)^
**
** ^The sqlcipher_sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated.
**
-** ^If the argument to sqlcipher_sqlite3_mutex_enter(), sqlcipher_sqlite3_mutex_try(), or
-** sqlcipher_sqlite3_mutex_leave() is a NULL pointer, then all three routines
-** behave as no-ops.
+** ^If the argument to sqlcipher_sqlite3_mutex_enter(), sqlcipher_sqlite3_mutex_try(),
+** sqlcipher_sqlite3_mutex_leave(), or sqlcipher_sqlite3_mutex_free() is a NULL pointer,
+** then any of the four routines behaves as a no-op.
**
** See also: [sqlcipher_sqlite3_mutex_held()] and [sqlcipher_sqlite3_mutex_notheld()].
*/
@@ -8051,6 +8379,7 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
+#define SQLITE_TESTCTRL_FK_NO_ACTION 7
#define SQLITE_TESTCTRL_BITVEC_TEST 8
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
@@ -8058,6 +8387,7 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ASSERT 12
#define SQLITE_TESTCTRL_ALWAYS 13
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
+#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
@@ -8079,7 +8409,8 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33
-#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34
+#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -8092,7 +8423,7 @@ SQLITE_API int sqlcipher_sqlite3_test_control(int op, ...);
** The sqlcipher_sqlite3_keyword_count() interface returns the number of distinct
** keywords understood by SQLite.
**
-** The sqlcipher_sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and
+** The sqlcipher_sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and
** makes *Z point to that keyword expressed as UTF8 and writes the number
** of bytes in the keyword into *L. The string that *Z points to is not
** zero-terminated. The sqlcipher_sqlite3_keyword_name(N,Z,L) routine returns
@@ -9039,7 +9370,7 @@ typedef struct sqlcipher_sqlite3_backup sqlcipher_sqlite3_backup;
** if the application incorrectly accesses the destination [database connection]
** and so no error code is reported, but the operations may malfunction
** nevertheless. Use of the destination database connection while a
-** backup is in progress might also also cause a mutex deadlock.
+** backup is in progress might also cause a mutex deadlock.
**
** If running in [shared cache mode], the application must
** guarantee that the shared cache used by the destination database
@@ -9467,7 +9798,7 @@ SQLITE_API int sqlcipher_sqlite3_wal_checkpoint_v2(
*/
#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
-#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */
#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
/*
@@ -9535,7 +9866,7 @@ SQLITE_API int sqlcipher_sqlite3_vtab_config(sqlcipher_sqlite3*, int op, ...);
** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
** <dd>Calls of the form
** [sqlcipher_sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** prohibits that virtual table from being used from within triggers and
** views.
** </dd>
@@ -9543,18 +9874,28 @@ SQLITE_API int sqlcipher_sqlite3_vtab_config(sqlcipher_sqlite3*, int op, ...);
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [sqlcipher_sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
+**
+** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
+** <dd>Calls of the form
+** [sqlcipher_sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
+** instruct the query planner to begin at least a read transaction on
+** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
+** virtual table is used.
+** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3
+#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -9627,7 +9968,7 @@ SQLITE_API int sqlcipher_sqlite3_vtab_nochange(sqlcipher_sqlite3_context*);
** <li><p> Otherwise, "BINARY" is returned.
** </ol>
*/
-SQLITE_API SQLITE_EXPERIMENTAL const char *sqlcipher_sqlite3_vtab_collation(sqlcipher_sqlite3_index_info*,int);
+SQLITE_API const char *sqlcipher_sqlite3_vtab_collation(sqlcipher_sqlite3_index_info*,int);
/*
** CAPI3REF: Determine if a virtual table query is DISTINCT
@@ -9661,24 +10002,45 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlcipher_sqlite3_vtab_collation(sqlc
** <li value="2"><p>
** ^(If the sqlcipher_sqlite3_vtab_distinct() interface returns 2, that means
** that the query planner does not need the rows returned in any particular
-** order, as long as rows with the same values in all "aOrderBy" columns
-** are adjacent.)^ ^(Furthermore, only a single row for each particular
-** combination of values in the columns identified by the "aOrderBy" field
-** needs to be returned.)^ ^It is always ok for two or more rows with the same
-** values in all "aOrderBy" columns to be returned, as long as all such rows
-** are adjacent. ^The virtual table may, if it chooses, omit extra rows
-** that have the same value for all columns identified by "aOrderBy".
-** ^However omitting the extra rows is optional.
+** order, as long as rows with the same values in all columns identified
+** by "aOrderBy" are adjacent.)^ ^(Furthermore, when two or more rows
+** contain the same values for all columns identified by "colUsed", all but
+** one such row may optionally be omitted from the result.)^
+** The virtual table is not required to omit rows that are duplicates
+** over the "colUsed" columns, but if the virtual table can do that without
+** too much extra effort, it could potentially help the query to run faster.
** This mode is used for a DISTINCT query.
** <li value="3"><p>
-** ^(If the sqlcipher_sqlite3_vtab_distinct() interface returns 3, that means
-** that the query planner needs only distinct rows but it does need the
-** rows to be sorted.)^ ^The virtual table implementation is free to omit
-** rows that are identical in all aOrderBy columns, if it wants to, but
-** it is not required to omit any rows. This mode is used for queries
+** ^(If the sqlcipher_sqlite3_vtab_distinct() interface returns 3, that means the
+** virtual table must return rows in the order defined by "aOrderBy" as
+** if the sqlcipher_sqlite3_vtab_distinct() interface had returned 0. However if
+** two or more rows in the result have the same values for all columns
+** identified by "colUsed", then all but one such row may optionally be
+** omitted.)^ Like when the return value is 2, the virtual table
+** is not required to omit rows that are duplicates over the "colUsed"
+** columns, but if the virtual table can do that without
+** too much extra effort, it could potentially help the query to run faster.
+** This mode is used for queries
** that have both DISTINCT and ORDER BY clauses.
** </ol>
**
+** <p>The following table summarizes the conditions under which the
+** virtual table is allowed to set the "orderByConsumed" flag based on
+** the value returned by sqlcipher_sqlite3_vtab_distinct(). This table is a
+** restatement of the previous four paragraphs:
+**
+** <table border=1 cellspacing=0 cellpadding=10 width="90%">
+** <tr>
+** <td valign="top">sqlcipher_sqlite3_vtab_distinct() return value
+** <td valign="top">Rows are returned in aOrderBy order
+** <td valign="top">Rows with the same value in all aOrderBy columns are adjacent
+** <td valign="top">Duplicates over all colUsed columns may be omitted
+** <tr><td>0<td>yes<td>yes<td>no
+** <tr><td>1<td>no<td>yes<td>no
+** <tr><td>2<td>no<td>yes<td>yes
+** <tr><td>3<td>yes<td>yes<td>yes
+** </table>
+**
** ^For the purposes of comparing virtual table output values to see if the
** values are same value for sorting purposes, two NULL values are considered
** to be the same. In other words, the comparison operator is "IS"
@@ -9715,7 +10077,7 @@ SQLITE_API int sqlcipher_sqlite3_vtab_distinct(sqlcipher_sqlite3_index_info*);
** communicated to the xBestIndex method as a
** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use
** this constraint, it must set the corresponding
-** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under
+** aConstraintUsage[].argvIndex to a positive integer. ^(Then, under
** the usual mode of handling IN operators, SQLite generates [bytecode]
** that invokes the [xFilter|xFilter() method] once for each value
** on the right-hand side of the IN operator.)^ Thus the virtual table
@@ -9784,21 +10146,20 @@ SQLITE_API int sqlcipher_sqlite3_vtab_in(sqlcipher_sqlite3_index_info*, int iCon
** is undefined and probably harmful.
**
** The X parameter in a call to sqlcipher_sqlite3_vtab_in_first(X,P) or
-** sqlcipher_sqlite3_vtab_in_next(X,P) must be one of the parameters to the
+** sqlcipher_sqlite3_vtab_in_next(X,P) should be one of the parameters to the
** xFilter method which invokes these routines, and specifically
** a parameter that was previously selected for all-at-once IN constraint
** processing use the [sqlcipher_sqlite3_vtab_in()] interface in the
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
** an xFilter argument that was selected for all-at-once IN constraint
-** processing, then these routines return [SQLITE_MISUSE])^ or perhaps
-** exhibit some other undefined or harmful behavior.
+** processing, then these routines return [SQLITE_ERROR].)^
**
** ^(Use these routines to access all values on the right-hand side
** of the IN constraint using code like the following:
**
** <blockquote><pre>
** &nbsp; for(rc=sqlcipher_sqlite3_vtab_in_first(pList, &pVal);
-** &nbsp; rc==SQLITE_OK && pVal
+** &nbsp; rc==SQLITE_OK && pVal;
** &nbsp; rc=sqlcipher_sqlite3_vtab_in_next(pList, &pVal)
** &nbsp; ){
** &nbsp; // do something with pVal
@@ -9896,6 +10257,10 @@ SQLITE_API int sqlcipher_sqlite3_vtab_rhs_value(sqlcipher_sqlite3_index_info*, i
** managed by the prepared statement S and will be automatically freed when
** S is finalized.
**
+** Not all values are available for all query elements. When a value is
+** not available, the output variable is set to -1 if the value is numeric,
+** or to NULL if it is a string (SQLITE_SCANSTAT_NAME).
+**
** <dl>
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
** <dd>^The [sqlcipher_sqlite3_int64] variable pointed to by the V parameter will be
@@ -9923,12 +10288,24 @@ SQLITE_API int sqlcipher_sqlite3_vtab_rhs_value(sqlcipher_sqlite3_index_info*, i
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
-** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
+** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECTID</dt>
** <dd>^The "int" variable pointed to by the V parameter will be set to the
-** "select-id" for the X-th loop. The select-id identifies which query or
-** subquery the loop is part of. The main query has a select-id of zero.
-** The select-id is the same value as is output in the first column
-** of an [EXPLAIN QUERY PLAN] query.
+** id for the X-th query plan element. The id value is unique within the
+** statement. The select-id is the same value as is output in the first
+** column of an [EXPLAIN QUERY PLAN] query.
+**
+** [[SQLITE_SCANSTAT_PARENTID]] <dt>SQLITE_SCANSTAT_PARENTID</dt>
+** <dd>The "int" variable pointed to by the V parameter will be set to the
+** the id of the parent of the current query element, if applicable, or
+** to zero if the query element has no parent. This is the same value as
+** returned in the second column of an [EXPLAIN QUERY PLAN] query.
+**
+** [[SQLITE_SCANSTAT_NCYCLE]] <dt>SQLITE_SCANSTAT_NCYCLE</dt>
+** <dd>The sqlcipher_sqlite3_int64 output value is set to the number of cycles,
+** according to the processor time-stamp counter, that elapsed while the
+** query element was being processed. This value is not available for
+** all query elements - if it is unavailable the output variable is
+** set to -1.
** </dl>
*/
#define SQLITE_SCANSTAT_NLOOP 0
@@ -9937,12 +10314,14 @@ SQLITE_API int sqlcipher_sqlite3_vtab_rhs_value(sqlcipher_sqlite3_index_info*, i
#define SQLITE_SCANSTAT_NAME 3
#define SQLITE_SCANSTAT_EXPLAIN 4
#define SQLITE_SCANSTAT_SELECTID 5
+#define SQLITE_SCANSTAT_PARENTID 6
+#define SQLITE_SCANSTAT_NCYCLE 7
/*
** CAPI3REF: Prepared Statement Scan Status
** METHOD: sqlcipher_sqlite3_stmt
**
-** This interface returns information about the predicted and measured
+** These interfaces return information about the predicted and measured
** performance for pStmt. Advanced applications can use this
** interface to compare the predicted and the measured performance and
** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
@@ -9953,19 +10332,25 @@ SQLITE_API int sqlcipher_sqlite3_vtab_rhs_value(sqlcipher_sqlite3_index_info*, i
**
** The "iScanStatusOp" parameter determines which status information to return.
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
-** of this interface is undefined.
-** ^The requested measurement is written into a variable pointed to by
-** the "pOut" parameter.
-** Parameter "idx" identifies the specific loop to retrieve statistics for.
-** Loops are numbered starting from zero. ^If idx is out of range - less than
-** zero or greater than or equal to the total number of loops used to implement
-** the statement - a non-zero value is returned and the variable that pOut
-** points to is unchanged.
-**
-** ^Statistics might not be available for all loops in all statements. ^In cases
-** where there exist loops with no available statistics, this function behaves
-** as if the loop did not exist - it returns non-zero and leave the variable
-** that pOut points to unchanged.
+** of this interface is undefined. ^The requested measurement is written into
+** a variable pointed to by the "pOut" parameter.
+**
+** The "flags" parameter must be passed a mask of flags. At present only
+** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX
+** is specified, then status information is available for all elements
+** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If
+** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements
+** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of
+** the EXPLAIN QUERY PLAN output) are available. Invoking API
+** sqlcipher_sqlite3_stmt_scanstatus() is equivalent to calling
+** sqlcipher_sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter.
+**
+** Parameter "idx" identifies the specific query element to retrieve statistics
+** for. Query elements are numbered starting from zero. A value of -1 may be
+** to query for statistics regarding the entire query. ^If idx is out of range
+** - less than -1 or greater than or equal to the total number of query
+** elements used to implement the statement - a non-zero value is returned and
+** the variable that pOut points to is unchanged.
**
** See also: [sqlcipher_sqlite3_stmt_scanstatus_reset()]
*/
@@ -9975,6 +10360,19 @@ SQLITE_API int sqlcipher_sqlite3_stmt_scanstatus(
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
void *pOut /* Result written here */
);
+SQLITE_API int sqlcipher_sqlite3_stmt_scanstatus_v2(
+ sqlcipher_sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
+ int idx, /* Index of loop to report on */
+ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
+ int flags, /* Mask of flags defined below */
+ void *pOut /* Result written here */
+);
+
+/*
+** CAPI3REF: Prepared Statement Scan Status
+** KEYWORDS: {scan status flags}
+*/
+#define SQLITE_SCANSTAT_COMPLEX 0x0001
/*
** CAPI3REF: Zero Scan-Status Counters
@@ -10065,6 +10463,10 @@ SQLITE_API int sqlcipher_sqlite3_db_cacheflush(sqlcipher_sqlite3*);
** function is not defined for operations on WITHOUT ROWID tables, or for
** DELETE operations on rowid tables.
**
+** ^The sqlcipher_sqlite3_preupdate_hook(D,C,P) function returns the P argument from
+** the previous call on the same [database connection] D, or NULL for
+** the first call on D.
+**
** The [sqlcipher_sqlite3_preupdate_old()], [sqlcipher_sqlite3_preupdate_new()],
** [sqlcipher_sqlite3_preupdate_count()], and [sqlcipher_sqlite3_preupdate_depth()] interfaces
** provide additional information about a preupdate event. These routines
@@ -10104,7 +10506,7 @@ SQLITE_API int sqlcipher_sqlite3_db_cacheflush(sqlcipher_sqlite3*);
** When the [sqlcipher_sqlite3_blob_write()] API is used to update a blob column,
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
** in this case the new values are not available. In this case, when a
-** callback made with op==SQLITE_DELETE is actuall a write using the
+** callback made with op==SQLITE_DELETE is actually a write using the
** sqlcipher_sqlite3_blob_write() API, the [sqlcipher_sqlite3_preupdate_blobwrite()] returns
** the index of the column being written. In other cases, where the
** pre-update hook is being invoked for some other reason, including a
@@ -10365,6 +10767,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlcipher_sqlite3_snapshot_recover(sqlcipher_
** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
** of the database exists.
**
+** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set,
+** the returned buffer content will remain accessible and unchanged
+** until either the next write operation on the connection or when
+** the connection is closed, and applications must not modify the
+** buffer. If the bit had been clear, the returned buffer will not
+** be accessed by SQLite after the call.
+**
** A call to sqlcipher_sqlite3_serialize(D,S,P,F) might return NULL even if the
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
** allocation error occurs.
@@ -10413,6 +10822,9 @@ SQLITE_API unsigned char *sqlcipher_sqlite3_serialize(
** SQLite will try to increase the buffer size using sqlcipher_sqlite3_realloc64()
** if writes on the database cause it to grow larger than M bytes.
**
+** Applications must not modify the buffer P or invalidate it before
+** the database connection D is closed.
+**
** The sqlcipher_sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
** database is currently in a read transaction or is involved in a backup
** operation.
@@ -10421,6 +10833,13 @@ SQLITE_API unsigned char *sqlcipher_sqlite3_serialize(
** S argument to sqlcipher_sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
** function returns SQLITE_ERROR.
**
+** The deserialized database should not be in [WAL mode]. If the database
+** is in WAL mode, then any attempt to use the database file will result
+** in an [SQLITE_CANTOPEN] error. The application can set the
+** [file format version numbers] (bytes 18 and 19) of the input database P
+** to 0x01 prior to invoking sqlcipher_sqlite3_deserialize(D,S,P,N,M,F) to force the
+** database file into rollback mode and work around this limitation.
+**
** If sqlcipher_sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
** [sqlcipher_sqlite3_free()] is invoked on argument P prior to returning.
@@ -10470,6 +10889,19 @@ SQLITE_API int sqlcipher_sqlite3_deserialize(
# undef double
#endif
+#if defined(__wasi__)
+# undef SQLITE_WASI
+# define SQLITE_WASI 1
+# undef SQLITE_OMIT_WAL
+# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
+# ifndef SQLITE_OMIT_LOAD_EXTENSION
+# define SQLITE_OMIT_LOAD_EXTENSION
+# endif
+# ifndef SQLITE_THREADSAFE
+# define SQLITE_THREADSAFE 0
+# endif
+#endif
+
#ifdef __cplusplus
} /* End of the 'extern "C"' block */
#endif
@@ -10676,16 +11108,20 @@ SQLITE_API int sqlcipher_sqlite3session_create(
SQLITE_API void sqlcipher_sqlite3session_delete(sqlcipher_sqlite3_session *pSession);
/*
-** CAPIREF: Conigure a Session Object
+** CAPI3REF: Configure a Session Object
** METHOD: sqlcipher_sqlite3_session
**
** This method is used to configure a session object after it has been
-** created. At present the only valid value for the second parameter is
-** [SQLITE_SESSION_OBJCONFIG_SIZE].
+** created. At present the only valid values for the second parameter are
+** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
**
-** Arguments for sqlcipher_sqlite3session_object_config()
+*/
+SQLITE_API int sqlcipher_sqlite3session_object_config(sqlcipher_sqlite3_session*, int op, void *pArg);
+
+/*
+** CAPI3REF: Options for sqlcipher_sqlite3session_object_config
**
-** The following values may passed as the the 4th parameter to
+** The following values may passed as the the 2nd parameter to
** sqlcipher_sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
@@ -10701,12 +11137,21 @@ SQLITE_API void sqlcipher_sqlite3session_delete(sqlcipher_sqlite3_session *pSess
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
+**
+** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd>
+** This option is used to set, clear or query the flag that enables
+** collection of data for tables with no explicit PRIMARY KEY.
+**
+** Normally, tables with no explicit PRIMARY KEY are simply ignored
+** by the sessions module. However, if this flag is set, it behaves
+** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
+** as their leftmost columns.
+**
+** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
+** the first table has been attached to the session object.
*/
-SQLITE_API int sqlcipher_sqlite3session_object_config(sqlcipher_sqlite3_session*, int op, void *pArg);
-
-/*
-*/
-#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/*
** CAPI3REF: Enable Or Disable A Session Object
@@ -11468,6 +11913,18 @@ SQLITE_API int sqlcipher_sqlite3changeset_concat(
/*
+** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
+*/
+SQLITE_API int sqlcipher_sqlite3changeset_upgrade(
+ sqlcipher_sqlite3 *db,
+ const char *zDb,
+ int nIn, const void *pIn, /* Input changeset */
+ int *pnOut, void **ppOut /* OUT: Inverse of input */
+);
+
+
+
+/*
** CAPI3REF: Changegroup Handle
**
** A changegroup is an object used to combine two or more
@@ -11514,6 +11971,38 @@ typedef struct sqlcipher_sqlite3_changegroup sqlcipher_sqlite3_changegroup;
SQLITE_API int sqlcipher_sqlite3changegroup_new(sqlcipher_sqlite3_changegroup **pp);
/*
+** CAPI3REF: Add a Schema to a Changegroup
+** METHOD: sqlcipher_sqlite3_changegroup_schema
+**
+** This method may be used to optionally enforce the rule that the changesets
+** added to the changegroup handle must match the schema of database zDb
+** ("main", "temp", or the name of an attached database). If
+** sqlcipher_sqlite3changegroup_add() is called to add a changeset that is not compatible
+** with the configured schema, SQLITE_SCHEMA is returned and the changegroup
+** object is left in an undefined state.
+**
+** A changeset schema is considered compatible with the database schema in
+** the same way as for sqlcipher_sqlite3changeset_apply(). Specifically, for each
+** table in the changeset, there exists a database table with:
+**
+** <ul>
+** <li> The name identified by the changeset, and
+** <li> at least as many columns as recorded in the changeset, and
+** <li> the primary key columns in the same position as recorded in
+** the changeset.
+** </ul>
+**
+** The output of the changegroup object always has the same schema as the
+** database nominated using this function. In cases where changesets passed
+** to sqlcipher_sqlite3changegroup_add() have fewer columns than the corresponding table
+** in the database schema, these are filled in using the default column
+** values from the database schema. This makes it possible to combined
+** changesets that have different numbers of columns for a single table
+** within a changegroup, provided that they are otherwise compatible.
+*/
+SQLITE_API int sqlcipher_sqlite3changegroup_schema(sqlcipher_sqlite3_changegroup*, sqlcipher_sqlite3*, const char *zDb);
+
+/*
** CAPI3REF: Add A Changeset To A Changegroup
** METHOD: sqlcipher_sqlite3_changegroup
**
@@ -11581,17 +12070,46 @@ SQLITE_API int sqlcipher_sqlite3changegroup_new(sqlcipher_sqlite3_changegroup **
** If the new changeset contains changes to a table that is already present
** in the changegroup, then the number of columns and the position of the
** primary key columns for the table must be consistent. If this is not the
-** case, this function fails with SQLITE_SCHEMA. If the input changeset
-** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
-** returned. Or, if an out-of-memory condition occurs during processing, this
-** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
-** of the final contents of the changegroup is undefined.
+** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup
+** object has been configured with a database schema using the
+** sqlcipher_sqlite3changegroup_schema() API, then it is possible to combine changesets
+** with different numbers of columns for a single table, provided that
+** they are otherwise compatible.
+**
+** If the input changeset appears to be corrupt and the corruption is
+** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition
+** occurs during processing, this function returns SQLITE_NOMEM.
**
-** If no error occurs, SQLITE_OK is returned.
+** In all cases, if an error occurs the state of the final contents of the
+** changegroup is undefined. If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int sqlcipher_sqlite3changegroup_add(sqlcipher_sqlite3_changegroup*, int nData, void *pData);
/*
+** CAPI3REF: Add A Single Change To A Changegroup
+** METHOD: sqlcipher_sqlite3_changegroup
+**
+** This function adds the single change currently indicated by the iterator
+** passed as the second argument to the changegroup object. The rules for
+** adding the change are just as described for [sqlcipher_sqlite3changegroup_add()].
+**
+** If the change is successfully added to the changegroup, SQLITE_OK is
+** returned. Otherwise, an SQLite error code is returned.
+**
+** The iterator must point to a valid entry when this function is called.
+** If it does not, SQLITE_ERROR is returned and no change is added to the
+** changegroup. Additionally, the iterator must not have been opened with
+** the SQLITE_CHANGESETAPPLY_INVERT flag. In this case SQLITE_ERROR is also
+** returned.
+*/
+SQLITE_API int sqlcipher_sqlite3changegroup_add_change(
+ sqlcipher_sqlite3_changegroup*,
+ sqlcipher_sqlite3_changeset_iter*
+);
+
+
+
+/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
** METHOD: sqlcipher_sqlite3_changegroup
**
@@ -11839,9 +12357,30 @@ SQLITE_API int sqlcipher_sqlite3changeset_apply_v2(
** Invert the changeset before applying it. This is equivalent to inverting
** a changeset using sqlcipher_sqlite3changeset_invert() before applying it. It is
** an error to specify this flag with a patchset.
+**
+** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd>
+** Do not invoke the conflict handler callback for any changes that
+** would not actually modify the database even if they were applied.
+** Specifically, this means that the conflict handler is not invoked
+** for:
+** <ul>
+** <li>a delete change if the row being deleted cannot be found,
+** <li>an update change if the modified fields are already set to
+** their new values in the conflicting row, or
+** <li>an insert change if all fields of the conflicting row match
+** the row being inserted.
+** </ul>
+**
+** <dt>SQLITE_CHANGESETAPPLY_FKNOACTION <dd>
+** If this flag it set, then all foreign key constraints in the target
+** database behave as if they were declared with "ON UPDATE NO ACTION ON
+** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL
+** or SET DEFAULT.
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
+#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
+#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008
/*
** CAPI3REF: Constants Passed To The Conflict Handler
@@ -12374,8 +12913,8 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
-** registered with.
+** Return a copy of the pUserData pointer passed to the xCreateFunction()
+** API when the extension function was registered.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
@@ -12407,8 +12946,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the text of column iCol of
+** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -12418,8 +12960,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of phrases in the current query, as returned by xPhraseCount,
+** 0 is returned. Otherwise, this function returns the number of tokens in
+** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -12435,12 +12979,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
+** output by xInstCount(). If iIdx is less than zero or greater than
+** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
+** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. Returns SQLITE_OK if successful, or an error
-** code (i.e. SQLITE_NOMEM) if an error occurs.
+** first token of the phrase. SQLITE_OK is returned if successful, or an
+** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -12466,6 +13011,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
+** If parameter iPhrase is less than zero, or greater than or equal to
+** the number of phrases in the query, as returned by xPhraseCount(),
+** this function returns SQLITE_RANGE.
+**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -12580,6 +13129,39 @@ struct Fts5PhraseIter {
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
+**
+** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase iPhrase of the current
+** query. Before returning, output parameter *ppToken is set to point
+** to a buffer containing the requested token, and *pnToken to the
+** size of this buffer in bytes.
+**
+** If iPhrase or iToken are less than zero, or if iPhrase is greater than
+** or equal to the number of phrases in the query as reported by
+** xPhraseCount(), or if iToken is equal to or greater than the number of
+** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
+ are both zeroed.
+**
+** The output text is not a copy of the query text that specified the
+** token. It is the output of the tokenizer module. For tokendata=1
+** tables, this includes any embedded 0x00 and trailing data.
+**
+** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase hit iIdx within the
+** current row. If iIdx is less than zero or greater than or equal to the
+** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
+** output variable (*ppToken) is set to point to a buffer containing the
+** matching document token, and (*pnToken) to the size of that buffer in
+** bytes. This API is not available if the specified token matches a
+** prefix query term. In that case both output variables are always set
+** to 0.
+**
+** The output text is not a copy of the document text that was tokenized.
+** It is the output of the tokenizer module. For tokendata=1 tables, this
+** includes any embedded 0x00 and trailing data.
+**
+** This API can be quite slow if used with an FTS5 table created with the
+** "detail=none" or "detail=column" option.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 3 */
@@ -12617,6 +13199,13 @@ struct Fts5ExtensionApi {
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
+
+ /* Below this point are iVersion>=3 only */
+ int (*xQueryToken)(Fts5Context*,
+ int iPhrase, int iToken,
+ const char **ppToken, int *pnToken
+ );
+ int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
};
/*
@@ -12811,8 +13400,8 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
@@ -12860,7 +13449,7 @@ struct fts5_api {
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -12869,7 +13458,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -12877,7 +13466,7 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
diff --git a/Plugins/DbSqliteCipher/update_sqlite_version.tcl b/Plugins/DbSqliteCipher/update_sqlite_version.tcl
index 4b6b04e..73c0c28 100644
--- a/Plugins/DbSqliteCipher/update_sqlite_version.tcl
+++ b/Plugins/DbSqliteCipher/update_sqlite_version.tcl
@@ -5,7 +5,7 @@
# Download page:
# https://github.com/sqlcipher/sqlcipher/releases
-set THE_URL "https://codeload.github.com/sqlcipher/sqlcipher/zip/v4.5.3"
+set THE_URL "https://codeload.github.com/sqlcipher/sqlcipher/zip/v4.6.1"
proc process {} {
if {[catch {
diff --git a/Plugins/DbSqliteWx/DbSqliteWx.pro b/Plugins/DbSqliteWx/DbSqliteWx.pro
index f2f4e88..9b65599 100644
--- a/Plugins/DbSqliteWx/DbSqliteWx.pro
+++ b/Plugins/DbSqliteWx/DbSqliteWx.pro
@@ -27,9 +27,17 @@ isEmpty(WXSQLITE_LIB): {
HEADERS += wxsqlite3.h
}
-max: {
- INCLUDEPATH += /usr/local/opt/openssl/include
- LIBS += -L/usr/local/opt/openssl/lib
+macx: {
+ exists( /opt/local/include/openssl-3/openssl/crypto.h ) {
+ message( "Configuring OpenSSL from MacPorts" )
+ INCLUDEPATH += /opt/local/include/openssl-3
+ LIBS += -L/opt/local/lib/openssl-3
+ } else {
+ message( "Configuring OpenSSL from HomeBrew" )
+ INCLUDEPATH += /usr/local/opt/openssl/include
+ LIBS += -L/usr/local/opt/openssl/lib
+ }
+ LIBS += -framework Security
}
!macx: {
LIBS += -L$${PWD}/../deps/lib/$${PLATFORM}/
diff --git a/Plugins/DbSqliteWx/update_sqlite_version.tcl b/Plugins/DbSqliteWx/update_sqlite_version.tcl
index 9f4966f..c09e863 100644
--- a/Plugins/DbSqliteWx/update_sqlite_version.tcl
+++ b/Plugins/DbSqliteWx/update_sqlite_version.tcl
@@ -4,7 +4,7 @@
# https://github.com/utelle/wxsqlite3/releases
# Link from download page will redicrect to the codeload.....
-set THE_URL "https://github.com/utelle/SQLite3MultipleCiphers/releases/download/v1.6.2/sqlite3mc-1.6.2-sqlite-3.41.2-amalgamation.zip"
+set THE_URL "https://github.com/utelle/SQLite3MultipleCiphers/releases/download/v1.9.2/sqlite3mc-1.9.2-sqlite-3.47.2-amalgamation.zip"
set SRC_DIR "src"
set FILES [list \
diff --git a/Plugins/DbSqliteWx/wxsqlite3.c b/Plugins/DbSqliteWx/wxsqlite3.c
index 1b306bf..e13cc99 100644
--- a/Plugins/DbSqliteWx/wxsqlite3.c
+++ b/Plugins/DbSqliteWx/wxsqlite3.c
@@ -3,13 +3,35 @@
** Purpose: Amalgamation of the SQLite3 Multiple Ciphers encryption extension for SQLite
** Author: Ulrich Telle
** Created: 2020-02-28
-** Copyright: (c) 2006-2022 Ulrich Telle
+** Copyright: (c) 2006-2024 Ulrich Telle
** License: MIT
*/
/*
+** Force some options required for WASM builds
+*/
+
+#ifdef __WASM__
+
+/* Disable User Authentication Extension */
+#ifdef SQLITE_USER_AUTHENTICATION
+#undef SQLITE_USER_AUTHENTICATION
+#endif
+#define SQLITE_USER_AUTHENTICATION 0
+
+/* Disable AES hardware support */
+/* Note: this may be changed in the future depending on available support */
+#ifdef SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT
+#undef SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT
+#endif
+#define SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT 1
+
+#endif
+
+/*
** Enable SQLite debug assertions if requested
*/
+
#ifndef SQLITE_DEBUG
#if defined(SQLITE_ENABLE_DEBUG) && (SQLITE_ENABLE_DEBUG == 1)
#define SQLITE_DEBUG 1
@@ -29,8 +51,15 @@
#define SQLITE_EXTRA_INIT wx_sqlite3mc_initialize
#define SQLITE_EXTRA_SHUTDOWN wx_sqlite3mc_shutdown
-int wx_sqlite3mc_initialize(const char* arg);
-void wx_sqlite3mc_shutdown(void);
+/*
+** Declare all internal functions as 'static' unless told otherwise
+*/
+#ifndef SQLITE_PRIVATE
+#define SQLITE_PRIVATE static
+#endif
+
+SQLITE_PRIVATE int wx_sqlite3mc_initialize(const char* arg);
+SQLITE_PRIVATE void wx_sqlite3mc_shutdown(void);
/*
** To enable the extension functions define SQLITE_ENABLE_EXTFUNC on compiling this module
@@ -43,14 +72,10 @@ void wx_sqlite3mc_shutdown(void);
*/
/*
-** Enable the user authentication feature
+** Disable the user authentication feature by default
*/
+#ifdef SQLITE_USER_AUTHENTICATION
#if !SQLITE_USER_AUTHENTICATION
-/* Option not defined or explicitly disabled */
-#ifndef SQLITE_USER_AUTHENTICATION
-/* Option not defined, therefore enable by default */
-#define SQLITE_USER_AUTHENTICATION 1
-#else
/* Option defined and disabled, therefore undefine option */
#undef SQLITE_USER_AUTHENTICATION
#endif
@@ -67,22 +92,41 @@ void wx_sqlite3mc_shutdown(void);
#if !defined(_CRT_RAND_S)
#define _CRT_RAND_S
#endif
+
+#else /* !WIN32 */
+
+/* Define this before <string.h> is included to */
+/* retrieve memset_s() declaration if available. */
+#define __STDC_WANT_LIB_EXT1__ 1
+
#endif
#ifndef SQLITE_API
#define SQLITE_API
#endif
+/*
+** We need to do the following check here BEFORE including <windows.h>,
+** because the header <arm_neon.h> is included from somewhere within
+** <windows.h>, and we need support for the new Neon intrinsics, if
+** AES hardware support is enabled.
+*/
+#if defined (_MSC_VER)
+#if defined _M_ARM
+#define _ARM_USE_NEW_NEON_INTRINSICS
+#endif
+#endif
+
#include <windows.h>
/* SQLite functions only needed on Win32 */
-extern SQLITE_API void wx_sqlite3_win32_write_debug(const char*, int);
-extern SQLITE_API char *wx_sqlite3_win32_unicode_to_utf8(LPCWSTR);
-extern SQLITE_API char *wx_sqlite3_win32_mbcs_to_utf8(const char*);
-extern SQLITE_API char *wx_sqlite3_win32_mbcs_to_utf8_v2(const char*, int);
-extern SQLITE_API char *wx_sqlite3_win32_utf8_to_mbcs(const char*);
-extern SQLITE_API char *wx_sqlite3_win32_utf8_to_mbcs_v2(const char*, int);
-extern SQLITE_API LPWSTR wx_sqlite3_win32_utf8_to_unicode(const char*);
+SQLITE_API void wx_sqlite3_win32_write_debug(const char*, int);
+SQLITE_API char *wx_sqlite3_win32_unicode_to_utf8(LPCWSTR);
+SQLITE_API char *wx_sqlite3_win32_mbcs_to_utf8(const char*);
+SQLITE_API char *wx_sqlite3_win32_mbcs_to_utf8_v2(const char*, int);
+SQLITE_API char *wx_sqlite3_win32_utf8_to_mbcs(const char*);
+SQLITE_API char *wx_sqlite3_win32_utf8_to_mbcs_v2(const char*, int);
+SQLITE_API LPWSTR wx_sqlite3_win32_utf8_to_unicode(const char*);
#endif
/*
@@ -92,7 +136,7 @@ extern SQLITE_API LPWSTR wx_sqlite3_win32_utf8_to_unicode(const char*);
/*** Begin of #include "wx_sqlite3patched.c" ***/
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.41.2. By combining all the individual C code files into this
+** version 3.47.2. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -108,6 +152,9 @@ extern SQLITE_API LPWSTR wx_sqlite3_win32_utf8_to_unicode(const char*);
** if you want a wrapper to interface SQLite with your choice of programming
** language. The code for the "wx_sqlite3" command-line shell is also in a
** separate file. This file contains only code for the core SQLite library.
+**
+** The content in this amalgamation comes from Fossil check-in
+** 2aabe05e2e8cae4847a802ee2daddc1d7413.
*/
#define SQLITE_CORE 1
#define SQLITE_AMALGAMATION 1
@@ -142,11 +189,11 @@ extern SQLITE_API LPWSTR wx_sqlite3_win32_utf8_to_unicode(const char*);
** used on lines of code that actually
** implement parts of coverage testing.
**
-** OPTIMIZATION-IF-TRUE - This branch is allowed to alway be false
+** OPTIMIZATION-IF-TRUE - This branch is allowed to always be false
** and the correct answer is still obtained,
** though perhaps more slowly.
**
-** OPTIMIZATION-IF-FALSE - This branch is allowed to alway be true
+** OPTIMIZATION-IF-FALSE - This branch is allowed to always be true
** and the correct answer is still obtained,
** though perhaps more slowly.
**
@@ -215,6 +262,10 @@ extern SQLITE_API LPWSTR wx_sqlite3_win32_utf8_to_unicode(const char*);
#define SQLITE_4_BYTE_ALIGNED_MALLOC
#endif /* defined(_MSC_VER) && !defined(_WIN64) */
+#if !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800
+#define HAVE_LOG2 0
+#endif /* !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800 */
+
#endif /* SQLITE_MSVC_H */
/************** End of msvc.h ************************************************/
@@ -341,10 +392,13 @@ extern SQLITE_API LPWSTR wx_sqlite3_win32_utf8_to_unicode(const char*);
/*
** Macro to disable warnings about missing "break" at the end of a "case".
*/
-#if GCC_VERSION>=7000000
-# define deliberate_fall_through __attribute__((fallthrough));
-#else
-# define deliberate_fall_through
+#if defined(__has_attribute)
+# if __has_attribute(fallthrough)
+# define deliberate_fall_through __attribute__((fallthrough));
+# endif
+#endif
+#if !defined(deliberate_fall_through)
+# define deliberate_fall_through
#endif
/*
@@ -544,9 +598,9 @@ extern "C" {
** [wx_sqlite3_libversion_number()], [wx_sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.41.2"
-#define SQLITE_VERSION_NUMBER 3041002
-#define SQLITE_SOURCE_ID "2023-03-22 11:56:21 0d1fc92f94cb6b76bffe3ec34d69cffde2924203304e8ffc4155597af0c191da"
+#define SQLITE_VERSION "3.47.2"
+#define SQLITE_VERSION_NUMBER 3047002
+#define SQLITE_SOURCE_ID "2024-12-07 20:39:59 2aabe05e2e8cae4847a802ee2daddc1d7413d8fc560254d93ee3e72c14685b6c"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -818,6 +872,8 @@ typedef int (*wx_sqlite3_callback)(void*,int,char**, char**);
** the 1st parameter to wx_sqlite3_exec() while wx_sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into
** the 2nd parameter of wx_sqlite3_exec() while wx_sqlite3_exec() is running.
+** <li> The application must not dereference the arrays or string pointers
+** passed as the 3rd and 4th callback parameters after it returns.
** </ul>
*/
SQLITE_API int wx_sqlite3_exec(
@@ -926,6 +982,7 @@ SQLITE_API int wx_sqlite3_exec(
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
+#define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
@@ -1047,6 +1104,13 @@ SQLITE_API int wx_sqlite3_exec(
** filesystem supports doing multiple write operations atomically when those
** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
+**
+** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read
+** from the database file in amounts that are not a multiple of the
+** page size and that do not begin at a page boundary. Without this
+** property, SQLite is careful to only do full-page reads and write
+** on aligned pages, with the one exception that it will do a sub-page
+** read of the first page to access the database header.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -1063,6 +1127,7 @@ SQLITE_API int wx_sqlite3_exec(
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
+#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000
/*
** CAPI3REF: File Locking Levels
@@ -1159,16 +1224,16 @@ struct wx_sqlite3_file {
** </ul>
** xLock() upgrades the database file lock. In other words, xLock() moves the
** database file lock in the direction NONE toward EXCLUSIVE. The argument to
-** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
+** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
** SQLITE_LOCK_NONE. If the database file lock is already at or above the
** requested lock, then the call to xLock() is a no-op.
** xUnlock() downgrades the database file lock to either SHARED or NONE.
-* If the lock is already at or below the requested lock state, then the call
+** If the lock is already at or below the requested lock state, then the call
** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
-** PENDING, or EXCLUSIVE lock on the file. It returns true
-** if such a lock exists and false otherwise.
+** PENDING, or EXCLUSIVE lock on the file. It returns, via its output
+** pointer parameter, true if such a lock exists and false otherwise.
**
** The xFileControl() method is a generic interface that allows custom
** VFS implementations to directly control an open file using the
@@ -1209,6 +1274,7 @@ struct wx_sqlite3_file {
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
** <li> [SQLITE_IOCAP_IMMUTABLE]
** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
+** <li> [SQLITE_IOCAP_SUBPAGE_READ]
** </ul>
**
** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -1588,7 +1654,7 @@ struct wx_sqlite3_io_methods {
** by clients within the current process, only within other processes.
**
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
-** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use interally by the
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the
** [checksum VFS shim] only.
**
** <li>[[SQLITE_FCNTL_RESET_CACHE]]
@@ -2053,20 +2119,23 @@ SQLITE_API int wx_sqlite3_os_end(void);
** must ensure that no other SQLite interfaces are invoked by other
** threads while wx_sqlite3_config() is running.</b>
**
-** The wx_sqlite3_config() interface
-** may only be invoked prior to library initialization using
-** [wx_sqlite3_initialize()] or after shutdown by [wx_sqlite3_shutdown()].
-** ^If wx_sqlite3_config() is called after [wx_sqlite3_initialize()] and before
-** [wx_sqlite3_shutdown()] then it will return SQLITE_MISUSE.
-** Note, however, that ^wx_sqlite3_config() can be called as part of the
-** implementation of an application-defined [wx_sqlite3_os_init()].
-**
** The first argument to wx_sqlite3_config() is an integer
** [configuration option] that determines
** what property of SQLite is to be configured. Subsequent arguments
** vary depending on the [configuration option]
** in the first argument.
**
+** For most configuration options, the wx_sqlite3_config() interface
+** may only be invoked prior to library initialization using
+** [wx_sqlite3_initialize()] or after shutdown by [wx_sqlite3_shutdown()].
+** The exceptional configuration options that may be invoked at any time
+** are called "anytime configuration options".
+** ^If wx_sqlite3_config() is called after [wx_sqlite3_initialize()] and before
+** [wx_sqlite3_shutdown()] with a first argument that is not an anytime
+** configuration option, then the wx_sqlite3_config() call will return SQLITE_MISUSE.
+** Note, however, that ^wx_sqlite3_config() can be called as part of the
+** implementation of an application-defined [wx_sqlite3_os_init()].
+**
** ^When a configuration option is set, wx_sqlite3_config() returns [SQLITE_OK].
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
@@ -2174,6 +2243,23 @@ struct wx_sqlite3_mem_methods {
** These constants are the available integer configuration options that
** can be passed as the first argument to the [wx_sqlite3_config()] interface.
**
+** Most of the configuration options for wx_sqlite3_config()
+** will only work if invoked prior to [wx_sqlite3_initialize()] or after
+** [wx_sqlite3_shutdown()]. The few exceptions to this rule are called
+** "anytime configuration options".
+** ^Calling [wx_sqlite3_config()] with a first argument that is not an
+** anytime configuration option in between calls to [wx_sqlite3_initialize()] and
+** [wx_sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE.
+**
+** The set of anytime configuration options can change (by insertions
+** and/or deletions) from one release of SQLite to the next.
+** As of SQLite version 3.42.0, the complete set of anytime configuration
+** options is:
+** <ul>
+** <li> SQLITE_CONFIG_LOG
+** <li> SQLITE_CONFIG_PCACHE_HDRSZ
+** </ul>
+**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
** should check the return code from [wx_sqlite3_config()] to make sure that
@@ -2504,7 +2590,7 @@ struct wx_sqlite3_mem_methods {
** is stored in each sorted record and the required column values loaded
** from the database as records are returned in sorted order. The default
** value for this option is to never use this optimization. Specifying a
-** negative value for this option restores the default behaviour.
+** negative value for this option restores the default behavior.
** This option is only available if SQLite is compiled with the
** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
**
@@ -2518,30 +2604,46 @@ struct wx_sqlite3_mem_methods {
** configuration setting is never used, then the default maximum is determined
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
** compile-time option is not set, then the default maximum is 1073741824.
+**
+** [[SQLITE_CONFIG_ROWID_IN_VIEW]]
+** <dt>SQLITE_CONFIG_ROWID_IN_VIEW
+** <dd>The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability
+** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is
+** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability
+** defaults to on. This configuration option queries the current setting or
+** changes the setting to off or on. The argument is a pointer to an integer.
+** If that integer initially holds a value of 1, then the ability for VIEWs to
+** have ROWIDs is activated. If the integer initially holds zero, then the
+** ability is deactivated. Any other initial value for the integer leaves the
+** setting unchanged. After changes, if any, the integer is written with
+** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite
+** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and
+** recommended case) then the integer is always filled with zero, regardless
+** if its initial value.
** </dl>
*/
-#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
-#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
-#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* wx_sqlite3_mem_methods* */
-#define SQLITE_CONFIG_GETMALLOC 5 /* wx_sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
-#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
-#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
-#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
-#define SQLITE_CONFIG_MUTEX 10 /* wx_sqlite3_mutex_methods* */
-#define SQLITE_CONFIG_GETMUTEX 11 /* wx_sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
-#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#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 /* wx_sqlite3_pcache_methods2* */
-#define SQLITE_CONFIG_GETPCACHE2 19 /* wx_sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
+#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
+#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
+#define SQLITE_CONFIG_MALLOC 4 /* wx_sqlite3_mem_methods* */
+#define SQLITE_CONFIG_GETMALLOC 5 /* wx_sqlite3_mem_methods* */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
+#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
+#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
+#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
+#define SQLITE_CONFIG_MUTEX 10 /* wx_sqlite3_mutex_methods* */
+#define SQLITE_CONFIG_GETMUTEX 11 /* wx_sqlite3_mutex_methods* */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
+#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 /* wx_sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* wx_sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
-#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
-#define SQLITE_CONFIG_MMAP_SIZE 22 /* wx_sqlite3_int64, wx_sqlite3_int64 */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* wx_sqlite3_int64, wx_sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
@@ -2549,6 +2651,7 @@ struct wx_sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* wx_sqlite3_int64 */
+#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2679,7 +2782,7 @@ struct wx_sqlite3_mem_methods {
** database handle, SQLite checks if this will mean that there are now no
** connections at all to the database. If so, it performs a checkpoint
** operation before closing the connection. This option may be used to
-** override this behaviour. The first parameter passed to this operation
+** override this behavior. The first parameter passed to this operation
** is an integer - positive to disable checkpoints-on-close, or zero (the
** default) to enable them, and negative to leave the setting unchanged.
** The second parameter is a pointer to an integer
@@ -2776,7 +2879,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
-** <dt>SQLITE_DBCONFIG_DQS_DML</td>
+** <dt>SQLITE_DBCONFIG_DQS_DML</dt>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@@ -2785,7 +2888,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
-** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
+** <dt>SQLITE_DBCONFIG_DQS_DDL</dt>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
@@ -2794,7 +2897,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
-** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
+** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@@ -2814,7 +2917,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
-** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
+** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
@@ -2823,7 +2926,7 @@ struct wx_sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
-** is now scarcely any need to generated database files that are compatible
+** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version
@@ -2832,8 +2935,40 @@ struct wx_sqlite3_mem_methods {
** the [VACUUM] command will fail with an obscure error when attempting to
** process a table with generated columns and a descending index. This is
** not considered a bug since SQLite versions 3.3.0 and earlier do not support
-** either generated columns or decending indexes.
+** either generated columns or descending indexes.
** </dd>
+**
+** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
+** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
+** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
+** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
+** a flag that enables collection of the wx_sqlite3_stmt_scanstatus_v2()
+** statistics. For statistics to be collected, the flag must be set on
+** the database handle both when the SQL statement is prepared and when it
+** is stepped. The flag is set (collection of statistics is enabled)
+** by default. This option takes two arguments: an integer and a pointer to
+** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the statement scanstatus option. If the second argument
+** is not NULL, then the value of the statement scanstatus setting after
+** processing the first argument is written into the integer that the second
+** argument points to.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
+** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
+** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
+** in which tables and indexes are scanned so that the scans start at the end
+** and work toward the beginning rather than starting at the beginning and
+** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
+** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** two arguments which are an integer and a pointer to an integer. The first
+** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
+** reverse scan order flag, respectively. If the second argument is not NULL,
+** then 0 or 1 is written into the integer that the second argument points to
+** depending on if the reverse scan order flag is set after processing the
+** first argument.
+** </dd>
+**
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2854,7 +2989,9 @@ struct wx_sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
+#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -3079,6 +3216,7 @@ SQLITE_API wx_sqlite3_int64 wx_sqlite3_total_changes64(wx_sqlite3*);
**
** ^The [wx_sqlite3_is_interrupted(D)] interface can be used to determine whether
** or not an interrupt is currently in effect for [database connection] D.
+** It returns 1 if an interrupt is currently in effect, or 0 otherwise.
*/
SQLITE_API void wx_sqlite3_interrupt(wx_sqlite3*);
SQLITE_API int wx_sqlite3_is_interrupted(wx_sqlite3*);
@@ -3628,8 +3766,8 @@ SQLITE_API int wx_sqlite3_set_authorizer(
#define SQLITE_RECURSIVE 33 /* NULL NULL */
/*
-** CAPI3REF: Tracing And Profiling Functions
-** METHOD: wx_sqlite3
+** CAPI3REF: Deprecated Tracing And Profiling Functions
+** DEPRECATED
**
** These routines are deprecated. Use the [wx_sqlite3_trace_v2()] interface
** instead of the routines described here.
@@ -3732,8 +3870,10 @@ SQLITE_API SQLITE_DEPRECATED void *wx_sqlite3_profile(wx_sqlite3*,
** M argument should be the bitwise OR-ed combination of
** zero or more [SQLITE_TRACE] constants.
**
-** ^Each call to either wx_sqlite3_trace() or wx_sqlite3_trace_v2() overrides
-** (cancels) any prior calls to wx_sqlite3_trace() or wx_sqlite3_trace_v2().
+** ^Each call to either wx_sqlite3_trace(D,X,P) or wx_sqlite3_trace_v2(D,M,X,P)
+** overrides (cancels) all prior calls to wx_sqlite3_trace(D,X,P) or
+** wx_sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each
+** database connection may have at most one trace callback.
**
** ^The X callback is invoked whenever any of the events identified by
** mask M occur. ^The integer return value from the callback is currently
@@ -3891,8 +4031,8 @@ SQLITE_API void wx_sqlite3_progress_handler(wx_sqlite3*, int, int(*)(void*), voi
**
** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt>
** <dd>The database connection comes up in "extended result code mode".
-** In other words, the database behaves has if
-** [wx_sqlite3_extended_result_codes(db,1)] where called on the database
+** In other words, the database behaves as if
+** [wx_sqlite3_extended_result_codes(db,1)] were called on the database
** connection as soon as the connection is created. In addition to setting
** the extended result code mode, this flag also causes [wx_sqlite3_open_v2()]
** to return an extended result code.</dd>
@@ -4102,7 +4242,7 @@ SQLITE_API int wx_sqlite3_open_v2(
** as F) must be one of:
** <ul>
** <li> A database filename pointer created by the SQLite core and
-** passed into the xOpen() method of a VFS implemention, or
+** passed into the xOpen() method of a VFS implementation, or
** <li> A filename obtained from [wx_sqlite3_db_filename()], or
** <li> A new filename constructed using [wx_sqlite3_create_filename()].
** </ul>
@@ -4215,7 +4355,7 @@ SQLITE_API wx_sqlite3_file *wx_sqlite3_database_file_object(const char*);
/*
** CAPI3REF: Create and Destroy VFS Filenames
**
-** These interfces are provided for use by [VFS shim] implementations and
+** These interfaces are provided for use by [VFS shim] implementations and
** are not useful outside of that context.
**
** The wx_sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
@@ -4294,14 +4434,17 @@ SQLITE_API void wx_sqlite3_free_filename(wx_sqlite3_filename);
** </ul>
**
** ^The wx_sqlite3_errmsg() and wx_sqlite3_errmsg16() return English-language
-** text that describes the error, as either UTF-8 or UTF-16 respectively.
+** text that describes the error, as either UTF-8 or UTF-16 respectively,
+** or NULL if no error message is available.
+** (See how SQLite handles [invalid UTF] for exceptions to this rule.)
** ^(Memory to hold the error message string is managed internally.
** The application does not need to worry about freeing the result.
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
-** ^The wx_sqlite3_errstr() interface returns the English-language text
-** that describes the [result code], as UTF-8.
+** ^The wx_sqlite3_errstr(E) interface returns the English-language text
+** that describes the [result code] E, as UTF-8, or NULL if E is not an
+** result code for which a text error message is available.
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
@@ -4540,13 +4683,17 @@ SQLITE_API int wx_sqlite3_limit(wx_sqlite3*, int id, int newVal);
** and wx_sqlite3_prepare16_v3() use UTF-16.
**
** ^If the nByte argument is negative, then zSql is read up to the
-** first zero terminator. ^If nByte is positive, then it is the
-** number of bytes read from zSql. ^If nByte is zero, then no prepared
+** first zero terminator. ^If nByte is positive, then it is the maximum
+** number of bytes read from zSql. When nByte is positive, zSql is read
+** up to the first zero terminator or until the nByte bytes have been read,
+** whichever comes first. ^If nByte is zero, then no prepared
** statement is generated.
** If the caller knows that the supplied string is nul-terminated, then
** there is a small performance advantage to passing an nByte parameter that
** is the number of bytes in the input string <i>including</i>
** the nul-terminator.
+** Note that nByte measure the length of the input in bytes, not
+** characters, even for the UTF-16 interfaces.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only
@@ -4763,6 +4910,41 @@ SQLITE_API int wx_sqlite3_stmt_readonly(wx_sqlite3_stmt *pStmt);
SQLITE_API int wx_sqlite3_stmt_isexplain(wx_sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement
+** METHOD: wx_sqlite3_stmt
+**
+** The wx_sqlite3_stmt_explain(S,E) interface changes the EXPLAIN
+** setting for [prepared statement] S. If E is zero, then S becomes
+** a normal prepared statement. If E is 1, then S behaves as if
+** its SQL text began with "[EXPLAIN]". If E is 2, then S behaves as if
+** its SQL text began with "[EXPLAIN QUERY PLAN]".
+**
+** Calling wx_sqlite3_stmt_explain(S,E) might cause S to be reprepared.
+** SQLite tries to avoid a reprepare, but a reprepare might be necessary
+** on the first transition into EXPLAIN or EXPLAIN QUERY PLAN mode.
+**
+** Because of the potential need to reprepare, a call to
+** wx_sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be
+** reprepared because it was created using [wx_sqlite3_prepare()] instead of
+** the newer [wx_sqlite3_prepare_v2()] or [wx_sqlite3_prepare_v3()] interfaces and
+** hence has no saved SQL text with which to reprepare.
+**
+** Changing the explain setting for a prepared statement does not change
+** the original SQL text for the statement. Hence, if the SQL text originally
+** began with EXPLAIN or EXPLAIN QUERY PLAN, but wx_sqlite3_stmt_explain(S,0)
+** is called to convert the statement into an ordinary statement, the EXPLAIN
+** or EXPLAIN QUERY PLAN keywords will still appear in the wx_sqlite3_sql(S)
+** output, even though the statement now acts like a normal SQL statement.
+**
+** This routine returns SQLITE_OK if the explain mode is successfully
+** changed, or an error code if the explain mode could not be changed.
+** The explain mode cannot be changed while a statement is active.
+** Hence, it is good practice to call [wx_sqlite3_reset(S)]
+** immediately prior to calling wx_sqlite3_stmt_explain(S,E).
+*/
+SQLITE_API int wx_sqlite3_stmt_explain(wx_sqlite3_stmt *pStmt, int eMode);
+
+/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: wx_sqlite3_stmt
**
@@ -4925,7 +5107,7 @@ typedef struct wx_sqlite3_context wx_sqlite3_context;
** with it may be passed. ^It is called to dispose of the BLOB or string even
** if the call to the bind API fails, except the destructor is not called if
** the third parameter is a NULL pointer or the fourth parameter is negative.
-** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that
+** ^ (2) The special constant, [SQLITE_STATIC], may be passed to indicate that
** the application remains responsible for disposing of the object. ^In this
** case, the object and the provided pointer to it must remain valid until
** either the prepared statement is finalized or the same SQL parameter is
@@ -5604,20 +5786,33 @@ SQLITE_API int wx_sqlite3_finalize(wx_sqlite3_stmt *pStmt);
** ^The [wx_sqlite3_reset(S)] interface resets the [prepared statement] S
** back to the beginning of its program.
**
-** ^If the most recent call to [wx_sqlite3_step(S)] for the
-** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
-** or if [wx_sqlite3_step(S)] has never before been called on S,
-** then [wx_sqlite3_reset(S)] returns [SQLITE_OK].
+** ^The return code from [wx_sqlite3_reset(S)] indicates whether or not
+** the previous evaluation of prepared statement S completed successfully.
+** ^If [wx_sqlite3_step(S)] has never before been called on S or if
+** [wx_sqlite3_step(S)] has not been called since the previous call
+** to [wx_sqlite3_reset(S)], then [wx_sqlite3_reset(S)] will return
+** [SQLITE_OK].
**
** ^If the most recent call to [wx_sqlite3_step(S)] for the
** [prepared statement] S indicated an error, then
** [wx_sqlite3_reset(S)] returns an appropriate [error code].
+** ^The [wx_sqlite3_reset(S)] interface might also return an [error code]
+** if there were no prior errors but the process of resetting
+** the prepared statement caused a new error. ^For example, if an
+** [INSERT] statement with a [RETURNING] clause is only stepped one time,
+** that one call to [wx_sqlite3_step(S)] might return SQLITE_ROW but
+** the overall statement might still fail and the [wx_sqlite3_reset(S)] call
+** might return SQLITE_BUSY if locking constraints prevent the
+** database change from committing. Therefore, it is important that
+** applications check the return code from [wx_sqlite3_reset(S)] even if
+** no prior call to [wx_sqlite3_step(S)] indicated a problem.
**
** ^The [wx_sqlite3_reset(S)] interface does not change the values
** of any [wx_sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int wx_sqlite3_reset(wx_sqlite3_stmt *pStmt);
+
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
@@ -5828,7 +6023,7 @@ SQLITE_API int wx_sqlite3_create_window_function(
** [application-defined SQL function]
** that has side-effects or that could potentially leak sensitive information.
** This will prevent attacks in which an application is tricked
-** into using a database file that has had its schema surreptiously
+** into using a database file that has had its schema surreptitiously
** modified to invoke the application-defined function in ways that are
** harmful.
** <p>
@@ -5864,13 +6059,36 @@ SQLITE_API int wx_sqlite3_create_window_function(
** </dd>
**
** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd>
-** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
+** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
** [wx_sqlite3_value_subtype()] to inspect the sub-types of its arguments.
-** Specifying this flag makes no difference for scalar or aggregate user
-** functions. However, if it is not specified for a user-defined window
-** function, then any sub-types belonging to arguments passed to the window
-** function may be discarded before the window function is called (i.e.
-** wx_sqlite3_value_subtype() will always return 0).
+** This flag instructs SQLite to omit some corner-case optimizations that
+** might disrupt the operation of the [wx_sqlite3_value_subtype()] function,
+** causing it to return zero rather than the correct subtype().
+** All SQL functions that invoke [wx_sqlite3_value_subtype()] should have this
+** property. If the SQLITE_SUBTYPE property is omitted, then the return
+** value from [wx_sqlite3_value_subtype()] might sometimes be zero even though
+** a non-zero subtype was specified by the function argument expression.
+**
+** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
+** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call
+** [wx_sqlite3_result_subtype()] to cause a sub-type to be associated with its
+** result.
+** Every function that invokes [wx_sqlite3_result_subtype()] should have this
+** property. If it does not, then the call to [wx_sqlite3_result_subtype()]
+** might become a no-op if the function is used as term in an
+** [expression index]. On the other hand, SQL functions that never invoke
+** [wx_sqlite3_result_subtype()] should avoid setting this property, as the
+** purpose of this property is to disable certain optimizations that are
+** incompatible with subtypes.
+**
+** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
+** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
+** that internally orders the values provided to the first argument. The
+** ordered-set aggregate SQL notation with a single ORDER BY term can be
+** used to invoke this function. If the ordered-set aggregate notation is
+** used on a function that lacks this flag, then an error is raised. Note
+** that the ordered-set aggregate syntax is only available if SQLite is
+** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
** </dd>
** </dl>
*/
@@ -5878,6 +6096,8 @@ SQLITE_API int wx_sqlite3_create_window_function(
#define SQLITE_DIRECTONLY 0x000080000
#define SQLITE_SUBTYPE 0x000100000
#define SQLITE_INNOCUOUS 0x000200000
+#define SQLITE_RESULT_SUBTYPE 0x001000000
+#define SQLITE_SELFORDER1 0x002000000
/*
** CAPI3REF: Deprecated Functions
@@ -6074,6 +6294,12 @@ SQLITE_API int wx_sqlite3_value_encoding(wx_sqlite3_value*);
** information can be used to pass a limited amount of context from
** one SQL function to another. Use the [wx_sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
+**
+** Every [application-defined SQL function] that invokes this interface
+** should include the [SQLITE_SUBTYPE] property in the text
+** encoding argument when the function is [wx_sqlite3_create_function|registered].
+** If the [SQLITE_SUBTYPE] property is omitted, then wx_sqlite3_value_subtype()
+** might return zero instead of the upstream subtype in some corner cases.
*/
SQLITE_API unsigned int wx_sqlite3_value_subtype(wx_sqlite3_value*);
@@ -6172,48 +6398,56 @@ SQLITE_API wx_sqlite3 *wx_sqlite3_context_db_handle(wx_sqlite3_context*);
** METHOD: wx_sqlite3_context
**
** These functions may be used by (non-aggregate) SQL functions to
-** associate metadata with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated metadata may be preserved. An example
-** of where this might be useful is in a regular-expression matching
-** function. The compiled version of the regular expression can be stored as
-** metadata associated with the pattern string.
+** associate auxiliary data with argument values. If the same argument
+** value is passed to multiple invocations of the same SQL function during
+** query execution, under some circumstances the associated auxiliary data
+** might be preserved. An example of where this might be useful is in a
+** regular-expression matching function. The compiled version of the regular
+** expression can be stored as auxiliary data associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The wx_sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** ^The wx_sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
** associated by the wx_sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
** value to the application-defined function. ^N is zero for the left-most
-** function argument. ^If there is no metadata
+** function argument. ^If there is no auxiliary data
** associated with the function argument, the wx_sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
-** ^The wx_sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
-** argument of the application-defined function. ^Subsequent
+** ^The wx_sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
+** N-th argument of the application-defined function. ^Subsequent
** calls to wx_sqlite3_get_auxdata(C,N) return P from the most recent
-** wx_sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or
-** NULL if the metadata has been discarded.
+** wx_sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or
+** NULL if the auxiliary data has been discarded.
** ^After each call to wx_sqlite3_set_auxdata(C,N,P,X) where X is not NULL,
** SQLite will invoke the destructor function X with parameter P exactly
-** once, when the metadata is discarded.
-** SQLite is free to discard the metadata at any time, including: <ul>
+** once, when the auxiliary data is discarded.
+** SQLite is free to discard the auxiliary data at any time, including: <ul>
** <li> ^(when the corresponding function parameter changes)^, or
** <li> ^(when [wx_sqlite3_reset()] or [wx_sqlite3_finalize()] is called for the
** SQL statement)^, or
** <li> ^(when wx_sqlite3_set_auxdata() is invoked again on the same
** parameter)^, or
** <li> ^(during the original wx_sqlite3_set_auxdata() call when a memory
-** allocation error occurs.)^ </ul>
+** allocation error occurs.)^
+** <li> ^(during the original wx_sqlite3_set_auxdata() call if the function
+** is evaluated during query planning instead of during query execution,
+** as sometimes happens with [SQLITE_ENABLE_STAT4].)^ </ul>
**
-** Note the last bullet in particular. The destructor X in
+** Note the last two bullets in particular. The destructor X in
** wx_sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
** wx_sqlite3_set_auxdata() interface even returns. Hence wx_sqlite3_set_auxdata()
** should be called near the end of the function implementation and the
** function implementation should not make any use of P after
-** wx_sqlite3_set_auxdata() has been called.
-**
-** ^(In practice, metadata is preserved between function calls for
+** wx_sqlite3_set_auxdata() has been called. Furthermore, a call to
+** wx_sqlite3_get_auxdata() that occurs immediately after a corresponding call
+** to wx_sqlite3_set_auxdata() might still return NULL if an out-of-memory
+** condition occurred during the wx_sqlite3_set_auxdata() call or if the
+** function is being evaluated during query planning rather than during
+** query execution.
+**
+** ^(In practice, auxiliary data is preserved between function calls for
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
**
@@ -6223,10 +6457,67 @@ SQLITE_API wx_sqlite3 *wx_sqlite3_context_db_handle(wx_sqlite3_context*);
**
** These routines must be called from the same thread in which
** the SQL function is running.
+**
+** See also: [wx_sqlite3_get_clientdata()] and [wx_sqlite3_set_clientdata()].
*/
SQLITE_API void *wx_sqlite3_get_auxdata(wx_sqlite3_context*, int N);
SQLITE_API void wx_sqlite3_set_auxdata(wx_sqlite3_context*, int N, void*, void (*)(void*));
+/*
+** CAPI3REF: Database Connection Client Data
+** METHOD: wx_sqlite3
+**
+** These functions are used to associate one or more named pointers
+** with a [database connection].
+** A call to wx_sqlite3_set_clientdata(D,N,P,X) causes the pointer P
+** to be attached to [database connection] D using name N. Subsequent
+** calls to wx_sqlite3_get_clientdata(D,N) will return a copy of pointer P
+** or a NULL pointer if there were no prior calls to
+** wx_sqlite3_set_clientdata() with the same values of D and N.
+** Names are compared using strcmp() and are thus case sensitive.
+**
+** If P and X are both non-NULL, then the destructor X is invoked with
+** argument P on the first of the following occurrences:
+** <ul>
+** <li> An out-of-memory error occurs during the call to
+** wx_sqlite3_set_clientdata() which attempts to register pointer P.
+** <li> A subsequent call to wx_sqlite3_set_clientdata(D,N,P,X) is made
+** with the same D and N parameters.
+** <li> The database connection closes. SQLite does not make any guarantees
+** about the order in which destructors are called, only that all
+** destructors will be called exactly once at some point during the
+** database connection closing process.
+** </ul>
+**
+** SQLite does not do anything with client data other than invoke
+** destructors on the client data at the appropriate time. The intended
+** use for client data is to provide a mechanism for wrapper libraries
+** to store additional information about an SQLite database connection.
+**
+** There is no limit (other than available memory) on the number of different
+** client data pointers (with different names) that can be attached to a
+** single database connection. However, the implementation is optimized
+** for the case of having only one or two different client data names.
+** Applications and wrapper libraries are discouraged from using more than
+** one client data name each.
+**
+** There is no way to enumerate the client data pointers
+** associated with a database connection. The N parameter can be thought
+** of as a secret key such that only code that knows the secret key is able
+** to access the associated data.
+**
+** Security Warning: These interfaces should not be exposed in scripting
+** languages or in other circumstances where it might be possible for an
+** an attacker to invoke them. Any agent that can invoke these interfaces
+** can probably also take control of the process.
+**
+** Database connection client data is only available for SQLite
+** version 3.44.0 ([dateof:3.44.0]) and later.
+**
+** See also: [wx_sqlite3_set_auxdata()] and [wx_sqlite3_get_auxdata()].
+*/
+SQLITE_API void *wx_sqlite3_get_clientdata(wx_sqlite3*,const char*);
+SQLITE_API int wx_sqlite3_set_clientdata(wx_sqlite3*, const char*, void*, void(*)(void*));
/*
** CAPI3REF: Constants Defining Special Destructor Behavior
@@ -6428,6 +6719,20 @@ SQLITE_API int wx_sqlite3_result_zeroblob64(wx_sqlite3_context*, wx_sqlite3_uint
** higher order bits are discarded.
** The number of subtype bytes preserved by SQLite might increase
** in future releases of SQLite.
+**
+** Every [application-defined SQL function] that invokes this interface
+** should include the [SQLITE_RESULT_SUBTYPE] property in its
+** text encoding argument when the SQL function is
+** [wx_sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE]
+** property is omitted from the function that invokes wx_sqlite3_result_subtype(),
+** then in some cases the wx_sqlite3_result_subtype() might fail to set
+** the result subtype.
+**
+** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any
+** SQL function that invokes the wx_sqlite3_result_subtype() interface
+** and that does not have the SQLITE_RESULT_SUBTYPE property will raise
+** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1
+** by default.
*/
SQLITE_API void wx_sqlite3_result_subtype(wx_sqlite3_context*,unsigned int);
@@ -6599,6 +6904,13 @@ SQLITE_API void wx_sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of wx_sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
+**
+** If a negative argument is passed to wx_sqlite3_sleep() the results vary by
+** VFS and operating system. Some system treat a negative argument as an
+** instruction to sleep forever. Others understand it to mean do not sleep
+** at all. ^In SQLite version 3.42.0 and later, a negative
+** argument passed into wx_sqlite3_sleep() is changed to zero before it is relayed
+** down into the xSleep method of the VFS.
*/
SQLITE_API int wx_sqlite3_sleep(int);
@@ -6852,7 +7164,7 @@ SQLITE_API int wx_sqlite3_db_readonly(wx_sqlite3 *db, const char *zDbName);
SQLITE_API int wx_sqlite3_txn_state(wx_sqlite3*,const char *zSchema);
/*
-** CAPI3REF: Allowed return values from [wx_sqlite3_txn_state()]
+** CAPI3REF: Allowed return values from wx_sqlite3_txn_state()
** KEYWORDS: {transaction state}
**
** These constants define the current transaction state of a database file.
@@ -6984,7 +7296,7 @@ SQLITE_API void *wx_sqlite3_rollback_hook(wx_sqlite3*, void(*)(void *), void*);
** ^Each call to the wx_sqlite3_autovacuum_pages() interface overrides all
** previous invocations for that database connection. ^If the callback
** argument (C) to wx_sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer,
-** then the autovacuum steps callback is cancelled. The return value
+** then the autovacuum steps callback is canceled. The return value
** from wx_sqlite3_autovacuum_pages() is normally SQLITE_OK, but might
** be some other error code if something goes wrong. The current
** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other
@@ -7050,6 +7362,12 @@ SQLITE_API int wx_sqlite3_autovacuum_pages(
** The exceptions defined in this paragraph might change in a future
** release of SQLite.
**
+** Whether the update hook is invoked before or after the
+** corresponding change is currently unspecified and may differ
+** depending on the type of change. Do not rely on the order of the
+** hook call with regards to the final result of the operation which
+** triggers the hook.
+**
** The update hook implementation must not do anything that will modify
** the database connection that invoked the update hook. Any actions
** to modify the database connection must be deferred until after the
@@ -7503,6 +7821,10 @@ struct wx_sqlite3_module {
/* The methods above are in versions 1 and 2 of the sqlite_module object.
** Those below are for version 3 and greater. */
int (*xShadowName)(const char*);
+ /* The methods above are in versions 1 through 3 of the sqlite_module object.
+ ** Those below are for version 4 and greater. */
+ int (*xIntegrity)(wx_sqlite3_vtab *pVTab, const char *zSchema,
+ const char *zTabName, int mFlags, char **pzErr);
};
/*
@@ -7580,9 +7902,11 @@ struct wx_sqlite3_module {
** will be returned by the strategy.
**
** The xBestIndex method may optionally populate the idxFlags field with a
-** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
-** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
-** assumes that the strategy may visit at most one row.
+** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
+** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
+** output to show the idxNum has hex instead of as decimal. Another flag is
+** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
+** return at most one row.
**
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
** SQLite also assumes that if a call to the xUpdate() method is made as
@@ -7646,7 +7970,9 @@ struct wx_sqlite3_index_info {
** [wx_sqlite3_index_info].idxFlags field to some combination of
** these bits.
*/
-#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
+#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */
+#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */
+ /* in EXPLAIN QUERY PLAN */
/*
** CAPI3REF: Virtual Table Constraint Operator Codes
@@ -7990,7 +8316,7 @@ SQLITE_API int wx_sqlite3_blob_reopen(wx_sqlite3_blob *, wx_sqlite3_int64);
** code is returned and the transaction rolled back.
**
** Calling this function with an argument that is not a NULL pointer or an
-** open blob handle results in undefined behaviour. ^Calling this routine
+** open blob handle results in undefined behavior. ^Calling this routine
** with a null pointer (such as would be returned by a failed call to
** [wx_sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
** is passed a valid open blob handle, the values returned by the
@@ -8217,18 +8543,20 @@ SQLITE_API int wx_sqlite3_vfs_unregister(wx_sqlite3_vfs*);
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by wx_sqlite3_mutex_try(). On those systems, wx_sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** wx_sqlite3_mutex_try() as an optimization so this is acceptable
-** behavior.)^
+** will always return SQLITE_BUSY. In most cases the SQLite core only uses
+** wx_sqlite3_mutex_try() as an optimization, so this is acceptable
+** behavior. The exceptions are unix builds that set the
+** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working
+** wx_sqlite3_mutex_try() is required.)^
**
** ^The wx_sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated.
**
-** ^If the argument to wx_sqlite3_mutex_enter(), wx_sqlite3_mutex_try(), or
-** wx_sqlite3_mutex_leave() is a NULL pointer, then all three routines
-** behave as no-ops.
+** ^If the argument to wx_sqlite3_mutex_enter(), wx_sqlite3_mutex_try(),
+** wx_sqlite3_mutex_leave(), or wx_sqlite3_mutex_free() is a NULL pointer,
+** then any of the four routines behaves as a no-op.
**
** See also: [wx_sqlite3_mutex_held()] and [wx_sqlite3_mutex_notheld()].
*/
@@ -8470,6 +8798,7 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
+#define SQLITE_TESTCTRL_FK_NO_ACTION 7
#define SQLITE_TESTCTRL_BITVEC_TEST 8
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
@@ -8477,8 +8806,10 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ASSERT 12
#define SQLITE_TESTCTRL_ALWAYS 13
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
+#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
+#define SQLITE_TESTCTRL_GETOPT 16
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
@@ -8498,7 +8829,8 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33
-#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
+#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -8511,7 +8843,7 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
** The wx_sqlite3_keyword_count() interface returns the number of distinct
** keywords understood by SQLite.
**
-** The wx_sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and
+** The wx_sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and
** makes *Z point to that keyword expressed as UTF8 and writes the number
** of bytes in the keyword into *L. The string that *Z points to is not
** zero-terminated. The wx_sqlite3_keyword_name(N,Z,L) routine returns
@@ -9473,6 +9805,16 @@ typedef struct wx_sqlite3_backup wx_sqlite3_backup;
** APIs are not strictly speaking threadsafe. If they are invoked at the
** same time as another thread is invoking wx_sqlite3_backup_step() it is
** possible that they return invalid values.
+**
+** <b>Alternatives To Using The Backup API</b>
+**
+** Other techniques for safely creating a consistent backup of an SQLite
+** database include:
+**
+** <ul>
+** <li> The [VACUUM INTO] command.
+** <li> The [wx_sqlite3_rsync] utility program.
+** </ul>
*/
SQLITE_API wx_sqlite3_backup *wx_sqlite3_backup_init(
wx_sqlite3 *pDest, /* Destination database handle */
@@ -9954,7 +10296,7 @@ SQLITE_API int wx_sqlite3_vtab_config(wx_sqlite3*, int op, ...);
** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
** <dd>Calls of the form
** [wx_sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** prohibits that virtual table from being used from within triggers and
** views.
** </dd>
@@ -9962,18 +10304,28 @@ SQLITE_API int wx_sqlite3_vtab_config(wx_sqlite3*, int op, ...);
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [wx_sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
+**
+** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
+** <dd>Calls of the form
+** [wx_sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
+** instruct the query planner to begin at least a read transaction on
+** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
+** virtual table is used.
+** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3
+#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -10080,24 +10432,45 @@ SQLITE_API const char *wx_sqlite3_vtab_collation(wx_sqlite3_index_info*,int);
** <li value="2"><p>
** ^(If the wx_sqlite3_vtab_distinct() interface returns 2, that means
** that the query planner does not need the rows returned in any particular
-** order, as long as rows with the same values in all "aOrderBy" columns
-** are adjacent.)^ ^(Furthermore, only a single row for each particular
-** combination of values in the columns identified by the "aOrderBy" field
-** needs to be returned.)^ ^It is always ok for two or more rows with the same
-** values in all "aOrderBy" columns to be returned, as long as all such rows
-** are adjacent. ^The virtual table may, if it chooses, omit extra rows
-** that have the same value for all columns identified by "aOrderBy".
-** ^However omitting the extra rows is optional.
+** order, as long as rows with the same values in all columns identified
+** by "aOrderBy" are adjacent.)^ ^(Furthermore, when two or more rows
+** contain the same values for all columns identified by "colUsed", all but
+** one such row may optionally be omitted from the result.)^
+** The virtual table is not required to omit rows that are duplicates
+** over the "colUsed" columns, but if the virtual table can do that without
+** too much extra effort, it could potentially help the query to run faster.
** This mode is used for a DISTINCT query.
** <li value="3"><p>
-** ^(If the wx_sqlite3_vtab_distinct() interface returns 3, that means
-** that the query planner needs only distinct rows but it does need the
-** rows to be sorted.)^ ^The virtual table implementation is free to omit
-** rows that are identical in all aOrderBy columns, if it wants to, but
-** it is not required to omit any rows. This mode is used for queries
+** ^(If the wx_sqlite3_vtab_distinct() interface returns 3, that means the
+** virtual table must return rows in the order defined by "aOrderBy" as
+** if the wx_sqlite3_vtab_distinct() interface had returned 0. However if
+** two or more rows in the result have the same values for all columns
+** identified by "colUsed", then all but one such row may optionally be
+** omitted.)^ Like when the return value is 2, the virtual table
+** is not required to omit rows that are duplicates over the "colUsed"
+** columns, but if the virtual table can do that without
+** too much extra effort, it could potentially help the query to run faster.
+** This mode is used for queries
** that have both DISTINCT and ORDER BY clauses.
** </ol>
**
+** <p>The following table summarizes the conditions under which the
+** virtual table is allowed to set the "orderByConsumed" flag based on
+** the value returned by wx_sqlite3_vtab_distinct(). This table is a
+** restatement of the previous four paragraphs:
+**
+** <table border=1 cellspacing=0 cellpadding=10 width="90%">
+** <tr>
+** <td valign="top">wx_sqlite3_vtab_distinct() return value
+** <td valign="top">Rows are returned in aOrderBy order
+** <td valign="top">Rows with the same value in all aOrderBy columns are adjacent
+** <td valign="top">Duplicates over all colUsed columns may be omitted
+** <tr><td>0<td>yes<td>yes<td>no
+** <tr><td>1<td>no<td>yes<td>no
+** <tr><td>2<td>no<td>yes<td>yes
+** <tr><td>3<td>yes<td>yes<td>yes
+** </table>
+**
** ^For the purposes of comparing virtual table output values to see if the
** values are same value for sorting purposes, two NULL values are considered
** to be the same. In other words, the comparison operator is "IS"
@@ -10134,7 +10507,7 @@ SQLITE_API int wx_sqlite3_vtab_distinct(wx_sqlite3_index_info*);
** communicated to the xBestIndex method as a
** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use
** this constraint, it must set the corresponding
-** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under
+** aConstraintUsage[].argvIndex to a positive integer. ^(Then, under
** the usual mode of handling IN operators, SQLite generates [bytecode]
** that invokes the [xFilter|xFilter() method] once for each value
** on the right-hand side of the IN operator.)^ Thus the virtual table
@@ -10563,7 +10936,7 @@ SQLITE_API int wx_sqlite3_db_cacheflush(wx_sqlite3*);
** When the [wx_sqlite3_blob_write()] API is used to update a blob column,
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
** in this case the new values are not available. In this case, when a
-** callback made with op==SQLITE_DELETE is actuall a write using the
+** callback made with op==SQLITE_DELETE is actually a write using the
** wx_sqlite3_blob_write() API, the [wx_sqlite3_preupdate_blobwrite()] returns
** the index of the column being written. In other cases, where the
** pre-update hook is being invoked for some other reason, including a
@@ -10641,6 +11014,14 @@ typedef struct wx_sqlite3_snapshot {
** If there is not already a read-transaction open on schema S when
** this function is called, one is opened automatically.
**
+** If a read-transaction is opened by this function, then it is guaranteed
+** that the returned snapshot object may not be invalidated by a database
+** writer or checkpointer until after the read-transaction is closed. This
+** is not guaranteed if a read-transaction is already open when this
+** function is called. In that case, any subsequent write or checkpoint
+** operation on the database may invalidate the returned snapshot handle,
+** even while the read-transaction remains open.
+**
** The following must be true for this function to succeed. If any of
** the following statements are false when wx_sqlite3_snapshot_get() is
** called, SQLITE_ERROR is returned. The final value of *P is undefined
@@ -10824,6 +11205,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int wx_sqlite3_snapshot_recover(wx_sqlite3 *db, c
** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
** of the database exists.
**
+** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set,
+** the returned buffer content will remain accessible and unchanged
+** until either the next write operation on the connection or when
+** the connection is closed, and applications must not modify the
+** buffer. If the bit had been clear, the returned buffer will not
+** be accessed by SQLite after the call.
+**
** A call to wx_sqlite3_serialize(D,S,P,F) might return NULL even if the
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
** allocation error occurs.
@@ -10872,6 +11260,9 @@ SQLITE_API unsigned char *wx_sqlite3_serialize(
** SQLite will try to increase the buffer size using wx_sqlite3_realloc64()
** if writes on the database cause it to grow larger than M bytes.
**
+** Applications must not modify the buffer P or invalidate it before
+** the database connection D is closed.
+**
** The wx_sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
** database is currently in a read transaction or is involved in a backup
** operation.
@@ -10880,6 +11271,13 @@ SQLITE_API unsigned char *wx_sqlite3_serialize(
** S argument to wx_sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
** function returns SQLITE_ERROR.
**
+** The deserialized database should not be in [WAL mode]. If the database
+** is in WAL mode, then any attempt to use the database file will result
+** in an [SQLITE_CANTOPEN] error. The application can set the
+** [file format version numbers] (bytes 18 and 19) of the input database P
+** to 0x01 prior to invoking wx_sqlite3_deserialize(D,S,P,N,M,F) to force the
+** database file into rollback mode and work around this limitation.
+**
** If wx_sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
** [wx_sqlite3_free()] is invoked on argument P prior to returning.
@@ -10932,8 +11330,6 @@ SQLITE_API int wx_sqlite3_deserialize(
#if defined(__wasi__)
# undef SQLITE_WASI
# define SQLITE_WASI 1
-# undef SQLITE_OMIT_WAL
-# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
# ifndef SQLITE_OMIT_LOAD_EXTENSION
# define SQLITE_OMIT_LOAD_EXTENSION
# endif
@@ -10946,7 +11342,7 @@ SQLITE_API int wx_sqlite3_deserialize(
} /* End of the 'extern "C"' block */
#endif
#endif /* SQLITE3_H */
-
+
/* Function prototypes of SQLite3 Multiple Ciphers */
SQLITE_PRIVATE int wx_sqlite3mcCheckVfs(const char*);
SQLITE_PRIVATE int wx_sqlite3mcFileControlPragma(wx_sqlite3*, const char*, int, void*);
@@ -10954,6 +11350,11 @@ SQLITE_PRIVATE int wx_sqlite3mcHandleAttachKey(wx_sqlite3*, const char*, const c
SQLITE_PRIVATE int wx_sqlite3mcHandleMainKey(wx_sqlite3*, const char*);
typedef struct PgHdr PgHdrMC;
SQLITE_PRIVATE void* wx_sqlite3mcPagerCodec(PgHdrMC* pPg);
+typedef struct Pager PagerMC;
+SQLITE_PRIVATE int wx_sqlite3mcPagerHasCodec(PagerMC* pPager);
+SQLITE_PRIVATE void wx_sqlite3mcInitMemoryMethods();
+SQLITE_PRIVATE int wx_sqlite3mcIsBackupSupported(wx_sqlite3*, const char*, wx_sqlite3*, const char*);
+SQLITE_PRIVATE void wx_sqlite3mcCodecGetKey(wx_sqlite3* db, int nDb, void** zKey, int* nKey);
/******** Begin file wx_sqlite3rtree.h *********/
/*
@@ -11156,16 +11557,20 @@ SQLITE_API int wx_sqlite3session_create(
SQLITE_API void wx_sqlite3session_delete(wx_sqlite3_session *pSession);
/*
-** CAPIREF: Conigure a Session Object
+** CAPI3REF: Configure a Session Object
** METHOD: wx_sqlite3_session
**
** This method is used to configure a session object after it has been
-** created. At present the only valid value for the second parameter is
-** [SQLITE_SESSION_OBJCONFIG_SIZE].
+** created. At present the only valid values for the second parameter are
+** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
**
-** Arguments for wx_sqlite3session_object_config()
+*/
+SQLITE_API int wx_sqlite3session_object_config(wx_sqlite3_session*, int op, void *pArg);
+
+/*
+** CAPI3REF: Options for wx_sqlite3session_object_config
**
-** The following values may passed as the the 4th parameter to
+** The following values may passed as the the 2nd parameter to
** wx_sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
@@ -11181,12 +11586,21 @@ SQLITE_API void wx_sqlite3session_delete(wx_sqlite3_session *pSession);
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
+**
+** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd>
+** This option is used to set, clear or query the flag that enables
+** collection of data for tables with no explicit PRIMARY KEY.
+**
+** Normally, tables with no explicit PRIMARY KEY are simply ignored
+** by the sessions module. However, if this flag is set, it behaves
+** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
+** as their leftmost columns.
+**
+** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
+** the first table has been attached to the session object.
*/
-SQLITE_API int wx_sqlite3session_object_config(wx_sqlite3_session*, int op, void *pArg);
-
-/*
-*/
-#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/*
** CAPI3REF: Enable Or Disable A Session Object
@@ -11948,6 +12362,18 @@ SQLITE_API int wx_sqlite3changeset_concat(
/*
+** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
+*/
+SQLITE_API int wx_sqlite3changeset_upgrade(
+ wx_sqlite3 *db,
+ const char *zDb,
+ int nIn, const void *pIn, /* Input changeset */
+ int *pnOut, void **ppOut /* OUT: Inverse of input */
+);
+
+
+
+/*
** CAPI3REF: Changegroup Handle
**
** A changegroup is an object used to combine two or more
@@ -11994,6 +12420,38 @@ typedef struct wx_sqlite3_changegroup wx_sqlite3_changegroup;
SQLITE_API int wx_sqlite3changegroup_new(wx_sqlite3_changegroup **pp);
/*
+** CAPI3REF: Add a Schema to a Changegroup
+** METHOD: wx_sqlite3_changegroup_schema
+**
+** This method may be used to optionally enforce the rule that the changesets
+** added to the changegroup handle must match the schema of database zDb
+** ("main", "temp", or the name of an attached database). If
+** wx_sqlite3changegroup_add() is called to add a changeset that is not compatible
+** with the configured schema, SQLITE_SCHEMA is returned and the changegroup
+** object is left in an undefined state.
+**
+** A changeset schema is considered compatible with the database schema in
+** the same way as for wx_sqlite3changeset_apply(). Specifically, for each
+** table in the changeset, there exists a database table with:
+**
+** <ul>
+** <li> The name identified by the changeset, and
+** <li> at least as many columns as recorded in the changeset, and
+** <li> the primary key columns in the same position as recorded in
+** the changeset.
+** </ul>
+**
+** The output of the changegroup object always has the same schema as the
+** database nominated using this function. In cases where changesets passed
+** to wx_sqlite3changegroup_add() have fewer columns than the corresponding table
+** in the database schema, these are filled in using the default column
+** values from the database schema. This makes it possible to combined
+** changesets that have different numbers of columns for a single table
+** within a changegroup, provided that they are otherwise compatible.
+*/
+SQLITE_API int wx_sqlite3changegroup_schema(wx_sqlite3_changegroup*, wx_sqlite3*, const char *zDb);
+
+/*
** CAPI3REF: Add A Changeset To A Changegroup
** METHOD: wx_sqlite3_changegroup
**
@@ -12061,17 +12519,46 @@ SQLITE_API int wx_sqlite3changegroup_new(wx_sqlite3_changegroup **pp);
** If the new changeset contains changes to a table that is already present
** in the changegroup, then the number of columns and the position of the
** primary key columns for the table must be consistent. If this is not the
-** case, this function fails with SQLITE_SCHEMA. If the input changeset
-** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
-** returned. Or, if an out-of-memory condition occurs during processing, this
-** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
-** of the final contents of the changegroup is undefined.
+** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup
+** object has been configured with a database schema using the
+** wx_sqlite3changegroup_schema() API, then it is possible to combine changesets
+** with different numbers of columns for a single table, provided that
+** they are otherwise compatible.
+**
+** If the input changeset appears to be corrupt and the corruption is
+** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition
+** occurs during processing, this function returns SQLITE_NOMEM.
**
-** If no error occurs, SQLITE_OK is returned.
+** In all cases, if an error occurs the state of the final contents of the
+** changegroup is undefined. If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int wx_sqlite3changegroup_add(wx_sqlite3_changegroup*, int nData, void *pData);
/*
+** CAPI3REF: Add A Single Change To A Changegroup
+** METHOD: wx_sqlite3_changegroup
+**
+** This function adds the single change currently indicated by the iterator
+** passed as the second argument to the changegroup object. The rules for
+** adding the change are just as described for [wx_sqlite3changegroup_add()].
+**
+** If the change is successfully added to the changegroup, SQLITE_OK is
+** returned. Otherwise, an SQLite error code is returned.
+**
+** The iterator must point to a valid entry when this function is called.
+** If it does not, SQLITE_ERROR is returned and no change is added to the
+** changegroup. Additionally, the iterator must not have been opened with
+** the SQLITE_CHANGESETAPPLY_INVERT flag. In this case SQLITE_ERROR is also
+** returned.
+*/
+SQLITE_API int wx_sqlite3changegroup_add_change(
+ wx_sqlite3_changegroup*,
+ wx_sqlite3_changeset_iter*
+);
+
+
+
+/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
** METHOD: wx_sqlite3_changegroup
**
@@ -12319,9 +12806,30 @@ SQLITE_API int wx_sqlite3changeset_apply_v2(
** Invert the changeset before applying it. This is equivalent to inverting
** a changeset using wx_sqlite3changeset_invert() before applying it. It is
** an error to specify this flag with a patchset.
+**
+** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd>
+** Do not invoke the conflict handler callback for any changes that
+** would not actually modify the database even if they were applied.
+** Specifically, this means that the conflict handler is not invoked
+** for:
+** <ul>
+** <li>a delete change if the row being deleted cannot be found,
+** <li>an update change if the modified fields are already set to
+** their new values in the conflicting row, or
+** <li>an insert change if all fields of the conflicting row match
+** the row being inserted.
+** </ul>
+**
+** <dt>SQLITE_CHANGESETAPPLY_FKNOACTION <dd>
+** If this flag it set, then all foreign key constraints in the target
+** database behave as if they were declared with "ON UPDATE NO ACTION ON
+** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL
+** or SET DEFAULT.
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
+#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
+#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008
/*
** CAPI3REF: Constants Passed To The Conflict Handler
@@ -12854,8 +13362,8 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
-** registered with.
+** Return a copy of the pUserData pointer passed to the xCreateFunction()
+** API when the extension function was registered.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
@@ -12887,8 +13395,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the text of column iCol of
+** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -12898,8 +13409,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of phrases in the current query, as returned by xPhraseCount,
+** 0 is returned. Otherwise, this function returns the number of tokens in
+** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -12915,12 +13428,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
+** output by xInstCount(). If iIdx is less than zero or greater than
+** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
+** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. Returns SQLITE_OK if successful, or an error
-** code (i.e. SQLITE_NOMEM) if an error occurs.
+** first token of the phrase. SQLITE_OK is returned if successful, or an
+** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -12946,6 +13460,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
+** If parameter iPhrase is less than zero, or greater than or equal to
+** the number of phrases in the query, as returned by xPhraseCount(),
+** this function returns SQLITE_RANGE.
+**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -13027,6 +13545,10 @@ struct Fts5PhraseIter {
** (i.e. if it is a contentless table), then this API always iterates
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
**
+** In all cases, matches are visited in (column ASC, offset ASC) order.
+** i.e. all those in column 0, sorted by offset, followed by those in
+** column 1, etc.
+**
** xPhraseNext()
** See xPhraseFirst above.
**
@@ -13060,9 +13582,65 @@ struct Fts5PhraseIter {
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
+**
+** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase iPhrase of the current
+** query. Before returning, output parameter *ppToken is set to point
+** to a buffer containing the requested token, and *pnToken to the
+** size of this buffer in bytes.
+**
+** If iPhrase or iToken are less than zero, or if iPhrase is greater than
+** or equal to the number of phrases in the query as reported by
+** xPhraseCount(), or if iToken is equal to or greater than the number of
+** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
+ are both zeroed.
+**
+** The output text is not a copy of the query text that specified the
+** token. It is the output of the tokenizer module. For tokendata=1
+** tables, this includes any embedded 0x00 and trailing data.
+**
+** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase hit iIdx within the
+** current row. If iIdx is less than zero or greater than or equal to the
+** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
+** output variable (*ppToken) is set to point to a buffer containing the
+** matching document token, and (*pnToken) to the size of that buffer in
+** bytes. This API is not available if the specified token matches a
+** prefix query term. In that case both output variables are always set
+** to 0.
+**
+** The output text is not a copy of the document text that was tokenized.
+** It is the output of the tokenizer module. For tokendata=1 tables, this
+** includes any embedded 0x00 and trailing data.
+**
+** This API can be quite slow if used with an FTS5 table created with the
+** "detail=none" or "detail=column" option.
+**
+** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the locale associated
+** with column iCol of the current row. Usually, there is no associated
+** locale, and output parameters (*pzLocale) and (*pnLocale) are set
+** to NULL and 0, respectively. However, if the fts5_locale() function
+** was used to associate a locale with the value when it was inserted
+** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
+** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
+** is set to the size in bytes of the buffer, not including the
+** nul-terminator.
+**
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an
+** SQLite error code is returned. The final value of the output parameters
+** is undefined in this case.
+**
+** xTokenize_v2:
+** Tokenize text using the tokenizer belonging to the FTS5 table. This
+** API is the same as the xTokenize() API, except that it allows a tokenizer
+** locale to be specified.
*/
struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
+ int iVersion; /* Currently always set to 4 */
void *(*xUserData)(Fts5Context*);
@@ -13097,6 +13675,22 @@ struct Fts5ExtensionApi {
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
+
+ /* Below this point are iVersion>=3 only */
+ int (*xQueryToken)(Fts5Context*,
+ int iPhrase, int iToken,
+ const char **ppToken, int *pnToken
+ );
+ int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
+
+ /* Below this point are iVersion>=4 only */
+ int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
+ int (*xTokenize_v2)(Fts5Context*,
+ const char *pText, int nText, /* Text to tokenize */
+ const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
+ void *pCtx, /* Context passed to xToken() */
+ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
+ );
};
/*
@@ -13117,7 +13711,7 @@ struct Fts5ExtensionApi {
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
-** pointer provided by the application when the fts5_tokenizer object
+** pointer provided by the application when the fts5_tokenizer_v2 object
** was registered with FTS5 (the third argument to xCreateTokenizer()).
** The second and third arguments are an array of nul-terminated strings
** containing the tokenizer arguments, if any, specified following the
@@ -13141,7 +13735,7 @@ struct Fts5ExtensionApi {
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
**
-** The second argument indicates the reason that FTS5 is requesting
+** The third argument indicates the reason that FTS5 is requesting
** tokenization of the supplied text. This is always one of the following
** four values:
**
@@ -13165,6 +13759,13 @@ struct Fts5ExtensionApi {
** on a columnsize=0 database.
** </ul>
**
+** The sixth and seventh arguments passed to xTokenize() - pLocale and
+** nLocale - are a pointer to a buffer containing the locale to use for
+** tokenization (e.g. "en_US") and its size in bytes, respectively. The
+** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
+** which case nLocale is always 0) to indicate that the tokenizer should
+** use its default locale.
+**
** For each token in the input string, the supplied callback xToken() must
** be invoked. The first argument to it should be a copy of the pointer
** passed as the second argument to xTokenize(). The third and fourth
@@ -13188,6 +13789,30 @@ struct Fts5ExtensionApi {
** may abandon the tokenization and return any error code other than
** SQLITE_OK or SQLITE_DONE.
**
+** If the tokenizer is registered using an fts5_tokenizer_v2 object,
+** then the xTokenize() method has two additional arguments - pLocale
+** and nLocale. These specify the locale that the tokenizer should use
+** for the current request. If pLocale and nLocale are both 0, then the
+** tokenizer should use its default locale. Otherwise, pLocale points to
+** an nLocale byte buffer containing the name of the locale to use as utf-8
+** text. pLocale is not nul-terminated.
+**
+** FTS5_TOKENIZER
+**
+** There is also an fts5_tokenizer object. This is an older, deprecated,
+** version of fts5_tokenizer_v2. It is similar except that:
+**
+** <ul>
+** <li> There is no "iVersion" field, and
+** <li> The xTokenize() method does not take a locale argument.
+** </ul>
+**
+** Legacy fts5_tokenizer tokenizers must be registered using the
+** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
+**
+** Tokenizer implementations registered using either API may be retrieved
+** using both xFindTokenizer() and xFindTokenizer_v2().
+**
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
@@ -13291,11 +13916,38 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
+typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
+struct fts5_tokenizer_v2 {
+ int iVersion; /* Currently always 2 */
+
+ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
+ void (*xDelete)(Fts5Tokenizer*);
+ int (*xTokenize)(Fts5Tokenizer*,
+ void *pCtx,
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
+ const char *pText, int nText,
+ const char *pLocale, int nLocale,
+ int (*xToken)(
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
+ const char *pToken, /* Pointer to buffer containing token */
+ int nToken, /* Size of token in bytes */
+ int iStart, /* Byte offset of token within input text */
+ int iEnd /* Byte offset of end of token within input text */
+ )
+ );
+};
+
+/*
+** New code should use the fts5_tokenizer_v2 type to define tokenizer
+** implementations. The following type is included for legacy applications
+** that still use it.
+*/
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
@@ -13315,6 +13967,7 @@ struct fts5_tokenizer {
);
};
+
/* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002
@@ -13334,13 +13987,13 @@ struct fts5_tokenizer {
*/
typedef struct fts5_api fts5_api;
struct fts5_api {
- int iVersion; /* Currently always set to 2 */
+ int iVersion; /* Currently always set to 3 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -13349,7 +14002,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -13357,10 +14010,29 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
+
+ /* APIs below this point are only available if iVersion>=3 */
+
+ /* Create a new tokenizer */
+ int (*xCreateTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void *pUserData,
+ fts5_tokenizer_v2 *pTokenizer,
+ void (*xDestroy)(void*)
+ );
+
+ /* Find an existing tokenizer */
+ int (*xFindTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void **ppUserData,
+ fts5_tokenizer_v2 **ppTokenizer
+ );
};
/*
@@ -13468,7 +14140,7 @@ struct fts5_api {
** level of recursion for each term. A stack overflow can result
** if the number of terms is too large. In practice, most SQL
** never has more than 3 or 4 terms. Use a value of 0 to disable
-** any limit on the number of terms in a compount SELECT.
+** any limit on the number of terms in a compound SELECT.
*/
#ifndef SQLITE_MAX_COMPOUND_SELECT
# define SQLITE_MAX_COMPOUND_SELECT 500
@@ -13583,7 +14255,7 @@ struct fts5_api {
** max_page_count macro.
*/
#ifndef SQLITE_MAX_PAGE_COUNT
-# define SQLITE_MAX_PAGE_COUNT 1073741823
+# define SQLITE_MAX_PAGE_COUNT 0xfffffffe /* 4294967294 */
#endif
/*
@@ -13618,8 +14290,8 @@ struct fts5_api {
#endif
/*
-** WAL mode depends on atomic aligned 32-bit loads and stores in a few
-** places. The following macros try to make this explicit.
+** A few places in the code require atomic load/store of aligned
+** integer values.
*/
#ifndef __has_extension
# define __has_extension(x) 0 /* compatibility with non-clang compilers */
@@ -13675,15 +14347,22 @@ struct fts5_api {
#endif
/*
-** A macro to hint to the compiler that a function should not be
+** Macros to hint to the compiler that a function should or should not be
** inlined.
*/
#if defined(__GNUC__)
# define SQLITE_NOINLINE __attribute__((noinline))
+# define SQLITE_INLINE __attribute__((always_inline)) inline
#elif defined(_MSC_VER) && _MSC_VER>=1310
# define SQLITE_NOINLINE __declspec(noinline)
+# define SQLITE_INLINE __forceinline
#else
# define SQLITE_NOINLINE
+# define SQLITE_INLINE
+#endif
+#if defined(SQLITE_COVERAGE_TEST) || defined(__STRICT_ANSI__)
+# undef SQLITE_INLINE
+# define SQLITE_INLINE
#endif
/*
@@ -13706,6 +14385,29 @@ struct fts5_api {
#endif
/*
+** Enable SQLITE_USE_SEH by default on MSVC builds. Only omit
+** SEH support if the -DSQLITE_OMIT_SEH option is given.
+*/
+#if defined(_MSC_VER) && !defined(SQLITE_OMIT_SEH)
+# define SQLITE_USE_SEH 1
+#else
+# undef SQLITE_USE_SEH
+#endif
+
+/*
+** Enable SQLITE_DIRECT_OVERFLOW_READ, unless the build explicitly
+** disables it using -DSQLITE_DIRECT_OVERFLOW_READ=0
+*/
+#if defined(SQLITE_DIRECT_OVERFLOW_READ) && SQLITE_DIRECT_OVERFLOW_READ+1==1
+ /* Disable if -DSQLITE_DIRECT_OVERFLOW_READ=0 */
+# undef SQLITE_DIRECT_OVERFLOW_READ
+#else
+ /* In all other cases, enable */
+# define SQLITE_DIRECT_OVERFLOW_READ 1
+#endif
+
+
+/*
** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
** 0 means mutexes are permanently disable and the library is never
** threadsafe. 1 means the library is serialized which is the highest
@@ -13973,6 +14675,8 @@ struct fts5_api {
# define SQLITE_OMIT_ALTERTABLE
#endif
+#define SQLITE_DIGIT_SEPARATOR '_'
+
/*
** Return true (non-zero) if the input is an integer that is too large
** to fit in 32-bits. This macro is used inside of various testcase()
@@ -14138,135 +14842,135 @@ SQLITE_PRIVATE void wx_sqlite3HashClear(Hash*);
#define TK_OR 43
#define TK_AND 44
#define TK_IS 45
-#define TK_MATCH 46
-#define TK_LIKE_KW 47
-#define TK_BETWEEN 48
-#define TK_IN 49
-#define TK_ISNULL 50
-#define TK_NOTNULL 51
-#define TK_NE 52
-#define TK_EQ 53
-#define TK_GT 54
-#define TK_LE 55
-#define TK_LT 56
-#define TK_GE 57
-#define TK_ESCAPE 58
-#define TK_ID 59
-#define TK_COLUMNKW 60
-#define TK_DO 61
-#define TK_FOR 62
-#define TK_IGNORE 63
-#define TK_INITIALLY 64
-#define TK_INSTEAD 65
-#define TK_NO 66
-#define TK_KEY 67
-#define TK_OF 68
-#define TK_OFFSET 69
-#define TK_PRAGMA 70
-#define TK_RAISE 71
-#define TK_RECURSIVE 72
-#define TK_REPLACE 73
-#define TK_RESTRICT 74
-#define TK_ROW 75
-#define TK_ROWS 76
-#define TK_TRIGGER 77
-#define TK_VACUUM 78
-#define TK_VIEW 79
-#define TK_VIRTUAL 80
-#define TK_WITH 81
-#define TK_NULLS 82
-#define TK_FIRST 83
-#define TK_LAST 84
-#define TK_CURRENT 85
-#define TK_FOLLOWING 86
-#define TK_PARTITION 87
-#define TK_PRECEDING 88
-#define TK_RANGE 89
-#define TK_UNBOUNDED 90
-#define TK_EXCLUDE 91
-#define TK_GROUPS 92
-#define TK_OTHERS 93
-#define TK_TIES 94
-#define TK_GENERATED 95
-#define TK_ALWAYS 96
-#define TK_MATERIALIZED 97
-#define TK_REINDEX 98
-#define TK_RENAME 99
-#define TK_CTIME_KW 100
-#define TK_ANY 101
-#define TK_BITAND 102
-#define TK_BITOR 103
-#define TK_LSHIFT 104
-#define TK_RSHIFT 105
-#define TK_PLUS 106
-#define TK_MINUS 107
-#define TK_STAR 108
-#define TK_SLASH 109
-#define TK_REM 110
-#define TK_CONCAT 111
-#define TK_PTR 112
-#define TK_COLLATE 113
-#define TK_BITNOT 114
-#define TK_ON 115
-#define TK_INDEXED 116
-#define TK_STRING 117
-#define TK_JOIN_KW 118
-#define TK_CONSTRAINT 119
-#define TK_DEFAULT 120
-#define TK_NULL 121
-#define TK_PRIMARY 122
-#define TK_UNIQUE 123
-#define TK_CHECK 124
-#define TK_REFERENCES 125
-#define TK_AUTOINCR 126
-#define TK_INSERT 127
-#define TK_DELETE 128
-#define TK_UPDATE 129
-#define TK_SET 130
-#define TK_DEFERRABLE 131
-#define TK_FOREIGN 132
-#define TK_DROP 133
-#define TK_UNION 134
-#define TK_ALL 135
-#define TK_EXCEPT 136
-#define TK_INTERSECT 137
-#define TK_SELECT 138
-#define TK_VALUES 139
-#define TK_DISTINCT 140
-#define TK_DOT 141
-#define TK_FROM 142
-#define TK_JOIN 143
-#define TK_USING 144
-#define TK_ORDER 145
-#define TK_GROUP 146
-#define TK_HAVING 147
-#define TK_LIMIT 148
-#define TK_WHERE 149
-#define TK_RETURNING 150
-#define TK_INTO 151
-#define TK_NOTHING 152
-#define TK_FLOAT 153
-#define TK_BLOB 154
-#define TK_INTEGER 155
-#define TK_VARIABLE 156
-#define TK_CASE 157
-#define TK_WHEN 158
-#define TK_THEN 159
-#define TK_ELSE 160
-#define TK_INDEX 161
-#define TK_ALTER 162
-#define TK_ADD 163
-#define TK_WINDOW 164
-#define TK_OVER 165
-#define TK_FILTER 166
-#define TK_COLUMN 167
-#define TK_AGG_FUNCTION 168
-#define TK_AGG_COLUMN 169
-#define TK_TRUEFALSE 170
-#define TK_ISNOT 171
+#define TK_ISNOT 46
+#define TK_MATCH 47
+#define TK_LIKE_KW 48
+#define TK_BETWEEN 49
+#define TK_IN 50
+#define TK_ISNULL 51
+#define TK_NOTNULL 52
+#define TK_NE 53
+#define TK_EQ 54
+#define TK_GT 55
+#define TK_LE 56
+#define TK_LT 57
+#define TK_GE 58
+#define TK_ESCAPE 59
+#define TK_ID 60
+#define TK_COLUMNKW 61
+#define TK_DO 62
+#define TK_FOR 63
+#define TK_IGNORE 64
+#define TK_INITIALLY 65
+#define TK_INSTEAD 66
+#define TK_NO 67
+#define TK_KEY 68
+#define TK_OF 69
+#define TK_OFFSET 70
+#define TK_PRAGMA 71
+#define TK_RAISE 72
+#define TK_RECURSIVE 73
+#define TK_REPLACE 74
+#define TK_RESTRICT 75
+#define TK_ROW 76
+#define TK_ROWS 77
+#define TK_TRIGGER 78
+#define TK_VACUUM 79
+#define TK_VIEW 80
+#define TK_VIRTUAL 81
+#define TK_WITH 82
+#define TK_NULLS 83
+#define TK_FIRST 84
+#define TK_LAST 85
+#define TK_CURRENT 86
+#define TK_FOLLOWING 87
+#define TK_PARTITION 88
+#define TK_PRECEDING 89
+#define TK_RANGE 90
+#define TK_UNBOUNDED 91
+#define TK_EXCLUDE 92
+#define TK_GROUPS 93
+#define TK_OTHERS 94
+#define TK_TIES 95
+#define TK_GENERATED 96
+#define TK_ALWAYS 97
+#define TK_MATERIALIZED 98
+#define TK_REINDEX 99
+#define TK_RENAME 100
+#define TK_CTIME_KW 101
+#define TK_ANY 102
+#define TK_BITAND 103
+#define TK_BITOR 104
+#define TK_LSHIFT 105
+#define TK_RSHIFT 106
+#define TK_PLUS 107
+#define TK_MINUS 108
+#define TK_STAR 109
+#define TK_SLASH 110
+#define TK_REM 111
+#define TK_CONCAT 112
+#define TK_PTR 113
+#define TK_COLLATE 114
+#define TK_BITNOT 115
+#define TK_ON 116
+#define TK_INDEXED 117
+#define TK_STRING 118
+#define TK_JOIN_KW 119
+#define TK_CONSTRAINT 120
+#define TK_DEFAULT 121
+#define TK_NULL 122
+#define TK_PRIMARY 123
+#define TK_UNIQUE 124
+#define TK_CHECK 125
+#define TK_REFERENCES 126
+#define TK_AUTOINCR 127
+#define TK_INSERT 128
+#define TK_DELETE 129
+#define TK_UPDATE 130
+#define TK_SET 131
+#define TK_DEFERRABLE 132
+#define TK_FOREIGN 133
+#define TK_DROP 134
+#define TK_UNION 135
+#define TK_ALL 136
+#define TK_EXCEPT 137
+#define TK_INTERSECT 138
+#define TK_SELECT 139
+#define TK_VALUES 140
+#define TK_DISTINCT 141
+#define TK_DOT 142
+#define TK_FROM 143
+#define TK_JOIN 144
+#define TK_USING 145
+#define TK_ORDER 146
+#define TK_GROUP 147
+#define TK_HAVING 148
+#define TK_LIMIT 149
+#define TK_WHERE 150
+#define TK_RETURNING 151
+#define TK_INTO 152
+#define TK_NOTHING 153
+#define TK_FLOAT 154
+#define TK_BLOB 155
+#define TK_INTEGER 156
+#define TK_VARIABLE 157
+#define TK_CASE 158
+#define TK_WHEN 159
+#define TK_THEN 160
+#define TK_ELSE 161
+#define TK_INDEX 162
+#define TK_ALTER 163
+#define TK_ADD 164
+#define TK_WINDOW 165
+#define TK_OVER 166
+#define TK_FILTER 167
+#define TK_COLUMN 168
+#define TK_AGG_FUNCTION 169
+#define TK_AGG_COLUMN 170
+#define TK_TRUEFALSE 171
#define TK_FUNCTION 172
-#define TK_UMINUS 173
-#define TK_UPLUS 174
+#define TK_UPLUS 173
+#define TK_UMINUS 174
#define TK_TRUTH 175
#define TK_REGISTER 176
#define TK_VECTOR 177
@@ -14275,8 +14979,9 @@ SQLITE_PRIVATE void wx_sqlite3HashClear(Hash*);
#define TK_ASTERISK 180
#define TK_SPAN 181
#define TK_ERROR 182
-#define TK_SPACE 183
-#define TK_ILLEGAL 184
+#define TK_QNUMBER 183
+#define TK_SPACE 184
+#define TK_ILLEGAL 185
/************** End of parse.h ***********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -14285,6 +14990,7 @@ SQLITE_PRIVATE void wx_sqlite3HashClear(Hash*);
#include <string.h>
#include <assert.h>
#include <stddef.h>
+#include <ctype.h>
/*
** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY.
@@ -14305,7 +15011,8 @@ SQLITE_PRIVATE void wx_sqlite3HashClear(Hash*);
#ifdef SQLITE_OMIT_FLOATING_POINT
# define double sqlite_int64
# define float sqlite_int64
-# define LONGDOUBLE_TYPE sqlite_int64
+# define fabs(X) ((X)<0?-(X):(X))
+# define wx_sqlite3IsOverflow(X) 0
# ifndef SQLITE_BIG_DBL
# define SQLITE_BIG_DBL (((wx_sqlite3_int64)1)<<50)
# endif
@@ -14480,9 +15187,6 @@ SQLITE_PRIVATE void wx_sqlite3HashClear(Hash*);
# define INT8_TYPE signed char
# endif
#endif
-#ifndef LONGDOUBLE_TYPE
-# define LONGDOUBLE_TYPE long double
-#endif
typedef sqlite_int64 i64; /* 8-byte signed integer */
typedef sqlite_uint64 u64; /* 8-byte unsigned integer */
typedef UINT32_TYPE u32; /* 4-byte unsigned integer */
@@ -14538,7 +15242,7 @@ typedef INT16_TYPE LogEst;
# define SQLITE_PTRSIZE __SIZEOF_POINTER__
# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
defined(_M_ARM) || defined(__arm__) || defined(__x86) || \
- (defined(__APPLE__) && defined(__POWERPC__)) || \
+ (defined(__APPLE__) && defined(__ppc__)) || \
(defined(__TOS_AIX__) && !defined(__64BIT__))
# define SQLITE_PTRSIZE 4
# else
@@ -14564,8 +15268,31 @@ typedef INT16_TYPE LogEst;
** the end of buffer S. This macro returns true if P points to something
** contained within the buffer S.
*/
-#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
+#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
+/*
+** P is one byte past the end of a large buffer. Return true if a span of bytes
+** between S..E crosses the end of that buffer. In other words, return true
+** if the sub-buffer S..E-1 overflows the buffer whose last byte is P-1.
+**
+** S is the start of the span. E is one byte past the end of end of span.
+**
+** P
+** |-----------------| FALSE
+** |-------|
+** S E
+**
+** P
+** |-----------------|
+** |-------| TRUE
+** S E
+**
+** P
+** |-----------------|
+** |-------| FALSE
+** S E
+*/
+#define SQLITE_OVERFLOW(P,S,E) (((uptr)(S)<(uptr)(P))&&((uptr)(E)>(uptr)(P)))
/*
** Macros to determine whether the machine is big or little endian,
@@ -14575,16 +15302,33 @@ typedef INT16_TYPE LogEst;
** using C-preprocessor macros. If that is unsuccessful, or if
** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined
** at run-time.
+**
+** If you are building SQLite on some obscure platform for which the
+** following ifdef magic does not work, you can always include either:
+**
+** -DSQLITE_BYTEORDER=1234
+**
+** or
+**
+** -DSQLITE_BYTEORDER=4321
+**
+** to cause the build to work for little-endian or big-endian processors,
+** respectively.
*/
-#ifndef SQLITE_BYTEORDER
-# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+#ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */
+# if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
+# define SQLITE_BYTEORDER 4321
+# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
+# define SQLITE_BYTEORDER 1234
+# elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1
+# define SQLITE_BYTEORDER 4321
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64)
-# define SQLITE_BYTEORDER 1234
-# elif defined(sparc) || defined(__ppc__) || \
- defined(__ARMEB__) || defined(__AARCH64EB__)
-# define SQLITE_BYTEORDER 4321
+# define SQLITE_BYTEORDER 1234
+# elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__)
+# define SQLITE_BYTEORDER 4321
# else
# define SQLITE_BYTEORDER 0
# endif
@@ -14735,6 +15479,7 @@ SQLITE_PRIVATE u32 wx_sqlite3TreeTrace;
** 0x00010000 Beginning of DELETE/INSERT/UPDATE processing
** 0x00020000 Transform DISTINCT into GROUP BY
** 0x00040000 SELECT tree dump after all code has been generated
+** 0x00080000 NOT NULL strength reduction
*/
/*
@@ -14765,7 +15510,7 @@ SQLITE_PRIVATE u32 wx_sqlite3WhereTrace;
** 0x00000010 Display wx_sqlite3_index_info xBestIndex calls
** 0x00000020 Range an equality scan metrics
** 0x00000040 IN operator decisions
-** 0x00000080 WhereLoop cost adjustements
+** 0x00000080 WhereLoop cost adjustments
** 0x00000100
** 0x00000200 Covering index decisions
** 0x00000400 OR optimization
@@ -14799,7 +15544,7 @@ struct BusyHandler {
/*
** Name of table that holds the database schema.
**
-** The PREFERRED names are used whereever possible. But LEGACY is also
+** The PREFERRED names are used wherever possible. But LEGACY is also
** used for backwards compatibility.
**
** 1. Queries can use either the PREFERRED or the LEGACY names
@@ -14908,11 +15653,13 @@ typedef struct Column Column;
typedef struct Cte Cte;
typedef struct CteUse CteUse;
typedef struct Db Db;
+typedef struct DbClientData DbClientData;
typedef struct DbFixer DbFixer;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct FKey FKey;
+typedef struct FpDecode FpDecode;
typedef struct FuncDestructor FuncDestructor;
typedef struct FuncDef FuncDef;
typedef struct FuncDefHash FuncDefHash;
@@ -14931,6 +15678,7 @@ typedef struct Parse Parse;
typedef struct ParseCleanup ParseCleanup;
typedef struct PreUpdate PreUpdate;
typedef struct PrintfArguments PrintfArguments;
+typedef struct RCStr RCStr;
typedef struct RenameToken RenameToken;
typedef struct Returning Returning;
typedef struct RowSet RowSet;
@@ -14938,6 +15686,7 @@ typedef struct Savepoint Savepoint;
typedef struct Select Select;
typedef struct SQLiteThread SQLiteThread;
typedef struct SelectDest SelectDest;
+typedef struct Subquery Subquery;
typedef struct SrcItem SrcItem;
typedef struct SrcList SrcList;
typedef struct wx_sqlite3_str StrAccum; /* Internal alias for wx_sqlite3_str */
@@ -15544,7 +16293,7 @@ SQLITE_PRIVATE wx_sqlite3_file *wx_sqlite3PagerJrnlFile(Pager*);
SQLITE_PRIVATE const char *wx_sqlite3PagerJournalname(Pager*);
SQLITE_PRIVATE void *wx_sqlite3PagerTempSpace(Pager*);
SQLITE_PRIVATE int wx_sqlite3PagerIsMemdb(Pager*);
-SQLITE_PRIVATE void wx_sqlite3PagerCacheStat(Pager *, int, int, int *);
+SQLITE_PRIVATE void wx_sqlite3PagerCacheStat(Pager *, int, int, u64*);
SQLITE_PRIVATE void wx_sqlite3PagerClearCache(Pager*);
SQLITE_PRIVATE int wx_sqlite3SectorSize(wx_sqlite3_file *);
@@ -15568,6 +16317,10 @@ SQLITE_PRIVATE void wx_sqlite3PagerRefdump(Pager*);
# define enable_simulated_io_errors()
#endif
+#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
+SQLITE_PRIVATE int wx_sqlite3PagerWalSystemErrno(Pager*);
+#endif
+
#endif /* SQLITE_PAGER_H */
/************** End of pager.h ***********************************************/
@@ -15816,6 +16569,9 @@ SQLITE_PRIVATE int wx_sqlite3BtreeCursor(
);
SQLITE_PRIVATE BtCursor *wx_sqlite3BtreeFakeValidCursor(void);
SQLITE_PRIVATE int wx_sqlite3BtreeCursorSize(void);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int wx_sqlite3BtreeClosesWithCursor(Btree*,BtCursor*);
+#endif
SQLITE_PRIVATE void wx_sqlite3BtreeCursorZero(BtCursor*);
SQLITE_PRIVATE void wx_sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
@@ -15897,9 +16653,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreePrevious(BtCursor*, int flags);
SQLITE_PRIVATE i64 wx_sqlite3BtreeIntegerKey(BtCursor*);
SQLITE_PRIVATE void wx_sqlite3BtreeCursorPin(BtCursor*);
SQLITE_PRIVATE void wx_sqlite3BtreeCursorUnpin(BtCursor*);
-#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
SQLITE_PRIVATE i64 wx_sqlite3BtreeOffset(BtCursor*);
-#endif
SQLITE_PRIVATE int wx_sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE const void *wx_sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
SQLITE_PRIVATE u32 wx_sqlite3BtreePayloadSize(BtCursor*);
@@ -15909,6 +16663,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeIntegrityCheck(
wx_sqlite3 *db, /* Database connection that is running the check */
Btree *p, /* The btree to be checked */
Pgno *aRoot, /* An array of root pages numbers for individual trees */
+ wx_sqlite3_value *aCnt, /* OUT: entry counts for each btree in aRoot[] */
int nRoot, /* Number of entries in aRoot[] */
int mxErr, /* Stop reporting errors after this many */
int *pnErr, /* OUT: Write number of errors seen to this variable */
@@ -16035,6 +16790,19 @@ typedef struct Vdbe Vdbe;
*/
typedef struct wx_sqlite3_value Mem;
typedef struct SubProgram SubProgram;
+typedef struct SubrtnSig SubrtnSig;
+
+/*
+** A signature for a reusable subroutine that materializes the RHS of
+** an IN operator.
+*/
+struct SubrtnSig {
+ int selId; /* SELECT-id for the SELECT statement on the RHS */
+ char *zAff; /* Affinity of the overall IN expression */
+ int iTable; /* Ephemeral table generated by the subroutine */
+ int iAddr; /* Subroutine entry address */
+ int regReturn; /* Register used to hold return address */
+};
/*
** A single instruction of the virtual machine has an opcode
@@ -16063,6 +16831,7 @@ struct VdbeOp {
u32 *ai; /* Used when p4type is P4_INTARRAY */
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
Table *pTab; /* Used when p4type is P4_TABLE */
+ SubrtnSig *pSubrtnSig; /* Used when p4type is P4_SUBRTNSIG */
#ifdef SQLITE_ENABLE_CURSOR_HINTS
Expr *pExpr; /* Used when p4type is P4_EXPR */
#endif
@@ -16129,6 +16898,8 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */
#define P4_FUNCCTX (-15) /* P4 is a pointer to an wx_sqlite3_context object */
+#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */
+#define P4_SUBRTNSIG (-17) /* P4 is a SubrtnSig pointer */
/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
@@ -16178,12 +16949,12 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Vacuum 5
#define OP_VFilter 6 /* jump, synopsis: iplan=r[P3] zplan='P4' */
#define OP_VUpdate 7 /* synopsis: data=r[P3@P2] */
-#define OP_Init 8 /* jump, synopsis: Start at P2 */
+#define OP_Init 8 /* jump0, synopsis: Start at P2 */
#define OP_Goto 9 /* jump */
#define OP_Gosub 10 /* jump */
-#define OP_InitCoroutine 11 /* jump */
-#define OP_Yield 12 /* jump */
-#define OP_MustBeInt 13 /* jump */
+#define OP_InitCoroutine 11 /* jump0 */
+#define OP_Yield 12 /* jump0 */
+#define OP_MustBeInt 13 /* jump0 */
#define OP_Jump 14 /* jump */
#define OP_Once 15 /* jump */
#define OP_If 16 /* jump */
@@ -16191,22 +16962,22 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_IsType 18 /* jump, synopsis: if typeof(P1.P3) in P5 goto P2 */
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
#define OP_IfNullRow 20 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
-#define OP_SeekLT 21 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekLE 22 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekGE 23 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekGT 24 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekLT 21 /* jump0, synopsis: key=r[P3@P4] */
+#define OP_SeekLE 22 /* jump0, synopsis: key=r[P3@P4] */
+#define OP_SeekGE 23 /* jump0, synopsis: key=r[P3@P4] */
+#define OP_SeekGT 24 /* jump0, synopsis: key=r[P3@P4] */
#define OP_IfNotOpen 25 /* jump, synopsis: if( !csr[P1] ) goto P2 */
#define OP_IfNoHope 26 /* jump, synopsis: key=r[P3@P4] */
#define OP_NoConflict 27 /* jump, synopsis: key=r[P3@P4] */
#define OP_NotFound 28 /* jump, synopsis: key=r[P3@P4] */
#define OP_Found 29 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekRowid 30 /* jump, synopsis: intkey=r[P3] */
+#define OP_SeekRowid 30 /* jump0, synopsis: intkey=r[P3] */
#define OP_NotExists 31 /* jump, synopsis: intkey=r[P3] */
-#define OP_Last 32 /* jump */
-#define OP_IfSmaller 33 /* jump */
+#define OP_Last 32 /* jump0 */
+#define OP_IfSizeBetween 33 /* jump */
#define OP_SorterSort 34 /* jump */
#define OP_Sort 35 /* jump */
-#define OP_Rewind 36 /* jump */
+#define OP_Rewind 36 /* jump0 */
#define OP_SorterNext 37 /* jump */
#define OP_Prev 38 /* jump */
#define OP_Next 39 /* jump */
@@ -16218,18 +16989,18 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_IdxGE 45 /* jump, synopsis: key=r[P3@P4] */
#define OP_RowSetRead 46 /* jump, synopsis: r[P3]=rowset(P1) */
#define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program 48 /* jump */
+#define OP_Program 48 /* jump0 */
#define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
-#define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
-#define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
-#define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
-#define OP_Eq 53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
-#define OP_Gt 54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
-#define OP_Le 55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
-#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
-#define OP_Ge 57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
-#define OP_ElseEq 58 /* jump, same as TK_ESCAPE */
-#define OP_IfPos 59 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IfPos 50 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IsNull 51 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
+#define OP_NotNull 52 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
+#define OP_Ne 53 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
+#define OP_Eq 54 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
+#define OP_Gt 55 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
+#define OP_Le 56 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
+#define OP_Lt 57 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
+#define OP_Ge 58 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
+#define OP_ElseEq 59 /* jump, same as TK_ESCAPE */
#define OP_IfNotZero 60 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
#define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */
#define OP_IncrVacuum 62 /* jump */
@@ -16248,7 +17019,7 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Null 75 /* synopsis: r[P2..P3]=NULL */
#define OP_SoftNull 76 /* synopsis: r[P1]=NULL */
#define OP_Blob 77 /* synopsis: r[P2]=P4 (len=P1) */
-#define OP_Variable 78 /* synopsis: r[P2]=parameter(P1,P4) */
+#define OP_Variable 78 /* synopsis: r[P2]=parameter(P1) */
#define OP_Move 79 /* synopsis: r[P2@P3]=r[P1@P3] */
#define OP_Copy 80 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
#define OP_SCopy 81 /* synopsis: r[P2]=r[P1] */
@@ -16272,23 +17043,23 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_ReadCookie 99
#define OP_SetCookie 100
#define OP_ReopenIdx 101 /* synopsis: root=P2 iDb=P3 */
-#define OP_BitAnd 102 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
-#define OP_BitOr 103 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
-#define OP_ShiftLeft 104 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
-#define OP_ShiftRight 105 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
-#define OP_Add 106 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
-#define OP_Subtract 107 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
-#define OP_Multiply 108 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
-#define OP_Divide 109 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
-#define OP_Remainder 110 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
-#define OP_Concat 111 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
-#define OP_OpenRead 112 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenRead 102 /* synopsis: root=P2 iDb=P3 */
+#define OP_BitAnd 103 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
+#define OP_BitOr 104 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
+#define OP_ShiftLeft 105 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
+#define OP_ShiftRight 106 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
+#define OP_Add 107 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
+#define OP_Subtract 108 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
+#define OP_Multiply 109 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
+#define OP_Divide 110 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
+#define OP_Remainder 111 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
+#define OP_Concat 112 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
#define OP_OpenWrite 113 /* synopsis: root=P2 iDb=P3 */
-#define OP_BitNot 114 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
-#define OP_OpenDup 115
+#define OP_OpenDup 114
+#define OP_BitNot 115 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
#define OP_OpenAutoindex 116 /* synopsis: nColumn=P2 */
-#define OP_String8 117 /* same as TK_STRING, synopsis: r[P2]='P4' */
-#define OP_OpenEphemeral 118 /* synopsis: nColumn=P2 */
+#define OP_OpenEphemeral 117 /* synopsis: nColumn=P2 */
+#define OP_String8 118 /* same as TK_STRING, synopsis: r[P2]='P4' */
#define OP_SorterOpen 119
#define OP_SequenceTest 120 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
#define OP_OpenPseudo 121 /* synopsis: P3 columns in r[P2] */
@@ -16323,8 +17094,8 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_LoadAnalysis 150
#define OP_DropTable 151
#define OP_DropIndex 152
-#define OP_Real 153 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_DropTrigger 154
+#define OP_DropTrigger 153
+#define OP_Real 154 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
#define OP_IntegrityCk 155
#define OP_RowSetAdd 156 /* synopsis: rowset(P1)=r[P2] */
#define OP_Param 157
@@ -16344,19 +17115,22 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_VCreate 171
#define OP_VDestroy 172
#define OP_VOpen 173
-#define OP_VInitIn 174 /* synopsis: r[P2]=ValueList(P1,P3) */
-#define OP_VColumn 175 /* synopsis: r[P3]=vcolumn(P2) */
-#define OP_VRename 176
-#define OP_Pagecount 177
-#define OP_MaxPgcnt 178
-#define OP_ClrSubtype 179 /* synopsis: r[P1].subtype = 0 */
-#define OP_FilterAdd 180 /* synopsis: filter(P1) += key(P3@P4) */
-#define OP_Trace 181
-#define OP_CursorHint 182
-#define OP_ReleaseReg 183 /* synopsis: release r[P1@P2] mask P3 */
-#define OP_Noop 184
-#define OP_Explain 185
-#define OP_Abortable 186
+#define OP_VCheck 174
+#define OP_VInitIn 175 /* synopsis: r[P2]=ValueList(P1,P3) */
+#define OP_VColumn 176 /* synopsis: r[P3]=vcolumn(P2) */
+#define OP_VRename 177
+#define OP_Pagecount 178
+#define OP_MaxPgcnt 179
+#define OP_ClrSubtype 180 /* synopsis: r[P1].subtype = 0 */
+#define OP_GetSubtype 181 /* synopsis: r[P2] = r[P1].subtype */
+#define OP_SetSubtype 182 /* synopsis: r[P2].subtype = r[P1] */
+#define OP_FilterAdd 183 /* synopsis: filter(P1) += key(P3@P4) */
+#define OP_Trace 184
+#define OP_CursorHint 185
+#define OP_ReleaseReg 186 /* synopsis: release r[P1@P2] mask P3 */
+#define OP_Noop 187
+#define OP_Explain 188
+#define OP_Abortable 189
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
@@ -16369,31 +17143,32 @@ typedef struct VdbeOpList VdbeOpList;
#define OPFLG_OUT2 0x10 /* out2: P2 is an output */
#define OPFLG_OUT3 0x20 /* out3: P3 is an output */
#define OPFLG_NCYCLE 0x40 /* ncycle:Cycles count against P1 */
+#define OPFLG_JUMP0 0x80 /* jump0: P2 might be zero */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x41, 0x00,\
-/* 8 */ 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01,\
-/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x49, 0x49, 0x49,\
-/* 24 */ 0x49, 0x01, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,\
-/* 32 */ 0x41, 0x01, 0x01, 0x01, 0x41, 0x01, 0x41, 0x41,\
+/* 8 */ 0x81, 0x01, 0x01, 0x81, 0x83, 0x83, 0x01, 0x01,\
+/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0xc9, 0xc9, 0xc9,\
+/* 24 */ 0xc9, 0x01, 0x49, 0x49, 0x49, 0x49, 0xc9, 0x49,\
+/* 32 */ 0xc1, 0x01, 0x41, 0x41, 0xc1, 0x01, 0x41, 0x41,\
/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x23, 0x0b,\
-/* 48 */ 0x01, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
-/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01, 0x41,\
+/* 48 */ 0x81, 0x01, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\
+/* 56 */ 0x0b, 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x01, 0x41,\
/* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\
/* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\
/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\
/* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40, 0x00,\
-/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x26, 0x26,\
+/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x40, 0x26,\
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
-/* 112 */ 0x40, 0x00, 0x12, 0x40, 0x40, 0x10, 0x40, 0x00,\
+/* 112 */ 0x26, 0x00, 0x40, 0x12, 0x40, 0x40, 0x10, 0x00,\
/* 120 */ 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10, 0x10,\
-/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,\
+/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50,\
/* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\
/* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\
-/* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\
+/* 152 */ 0x00, 0x00, 0x10, 0x00, 0x06, 0x10, 0x00, 0x04,\
/* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x50, 0x40,\
-/* 176 */ 0x00, 0x10, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,\
-/* 184 */ 0x00, 0x00, 0x00,}
+/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x50,\
+/* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12, 0x00,\
+/* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}
/* The resolve3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode. The smaller the maximum
@@ -16536,6 +17311,8 @@ SQLITE_PRIVATE RecordCompare wx_sqlite3VdbeFindCompare(UnpackedRecord*);
SQLITE_PRIVATE void wx_sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
SQLITE_PRIVATE int wx_sqlite3VdbeHasSubProgram(Vdbe*);
+SQLITE_PRIVATE void wx_sqlite3MemSetArrayInt64(wx_sqlite3_value *aMem, int iIdx, i64 val);
+
SQLITE_PRIVATE int wx_sqlite3NotPureFunc(wx_sqlite3_context*);
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
SQLITE_PRIVATE int wx_sqlite3VdbeBytecodeVtabInit(wx_sqlite3*);
@@ -16568,7 +17345,7 @@ SQLITE_PRIVATE void wx_sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** The VdbeCoverage macros are used to set a coverage testing point
** for VDBE branch instructions. The coverage testing points are line
** numbers in the wx_sqlite3.c source file. VDBE branch coverage testing
-** only works with an amalagmation build. That's ok since a VDBE branch
+** only works with an amalgamation build. That's ok since a VDBE branch
** coverage build designed for testing the test suite only. No application
** should ever ship with VDBE branch coverage measuring turned on.
**
@@ -16586,7 +17363,7 @@ SQLITE_PRIVATE void wx_sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** // NULL option is not possible
**
** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested
-** // in distingishing equal and not-equal.
+** // in distinguishing equal and not-equal.
**
** Every VDBE branch operation must be tagged with one of the macros above.
** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and
@@ -16596,7 +17373,7 @@ SQLITE_PRIVATE void wx_sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** During testing, the test application will invoke
** wx_sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback
** routine that is invoked as each bytecode branch is taken. The callback
-** contains the wx_sqlite3.c source line number ov the VdbeCoverage macro and
+** contains the wx_sqlite3.c source line number of the VdbeCoverage macro and
** flags to indicate whether or not the branch was taken. The test application
** is responsible for keeping track of this and reporting byte-code branches
** that are never taken.
@@ -16644,6 +17421,10 @@ SQLITE_PRIVATE void wx_sqlite3VdbeScanStatusCounters(Vdbe*, int, int, int);
SQLITE_PRIVATE void wx_sqlite3VdbePrintOp(FILE*, int, VdbeOp*);
#endif
+#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int wx_sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr);
+#endif
+
#endif /* SQLITE_VDBE_H */
/************** End of vdbe.h ************************************************/
@@ -16931,7 +17712,7 @@ SQLITE_API int wx_sqlite3_mutex_held(wx_sqlite3_mutex*);
/*
** Default synchronous levels.
**
-** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ
+** Note that (for historical reasons) the PAGER_SYNCHRONOUS_* macros differ
** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1.
**
** PAGER_SYNCHRONOUS DEFAULT_SYNCHRONOUS
@@ -16970,7 +17751,7 @@ struct Db {
** An instance of the following structure stores a database schema.
**
** Most Schema objects are associated with a Btree. The exception is
-** the Schema for the TEMP databaes (wx_sqlite3.aDb[1]) which is free-standing.
+** the Schema for the TEMP database (wx_sqlite3.aDb[1]) which is free-standing.
** In shared cache mode, a single Schema object can be shared by multiple
** Btrees that refer to the same underlying BtShared object.
**
@@ -17081,7 +17862,7 @@ struct Lookaside {
LookasideSlot *pInit; /* List of buffers not previously used */
LookasideSlot *pFree; /* List of available buffers */
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
- LookasideSlot *pSmallInit; /* List of small buffers not prediously used */
+ LookasideSlot *pSmallInit; /* List of small buffers not previously used */
LookasideSlot *pSmallFree; /* List of available small buffers */
void *pMiddle; /* First byte past end of full-size buffers and
** the first byte of LOOKASIDE_SMALL buffers */
@@ -17098,7 +17879,7 @@ struct LookasideSlot {
#define EnableLookaside db->lookaside.bDisable--;\
db->lookaside.sz=db->lookaside.bDisable?0:db->lookaside.szTrue
-/* Size of the smaller allocations in two-size lookside */
+/* Size of the smaller allocations in two-size lookaside */
#ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE
# define LOOKASIDE_SMALL 0
#else
@@ -17119,6 +17900,10 @@ struct FuncDefHash {
};
#define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ)
+#if defined(SQLITE_USER_AUTHENTICATION)
+# warning "The SQLITE_USER_AUTHENTICATION extension is deprecated. \
+ See ext/userauth/user-auth.txt for details."
+#endif
#ifdef SQLITE_USER_AUTHENTICATION
/*
** Information held in the "wx_sqlite3" database connection object and used
@@ -17298,6 +18083,7 @@ struct wx_sqlite3 {
i64 nDeferredCons; /* Net deferred constraints this transaction. */
i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
+ DbClientData *pDbData; /* wx_sqlite3_set_clientdata() content */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/* The following variables are all protected by the STATIC_MAIN
** mutex, not by wx_sqlite3.mutex. They are used by code in notify.c.
@@ -17353,7 +18139,7 @@ struct wx_sqlite3 {
#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
/* result set is empty */
#define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */
-#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */
+#define SQLITE_StmtScanStatus 0x00000400 /* Enable stmt_scanstats() counters */
#define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */
#define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */
#define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */
@@ -17379,6 +18165,8 @@ struct wx_sqlite3 {
/* DELETE, or UPDATE and return */
/* the count using a callback. */
#define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */
+#define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */
+#define SQLITE_FkNoAction HI(0x00008) /* Treat all FK as NO ACTION */
/* Flags used only if debugging */
#ifdef SQLITE_DEBUG
@@ -17419,7 +18207,7 @@ struct wx_sqlite3 {
#define SQLITE_CursorHints 0x00000400 /* Add OP_CursorHint opcodes */
#define SQLITE_Stat4 0x00000800 /* Use STAT4 data */
/* TH3 expects this value ^^^^^^^^^^ to be 0x0000800. Don't change it */
-#define SQLITE_PushDown 0x00001000 /* The push-down optimization */
+#define SQLITE_PushDown 0x00001000 /* WHERE-clause push-down opt */
#define SQLITE_SimplifyJoin 0x00002000 /* Convert LEFT JOIN to JOIN */
#define SQLITE_SkipScan 0x00004000 /* Skip-scans */
#define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */
@@ -17435,6 +18223,9 @@ struct wx_sqlite3 {
/* TH3 expects this value ^^^^^^^^^^ See flatten04.test */
#define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */
#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */
+#define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */
+#define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */
+#define SQLITE_OrderBySubq 0x10000000 /* ORDER BY in subquery helps outer */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -17517,6 +18308,7 @@ struct FuncDestructor {
** SQLITE_FUNC_ANYORDER == NC_OrderAgg == SF_OrderByReqd
** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
+** SQLITE_FUNC_BYTELEN == OPFLAG_BYTELENARG
** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS -- opposite meanings!!!
@@ -17524,7 +18316,7 @@ struct FuncDestructor {
**
** Note that even though SQLITE_FUNC_UNSAFE and SQLITE_INNOCUOUS have the
** same bit value, their meanings are inverted. SQLITE_FUNC_UNSAFE is
-** used internally and if set means tha the function has side effects.
+** used internally and if set means that the function has side effects.
** SQLITE_INNOCUOUS is used by application code and means "not unsafe".
** See multiple instances of tag-20230109-1.
*/
@@ -17535,6 +18327,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_NEEDCOLL 0x0020 /* wx_sqlite3GetFuncCollSeq() might be called*/
#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
+#define SQLITE_FUNC_BYTELEN 0x00c0 /* Built-in octet_length() function */
#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
/* 0x0200 -- available for reuse */
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
@@ -17543,14 +18336,15 @@ struct FuncDestructor {
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
** single query - might change over time */
#define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */
-/* 0x8000 -- available for reuse */
+#define SQLITE_FUNC_RUNONLY 0x8000 /* Cannot be used by valueFromFunction */
#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */
-#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */
+/* SQLITE_SUBTYPE 0x00100000 // Consumer of subtypes */
#define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */
#define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */
#define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */
+/* SQLITE_RESULT_SUBTYPE 0x01000000 // Generator of subtypes */
#define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */
/* Identifier numbers for each in-line function */
@@ -17642,10 +18436,11 @@ struct FuncDestructor {
#define MFUNCTION(zName, nArg, xPtr, xFunc) \
{nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
-#define JFUNCTION(zName, nArg, iArg, xFunc) \
- {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|\
- SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
+#define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, bJsonB, iArg, xFunc) \
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\
+ SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|\
+ ((bRS)*SQLITE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \
+ SQLITE_INT_TO_PTR(iArg|((bJsonB)*JSON_BLOB)),0,xFunc,0, 0, 0, #zName, {0} }
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
{nArg, SQLITE_FUNC_BUILTIN|\
SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
@@ -17906,6 +18701,7 @@ struct VTable {
wx_sqlite3_vtab *pVtab; /* Pointer to vtab instance */
int nRef; /* Number of pointers to this structure */
u8 bConstraint; /* True if constraints are supported */
+ u8 bAllSchemas; /* True if might use any attached schema */
u8 eVtabRisk; /* Riskiness of allowing hacker access */
int iSavepoint; /* Depth of the SAVEPOINT stack */
VTable *pNext; /* Next in linked list (see above) */
@@ -17985,8 +18781,7 @@ struct Table {
#define TF_HasStored 0x00000040 /* Has one or more STORED columns */
#define TF_HasGenerated 0x00000060 /* Combo: HasVirtual + HasStored */
#define TF_WithoutRowid 0x00000080 /* No rowid. PRIMARY KEY is the key */
-#define TF_StatsUsed 0x00000100 /* Query planner decisions affected by
- ** Index.aiRowLogEst[] values */
+#define TF_MaybeReanalyze 0x00000100 /* Maybe run ANALYZE on this table */
#define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */
#define TF_OOOHidden 0x00000400 /* Out-of-Order hidden columns */
#define TF_HasNotNull 0x00000800 /* Contains NOT NULL constraints */
@@ -18042,6 +18837,15 @@ struct Table {
#define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0)
#define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0)
+/* Macro is true if the SQLITE_ALLOW_ROWID_IN_VIEW (mis-)feature is
+** available. By default, this macro is false
+*/
+#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
+# define ViewCanHaveRowid 0
+#else
+# define ViewCanHaveRowid (wx_sqlite3Config.mNoVisibleRowid==0)
+#endif
+
/*
** Each foreign key constraint is an instance of the following structure.
**
@@ -18113,7 +18917,7 @@ struct FKey {
** foreign key.
**
** The OE_Default value is a place holder that means to use whatever
-** conflict resolution algorthm is required from context.
+** conflict resolution algorithm is required from context.
**
** The following symbolic values are used to record which type
** of conflict resolution action to take.
@@ -18279,6 +19083,7 @@ struct Index {
unsigned isCovering:1; /* True if this is a covering index */
unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
+ unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
@@ -18286,6 +19091,7 @@ struct Index {
** expression, or a reference to a VIRTUAL column */
#ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */
+ int mxSample; /* Number of slots allocated to aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
@@ -18388,6 +19194,10 @@ struct AggInfo {
FuncDef *pFunc; /* The aggregate function implementation */
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
int iDistAddr; /* Address of OP_OpenEphemeral */
+ int iOBTab; /* Ephemeral table to implement ORDER BY */
+ u8 bOBPayload; /* iOBTab has payload columns separate from key */
+ u8 bOBUnique; /* Enforce uniqueness on iOBTab keys */
+ u8 bUseSubtype; /* Transfer subtype info through sorter */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
u32 selId; /* Select to which this AggInfo belongs */
@@ -18403,9 +19213,15 @@ struct AggInfo {
** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg.
** The assert()s that are part of this macro verify that constraint.
*/
+#ifndef NDEBUG
#define AggInfoColumnReg(A,I) (assert((A)->iFirstReg),(A)->iFirstReg+(I))
#define AggInfoFuncReg(A,I) \
(assert((A)->iFirstReg),(A)->iFirstReg+(A)->nColumn+(I))
+#else
+#define AggInfoColumnReg(A,I) ((A)->iFirstReg+(I))
+#define AggInfoFuncReg(A,I) \
+ ((A)->iFirstReg+(A)->nColumn+(I))
+#endif
/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
@@ -18526,7 +19342,7 @@ struct Expr {
** TK_REGISTER: register number
** TK_TRIGGER: 1 -> new, 0 -> old
** EP_Unlikely: 134217728 times likelihood
- ** TK_IN: ephemerial table holding RHS
+ ** TK_IN: ephemeral table holding RHS
** TK_SELECT_COLUMN: Number of columns on the LHS
** TK_SELECT: 1st register of result vector */
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
@@ -18572,7 +19388,7 @@ struct Expr {
#define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
#define EP_Win 0x008000 /* Contains window functions */
#define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
- /* 0x020000 // Available for reuse */
+#define EP_FullSize 0x020000 /* Expr structure must remain full sized */
#define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */
#define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */
#define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
@@ -18586,7 +19402,7 @@ struct Expr {
#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
#define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */
- /* 0x80000000 // Available */
+#define EP_SubtArg 0x80000000 /* Is argument to SQLITE_SUBTYPE function */
/* The EP_Propagate mask is a set of properties that automatically propagate
** upwards into parent nodes.
@@ -18602,12 +19418,15 @@ struct Expr {
#define ExprClearProperty(E,P) (E)->flags&=~(P)
#define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue)
#define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse)
+#define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0)
/* Macros used to ensure that the correct members of unions are accessed
** in Expr.
*/
#define ExprUseUToken(E) (((E)->flags&EP_IntValue)==0)
#define ExprUseUValue(E) (((E)->flags&EP_IntValue)!=0)
+#define ExprUseWOfst(E) (((E)->flags&(EP_InnerON|EP_OuterON))==0)
+#define ExprUseWJoin(E) (((E)->flags&(EP_InnerON|EP_OuterON))!=0)
#define ExprUseXList(E) (((E)->flags&EP_xIsSelect)==0)
#define ExprUseXSelect(E) (((E)->flags&EP_xIsSelect)!=0)
#define ExprUseYTab(E) (((E)->flags&(EP_WinFunc|EP_Subrtn))==0)
@@ -18717,6 +19536,7 @@ struct ExprList {
#define ENAME_NAME 0 /* The AS clause of a result set */
#define ENAME_SPAN 1 /* Complete text of the result set expression */
#define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */
+#define ENAME_ROWID 3 /* "DB.TABLE._rowid_" for * expansion of rowid */
/*
** An instance of this structure can hold a simple list of identifiers,
@@ -18754,6 +19574,16 @@ struct IdList {
#define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */
/*
+** Details of the implementation of a subquery.
+*/
+struct Subquery {
+ Select *pSelect; /* A SELECT statement used in place of a table name */
+ int addrFillSub; /* Address of subroutine to initialize a subquery */
+ int regReturn; /* Register holding return address of addrFillSub */
+ int regResult; /* Registers holding results of a co-routine */
+};
+
+/*
** The SrcItem object represents a single term in the FROM clause of a query.
** The SrcList object is mostly an array of SrcItems.
**
@@ -18765,27 +19595,40 @@ struct IdList {
** In the colUsed field, the high-order bit (bit 63) is set if the table
** contains more than 63 columns and the 64-th or later column is used.
**
-** Union member validity:
+** Aggressive use of "union" helps keep the size of the object small. This
+** has been shown to boost performance, in addition to saving memory.
+** Access to union elements is gated by the following rules which should
+** always be checked, either by an if-statement or by an assert().
+**
+** Field Only access if this is true
+** --------------- -----------------------------------
+** u1.zIndexedBy fg.isIndexedBy
+** u1.pFuncArg fg.isTabFunc
+** u1.nRow !fg.isTabFunc && !fg.isIndexedBy
+**
+** u2.pIBIndex fg.isIndexedBy
+** u2.pCteUse fg.isCte
**
-** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
-** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy
-** u2.pIBIndex fg.isIndexedBy && !fg.isCte
-** u2.pCteUse fg.isCte && !fg.isIndexedBy
+** u3.pOn !fg.isUsing
+** u3.pUsing fg.isUsing
+**
+** u4.zDatabase !fg.fixedSchema && !fg.isSubquery
+** u4.pSchema fg.fixedSchema
+** u4.pSubq fg.isSubquery
+**
+** See also the wx_sqlite3SrcListDelete() routine for assert() statements that
+** check invariants on the fields of this object, especially the flags
+** inside the fg struct.
*/
struct SrcItem {
- Schema *pSchema; /* Schema to which this item is fixed */
- char *zDatabase; /* Name of database holding this table */
char *zName; /* Name of the table */
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
- Table *pTab; /* An SQL table corresponding to zName */
- Select *pSelect; /* A SELECT statement used in place of a table name */
- int addrFillSub; /* Address of subroutine to manifest a subquery */
- int regReturn; /* Register holding return address of addrFillSub */
- int regResult; /* Registers holding results of a co-routine */
+ Table *pSTab; /* Table object for zName. Mnemonic: Srcitem-TABle */
struct {
u8 jointype; /* Type of join between this table and the previous */
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
+ unsigned isSubquery :1; /* True if this term is a subquery */
unsigned isTabFunc :1; /* True if table-valued-function syntax */
unsigned isCorrelated :1; /* True if sub-query is correlated */
unsigned isMaterialized:1; /* This is a materialized view */
@@ -18796,23 +19639,32 @@ struct SrcItem {
unsigned notCte :1; /* This item may not match a CTE */
unsigned isUsing :1; /* u3.pUsing is valid */
unsigned isOn :1; /* u3.pOn was once valid and non-NULL */
- unsigned isSynthUsing :1; /* u3.pUsing is synthensized from NATURAL */
+ unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
+ unsigned rowidUsed :1; /* The ROWID of this table is referenced */
+ unsigned fixedSchema :1; /* Uses u4.pSchema, not u4.zDatabase */
+ unsigned hadSchema :1; /* Had u4.zDatabase before u4.pSchema */
} fg;
int iCursor; /* The VDBE cursor number used to access this table */
- union {
- Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
- IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
- } u3;
Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
union {
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
ExprList *pFuncArg; /* Arguments to table-valued-function */
+ u32 nRow; /* Number of rows in a VALUES clause */
} u1;
union {
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
} u2;
+ union {
+ Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
+ IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
+ } u3;
+ union {
+ Schema *pSchema; /* Schema to which this item is fixed */
+ char *zDatabase; /* Name of database holding this table */
+ Subquery *pSubq; /* Description of a subquery */
+ } u4;
};
/*
@@ -18872,7 +19724,7 @@ struct SrcList {
#define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */
#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */
#define WHERE_RIGHT_JOIN 0x1000 /* Processing a RIGHT JOIN */
- /* 0x2000 not currently used */
+#define WHERE_KEEP_ALL_JOINS 0x2000 /* Do not do the omit-noop-join opt */
#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */
/* 0x8000 not currently used */
@@ -18917,6 +19769,7 @@ struct NameContext {
int nRef; /* Number of names resolved by this context */
int nNcErr; /* Number of errors encountered while resolving names */
int ncFlags; /* Zero or more NC_* flags defined below */
+ u32 nNestedSelect; /* Number of nested selects using this NC */
Select *pWinSelect; /* SELECT statement for any window functions */
};
@@ -18943,13 +19796,14 @@ struct NameContext {
#define NC_UUpsert 0x000200 /* True if uNC.pUpsert is used */
#define NC_UBaseReg 0x000400 /* True if uNC.iBaseReg is used */
#define NC_MinMaxAgg 0x001000 /* min/max aggregates seen. See note above */
-#define NC_Complex 0x002000 /* True if a function or subquery seen */
+/* 0x002000 // available for reuse */
#define NC_AllowWin 0x004000 /* Window functions are allowed here */
#define NC_HasWin 0x008000 /* One or more window functions seen */
#define NC_IsDDL 0x010000 /* Resolving names in a CREATE statement */
#define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */
#define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */
#define NC_NoSelect 0x080000 /* Do not descend into sub-selects */
+#define NC_Where 0x100000 /* Processing WHERE clause of a SELECT */
#define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */
/*
@@ -18973,6 +19827,7 @@ struct Upsert {
Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */
u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */
+ u8 isDup; /* True if 2nd or later with same pUpsertIdx */
/* Above this point is the parse tree for the ON CONFLICT clauses.
** The next group of fields stores intermediate data. */
void *pToFree; /* Free memory when deleting the Upsert object */
@@ -19062,14 +19917,17 @@ struct Select {
#define SF_View 0x0200000 /* SELECT statement is a view */
#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
#define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */
-#define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */
+#define SF_PushDown 0x1000000 /* Modified by WHERE-clause push-down opt */
#define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */
#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
#define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
+#define SF_Correlated 0x20000000 /* True if references the outer context */
-/* True if S exists and has SF_NestedFrom */
-#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
+/* True if SrcItem X is a subquery that has SF_NestedFrom */
+#define IsNestedFrom(X) \
+ ((X)->fg.isSubquery && \
+ ((X)->u4.pSubq->pSelect->selFlags&SF_NestedFrom)!=0)
/*
** The results of a SELECT can be distributed in several ways, as defined
@@ -19099,7 +19957,11 @@ struct Select {
** SRT_Set The result must be a single column. Store each
** row of result as the key in table pDest->iSDParm.
** Apply the affinity pDest->affSdst before storing
-** results. Used to implement "IN (SELECT ...)".
+** results. if pDest->iSDParm2 is positive, then it is
+** a register holding a Bloom filter for the IN operator
+** that should be populated in addition to the
+** pDest->iSDParm table. This SRT is used to
+** implement "IN (SELECT ...)".
**
** SRT_EphemTab Create an temporary table pDest->iSDParm and store
** the result there. The cursor is left open after
@@ -19306,6 +20168,8 @@ struct Parse {
u8 disableLookaside; /* Number of times lookaside has been disabled */
u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
+ u8 bHasWith; /* True if statement contains WITH */
+ u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside wx_sqlite3ParserAddCleanup() */
#endif
@@ -19325,6 +20189,7 @@ struct Parse {
int *aLabel; /* Space to hold the labels */
ExprList *pConstExpr;/* Constant expressions */
IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */
+ IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */
Token constraintName;/* Name of the constraint currently being parsed */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
@@ -19332,6 +20197,9 @@ struct Parse {
int regRoot; /* Register holding root page number for new objects */
int nMaxArg; /* Max args passed to user function by sub-program */
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ u32 nProgressSteps; /* xProgress steps taken during wx_sqlite3_prepare() */
+#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
int nTableLock; /* Number of locks in aTableLock */
TableLock *aTableLock; /* Required table locks for shared-cache mode */
@@ -19345,12 +20213,9 @@ struct Parse {
int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
Returning *pReturning; /* The RETURNING clause */
} u1;
- u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u32 oldmask; /* Mask of old.* columns referenced */
u32 newmask; /* Mask of new.* columns referenced */
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- u32 nProgressSteps; /* xProgress steps taken during wx_sqlite3_prepare() */
-#endif
+ LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
u8 bReturning; /* Coding a RETURNING trigger */
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
@@ -19474,6 +20339,7 @@ struct AuthContext {
#define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
+#define OPFLAG_BYTELENARG 0xc0 /* OP_Column only for octet_length() */
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
#define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */
#define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */
@@ -19595,10 +20461,11 @@ struct Returning {
int iRetCur; /* Transient table holding RETURNING results */
int nRetCol; /* Number of in pReturnEL after expansion */
int iRetReg; /* Register array for holding a row of RETURNING */
+ char zName[40]; /* Name of trigger: "sqlite_returning_%p" */
};
/*
-** An objected used to accumulate the text of a string where we
+** An object used to accumulate the text of a string where we
** do not necessarily know how big the string will be in the end.
*/
struct wx_sqlite3_str {
@@ -19612,10 +20479,32 @@ struct wx_sqlite3_str {
};
#define SQLITE_PRINTF_INTERNAL 0x01 /* Internal-use-only converters allowed */
#define SQLITE_PRINTF_SQLFUNC 0x02 /* SQL function arguments to VXPrintf */
-#define SQLITE_PRINTF_MALLOCED 0x04 /* True if xText is allocated space */
+#define SQLITE_PRINTF_MALLOCED 0x04 /* True if zText is allocated space */
#define isMalloced(X) (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0)
+/*
+** The following object is the header for an "RCStr" or "reference-counted
+** string". An RCStr is passed around and used like any other char*
+** that has been dynamically allocated. The important interface
+** differences:
+**
+** 1. RCStr strings are reference counted. They are deallocated
+** when the reference count reaches zero.
+**
+** 2. Use wx_sqlite3RCStrUnref() to free an RCStr string rather than
+** wx_sqlite3_free()
+**
+** 3. Make a (read-only) copy of a read-only RCStr string using
+** wx_sqlite3RCStrRef().
+**
+** "String" is in the name, but an RCStr object can also be used to hold
+** binary data.
+*/
+struct RCStr {
+ u64 nRCRef; /* Number of references */
+ /* Total structure size should be a multiple of 8 bytes for alignment */
+};
/*
** A pointer to this structure is used to communicate information
@@ -19642,7 +20531,7 @@ typedef struct {
/* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled
** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning
** parameters are for temporary use during development, to help find
-** optimial values for parameters in the query planner. The should not
+** optimal values for parameters in the query planner. The should not
** be used on trunk check-ins. They are a temporary mechanism available
** for transient development builds only.
**
@@ -19668,6 +20557,9 @@ struct Sqlite3Config {
u8 bUseCis; /* Use covering indices for full-scans */
u8 bSmallMalloc; /* Avoid large memory allocations if true */
u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */
+#ifdef SQLITE_DEBUG
+ u8 bJsonSelfcheck; /* Double-check JSON parsing */
+#endif
int mxStrlen; /* Maximum string length */
int neverCorrupt; /* Database is always well-formed */
int szLookaside; /* Default lookaside buffer size */
@@ -19715,6 +20607,11 @@ struct Sqlite3Config {
#ifndef SQLITE_UNTESTABLE
int (*xTestCallback)(int); /* Invoked by wx_sqlite3FaultSim() */
#endif
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ u32 mNoVisibleRowid; /* TF_NoVisibleRowid if the ROWID_IN_VIEW
+ ** feature is disabled. 0 if rowids can
+ ** occur in views. */
+#endif
int bLocaltimeFault; /* True to fail localtime() calls */
int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */
int iOnceResetThreshold; /* When to reset OP_Once counters */
@@ -19754,6 +20651,7 @@ struct Walker {
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
int walkerDepth; /* Number of subqueries */
u16 eCode; /* A small processing code */
+ u16 mWFlags; /* Use-dependent flags */
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
int n; /* A counter */
@@ -19772,6 +20670,7 @@ struct Walker {
struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */
SrcItem *pSrcItem; /* A single FROM clause item */
DbFixer *pFix; /* See wx_sqlite3FixSelect() */
+ Mem *aMem; /* See wx_sqlite3BtreeCursorHint() */
} u;
};
@@ -19792,6 +20691,7 @@ struct DbFixer {
/* Forward declarations */
SQLITE_PRIVATE int wx_sqlite3WalkExpr(Walker*, Expr*);
+SQLITE_PRIVATE int wx_sqlite3WalkExprNN(Walker*, Expr*);
SQLITE_PRIVATE int wx_sqlite3WalkExprList(Walker*, ExprList*);
SQLITE_PRIVATE int wx_sqlite3WalkSelect(Walker*, Select*);
SQLITE_PRIVATE int wx_sqlite3WalkSelectExpr(Walker*, Select*);
@@ -19872,6 +20772,16 @@ struct CteUse {
};
+/* Client data associated with wx_sqlite3_set_clientdata() and
+** wx_sqlite3_get_clientdata().
+*/
+struct DbClientData {
+ DbClientData *pNext; /* Next in a linked list */
+ void *pData; /* The data */
+ void (*xDestructor)(void*); /* Destructor. Might be NULL */
+ char zName[1]; /* Name of this client data. MUST BE LAST */
+};
+
#ifdef SQLITE_DEBUG
/*
** An instance of the TreeView object is used for printing the content of
@@ -19938,6 +20848,9 @@ struct Window {
** due to the SQLITE_SUBTYPE flag */
};
+SQLITE_PRIVATE Select *wx_sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow);
+SQLITE_PRIVATE void wx_sqlite3MultiValuesEnd(Parse *pParse, Select *pVal);
+
#ifndef SQLITE_OMIT_WINDOWFUNC
SQLITE_PRIVATE void wx_sqlite3WindowDelete(wx_sqlite3*, Window*);
SQLITE_PRIVATE void wx_sqlite3WindowUnlinkFromSelect(Window*);
@@ -20019,15 +20932,6 @@ SQLITE_PRIVATE int wx_sqlite3CorruptPgnoError(int,Pgno);
#endif
/*
-** The ctype.h header is needed for non-ASCII systems. It is also
-** needed by FTS3 when FTS3 is included in the amalgamation.
-*/
-#if !defined(SQLITE_ASCII) || \
- (defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_AMALGAMATION))
-# include <ctype.h>
-#endif
-
-/*
** The following macros mimic the standard library functions toupper(),
** isspace(), isalnum(), isdigit() and isxdigit(), respectively. The
** sqlite versions only work for ASCII characters, regardless of locale.
@@ -20041,6 +20945,8 @@ SQLITE_PRIVATE int wx_sqlite3CorruptPgnoError(int,Pgno);
# define wx_sqlite3Isxdigit(x) (wx_sqlite3CtypeMap[(unsigned char)(x)]&0x08)
# define wx_sqlite3Tolower(x) (wx_sqlite3UpperToLower[(unsigned char)(x)])
# define wx_sqlite3Isquote(x) (wx_sqlite3CtypeMap[(unsigned char)(x)]&0x80)
+# define wx_sqlite3JsonId1(x) (wx_sqlite3CtypeMap[(unsigned char)(x)]&0x42)
+# define wx_sqlite3JsonId2(x) (wx_sqlite3CtypeMap[(unsigned char)(x)]&0x46)
#else
# define wx_sqlite3Toupper(x) toupper((unsigned char)(x))
# define wx_sqlite3Isspace(x) isspace((unsigned char)(x))
@@ -20050,6 +20956,8 @@ SQLITE_PRIVATE int wx_sqlite3CorruptPgnoError(int,Pgno);
# define wx_sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
# define wx_sqlite3Tolower(x) tolower((unsigned char)(x))
# define wx_sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
+# define wx_sqlite3JsonId1(x) (wx_sqlite3IsIdChar(x)&&(x)<'0')
+# define wx_sqlite3JsonId2(x) wx_sqlite3IsIdChar(x)
#endif
SQLITE_PRIVATE int wx_sqlite3IsIdChar(u8);
@@ -20153,10 +21061,13 @@ SQLITE_PRIVATE void wx_sqlite3MutexWarnOnContention(wx_sqlite3_mutex*);
# define EXP754 (((u64)0x7ff)<<52)
# define MAN754 ((((u64)1)<<52)-1)
# define IsNaN(X) (((X)&EXP754)==EXP754 && ((X)&MAN754)!=0)
+# define IsOvfl(X) (((X)&EXP754)==EXP754)
SQLITE_PRIVATE int wx_sqlite3IsNaN(double);
+SQLITE_PRIVATE int wx_sqlite3IsOverflow(double);
#else
-# define IsNaN(X) 0
-# define wx_sqlite3IsNaN(X) 0
+# define IsNaN(X) 0
+# define wx_sqlite3IsNaN(X) 0
+# define wx_sqlite3IsOVerflow(X) 0
#endif
/*
@@ -20169,6 +21080,20 @@ struct PrintfArguments {
wx_sqlite3_value **apArg; /* The argument values */
};
+/*
+** An instance of this object receives the decoding of a floating point
+** value into an approximate decimal representation.
+*/
+struct FpDecode {
+ char sign; /* '+' or '-' */
+ char isSpecial; /* 1: Infinity 2: NaN */
+ int n; /* Significant digits in the decode */
+ int iDP; /* Location of the decimal point */
+ char *z; /* Start of significant digits */
+ char zBuf[24]; /* Storage for significant digits */
+};
+
+SQLITE_PRIVATE void wx_sqlite3FpDecode(FpDecode*,double,int,int);
SQLITE_PRIVATE char *wx_sqlite3MPrintf(wx_sqlite3*,const char*, ...);
SQLITE_PRIVATE char *wx_sqlite3VMPrintf(wx_sqlite3*,const char*, va_list);
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
@@ -20234,6 +21159,7 @@ SQLITE_PRIVATE int wx_sqlite3ErrorToParser(wx_sqlite3*,int);
SQLITE_PRIVATE void wx_sqlite3Dequote(char*);
SQLITE_PRIVATE void wx_sqlite3DequoteExpr(Expr*);
SQLITE_PRIVATE void wx_sqlite3DequoteToken(Token*);
+SQLITE_PRIVATE void wx_sqlite3DequoteNumber(Parse*, Expr*);
SQLITE_PRIVATE void wx_sqlite3TokenInit(Token*,char*);
SQLITE_PRIVATE int wx_sqlite3KeywordCode(const unsigned char*, int);
SQLITE_PRIVATE int wx_sqlite3RunParser(Parse*, const char*);
@@ -20243,6 +21169,10 @@ SQLITE_PRIVATE void wx_sqlite3ReleaseTempReg(Parse*,int);
SQLITE_PRIVATE int wx_sqlite3GetTempRange(Parse*,int);
SQLITE_PRIVATE void wx_sqlite3ReleaseTempRange(Parse*,int,int);
SQLITE_PRIVATE void wx_sqlite3ClearTempRegCache(Parse*);
+SQLITE_PRIVATE void wx_sqlite3TouchRegister(Parse*,int);
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int wx_sqlite3FirstAvailableRegister(Parse*,int);
+#endif
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int wx_sqlite3NoTempsInRange(Parse*,int,int);
#endif
@@ -20254,10 +21184,13 @@ SQLITE_PRIVATE void wx_sqlite3PExprAddSelect(Parse*, Expr*, Select*);
SQLITE_PRIVATE Expr *wx_sqlite3ExprAnd(Parse*,Expr*, Expr*);
SQLITE_PRIVATE Expr *wx_sqlite3ExprSimplifiedAndOr(Expr*);
SQLITE_PRIVATE Expr *wx_sqlite3ExprFunction(Parse*,ExprList*, const Token*, int);
+SQLITE_PRIVATE void wx_sqlite3ExprAddFunctionOrderBy(Parse*,Expr*,ExprList*);
+SQLITE_PRIVATE void wx_sqlite3ExprOrderByAggregateError(Parse*,Expr*);
SQLITE_PRIVATE void wx_sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*);
SQLITE_PRIVATE void wx_sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
SQLITE_PRIVATE void wx_sqlite3ExprDelete(wx_sqlite3*, Expr*);
-SQLITE_PRIVATE void wx_sqlite3ExprDeferredDelete(Parse*, Expr*);
+SQLITE_PRIVATE void wx_sqlite3ExprDeleteGeneric(wx_sqlite3*,void*);
+SQLITE_PRIVATE int wx_sqlite3ExprDeferredDelete(Parse*, Expr*);
SQLITE_PRIVATE void wx_sqlite3ExprUnmapAndDelete(Parse*, Expr*);
SQLITE_PRIVATE ExprList *wx_sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
SQLITE_PRIVATE ExprList *wx_sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
@@ -20266,6 +21199,7 @@ SQLITE_PRIVATE void wx_sqlite3ExprListSetSortOrder(ExprList*,int,int);
SQLITE_PRIVATE void wx_sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int);
SQLITE_PRIVATE void wx_sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
SQLITE_PRIVATE void wx_sqlite3ExprListDelete(wx_sqlite3*, ExprList*);
+SQLITE_PRIVATE void wx_sqlite3ExprListDeleteGeneric(wx_sqlite3*,void*);
SQLITE_PRIVATE u32 wx_sqlite3ExprListFlags(const ExprList*);
SQLITE_PRIVATE int wx_sqlite3IndexHasDuplicateRootPage(Index*);
SQLITE_PRIVATE int wx_sqlite3Init(wx_sqlite3*, char**);
@@ -20356,6 +21290,7 @@ SQLITE_PRIVATE int wx_sqlite3DbMaskAllZero(yDbMask);
SQLITE_PRIVATE void wx_sqlite3DropTable(Parse*, SrcList*, int, int);
SQLITE_PRIVATE void wx_sqlite3CodeDropTable(Parse*, Table*, int, int);
SQLITE_PRIVATE void wx_sqlite3DeleteTable(wx_sqlite3*, Table*);
+SQLITE_PRIVATE void wx_sqlite3DeleteTableGeneric(wx_sqlite3*, void*);
SQLITE_PRIVATE void wx_sqlite3FreeIndex(wx_sqlite3*, Index*);
#ifndef SQLITE_OMIT_AUTOINCREMENT
SQLITE_PRIVATE void wx_sqlite3AutoincrementBegin(Parse *pParse);
@@ -20374,6 +21309,9 @@ SQLITE_PRIVATE int wx_sqlite3IdListIndex(IdList*,const char*);
SQLITE_PRIVATE SrcList *wx_sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
SQLITE_PRIVATE SrcList *wx_sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
SQLITE_PRIVATE SrcList *wx_sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
+SQLITE_PRIVATE void wx_sqlite3SubqueryDelete(wx_sqlite3*,Subquery*);
+SQLITE_PRIVATE Select *wx_sqlite3SubqueryDetach(wx_sqlite3*,SrcItem*);
+SQLITE_PRIVATE int wx_sqlite3SrcItemAttachSubquery(Parse*, SrcItem*, Select*, int);
SQLITE_PRIVATE SrcList *wx_sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
Token*, Select*, OnOrUsing*);
SQLITE_PRIVATE void wx_sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
@@ -20392,8 +21330,9 @@ SQLITE_PRIVATE int wx_sqlite3Select(Parse*, Select*, SelectDest*);
SQLITE_PRIVATE Select *wx_sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
Expr*,ExprList*,u32,Expr*);
SQLITE_PRIVATE void wx_sqlite3SelectDelete(wx_sqlite3*, Select*);
+SQLITE_PRIVATE void wx_sqlite3SelectDeleteGeneric(wx_sqlite3*,void*);
SQLITE_PRIVATE Table *wx_sqlite3SrcListLookup(Parse*, SrcList*);
-SQLITE_PRIVATE int wx_sqlite3IsReadOnly(Parse*, Table*, int);
+SQLITE_PRIVATE int wx_sqlite3IsReadOnly(Parse*, Table*, Trigger*);
SQLITE_PRIVATE void wx_sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE Expr *wx_sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
@@ -20422,6 +21361,7 @@ SQLITE_PRIVATE void wx_sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int,
SQLITE_PRIVATE int wx_sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
SQLITE_PRIVATE void wx_sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
SQLITE_PRIVATE void wx_sqlite3ExprCodeMove(Parse*, int, int, int);
+SQLITE_PRIVATE void wx_sqlite3ExprToRegister(Expr *pExpr, int iReg);
SQLITE_PRIVATE void wx_sqlite3ExprCode(Parse*, Expr*, int);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
SQLITE_PRIVATE void wx_sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int);
@@ -20455,7 +21395,7 @@ SQLITE_PRIVATE int wx_sqlite3ExprCompare(const Parse*,const Expr*,const Expr*, i
SQLITE_PRIVATE int wx_sqlite3ExprCompareSkip(Expr*,Expr*,int);
SQLITE_PRIVATE int wx_sqlite3ExprListCompare(const ExprList*,const ExprList*, int);
SQLITE_PRIVATE int wx_sqlite3ExprImpliesExpr(const Parse*,const Expr*,const Expr*, int);
-SQLITE_PRIVATE int wx_sqlite3ExprImpliesNonNullRow(Expr*,int);
+SQLITE_PRIVATE int wx_sqlite3ExprImpliesNonNullRow(Expr*,int,int);
SQLITE_PRIVATE void wx_sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
SQLITE_PRIVATE void wx_sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void wx_sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
@@ -20477,19 +21417,18 @@ SQLITE_PRIVATE void wx_sqlite3LeaveMutexAndCloseZombie(wx_sqlite3*);
SQLITE_PRIVATE u32 wx_sqlite3IsTrueOrFalse(const char*);
SQLITE_PRIVATE int wx_sqlite3ExprIdToTrueFalse(Expr*);
SQLITE_PRIVATE int wx_sqlite3ExprTruthValue(const Expr*);
-SQLITE_PRIVATE int wx_sqlite3ExprIsConstant(Expr*);
-SQLITE_PRIVATE int wx_sqlite3ExprIsConstantNotJoin(Expr*);
+SQLITE_PRIVATE int wx_sqlite3ExprIsConstant(Parse*,Expr*);
SQLITE_PRIVATE int wx_sqlite3ExprIsConstantOrFunction(Expr*, u8);
SQLITE_PRIVATE int wx_sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
-SQLITE_PRIVATE int wx_sqlite3ExprIsTableConstant(Expr*,int);
-SQLITE_PRIVATE int wx_sqlite3ExprIsTableConstraint(Expr*,const SrcItem*);
+SQLITE_PRIVATE int wx_sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int,int);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
SQLITE_PRIVATE int wx_sqlite3ExprContainsSubquery(Expr*);
#endif
-SQLITE_PRIVATE int wx_sqlite3ExprIsInteger(const Expr*, int*);
+SQLITE_PRIVATE int wx_sqlite3ExprIsInteger(const Expr*, int*, Parse*);
SQLITE_PRIVATE int wx_sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int wx_sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
SQLITE_PRIVATE int wx_sqlite3IsRowid(const char*);
+SQLITE_PRIVATE const char *wx_sqlite3RowidAlias(Table *pTab);
SQLITE_PRIVATE void wx_sqlite3GenerateRowDelete(
Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
SQLITE_PRIVATE void wx_sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
@@ -20604,6 +21543,7 @@ SQLITE_PRIVATE int wx_sqlite3FixSrcList(DbFixer*, SrcList*);
SQLITE_PRIVATE int wx_sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int wx_sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int wx_sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
+
SQLITE_PRIVATE int wx_sqlite3RealSameAsInt(double,wx_sqlite3_int64);
SQLITE_PRIVATE i64 wx_sqlite3RealToI64(double);
SQLITE_PRIVATE int wx_sqlite3Int64ToText(i64,char*);
@@ -20612,10 +21552,11 @@ SQLITE_PRIVATE int wx_sqlite3GetInt32(const char *, int*);
SQLITE_PRIVATE int wx_sqlite3GetUInt32(const char*, u32*);
SQLITE_PRIVATE int wx_sqlite3Atoi(const char*);
#ifndef SQLITE_OMIT_UTF16
-SQLITE_PRIVATE int wx_sqlite3Utf16ByteLen(const void *pData, int nChar);
+SQLITE_PRIVATE int wx_sqlite3Utf16ByteLen(const void *pData, int nByte, int nChar);
#endif
SQLITE_PRIVATE int wx_sqlite3Utf8CharLen(const char *pData, int nByte);
SQLITE_PRIVATE u32 wx_sqlite3Utf8Read(const u8**);
+SQLITE_PRIVATE int wx_sqlite3Utf8ReadLimited(const u8*, int, u32*);
SQLITE_PRIVATE LogEst wx_sqlite3LogEst(u64);
SQLITE_PRIVATE LogEst wx_sqlite3LogEstAdd(LogEst,LogEst);
SQLITE_PRIVATE LogEst wx_sqlite3LogEstFromDouble(double);
@@ -20664,7 +21605,9 @@ SQLITE_PRIVATE void wx_sqlite3ErrorWithMsg(wx_sqlite3*, int, const char*,...);
SQLITE_PRIVATE void wx_sqlite3Error(wx_sqlite3*,int);
SQLITE_PRIVATE void wx_sqlite3ErrorClear(wx_sqlite3*);
SQLITE_PRIVATE void wx_sqlite3SystemError(wx_sqlite3*,int);
+#if !defined(SQLITE_OMIT_BLOB_LITERAL)
SQLITE_PRIVATE void *wx_sqlite3HexToBlob(wx_sqlite3*, const char *z, int n);
+#endif
SQLITE_PRIVATE u8 wx_sqlite3HexToInt(int h);
SQLITE_PRIVATE int wx_sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
@@ -20708,6 +21651,7 @@ SQLITE_PRIVATE void wx_sqlite3FileSuffix3(const char*, char*);
SQLITE_PRIVATE u8 wx_sqlite3GetBoolean(const char *z,u8);
SQLITE_PRIVATE const void *wx_sqlite3ValueText(wx_sqlite3_value*, u8);
+SQLITE_PRIVATE int wx_sqlite3ValueIsOfClass(const wx_sqlite3_value*, void(*)(void*));
SQLITE_PRIVATE int wx_sqlite3ValueBytes(wx_sqlite3_value*, u8);
SQLITE_PRIVATE void wx_sqlite3ValueSetStr(wx_sqlite3_value*, int, const void *,u8,
void(*)(void*));
@@ -20759,7 +21703,8 @@ SQLITE_PRIVATE int wx_sqlite3MatchEName(
const struct ExprList_item*,
const char*,
const char*,
- const char*
+ const char*,
+ int*
);
SQLITE_PRIVATE Bitmask wx_sqlite3ExprColUsed(Expr*);
SQLITE_PRIVATE u8 wx_sqlite3StrIHash(const char*);
@@ -20815,6 +21760,11 @@ SQLITE_PRIVATE void wx_sqlite3OomClear(wx_sqlite3*);
SQLITE_PRIVATE int wx_sqlite3ApiExit(wx_sqlite3 *db, int);
SQLITE_PRIVATE int wx_sqlite3OpenTempDatabase(Parse *);
+SQLITE_PRIVATE char *wx_sqlite3RCStrRef(char*);
+SQLITE_PRIVATE void wx_sqlite3RCStrUnref(void*);
+SQLITE_PRIVATE char *wx_sqlite3RCStrNew(u64);
+SQLITE_PRIVATE char *wx_sqlite3RCStrResize(char*,u64);
+
SQLITE_PRIVATE void wx_sqlite3StrAccumInit(StrAccum*, wx_sqlite3*, char*, int, int);
SQLITE_PRIVATE int wx_sqlite3StrAccumEnlarge(StrAccum*, i64);
SQLITE_PRIVATE char *wx_sqlite3StrAccumFinish(StrAccum*);
@@ -20930,10 +21880,7 @@ SQLITE_PRIVATE int wx_sqlite3VtabCallDestroy(wx_sqlite3*, int, const char *);
SQLITE_PRIVATE int wx_sqlite3VtabBegin(wx_sqlite3 *, VTable *);
SQLITE_PRIVATE FuncDef *wx_sqlite3VtabOverloadFunction(wx_sqlite3 *,FuncDef*, int nArg, Expr*);
-#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
- && !defined(SQLITE_OMIT_VIRTUALTABLE)
-SQLITE_PRIVATE void wx_sqlite3VtabUsesAllSchemas(wx_sqlite3_index_info*);
-#endif
+SQLITE_PRIVATE void wx_sqlite3VtabUsesAllSchemas(Parse*);
SQLITE_PRIVATE wx_sqlite3_int64 wx_sqlite3StmtCurrentTime(wx_sqlite3_context*);
SQLITE_PRIVATE int wx_sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
SQLITE_PRIVATE int wx_sqlite3TransferBindings(wx_sqlite3_stmt *, wx_sqlite3_stmt *);
@@ -20958,6 +21905,7 @@ SQLITE_PRIVATE Cte *wx_sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8);
SQLITE_PRIVATE void wx_sqlite3CteDelete(wx_sqlite3*,Cte*);
SQLITE_PRIVATE With *wx_sqlite3WithAdd(Parse*,With*,Cte*);
SQLITE_PRIVATE void wx_sqlite3WithDelete(wx_sqlite3*,With*);
+SQLITE_PRIVATE void wx_sqlite3WithDeleteGeneric(wx_sqlite3*,void*);
SQLITE_PRIVATE With *wx_sqlite3WithPush(Parse*, With*, u8);
#else
# define wx_sqlite3CteNew(P,T,E,S) ((void*)0)
@@ -20970,7 +21918,7 @@ SQLITE_PRIVATE With *wx_sqlite3WithPush(Parse*, With*, u8);
SQLITE_PRIVATE Upsert *wx_sqlite3UpsertNew(wx_sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
SQLITE_PRIVATE void wx_sqlite3UpsertDelete(wx_sqlite3*,Upsert*);
SQLITE_PRIVATE Upsert *wx_sqlite3UpsertDup(wx_sqlite3*,Upsert*);
-SQLITE_PRIVATE int wx_sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*);
+SQLITE_PRIVATE int wx_sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*,Upsert*);
SQLITE_PRIVATE void wx_sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int);
SQLITE_PRIVATE Upsert *wx_sqlite3UpsertOfIndex(Upsert*,Index*);
SQLITE_PRIVATE int wx_sqlite3UpsertNextIsIPK(Upsert*);
@@ -21069,6 +22017,7 @@ SQLITE_PRIVATE int wx_sqlite3ExprCheckHeight(Parse*, int);
#define wx_sqlite3SelectExprHeight(x) 0
#define wx_sqlite3ExprCheckHeight(x,y)
#endif
+SQLITE_PRIVATE void wx_sqlite3ExprSetErrorOffset(Expr*,int);
SQLITE_PRIVATE u32 wx_sqlite3Get4byte(const u8*);
SQLITE_PRIVATE void wx_sqlite3Put4byte(u8*, u32);
@@ -21180,6 +22129,12 @@ SQLITE_PRIVATE int wx_sqlite3KvvfsInit(void);
SQLITE_PRIVATE wx_sqlite3_uint64 wx_sqlite3Hwtime(void);
#endif
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+# define IS_STMT_SCANSTATUS(db) (db->flags & SQLITE_StmtScanStatus)
+#else
+# define IS_STMT_SCANSTATUS(db) 0
+#endif
+
#endif /* SQLITEINT_H */
/************** End of sqliteInt.h *******************************************/
@@ -21348,14 +22303,14 @@ static const char * const wx_sqlite3azCompileOpt[] = {
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
"4_BYTE_ALIGNED_MALLOC",
#endif
-#ifdef SQLITE_64BIT_STATS
- "64BIT_STATS",
-#endif
#ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN
# if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1
"ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN),
# endif
#endif
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ "ALLOW_ROWID_IN_VIEW",
+#endif
#ifdef SQLITE_ALLOW_URI_AUTHORITY
"ALLOW_URI_AUTHORITY",
#endif
@@ -21583,6 +22538,9 @@ static const char * const wx_sqlite3azCompileOpt[] = {
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
"ENABLE_OFFSET_SQL_FUNC",
#endif
+#ifdef SQLITE_ENABLE_ORDERED_SET_AGGREGATES
+ "ENABLE_ORDERED_SET_AGGREGATES",
+#endif
#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
"ENABLE_OVERSIZE_CELL_CHECK",
#endif
@@ -21646,6 +22604,9 @@ static const char * const wx_sqlite3azCompileOpt[] = {
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
"EXPLAIN_ESTIMATED_ROWS",
#endif
+#ifdef SQLITE_EXTRA_AUTOEXT
+ "EXTRA_AUTOEXT=" CTIMEOPT_VAL(SQLITE_EXTRA_AUTOEXT),
+#endif
#ifdef SQLITE_EXTRA_IFNULLROW
"EXTRA_IFNULLROW",
#endif
@@ -21687,6 +22648,9 @@ static const char * const wx_sqlite3azCompileOpt[] = {
#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
"INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
#endif
+#ifdef SQLITE_LEGACY_JSON_VALID
+ "LEGACY_JSON_VALID",
+#endif
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
"LIKE_DOESNT_MATCH_BLOBS",
#endif
@@ -21924,6 +22888,9 @@ static const char * const wx_sqlite3azCompileOpt[] = {
#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
"OMIT_SCHEMA_VERSION_PRAGMAS",
#endif
+#ifdef SQLITE_OMIT_SEH
+ "OMIT_SEH",
+#endif
#ifdef SQLITE_OMIT_SHARED_CACHE
"OMIT_SHARED_CACHE",
#endif
@@ -22175,7 +23142,7 @@ SQLITE_PRIVATE const unsigned char *wx_sqlite3aGTb = &wx_sqlite3UpperToLower[256
** isalnum() 0x06
** isxdigit() 0x08
** toupper() 0x20
-** SQLite identifier character 0x40
+** SQLite identifier character 0x40 $, _, or non-ascii
** Quote character 0x80
**
** Bit 0x20 is set if the mapped character requires translation to upper
@@ -22321,6 +23288,9 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config wx_sqlite3Config = {
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
0, /* bSmallMalloc */
1, /* bExtraSchemaChecks */
+#ifdef SQLITE_DEBUG
+ 0, /* bJsonSelfcheck */
+#endif
0x7ffffffe, /* mxStrlen */
0, /* neverCorrupt */
SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
@@ -22363,13 +23333,16 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config wx_sqlite3Config = {
#ifndef SQLITE_UNTESTABLE
0, /* xTestCallback */
#endif
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ 0, /* mNoVisibleRowid. 0 == allow rowid-in-view */
+#endif
0, /* bLocaltimeFault */
0, /* xAltLocaltime */
0x7ffffffe, /* iOnceResetThreshold */
SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */
0, /* iPrngSeed */
#ifdef SQLITE_DEBUG
- {0,0,0,0,0,0} /* aTune */
+ {0,0,0,0,0,0}, /* aTune */
#endif
};
@@ -22550,6 +23523,9 @@ typedef struct VdbeSorter VdbeSorter;
/* Elements of the linked list at Vdbe.pAuxData */
typedef struct AuxData AuxData;
+/* A cache of large TEXT or BLOB values in a VdbeCursor */
+typedef struct VdbeTxtBlbCache VdbeTxtBlbCache;
+
/* Types of VDBE cursors */
#define CURTYPE_BTREE 0
#define CURTYPE_SORTER 1
@@ -22581,6 +23557,7 @@ struct VdbeCursor {
Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
Bool noReuse:1; /* OpenEphemeral may not reuse this cursor */
+ Bool colCache:1; /* pCache pointer is initialized and non-NULL */
u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */
union { /* pBtx for isEphermeral. pAltMap otherwise */
Btree *pBtx; /* Separate file holding temporary table */
@@ -22621,6 +23598,7 @@ struct VdbeCursor {
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
u64 maskUsed; /* Mask of columns used by this cursor */
#endif
+ VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */
/* 2*nField extra array elements allocated for aType[], beyond the one
** static element declared in the structure. nField total array slots for
@@ -22633,13 +23611,26 @@ struct VdbeCursor {
#define IsNullCursor(P) \
((P)->eCurType==CURTYPE_PSEUDO && (P)->nullRow && (P)->seekResult==0)
-
/*
** A value for VdbeCursor.cacheStatus that means the cache is always invalid.
*/
#define CACHE_STALE 0
/*
+** Large TEXT or BLOB values can be slow to load, so we want to avoid
+** loading them more than once. For that reason, large TEXT and BLOB values
+** can be stored in a cache defined by this object, and attached to the
+** VdbeCursor using the pCache field.
+*/
+struct VdbeTxtBlbCache {
+ char *pCValue; /* A RCStr buffer to hold the value */
+ i64 iOffset; /* File offset of the row being cached */
+ int iCol; /* Column for which the cache is valid */
+ u32 cacheStatus; /* Vdbe.cacheCtr value */
+ u32 colCacheCtr; /* Column cache counter */
+};
+
+/*
** When a sub-program is executed (OP_Program), a structure of this type
** is allocated to store the current value of the program counter, as
** well as the current memory cell array and various other frame specific
@@ -22959,16 +23950,18 @@ struct Vdbe {
u32 nWrite; /* Number of write operations that have occurred */
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
+ u16 nResAlloc; /* Column slots allocated to aColName[] */
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 eVdbeState; /* On of the VDBE_*_STATE values */
bft expired:2; /* 1: recompile VM immediately 2: when convenient */
- bft explain:2; /* True if EXPLAIN present on SQL command */
+ bft explain:2; /* 0: normal, 1: EXPLAIN, 2: EXPLAIN QUERY PLAN */
bft changeCntOn:1; /* True to update the change-counter */
bft usesStmtJournal:1; /* True if uses a statement journal */
bft readOnly:1; /* True for statements that do not write */
bft bIsReader:1; /* True for statements that read */
+ bft haveEqpOps:1; /* Bytecode supports EXPLAIN QUERY PLAN */
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
u32 aCounter[9]; /* Counters used by wx_sqlite3_stmt_status() */
@@ -23015,8 +24008,9 @@ struct PreUpdate {
i64 iKey1; /* First key value passed to hook */
i64 iKey2; /* Second key value passed to hook */
Mem *aNew; /* Array of new.* values */
- Table *pTab; /* Schema object being upated */
+ Table *pTab; /* Schema object being updated */
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
+ wx_sqlite3_value **apDflt; /* Array of default values, if required */
};
/*
@@ -23105,6 +24099,7 @@ SQLITE_PRIVATE int wx_sqlite3VdbeMemSetZeroBlob(Mem*,int);
SQLITE_PRIVATE int wx_sqlite3VdbeMemIsRowSet(const Mem*);
#endif
SQLITE_PRIVATE int wx_sqlite3VdbeMemSetRowSet(Mem*);
+SQLITE_PRIVATE void wx_sqlite3VdbeMemZeroTerminateIfAble(Mem*);
SQLITE_PRIVATE int wx_sqlite3VdbeMemMakeWriteable(Mem*);
SQLITE_PRIVATE int wx_sqlite3VdbeMemStringify(Mem*, u8, u8);
SQLITE_PRIVATE int wx_sqlite3IntFloatCompare(i64,double);
@@ -23552,7 +24547,7 @@ SQLITE_API int wx_sqlite3_db_status(
case SQLITE_DBSTATUS_CACHE_MISS:
case SQLITE_DBSTATUS_CACHE_WRITE:{
int i;
- int nRet = 0;
+ u64 nRet = 0;
assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 );
assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 );
@@ -23565,7 +24560,7 @@ SQLITE_API int wx_sqlite3_db_status(
*pHighwater = 0; /* IMP: R-42420-56072 */
/* IMP: R-54100-20147 */
/* IMP: R-29431-39229 */
- *pCurrent = nRet;
+ *pCurrent = (int)nRet & 0x7fffffff;
break;
}
@@ -23662,12 +24657,14 @@ struct DateTime {
int tz; /* Timezone offset in minutes */
double s; /* Seconds */
char validJD; /* True (1) if iJD is valid */
- char rawS; /* Raw numeric value stored in s */
char validYMD; /* True (1) if Y,M,D are valid */
char validHMS; /* True (1) if h,m,s are valid */
- char validTZ; /* True (1) if tz is valid */
- char tzSet; /* Timezone was set explicitly */
- char isError; /* An overflow has occurred */
+ char nFloor; /* Days to implement "floor" */
+ unsigned rawS : 1; /* Raw numeric value stored in s */
+ unsigned isError : 1; /* An overflow has occurred */
+ unsigned useSubsec : 1; /* Display subsecond precision */
+ unsigned isUtc : 1; /* Time is known to be UTC */
+ unsigned isLocal : 1; /* Time is known to be localtime */
};
@@ -23700,8 +24697,8 @@ struct DateTime {
*/
static int getDigits(const char *zDate, const char *zFormat, ...){
/* The aMx[] array translates the 3rd character of each format
- ** spec into a max size: a b c d e f */
- static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 };
+ ** spec into a max size: a b c d e f */
+ static const u16 aMx[] = { 12, 14, 24, 31, 59, 14712 };
va_list ap;
int cnt = 0;
char nextC;
@@ -23765,6 +24762,8 @@ static int parseTimezone(const char *zDate, DateTime *p){
sgn = +1;
}else if( c=='Z' || c=='z' ){
zDate++;
+ p->isLocal = 0;
+ p->isUtc = 1;
goto zulu_time;
}else{
return c!=0;
@@ -23777,7 +24776,6 @@ static int parseTimezone(const char *zDate, DateTime *p){
p->tz = sgn*(nMn + nHr*60);
zulu_time:
while( wx_sqlite3Isspace(*zDate) ){ zDate++; }
- p->tzSet = 1;
return *zDate!=0;
}
@@ -23821,7 +24819,6 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
p->m = m;
p->s = s + ms;
if( parseTimezone(zDate, p) ) return 1;
- p->validTZ = (p->tz!=0)?1:0;
return 0;
}
@@ -23860,24 +24857,49 @@ static void computeJD(DateTime *p){
Y--;
M += 12;
}
- A = Y/100;
- B = 2 - A + (A/4);
+ A = (Y+4800)/100;
+ B = 38 - A + (A/4);
X1 = 36525*(Y+4716)/100;
X2 = 306001*(M+1)/10000;
p->iJD = (wx_sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
p->validJD = 1;
if( p->validHMS ){
p->iJD += p->h*3600000 + p->m*60000 + (wx_sqlite3_int64)(p->s*1000 + 0.5);
- if( p->validTZ ){
+ if( p->tz ){
p->iJD -= p->tz*60000;
p->validYMD = 0;
p->validHMS = 0;
- p->validTZ = 0;
+ p->tz = 0;
+ p->isUtc = 1;
+ p->isLocal = 0;
}
}
}
/*
+** Given the YYYY-MM-DD information current in p, determine if there
+** is day-of-month overflow and set nFloor to the number of days that
+** would need to be subtracted from the date in order to bring the
+** date back to the end of the month.
+*/
+static void computeFloor(DateTime *p){
+ assert( p->validYMD || p->isError );
+ assert( p->D>=0 && p->D<=31 );
+ assert( p->M>=0 && p->M<=12 );
+ if( p->D<=28 ){
+ p->nFloor = 0;
+ }else if( (1<<p->M) & 0x15aa ){
+ p->nFloor = 0;
+ }else if( p->M!=2 ){
+ p->nFloor = (p->D==31);
+ }else if( p->Y%4!=0 || (p->Y%100==0 && p->Y%400!=0) ){
+ p->nFloor = p->D - 28;
+ }else{
+ p->nFloor = p->D - 29;
+ }
+}
+
+/*
** Parse dates of the form
**
** YYYY-MM-DD HH:MM:SS.FFF
@@ -23915,12 +24937,16 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
p->Y = neg ? -Y : Y;
p->M = M;
p->D = D;
- if( p->validTZ ){
+ computeFloor(p);
+ if( p->tz ){
computeJD(p);
}
return 0;
}
+
+static void clearYMD_HMS_TZ(DateTime *p); /* Forward declaration */
+
/*
** Set the time to the current time reported by the VFS.
**
@@ -23930,6 +24956,9 @@ static int setDateTimeToCurrent(wx_sqlite3_context *context, DateTime *p){
p->iJD = wx_sqlite3StmtCurrentTime(context);
if( p->iJD>0 ){
p->validJD = 1;
+ p->isUtc = 1;
+ p->isLocal = 0;
+ clearYMD_HMS_TZ(p);
return 0;
}else{
return 1;
@@ -23982,6 +25011,11 @@ static int parseDateOrTime(
}else if( wx_sqlite3AtoF(zDate, &r, wx_sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){
setRawDateNumber(p, r);
return 0;
+ }else if( (wx_sqlite3StrICmp(zDate,"subsec")==0
+ || wx_sqlite3StrICmp(zDate,"subsecond")==0)
+ && wx_sqlite3NotPureFunc(context) ){
+ p->useSubsec = 1;
+ return setDateTimeToCurrent(context, p);
}
return 1;
}
@@ -24008,7 +25042,7 @@ static int validJulianDay(wx_sqlite3_int64 iJD){
** Compute the Year, Month, and Day from the julian day number.
*/
static void computeYMD(DateTime *p){
- int Z, A, B, C, D, E, X1;
+ int Z, alpha, A, B, C, D, E, X1;
if( p->validYMD ) return;
if( !p->validJD ){
p->Y = 2000;
@@ -24019,8 +25053,8 @@ static void computeYMD(DateTime *p){
return;
}else{
Z = (int)((p->iJD + 43200000)/86400000);
- A = (int)((Z - 1867216.25)/36524.25);
- A = Z + 1 + A - (A/4);
+ alpha = (int)((Z + 32044.75)/36524.25) - 52;
+ A = Z + 1 + alpha - ((alpha+100)/4) + 25;
B = A + 1524;
C = (int)((B - 122.1)/365.25);
D = (36525*(C&32767))/100;
@@ -24037,17 +25071,14 @@ static void computeYMD(DateTime *p){
** Compute the Hour, Minute, and Seconds from the julian day number.
*/
static void computeHMS(DateTime *p){
- int s;
+ int day_ms, day_min; /* milliseconds, minutes into the day */
if( p->validHMS ) return;
computeJD(p);
- s = (int)((p->iJD + 43200000) % 86400000);
- p->s = s/1000.0;
- s = (int)p->s;
- p->s -= s;
- p->h = s/3600;
- s -= p->h*3600;
- p->m = s/60;
- p->s += s - p->m*60;
+ day_ms = (int)((p->iJD + 43200000) % 86400000);
+ p->s = (day_ms % 60000)/1000.0;
+ day_min = day_ms/60000;
+ p->m = day_min % 60;
+ p->h = day_min / 60;
p->rawS = 0;
p->validHMS = 1;
}
@@ -24066,7 +25097,7 @@ static void computeYMD_HMS(DateTime *p){
static void clearYMD_HMS_TZ(DateTime *p){
p->validYMD = 0;
p->validHMS = 0;
- p->validTZ = 0;
+ p->tz = 0;
}
#ifndef SQLITE_OMIT_LOCALTIME
@@ -24198,7 +25229,7 @@ static int toLocaltime(
p->validHMS = 1;
p->validJD = 0;
p->rawS = 0;
- p->validTZ = 0;
+ p->tz = 0;
p->isError = 0;
return SQLITE_OK;
}
@@ -24218,15 +25249,34 @@ static const struct {
float rLimit; /* Maximum NNN value for this transform */
float rXform; /* Constant used for this transform */
} aXformType[] = {
- { 6, "second", 4.6427e+14, 1.0 },
- { 6, "minute", 7.7379e+12, 60.0 },
- { 4, "hour", 1.2897e+11, 3600.0 },
- { 3, "day", 5373485.0, 86400.0 },
- { 5, "month", 176546.0, 2592000.0 },
- { 4, "year", 14713.0, 31536000.0 },
+ /* 0 */ { 6, "second", 4.6427e+14, 1.0 },
+ /* 1 */ { 6, "minute", 7.7379e+12, 60.0 },
+ /* 2 */ { 4, "hour", 1.2897e+11, 3600.0 },
+ /* 3 */ { 3, "day", 5373485.0, 86400.0 },
+ /* 4 */ { 5, "month", 176546.0, 2592000.0 },
+ /* 5 */ { 4, "year", 14713.0, 31536000.0 },
};
/*
+** If the DateTime p is raw number, try to figure out if it is
+** a julian day number of a unix timestamp. Set the p value
+** appropriately.
+*/
+static void autoAdjustDate(DateTime *p){
+ if( !p->rawS || p->validJD ){
+ p->rawS = 0;
+ }else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */
+ && p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */
+ ){
+ double r = p->s*1000.0 + 210866760000000.0;
+ clearYMD_HMS_TZ(p);
+ p->iJD = (wx_sqlite3_int64)(r + 0.5);
+ p->validJD = 1;
+ p->rawS = 0;
+ }
+}
+
+/*
** Process a modifier to a date-time stamp. The modifiers are
** as follows:
**
@@ -24236,14 +25286,20 @@ static const struct {
** NNN.NNNN seconds
** NNN months
** NNN years
+** +/-YYYY-MM-DD HH:MM:SS.SSS
+** ceiling
+** floor
** start of month
** start of year
** start of week
** start of day
** weekday N
** unixepoch
+** auto
** localtime
** utc
+** subsec
+** subsecond
**
** Return 0 on success and 1 if there is any kind of error. If the error
** is in a system call (i.e. localtime()), then an error message is written
@@ -24269,19 +25325,39 @@ static int parseModifier(
*/
if( wx_sqlite3_stricmp(z, "auto")==0 ){
if( idx>1 ) return 1; /* IMP: R-33611-57934 */
- if( !p->rawS || p->validJD ){
- rc = 0;
- p->rawS = 0;
- }else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */
- && p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */
- ){
- r = p->s*1000.0 + 210866760000000.0;
- clearYMD_HMS_TZ(p);
- p->iJD = (wx_sqlite3_int64)(r + 0.5);
- p->validJD = 1;
- p->rawS = 0;
- rc = 0;
- }
+ autoAdjustDate(p);
+ rc = 0;
+ }
+ break;
+ }
+ case 'c': {
+ /*
+ ** ceiling
+ **
+ ** Resolve day-of-month overflow by rolling forward into the next
+ ** month. As this is the default action, this modifier is really
+ ** a no-op that is only included for symmetry. See "floor".
+ */
+ if( wx_sqlite3_stricmp(z, "ceiling")==0 ){
+ computeJD(p);
+ clearYMD_HMS_TZ(p);
+ rc = 0;
+ p->nFloor = 0;
+ }
+ break;
+ }
+ case 'f': {
+ /*
+ ** floor
+ **
+ ** Resolve day-of-month overflow by rolling back to the end of the
+ ** previous month.
+ */
+ if( wx_sqlite3_stricmp(z, "floor")==0 ){
+ computeJD(p);
+ p->iJD -= p->nFloor*86400000;
+ clearYMD_HMS_TZ(p);
+ rc = 0;
}
break;
}
@@ -24311,7 +25387,9 @@ static int parseModifier(
** show local time.
*/
if( wx_sqlite3_stricmp(z, "localtime")==0 && wx_sqlite3NotPureFunc(pCtx) ){
- rc = toLocaltime(p, pCtx);
+ rc = p->isLocal ? SQLITE_OK : toLocaltime(p, pCtx);
+ p->isUtc = 0;
+ p->isLocal = 1;
}
break;
}
@@ -24336,7 +25414,7 @@ static int parseModifier(
}
#ifndef SQLITE_OMIT_LOCALTIME
else if( wx_sqlite3_stricmp(z, "utc")==0 && wx_sqlite3NotPureFunc(pCtx) ){
- if( p->tzSet==0 ){
+ if( p->isUtc==0 ){
i64 iOrigJD; /* Original localtime */
i64 iGuess; /* Guess at the corresponding utc time */
int cnt = 0; /* Safety to prevent infinite loop */
@@ -24359,7 +25437,8 @@ static int parseModifier(
memset(p, 0, sizeof(*p));
p->iJD = iGuess;
p->validJD = 1;
- p->tzSet = 1;
+ p->isUtc = 1;
+ p->isLocal = 0;
}
rc = SQLITE_OK;
}
@@ -24379,7 +25458,7 @@ static int parseModifier(
&& r>=0.0 && r<7.0 && (n=(int)r)==r ){
wx_sqlite3_int64 Z;
computeYMD_HMS(p);
- p->validTZ = 0;
+ p->tz = 0;
p->validJD = 0;
computeJD(p);
Z = ((p->iJD + 129600000)/86400000) % 7;
@@ -24396,8 +25475,22 @@ static int parseModifier(
**
** Move the date backwards to the beginning of the current day,
** or month or year.
+ **
+ ** subsecond
+ ** subsec
+ **
+ ** Show subsecond precision in the output of datetime() and
+ ** unixepoch() and strftime('%s').
*/
- if( wx_sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
+ if( wx_sqlite3_strnicmp(z, "start of ", 9)!=0 ){
+ if( wx_sqlite3_stricmp(z, "subsec")==0
+ || wx_sqlite3_stricmp(z, "subsecond")==0
+ ){
+ p->useSubsec = 1;
+ rc = 0;
+ }
+ break;
+ }
if( !p->validJD && !p->validYMD && !p->validHMS ) break;
z += 9;
computeYMD(p);
@@ -24405,7 +25498,7 @@ static int parseModifier(
p->h = p->m = 0;
p->s = 0.0;
p->rawS = 0;
- p->validTZ = 0;
+ p->tz = 0;
p->validJD = 0;
if( wx_sqlite3_stricmp(z,"month")==0 ){
p->D = 1;
@@ -24433,18 +25526,74 @@ static int parseModifier(
case '9': {
double rRounder;
int i;
- for(n=1; z[n] && z[n]!=':' && !wx_sqlite3Isspace(z[n]); n++){}
+ int Y,M,D,h,m,x;
+ const char *z2 = z;
+ char z0 = z[0];
+ for(n=1; z[n]; n++){
+ if( z[n]==':' ) break;
+ if( wx_sqlite3Isspace(z[n]) ) break;
+ if( z[n]=='-' ){
+ if( n==5 && getDigits(&z[1], "40f", &Y)==1 ) break;
+ if( n==6 && getDigits(&z[1], "50f", &Y)==1 ) break;
+ }
+ }
if( wx_sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){
- rc = 1;
+ assert( rc==1 );
break;
}
- if( z[n]==':' ){
+ if( z[n]=='-' ){
+ /* A modifier of the form (+|-)YYYY-MM-DD adds or subtracts the
+ ** specified number of years, months, and days. MM is limited to
+ ** the range 0-11 and DD is limited to 0-30.
+ */
+ if( z0!='+' && z0!='-' ) break; /* Must start with +/- */
+ if( n==5 ){
+ if( getDigits(&z[1], "40f-20a-20d", &Y, &M, &D)!=3 ) break;
+ }else{
+ assert( n==6 );
+ if( getDigits(&z[1], "50f-20a-20d", &Y, &M, &D)!=3 ) break;
+ z++;
+ }
+ if( M>=12 ) break; /* M range 0..11 */
+ if( D>=31 ) break; /* D range 0..30 */
+ computeYMD_HMS(p);
+ p->validJD = 0;
+ if( z0=='-' ){
+ p->Y -= Y;
+ p->M -= M;
+ D = -D;
+ }else{
+ p->Y += Y;
+ p->M += M;
+ }
+ x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
+ p->Y += x;
+ p->M -= x*12;
+ computeFloor(p);
+ computeJD(p);
+ p->validHMS = 0;
+ p->validYMD = 0;
+ p->iJD += (i64)D*86400000;
+ if( z[11]==0 ){
+ rc = 0;
+ break;
+ }
+ if( wx_sqlite3Isspace(z[11])
+ && getDigits(&z[12], "20c:20e", &h, &m)==2
+ ){
+ z2 = &z[12];
+ n = 2;
+ }else{
+ break;
+ }
+ }
+ if( z2[n]==':' ){
/* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
** specified number of hours, minutes, seconds, and fractional seconds
** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
** omitted.
*/
- const char *z2 = z;
+
DateTime tx;
wx_sqlite3_int64 day;
if( !wx_sqlite3Isdigit(*z2) ) z2++;
@@ -24454,7 +25603,7 @@ static int parseModifier(
tx.iJD -= 43200000;
day = tx.iJD/86400000;
tx.iJD -= day*86400000;
- if( z[0]=='-' ) tx.iJD = -tx.iJD;
+ if( z0=='-' ) tx.iJD = -tx.iJD;
computeJD(p);
clearYMD_HMS_TZ(p);
p->iJD += tx.iJD;
@@ -24467,11 +25616,12 @@ static int parseModifier(
z += n;
while( wx_sqlite3Isspace(*z) ) z++;
n = wx_sqlite3Strlen30(z);
- if( n>10 || n<3 ) break;
+ if( n<3 || n>10 ) break;
if( wx_sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
computeJD(p);
- rc = 1;
+ assert( rc==1 );
rRounder = r<0 ? -0.5 : +0.5;
+ p->nFloor = 0;
for(i=0; i<ArraySize(aXformType); i++){
if( aXformType[i].nName==n
&& wx_sqlite3_strnicmp(aXformType[i].zName, z, n)==0
@@ -24479,22 +25629,24 @@ static int parseModifier(
){
switch( i ){
case 4: { /* Special processing to add months */
- int x;
- assert( strcmp(aXformType[i].zName,"month")==0 );
+ assert( strcmp(aXformType[4].zName,"month")==0 );
computeYMD_HMS(p);
p->M += (int)r;
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
p->Y += x;
p->M -= x*12;
+ computeFloor(p);
p->validJD = 0;
r -= (int)r;
break;
}
case 5: { /* Special processing to add years */
int y = (int)r;
- assert( strcmp(aXformType[i].zName,"year")==0 );
+ assert( strcmp(aXformType[5].zName,"year")==0 );
computeYMD_HMS(p);
+ assert( p->M>=0 && p->M<=12 );
p->Y += y;
+ computeFloor(p);
p->validJD = 0;
r -= (int)r;
break;
@@ -24555,6 +25707,12 @@ static int isDate(
}
computeJD(p);
if( p->isError || !validJulianDay(p->iJD) ) return 1;
+ if( argc==1 && p->validYMD && p->D>28 ){
+ /* Make sure a YYYY-MM-DD is normalized.
+ ** Example: 2023-02-31 -> 2023-03-03 */
+ assert( p->validJD );
+ p->validYMD = 0;
+ }
return 0;
}
@@ -24595,7 +25753,11 @@ static void unixepochFunc(
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
computeJD(&x);
- wx_sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
+ if( x.useSubsec ){
+ wx_sqlite3_result_double(context, (x.iJD - 21086676*(i64)10000000)/1000.0);
+ }else{
+ wx_sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
+ }
}
}
@@ -24611,8 +25773,8 @@ static void datetimeFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
- int Y, s;
- char zBuf[24];
+ int Y, s, n;
+ char zBuf[32];
computeYMD_HMS(&x);
Y = x.Y;
if( Y<0 ) Y = -Y;
@@ -24633,15 +25795,28 @@ static void datetimeFunc(
zBuf[15] = '0' + (x.m/10)%10;
zBuf[16] = '0' + (x.m)%10;
zBuf[17] = ':';
- s = (int)x.s;
- zBuf[18] = '0' + (s/10)%10;
- zBuf[19] = '0' + (s)%10;
- zBuf[20] = 0;
+ if( x.useSubsec ){
+ s = (int)(1000.0*x.s + 0.5);
+ zBuf[18] = '0' + (s/10000)%10;
+ zBuf[19] = '0' + (s/1000)%10;
+ zBuf[20] = '.';
+ zBuf[21] = '0' + (s/100)%10;
+ zBuf[22] = '0' + (s/10)%10;
+ zBuf[23] = '0' + (s)%10;
+ zBuf[24] = 0;
+ n = 24;
+ }else{
+ s = (int)x.s;
+ zBuf[18] = '0' + (s/10)%10;
+ zBuf[19] = '0' + (s)%10;
+ zBuf[20] = 0;
+ n = 20;
+ }
if( x.Y<0 ){
zBuf[0] = '-';
- wx_sqlite3_result_text(context, zBuf, 20, SQLITE_TRANSIENT);
+ wx_sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
}else{
- wx_sqlite3_result_text(context, &zBuf[1], 19, SQLITE_TRANSIENT);
+ wx_sqlite3_result_text(context, &zBuf[1], n-1, SQLITE_TRANSIENT);
}
}
}
@@ -24658,7 +25833,7 @@ static void timeFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
- int s;
+ int s, n;
char zBuf[16];
computeHMS(&x);
zBuf[0] = '0' + (x.h/10)%10;
@@ -24667,11 +25842,24 @@ static void timeFunc(
zBuf[3] = '0' + (x.m/10)%10;
zBuf[4] = '0' + (x.m)%10;
zBuf[5] = ':';
- s = (int)x.s;
- zBuf[6] = '0' + (s/10)%10;
- zBuf[7] = '0' + (s)%10;
- zBuf[8] = 0;
- wx_sqlite3_result_text(context, zBuf, 8, SQLITE_TRANSIENT);
+ if( x.useSubsec ){
+ s = (int)(1000.0*x.s + 0.5);
+ zBuf[6] = '0' + (s/10000)%10;
+ zBuf[7] = '0' + (s/1000)%10;
+ zBuf[8] = '.';
+ zBuf[9] = '0' + (s/100)%10;
+ zBuf[10] = '0' + (s/10)%10;
+ zBuf[11] = '0' + (s)%10;
+ zBuf[12] = 0;
+ n = 12;
+ }else{
+ s = (int)x.s;
+ zBuf[6] = '0' + (s/10)%10;
+ zBuf[7] = '0' + (s)%10;
+ zBuf[8] = 0;
+ n = 8;
+ }
+ wx_sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
}
}
@@ -24713,21 +25901,82 @@ static void dateFunc(
}
/*
+** Compute the number of days after the most recent January 1.
+**
+** In other words, compute the zero-based day number for the
+** current year:
+**
+** Jan01 = 0, Jan02 = 1, ..., Jan31 = 30, Feb01 = 31, ...
+** Dec31 = 364 or 365.
+*/
+static int daysAfterJan01(DateTime *pDate){
+ DateTime jan01 = *pDate;
+ assert( jan01.validYMD );
+ assert( jan01.validHMS );
+ assert( pDate->validJD );
+ jan01.validJD = 0;
+ jan01.M = 1;
+ jan01.D = 1;
+ computeJD(&jan01);
+ return (int)((pDate->iJD-jan01.iJD+43200000)/86400000);
+}
+
+/*
+** Return the number of days after the most recent Monday.
+**
+** In other words, return the day of the week according
+** to this code:
+**
+** 0=Monday, 1=Tuesday, 2=Wednesday, ..., 6=Sunday.
+*/
+static int daysAfterMonday(DateTime *pDate){
+ assert( pDate->validJD );
+ return (int)((pDate->iJD+43200000)/86400000) % 7;
+}
+
+/*
+** Return the number of days after the most recent Sunday.
+**
+** In other words, return the day of the week according
+** to this code:
+**
+** 0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday
+*/
+static int daysAfterSunday(DateTime *pDate){
+ assert( pDate->validJD );
+ return (int)((pDate->iJD+129600000)/86400000) % 7;
+}
+
+/*
** strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
**
** Return a string described by FORMAT. Conversions as follows:
**
-** %d day of month
+** %d day of month 01-31
+** %e day of month 1-31
** %f ** fractional seconds SS.SSS
+** %F ISO date. YYYY-MM-DD
+** %G ISO year corresponding to %V 0000-9999.
+** %g 2-digit ISO year corresponding to %V 00-99
** %H hour 00-24
-** %j day of year 000-366
+** %k hour 0-24 (leading zero converted to space)
+** %I hour 01-12
+** %j day of year 001-366
** %J ** julian day number
+** %l hour 1-12 (leading zero converted to space)
** %m month 01-12
** %M minute 00-59
+** %p "am" or "pm"
+** %P "AM" or "PM"
+** %R time as HH:MM
** %s seconds since 1970-01-01
** %S seconds 00-59
-** %w day of week 0-6 sunday==0
-** %W week of year 00-53
+** %T time as HH:MM:SS
+** %u day of week 1-7 Monday==1, Sunday==7
+** %w day of week 0-6 Sunday==0, Monday==1
+** %U week of year 00-53 (First Sunday is start of week 01)
+** %V week of year 01-53 (First week containing Thursday is week 01)
+** %W week of year 00-53 (First Monday is start of week 01)
** %Y year 0000-9999
** %% %
*/
@@ -24752,44 +26001,61 @@ static void strftimeFunc(
computeJD(&x);
computeYMD_HMS(&x);
for(i=j=0; zFmt[i]; i++){
+ char cf;
if( zFmt[i]!='%' ) continue;
if( j<i ) wx_sqlite3_str_append(&sRes, zFmt+j, (int)(i-j));
i++;
j = i + 1;
- switch( zFmt[i] ){
- case 'd': {
- wx_sqlite3_str_appendf(&sRes, "%02d", x.D);
+ cf = zFmt[i];
+ switch( cf ){
+ case 'd': /* Fall thru */
+ case 'e': {
+ wx_sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D);
break;
}
- case 'f': {
+ case 'f': { /* Fractional seconds. (Non-standard) */
double s = x.s;
if( s>59.999 ) s = 59.999;
wx_sqlite3_str_appendf(&sRes, "%06.3f", s);
break;
}
- case 'H': {
- wx_sqlite3_str_appendf(&sRes, "%02d", x.h);
+ case 'F': {
+ wx_sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D);
break;
}
- case 'W': /* Fall thru */
- case 'j': {
- int nDay; /* Number of days since 1st day of year */
+ case 'G': /* Fall thru */
+ case 'g': {
DateTime y = x;
- y.validJD = 0;
- y.M = 1;
- y.D = 1;
- computeJD(&y);
- nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
- if( zFmt[i]=='W' ){
- int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
- wd = (int)(((x.iJD+43200000)/86400000)%7);
- wx_sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7);
+ assert( y.validJD );
+ /* Move y so that it is the Thursday in the same week as x */
+ y.iJD += (3 - daysAfterMonday(&x))*86400000;
+ y.validYMD = 0;
+ computeYMD(&y);
+ if( cf=='g' ){
+ wx_sqlite3_str_appendf(&sRes, "%02d", y.Y%100);
}else{
- wx_sqlite3_str_appendf(&sRes,"%03d",nDay+1);
+ wx_sqlite3_str_appendf(&sRes, "%04d", y.Y);
}
break;
}
- case 'J': {
+ case 'H':
+ case 'k': {
+ wx_sqlite3_str_appendf(&sRes, cf=='H' ? "%02d" : "%2d", x.h);
+ break;
+ }
+ case 'I': /* Fall thru */
+ case 'l': {
+ int h = x.h;
+ if( h>12 ) h -= 12;
+ if( h==0 ) h = 12;
+ wx_sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h);
+ break;
+ }
+ case 'j': { /* Day of year. Jan01==1, Jan02==2, and so forth */
+ wx_sqlite3_str_appendf(&sRes,"%03d",daysAfterJan01(&x)+1);
+ break;
+ }
+ case 'J': { /* Julian day number. (Non-standard) */
wx_sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0);
break;
}
@@ -24801,18 +26067,62 @@ static void strftimeFunc(
wx_sqlite3_str_appendf(&sRes,"%02d",x.m);
break;
}
+ case 'p': /* Fall thru */
+ case 'P': {
+ if( x.h>=12 ){
+ wx_sqlite3_str_append(&sRes, cf=='p' ? "PM" : "pm", 2);
+ }else{
+ wx_sqlite3_str_append(&sRes, cf=='p' ? "AM" : "am", 2);
+ }
+ break;
+ }
+ case 'R': {
+ wx_sqlite3_str_appendf(&sRes, "%02d:%02d", x.h, x.m);
+ break;
+ }
case 's': {
- i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
- wx_sqlite3_str_appendf(&sRes,"%lld",iS);
+ if( x.useSubsec ){
+ wx_sqlite3_str_appendf(&sRes,"%.3f",
+ (x.iJD - 21086676*(i64)10000000)/1000.0);
+ }else{
+ i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
+ wx_sqlite3_str_appendf(&sRes,"%lld",iS);
+ }
break;
}
case 'S': {
wx_sqlite3_str_appendf(&sRes,"%02d",(int)x.s);
break;
}
- case 'w': {
- wx_sqlite3_str_appendchar(&sRes, 1,
- (char)(((x.iJD+129600000)/86400000) % 7) + '0');
+ case 'T': {
+ wx_sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s);
+ break;
+ }
+ case 'u': /* Day of week. 1 to 7. Monday==1, Sunday==7 */
+ case 'w': { /* Day of week. 0 to 6. Sunday==0, Monday==1 */
+ char c = (char)daysAfterSunday(&x) + '0';
+ if( c=='0' && cf=='u' ) c = '7';
+ wx_sqlite3_str_appendchar(&sRes, 1, c);
+ break;
+ }
+ case 'U': { /* Week num. 00-53. First Sun of the year is week 01 */
+ wx_sqlite3_str_appendf(&sRes,"%02d",
+ (daysAfterJan01(&x)-daysAfterSunday(&x)+7)/7);
+ break;
+ }
+ case 'V': { /* Week num. 01-53. First week with a Thur is week 01 */
+ DateTime y = x;
+ /* Adjust y so that is the Thursday in the same week as x */
+ assert( y.validJD );
+ y.iJD += (3 - daysAfterMonday(&x))*86400000;
+ y.validYMD = 0;
+ computeYMD(&y);
+ wx_sqlite3_str_appendf(&sRes,"%02d", daysAfterJan01(&y)/7+1);
+ break;
+ }
+ case 'W': { /* Week num. 00-53. First Mon of the year is week 01 */
+ wx_sqlite3_str_appendf(&sRes,"%02d",
+ (daysAfterJan01(&x)-daysAfterMonday(&x)+7)/7);
break;
}
case 'Y': {
@@ -24862,6 +26172,115 @@ static void cdateFunc(
}
/*
+** timediff(DATE1, DATE2)
+**
+** Return the amount of time that must be added to DATE2 in order to
+** convert it into DATE2. The time difference format is:
+**
+** +YYYY-MM-DD HH:MM:SS.SSS
+**
+** The initial "+" becomes "-" if DATE1 occurs before DATE2. For
+** date/time values A and B, the following invariant should hold:
+**
+** datetime(A) == (datetime(B, timediff(A,B))
+**
+** Both DATE arguments must be either a julian day number, or an
+** ISO-8601 string. The unix timestamps are not supported by this
+** routine.
+*/
+static void timediffFunc(
+ wx_sqlite3_context *context,
+ int NotUsed1,
+ wx_sqlite3_value **argv
+){
+ char sign;
+ int Y, M;
+ DateTime d1, d2;
+ wx_sqlite3_str sRes;
+ UNUSED_PARAMETER(NotUsed1);
+ if( isDate(context, 1, &argv[0], &d1) ) return;
+ if( isDate(context, 1, &argv[1], &d2) ) return;
+ computeYMD_HMS(&d1);
+ computeYMD_HMS(&d2);
+ if( d1.iJD>=d2.iJD ){
+ sign = '+';
+ Y = d1.Y - d2.Y;
+ if( Y ){
+ d2.Y = d1.Y;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ M = d1.M - d2.M;
+ if( M<0 ){
+ Y--;
+ M += 12;
+ }
+ if( M!=0 ){
+ d2.M = d1.M;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ while( d1.iJD<d2.iJD ){
+ M--;
+ if( M<0 ){
+ M = 11;
+ Y--;
+ }
+ d2.M--;
+ if( d2.M<1 ){
+ d2.M = 12;
+ d2.Y--;
+ }
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ d1.iJD -= d2.iJD;
+ d1.iJD += (u64)1486995408 * (u64)100000;
+ }else /* d1<d2 */{
+ sign = '-';
+ Y = d2.Y - d1.Y;
+ if( Y ){
+ d2.Y = d1.Y;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ M = d2.M - d1.M;
+ if( M<0 ){
+ Y--;
+ M += 12;
+ }
+ if( M!=0 ){
+ d2.M = d1.M;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ while( d1.iJD>d2.iJD ){
+ M--;
+ if( M<0 ){
+ M = 11;
+ Y--;
+ }
+ d2.M++;
+ if( d2.M>12 ){
+ d2.M = 1;
+ d2.Y++;
+ }
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ d1.iJD = d2.iJD - d1.iJD;
+ d1.iJD += (u64)1486995408 * (u64)100000;
+ }
+ clearYMD_HMS_TZ(&d1);
+ computeYMD_HMS(&d1);
+ wx_sqlite3StrAccumInit(&sRes, 0, 0, 0, 100);
+ wx_sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f",
+ sign, Y, M, d1.D-1, d1.h, d1.m, d1.s);
+ wx_sqlite3ResultStrAccum(context, &sRes);
+}
+
+
+/*
** current_timestamp()
**
** This function returns the same value as datetime('now').
@@ -24921,6 +26340,36 @@ static void currentTimeFunc(
}
#endif
+#if !defined(SQLITE_OMIT_DATETIME_FUNCS) && defined(SQLITE_DEBUG)
+/*
+** datedebug(...)
+**
+** This routine returns JSON that describes the internal DateTime object.
+** Used for debugging and testing only. Subject to change.
+*/
+static void datedebugFunc(
+ wx_sqlite3_context *context,
+ int argc,
+ wx_sqlite3_value **argv
+){
+ DateTime x;
+ if( isDate(context, argc, argv, &x)==0 ){
+ char *zJson;
+ zJson = wx_sqlite3_mprintf(
+ "{iJD:%lld,Y:%d,M:%d,D:%d,h:%d,m:%d,tz:%d,"
+ "s:%.3f,validJD:%d,validYMS:%d,validHMS:%d,"
+ "nFloor:%d,rawS:%d,isError:%d,useSubsec:%d,"
+ "isUtc:%d,isLocal:%d}",
+ x.iJD, x.Y, x.M, x.D, x.h, x.m, x.tz,
+ x.s, x.validJD, x.validYMD, x.validHMS,
+ x.nFloor, x.rawS, x.isError, x.useSubsec,
+ x.isUtc, x.isLocal);
+ wx_sqlite3_result_text(context, zJson, -1, wx_sqlite3_free);
+ }
+}
+#endif /* !SQLITE_OMIT_DATETIME_FUNCS && SQLITE_DEBUG */
+
+
/*
** This function registered all of the above C functions as SQL
** functions. This should be the only routine in this file with
@@ -24935,6 +26384,10 @@ SQLITE_PRIVATE void wx_sqlite3RegisterDateTimeFunctions(void){
PURE_DATE(time, -1, 0, 0, timeFunc ),
PURE_DATE(datetime, -1, 0, 0, datetimeFunc ),
PURE_DATE(strftime, -1, 0, 0, strftimeFunc ),
+ PURE_DATE(timediff, 2, 0, 0, timediffFunc ),
+#ifdef SQLITE_DEBUG
+ PURE_DATE(datedebug, -1, 0, 0, datedebugFunc ),
+#endif
DFUNCTION(current_time, 0, 0, 0, ctimeFunc ),
DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
DFUNCTION(current_date, 0, 0, 0, cdateFunc ),
@@ -25088,7 +26541,7 @@ SQLITE_PRIVATE int wx_sqlite3OsFileControl(wx_sqlite3_file *id, int op, void *pA
/* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
** is using a regular VFS, it is called after the corresponding
** transaction has been committed. Injecting a fault at this point
- ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
+ ** confuses the test scripts - the COMMIT command returns SQLITE_NOMEM
** but the transaction is committed anyway.
**
** The core must call OsFileControl() though, not OsFileControlHint(),
@@ -25709,7 +27162,7 @@ static void *wx_sqlite3MemMalloc(int nByte){
** or wx_sqlite3MemRealloc().
**
** For this low-level routine, we already know that pPrior!=0 since
-** cases where pPrior==0 will have been intecepted and dealt with
+** cases where pPrior==0 will have been intercepted and dealt with
** by higher-level routines.
*/
static void wx_sqlite3MemFree(void *pPrior){
@@ -25797,7 +27250,7 @@ static int wx_sqlite3MemInit(void *NotUsed){
return SQLITE_OK;
}
len = sizeof(cpuCount);
- /* One usually wants to use hw.acctivecpu for MT decisions, but not here */
+ /* One usually wants to use hw.activecpu for MT decisions, but not here */
sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0);
if( cpuCount>1 ){
/* defer MT decisions to system malloc */
@@ -27789,7 +29242,7 @@ static void checkMutexFree(wx_sqlite3_mutex *p){
assert( SQLITE_MUTEX_FAST<2 );
assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( ((CheckMutex*)p)->iType<2 )
#endif
{
@@ -28003,16 +29456,29 @@ SQLITE_API void wx_sqlite3_mutex_leave(wx_sqlite3_mutex *p){
/*
** The wx_sqlite3_mutex_held() and wx_sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
+**
+** Because these routines raise false-positive alerts in TSAN, disable
+** them (make them always return 1) when compiling with TSAN.
*/
SQLITE_API int wx_sqlite3_mutex_held(wx_sqlite3_mutex *p){
+# if defined(__has_feature)
+# if __has_feature(thread_sanitizer)
+ p = 0;
+# endif
+# endif
assert( p==0 || wx_sqlite3GlobalConfig.mutex.xMutexHeld );
return p==0 || wx_sqlite3GlobalConfig.mutex.xMutexHeld(p);
}
SQLITE_API int wx_sqlite3_mutex_notheld(wx_sqlite3_mutex *p){
+# if defined(__has_feature)
+# if __has_feature(thread_sanitizer)
+ p = 0;
+# endif
+# endif
assert( p==0 || wx_sqlite3GlobalConfig.mutex.xMutexNotheld );
return p==0 || wx_sqlite3GlobalConfig.mutex.xMutexNotheld(p);
}
-#endif
+#endif /* NDEBUG */
#endif /* !defined(SQLITE_MUTEX_OMIT) */
@@ -28264,7 +29730,7 @@ SQLITE_PRIVATE wx_sqlite3_mutex_methods const *wx_sqlite3DefaultMutex(void){
/*
** The wx_sqlite3_mutex.id, wx_sqlite3_mutex.nRef, and wx_sqlite3_mutex.owner fields
-** are necessary under two condidtions: (1) Debug builds and (2) using
+** are necessary under two conditions: (1) Debug builds and (2) using
** home-grown mutexes. Encapsulate these conditions into a single #define.
*/
#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX)
@@ -28461,7 +29927,7 @@ static wx_sqlite3_mutex *pthreadMutexAlloc(int iType){
*/
static void pthreadMutexFree(wx_sqlite3_mutex *p){
assert( p->nRef==0 );
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE )
#endif
{
@@ -28765,7 +30231,7 @@ struct wx_sqlite3_mutex {
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
#ifdef SQLITE_DEBUG
- volatile int nRef; /* Number of enterances */
+ volatile int nRef; /* Number of entrances */
volatile DWORD owner; /* Thread holding this mutex */
volatile LONG trace; /* True to trace changes */
#endif
@@ -28814,7 +30280,7 @@ SQLITE_PRIVATE void wx_sqlite3MemoryBarrier(void){
SQLITE_MEMORY_BARRIER;
#elif defined(__GNUC__)
__sync_synchronize();
-#elif MSVC_VERSION>=1300
+#elif MSVC_VERSION>=1400
_ReadWriteBarrier();
#elif defined(MemoryBarrier)
MemoryBarrier();
@@ -29298,6 +30764,12 @@ SQLITE_PRIVATE int wx_sqlite3MallocInit(void){
}
rc = wx_sqlite3GlobalConfig.m.xInit(wx_sqlite3GlobalConfig.m.pAppData);
if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0));
+
+ /* Initialize wrapper for memory management.*/
+ if( rc==SQLITE_OK ) {
+ wx_sqlite3mcInitMemoryMethods();
+ }
+
return rc;
}
@@ -29350,6 +30822,24 @@ static void wx_sqlite3MallocAlarm(int nByte){
wx_sqlite3_mutex_enter(mem0.mutex);
}
+#ifdef SQLITE_DEBUG
+/*
+** This routine is called whenever an out-of-memory condition is seen,
+** It's only purpose to to serve as a breakpoint for gdb or similar
+** code debuggers when working on out-of-memory conditions, for example
+** caused by PRAGMA hard_heap_limit=N.
+*/
+static SQLITE_NOINLINE void test_oom_breakpoint(u64 n){
+ static u64 nOomFault = 0;
+ nOomFault += n;
+ /* The assert() is never reached in a human lifetime. It is here mostly
+ ** to prevent code optimizers from optimizing out this function. */
+ assert( (nOomFault>>32) < 0xffffffff );
+}
+#else
+# define test_oom_breakpoint(X) /* No-op for production builds */
+#endif
+
/*
** Do a memory allocation with statistics and alarms. Assume the
** lock is already held.
@@ -29376,6 +30866,7 @@ static void mallocWithAlarm(int n, void **pp){
if( mem0.hardLimit ){
nUsed = wx_sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.hardLimit - nFull ){
+ test_oom_breakpoint(1);
*pp = 0;
return;
}
@@ -29664,6 +31155,7 @@ SQLITE_PRIVATE void *wx_sqlite3Realloc(void *pOld, u64 nBytes){
wx_sqlite3MallocAlarm(nDiff);
if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){
wx_sqlite3_mutex_leave(mem0.mutex);
+ test_oom_breakpoint(1);
return 0;
}
}
@@ -30025,7 +31517,7 @@ SQLITE_PRIVATE int wx_sqlite3ApiExit(wx_sqlite3* db, int rc){
if( db->mallocFailed || rc ){
return apiHandleError(db, rc);
}
- return rc & db->errMask;
+ return 0;
}
/************** End of malloc.c **********************************************/
@@ -30137,43 +31629,6 @@ static const et_info fmtinfo[] = {
** %!S Like %S but prefer the zName over the zAlias
*/
-/* Floating point constants used for rounding */
-static const double arRound[] = {
- 5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05,
- 5.0e-06, 5.0e-07, 5.0e-08, 5.0e-09, 5.0e-10,
-};
-
-/*
-** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
-** conversions will work.
-*/
-#ifndef SQLITE_OMIT_FLOATING_POINT
-/*
-** "*val" is a double such that 0.1 <= *val < 10.0
-** Return the ascii code for the leading digit of *val, then
-** multiply "*val" by 10.0 to renormalize.
-**
-** Example:
-** input: *val = 3.14159
-** output: *val = 1.4159 function return = '3'
-**
-** The counter *cnt is incremented each time. After counter exceeds
-** 16 (the number of significant digits in a 64-bit float) '0' is
-** always returned.
-*/
-static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
- int digit;
- LONGDOUBLE_TYPE d;
- if( (*cnt)<=0 ) return '0';
- (*cnt)--;
- digit = (int)*val;
- d = digit;
- digit += '0';
- *val = (*val - d)*10.0;
- return (char)digit;
-}
-#endif /* SQLITE_OMIT_FLOATING_POINT */
-
/*
** Set the StrAccum object to an error mode.
*/
@@ -30265,18 +31720,15 @@ SQLITE_API void wx_sqlite3_str_vappendf(
u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
sqlite_uint64 longvalue; /* Value for integer types */
- LONGDOUBLE_TYPE realvalue; /* Value for real types */
+ double realvalue; /* Value for real types */
const et_info *infop; /* Pointer to the appropriate info structure */
char *zOut; /* Rendering buffer */
int nOut; /* Size of the rendering buffer */
char *zExtra = 0; /* Malloced memory used by some conversion */
-#ifndef SQLITE_OMIT_FLOATING_POINT
- int exp, e2; /* exponent of real numbers */
- int nsd; /* Number of significant digits returned */
- double rounder; /* Used for rounding floating point values */
+ int exp, e2; /* exponent of real numbers */
etByte flag_dp; /* True if decimal point should be shown */
etByte flag_rtz; /* True if trailing zeros should be removed */
-#endif
+
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
char buf[etBUFSIZE]; /* Conversion buffer */
@@ -30551,74 +32003,69 @@ SQLITE_API void wx_sqlite3_str_vappendf(
break;
case etFLOAT:
case etEXP:
- case etGENERIC:
+ case etGENERIC: {
+ FpDecode s;
+ int iRound;
+ int j;
+
if( bArgList ){
realvalue = getDoubleArg(pArgList);
}else{
realvalue = va_arg(ap,double);
}
-#ifdef SQLITE_OMIT_FLOATING_POINT
- length = 0;
-#else
if( precision<0 ) precision = 6; /* Set default precision */
#ifdef SQLITE_FP_PRECISION_LIMIT
if( precision>SQLITE_FP_PRECISION_LIMIT ){
precision = SQLITE_FP_PRECISION_LIMIT;
}
#endif
- if( realvalue<0.0 ){
- realvalue = -realvalue;
- prefix = '-';
- }else{
- prefix = flag_prefix;
- }
- if( xtype==etGENERIC && precision>0 ) precision--;
- testcase( precision>0xfff );
- idx = precision & 0xfff;
- rounder = arRound[idx%10];
- while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; }
if( xtype==etFLOAT ){
- double rx = (double)realvalue;
- wx_sqlite3_uint64 u;
- int ex;
- memcpy(&u, &rx, sizeof(u));
- ex = -1023 + (int)((u>>52)&0x7ff);
- if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16;
- realvalue += rounder;
- }
- /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
- exp = 0;
- if( wx_sqlite3IsNaN((double)realvalue) ){
- bufpt = "NaN";
- length = 3;
- break;
+ iRound = -precision;
+ }else if( xtype==etGENERIC ){
+ if( precision==0 ) precision = 1;
+ iRound = precision;
+ }else{
+ iRound = precision+1;
}
- if( realvalue>0.0 ){
- LONGDOUBLE_TYPE scale = 1.0;
- while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;}
- while( realvalue>=1e10*scale && exp<=350 ){ scale *= 1e10; exp+=10; }
- while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
- realvalue /= scale;
- while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
- while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
- if( exp>350 ){
+ wx_sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16);
+ if( s.isSpecial ){
+ if( s.isSpecial==2 ){
+ bufpt = flag_zeropad ? "null" : "NaN";
+ length = wx_sqlite3Strlen30(bufpt);
+ break;
+ }else if( flag_zeropad ){
+ s.z[0] = '9';
+ s.iDP = 1000;
+ s.n = 1;
+ }else{
+ memcpy(buf, "-Inf", 5);
bufpt = buf;
- buf[0] = prefix;
- memcpy(buf+(prefix!=0),"Inf",4);
- length = 3+(prefix!=0);
+ if( s.sign=='-' ){
+ /* no-op */
+ }else if( flag_prefix ){
+ buf[0] = flag_prefix;
+ }else{
+ bufpt++;
+ }
+ length = wx_sqlite3Strlen30(bufpt);
break;
}
}
- bufpt = buf;
+ if( s.sign=='-' ){
+ prefix = '-';
+ }else{
+ prefix = flag_prefix;
+ }
+
+ exp = s.iDP-1;
+
/*
** If the field type is etGENERIC, then convert to either etEXP
** or etFLOAT, as appropriate.
*/
- if( xtype!=etFLOAT ){
- realvalue += rounder;
- if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
- }
if( xtype==etGENERIC ){
+ assert( precision>0 );
+ precision--;
flag_rtz = !flag_alternateform;
if( exp<-4 || exp>precision ){
xtype = etEXP;
@@ -30632,29 +32079,32 @@ SQLITE_API void wx_sqlite3_str_vappendf(
if( xtype==etEXP ){
e2 = 0;
}else{
- e2 = exp;
+ e2 = s.iDP - 1;
}
+ bufpt = buf;
{
i64 szBufNeeded; /* Size of a temporary buffer needed */
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15;
+ if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
if( szBufNeeded > etBUFSIZE ){
bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded);
if( bufpt==0 ) return;
}
}
zOut = bufpt;
- nsd = 16 + flag_altform2*10;
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
/* The sign in front of the number */
if( prefix ){
*(bufpt++) = prefix;
}
/* Digits prior to the decimal point */
+ j = 0;
if( e2<0 ){
*(bufpt++) = '0';
}else{
for(; e2>=0; e2--){
- *(bufpt++) = et_getdigit(&realvalue,&nsd);
+ *(bufpt++) = j<s.n ? s.z[j++] : '0';
+ if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
}
}
/* The decimal point */
@@ -30663,13 +32113,12 @@ SQLITE_API void wx_sqlite3_str_vappendf(
}
/* "0" digits after the decimal point but before the first
** significant digit of the number */
- for(e2++; e2<0; precision--, e2++){
- assert( precision>0 );
+ for(e2++; e2<0 && precision>0; precision--, e2++){
*(bufpt++) = '0';
}
/* Significant digits after the decimal point */
while( (precision--)>0 ){
- *(bufpt++) = et_getdigit(&realvalue,&nsd);
+ *(bufpt++) = j<s.n ? s.z[j++] : '0';
}
/* Remove trailing zeros and the "." if no digits follow the "." */
if( flag_rtz && flag_dp ){
@@ -30685,6 +32134,7 @@ SQLITE_API void wx_sqlite3_str_vappendf(
}
/* Add the "eNNN" suffix */
if( xtype==etEXP ){
+ exp = s.iDP - 1;
*(bufpt++) = aDigits[infop->charset];
if( exp<0 ){
*(bufpt++) = '-'; exp = -exp;
@@ -30718,8 +32168,8 @@ SQLITE_API void wx_sqlite3_str_vappendf(
while( nPad-- ) bufpt[i++] = '0';
length = width;
}
-#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */
break;
+ }
case etSIZE:
if( !bArgList ){
*(va_arg(ap,int*)) = pAccum->nChar;
@@ -30922,18 +32372,25 @@ SQLITE_API void wx_sqlite3_str_vappendf(
if( pItem->zAlias && !flag_altform2 ){
wx_sqlite3_str_appendall(pAccum, pItem->zAlias);
}else if( pItem->zName ){
- if( pItem->zDatabase ){
- wx_sqlite3_str_appendall(pAccum, pItem->zDatabase);
+ if( pItem->fg.fixedSchema==0
+ && pItem->fg.isSubquery==0
+ && pItem->u4.zDatabase!=0
+ ){
+ wx_sqlite3_str_appendall(pAccum, pItem->u4.zDatabase);
wx_sqlite3_str_append(pAccum, ".", 1);
}
wx_sqlite3_str_appendall(pAccum, pItem->zName);
}else if( pItem->zAlias ){
wx_sqlite3_str_appendall(pAccum, pItem->zAlias);
- }else{
- Select *pSel = pItem->pSelect;
+ }else if( ALWAYS(pItem->fg.isSubquery) ){/* Because of tag-20240424-1 */
+ Select *pSel = pItem->u4.pSubq->pSelect;
assert( pSel!=0 );
if( pSel->selFlags & SF_NestedFrom ){
wx_sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
+ }else if( pSel->selFlags & SF_MultiValue ){
+ assert( !pItem->fg.isTabFunc && !pItem->fg.isIndexedBy );
+ wx_sqlite3_str_appendf(pAccum, "%u-ROW VALUES CLAUSE",
+ pItem->u1.nRow);
}else{
wx_sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId);
}
@@ -31005,6 +32462,7 @@ SQLITE_PRIVATE void wx_sqlite3RecordErrorOffsetOfExpr(wx_sqlite3 *db, const Expr
pExpr = pExpr->pLeft;
}
if( pExpr==0 ) return;
+ if( ExprHasProperty(pExpr, EP_FromDDL) ) return;
db->errByteOffset = pExpr->w.iOfst;
}
@@ -31350,12 +32808,22 @@ SQLITE_API char *wx_sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va
return zBuf;
}
SQLITE_API char *wx_sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
- char *z;
+ StrAccum acc;
va_list ap;
+ if( n<=0 ) return zBuf;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zBuf==0 || zFormat==0 ) {
+ (void)SQLITE_MISUSE_BKPT;
+ if( zBuf ) zBuf[0] = 0;
+ return zBuf;
+ }
+#endif
+ wx_sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
va_start(ap,zFormat);
- z = wx_sqlite3_vsnprintf(n, zBuf, zFormat, ap);
+ wx_sqlite3_str_vappendf(&acc, zFormat, ap);
va_end(ap);
- return z;
+ zBuf[acc.nChar] = 0;
+ return zBuf;
}
/*
@@ -31433,6 +32901,75 @@ SQLITE_API void wx_sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){
va_end(ap);
}
+
+/*****************************************************************************
+** Reference counted string/blob storage
+*****************************************************************************/
+
+/*
+** Increase the reference count of the string by one.
+**
+** The input parameter is returned.
+*/
+SQLITE_PRIVATE char *wx_sqlite3RCStrRef(char *z){
+ RCStr *p = (RCStr*)z;
+ assert( p!=0 );
+ p--;
+ p->nRCRef++;
+ return z;
+}
+
+/*
+** Decrease the reference count by one. Free the string when the
+** reference count reaches zero.
+*/
+SQLITE_PRIVATE void wx_sqlite3RCStrUnref(void *z){
+ RCStr *p = (RCStr*)z;
+ assert( p!=0 );
+ p--;
+ assert( p->nRCRef>0 );
+ if( p->nRCRef>=2 ){
+ p->nRCRef--;
+ }else{
+ wx_sqlite3_free(p);
+ }
+}
+
+/*
+** Create a new string that is capable of holding N bytes of text, not counting
+** the zero byte at the end. The string is uninitialized.
+**
+** The reference count is initially 1. Call wx_sqlite3RCStrUnref() to free the
+** newly allocated string.
+**
+** This routine returns 0 on an OOM.
+*/
+SQLITE_PRIVATE char *wx_sqlite3RCStrNew(u64 N){
+ RCStr *p = wx_sqlite3_malloc64( N + sizeof(*p) + 1 );
+ if( p==0 ) return 0;
+ p->nRCRef = 1;
+ return (char*)&p[1];
+}
+
+/*
+** Change the size of the string so that it is able to hold N bytes.
+** The string might be reallocated, so return the new allocation.
+*/
+SQLITE_PRIVATE char *wx_sqlite3RCStrResize(char *z, u64 N){
+ RCStr *p = (RCStr*)z;
+ RCStr *pNew;
+ assert( p!=0 );
+ p--;
+ assert( p->nRCRef==1 );
+ pNew = wx_sqlite3_realloc64(p, N+sizeof(RCStr)+1);
+ if( pNew==0 ){
+ wx_sqlite3_free(p);
+ return 0;
+ }else{
+ return (char*)&pNew[1];
+ }
+}
+
/************** End of printf.c **********************************************/
/************** Begin file treeview.c ****************************************/
/*
@@ -31630,9 +33167,11 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pS
wx_sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
x.printfFlags |= SQLITE_PRINTF_INTERNAL;
wx_sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem);
- if( pItem->pTab ){
- wx_sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx",
- pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed);
+ if( pItem->pSTab ){
+ wx_sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s",
+ pItem->pSTab->zName, pItem->pSTab->nCol, pItem->pSTab,
+ pItem->colUsed,
+ pItem->fg.rowidUsed ? "+rowid" : "");
}
if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){
wx_sqlite3_str_appendf(&x, " FULL-OUTER-JOIN");
@@ -31661,23 +33200,30 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pS
if( pItem->fg.viaCoroutine ) wx_sqlite3_str_appendf(&x, " viaCoroutine");
if( pItem->fg.notCte ) wx_sqlite3_str_appendf(&x, " notCte");
if( pItem->fg.isNestedFrom ) wx_sqlite3_str_appendf(&x, " isNestedFrom");
+ if( pItem->fg.fixedSchema ) wx_sqlite3_str_appendf(&x, " fixedSchema");
+ if( pItem->fg.hadSchema ) wx_sqlite3_str_appendf(&x, " hadSchema");
+ if( pItem->fg.isSubquery ) wx_sqlite3_str_appendf(&x, " isSubquery");
wx_sqlite3StrAccumFinish(&x);
wx_sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
n = 0;
- if( pItem->pSelect ) n++;
+ if( pItem->fg.isSubquery ) n++;
if( pItem->fg.isTabFunc ) n++;
if( pItem->fg.isUsing ) n++;
if( pItem->fg.isUsing ){
wx_sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING");
}
- if( pItem->pSelect ){
- if( pItem->pTab ){
- Table *pTab = pItem->pTab;
+ if( pItem->fg.isSubquery ){
+ assert( n==1 );
+ if( pItem->pSTab ){
+ Table *pTab = pItem->pSTab;
wx_sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
}
- assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
- wx_sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0);
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
+ wx_sqlite3TreeViewPush(&pView, 0);
+ wx_sqlite3TreeViewLine(pView, "SUBQUERY");
+ wx_sqlite3TreeViewPop(&pView);
+ wx_sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, 0);
}
if( pItem->fg.isTabFunc ){
wx_sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
@@ -31719,7 +33265,7 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewSelect(TreeView *pView, const Select *p, u
n = 1000;
}else{
n = 0;
- if( p->pSrc && p->pSrc->nSrc ) n++;
+ if( p->pSrc && p->pSrc->nSrc && p->pSrc->nAlloc ) n++;
if( p->pWhere ) n++;
if( p->pGroupBy ) n++;
if( p->pHaving ) n++;
@@ -31745,7 +33291,7 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewSelect(TreeView *pView, const Select *p, u
wx_sqlite3TreeViewPop(&pView);
}
#endif
- if( p->pSrc && p->pSrc->nSrc ){
+ if( p->pSrc && p->pSrc->nSrc && p->pSrc->nAlloc ){
wx_sqlite3TreeViewPush(&pView, (n--)>0);
wx_sqlite3TreeViewLine(pView, "FROM");
wx_sqlite3TreeViewSrcList(pView, p->pSrc);
@@ -31781,7 +33327,7 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewSelect(TreeView *pView, const Select *p, u
wx_sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
wx_sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0);
if( p->pLimit->pRight ){
- wx_sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
+ wx_sqlite3TreeViewItem(pView, "OFFSET", 0);
wx_sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0);
wx_sqlite3TreeViewPop(&pView);
}
@@ -31849,6 +33395,7 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewWindow(TreeView *pView, const Window *pWin
wx_sqlite3TreeViewItem(pView, "FILTER", 1);
wx_sqlite3TreeViewExpr(pView, pWin->pFilter, 0);
wx_sqlite3TreeViewPop(&pView);
+ if( pWin->eFrmType==TK_FILTER ) return;
}
wx_sqlite3TreeViewPush(&pView, more);
if( pWin->zName ){
@@ -31858,7 +33405,7 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewWindow(TreeView *pView, const Window *pWin
}
if( pWin->zBase ) nElement++;
if( pWin->pOrderBy ) nElement++;
- if( pWin->eFrmType ) nElement++;
+ if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ) nElement++;
if( pWin->eExclude ) nElement++;
if( pWin->zBase ){
wx_sqlite3TreeViewPush(&pView, (--nElement)>0);
@@ -31871,7 +33418,7 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewWindow(TreeView *pView, const Window *pWin
if( pWin->pOrderBy ){
wx_sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY");
}
- if( pWin->eFrmType ){
+ if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ){
char zBuf[30];
const char *zFrmType = "ROWS";
if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE";
@@ -32080,7 +33627,8 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u
};
assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT );
assert( pExpr->pRight );
- assert( wx_sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE );
+ assert( wx_sqlite3ExprSkipCollateAndLikely(pExpr->pRight)->op
+ == TK_TRUEFALSE );
x = (pExpr->op2==TK_ISNOT)*2 + wx_sqlite3ExprTruthValue(pExpr->pRight);
zUniOp = azOp[x];
break;
@@ -32118,7 +33666,7 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u
assert( ExprUseXList(pExpr) );
pFarg = pExpr->x.pList;
#ifndef SQLITE_OMIT_WINDOWFUNC
- pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0;
+ pWin = IsWindowFunc(pExpr) ? pExpr->y.pWin : 0;
#else
pWin = 0;
#endif
@@ -32144,7 +33692,13 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u
wx_sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs);
}
if( pFarg ){
- wx_sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);
+ wx_sqlite3TreeViewExprList(pView, pFarg, pWin!=0 || pExpr->pLeft, 0);
+ if( pExpr->pLeft ){
+ Expr *pOB = pExpr->pLeft;
+ assert( pOB->op==TK_ORDER );
+ assert( ExprUseXList(pOB) );
+ wx_sqlite3TreeViewExprList(pView, pOB->x.pList, pWin!=0, "ORDERBY");
+ }
}
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pWin ){
@@ -32153,6 +33707,10 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u
#endif
break;
}
+ case TK_ORDER: {
+ wx_sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, "ORDERBY");
+ break;
+ }
#ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS: {
assert( ExprUseXSelect(pExpr) );
@@ -32206,7 +33764,7 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u
assert( pExpr->x.pList->nExpr==2 );
pY = pExpr->x.pList->a[0].pExpr;
pZ = pExpr->x.pList->a[1].pExpr;
- wx_sqlite3TreeViewLine(pView, "BETWEEN");
+ wx_sqlite3TreeViewLine(pView, "BETWEEN%s", zFlgs);
wx_sqlite3TreeViewExpr(pView, pX, 1);
wx_sqlite3TreeViewExpr(pView, pY, 1);
wx_sqlite3TreeViewExpr(pView, pZ, 0);
@@ -32241,7 +33799,8 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u
case OE_Ignore: zType = "ignore"; break;
}
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- wx_sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken);
+ wx_sqlite3TreeViewLine(pView, "RAISE %s", zType);
+ wx_sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
break;
}
#endif
@@ -32321,9 +33880,10 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewBareExprList(
wx_sqlite3TreeViewLine(pView, "%s", zLabel);
for(i=0; i<pList->nExpr; i++){
int j = pList->a[i].u.x.iOrderByCol;
+ u8 sortFlags = pList->a[i].fg.sortFlags;
char *zName = pList->a[i].zEName;
int moreToFollow = i<pList->nExpr - 1;
- if( j || zName ){
+ if( j || zName || sortFlags ){
wx_sqlite3TreeViewPush(&pView, moreToFollow);
moreToFollow = 0;
wx_sqlite3TreeViewLine(pView, 0);
@@ -32344,13 +33904,18 @@ SQLITE_PRIVATE void wx_sqlite3TreeViewBareExprList(
}
}
if( j ){
- fprintf(stdout, "iOrderByCol=%d", j);
+ fprintf(stdout, "iOrderByCol=%d ", j);
+ }
+ if( sortFlags & KEYINFO_ORDER_DESC ){
+ fprintf(stdout, "DESC ");
+ }else if( sortFlags & KEYINFO_ORDER_BIGNULL ){
+ fprintf(stdout, "NULLS-LAST");
}
fprintf(stdout, "\n");
fflush(stdout);
}
wx_sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow);
- if( j || zName ){
+ if( j || zName || sortFlags ){
wx_sqlite3TreeViewPop(&pView);
}
}
@@ -33313,7 +34878,7 @@ static const unsigned char wx_sqlite3Utf8Trans1[] = {
c = *(zIn++); \
if( c>=0xc0 ){ \
c = wx_sqlite3Utf8Trans1[c-0xc0]; \
- while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
+ while( zIn<zTerm && (*zIn & 0xc0)==0x80 ){ \
c = (c<<6) + (0x3f & *(zIn++)); \
} \
if( c<0x80 \
@@ -33341,7 +34906,38 @@ SQLITE_PRIVATE u32 wx_sqlite3Utf8Read(
return c;
}
-
+/*
+** Read a single UTF8 character out of buffer z[], but reading no
+** more than n characters from the buffer. z[] is not zero-terminated.
+**
+** Return the number of bytes used to construct the character.
+**
+** Invalid UTF8 might generate a strange result. No effort is made
+** to detect invalid UTF8.
+**
+** At most 4 bytes will be read out of z[]. The return value will always
+** be between 1 and 4.
+*/
+SQLITE_PRIVATE int wx_sqlite3Utf8ReadLimited(
+ const u8 *z,
+ int n,
+ u32 *piOut
+){
+ u32 c;
+ int i = 1;
+ assert( n>0 );
+ c = z[0];
+ if( c>=0xc0 ){
+ c = wx_sqlite3Utf8Trans1[c-0xc0];
+ if( n>4 ) n = 4;
+ while( i<n && (z[i] & 0xc0)==0x80 ){
+ c = (c<<6) + (0x3f & z[i]);
+ i++;
+ }
+ }
+ *piOut = c;
+ return i;
+}
/*
@@ -33660,20 +35256,22 @@ SQLITE_PRIVATE char *wx_sqlite3Utf16to8(wx_sqlite3 *db, const void *z, int nByte
}
/*
-** zIn is a UTF-16 encoded unicode string at least nChar characters long.
+** zIn is a UTF-16 encoded unicode string at least nByte bytes long.
** Return the number of bytes in the first nChar unicode characters
-** in pZ. nChar must be non-negative.
+** in pZ. nChar must be non-negative. Surrogate pairs count as a single
+** character.
*/
-SQLITE_PRIVATE int wx_sqlite3Utf16ByteLen(const void *zIn, int nChar){
+SQLITE_PRIVATE int wx_sqlite3Utf16ByteLen(const void *zIn, int nByte, int nChar){
int c;
unsigned char const *z = zIn;
+ unsigned char const *zEnd = &z[nByte-1];
int n = 0;
if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++;
- while( n<nChar ){
+ while( n<nChar && ALWAYS(z<=zEnd) ){
c = z[0];
z += 2;
- if( c>=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
+ if( c>=0xd8 && c<0xdc && z<=zEnd && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
n++;
}
return (int)(z-(unsigned char const *)zIn)
@@ -33739,7 +35337,7 @@ SQLITE_PRIVATE void wx_sqlite3UtfSelfTest(void){
/*
** Calls to wx_sqlite3FaultSim() are used to simulate a failure during testing,
** or to bypass normal error detection during testing in order to let
-** execute proceed futher downstream.
+** execute proceed further downstream.
**
** In deployment, wx_sqlite3FaultSim() *always* return SQLITE_OK (0). The
** wx_sqlite3FaultSim() function only returns non-zero during testing.
@@ -33783,6 +35381,19 @@ SQLITE_PRIVATE int wx_sqlite3IsNaN(double x){
}
#endif /* SQLITE_OMIT_FLOATING_POINT */
+#ifndef SQLITE_OMIT_FLOATING_POINT
+/*
+** Return true if the floating point value is NaN or +Inf or -Inf.
+*/
+SQLITE_PRIVATE int wx_sqlite3IsOverflow(double x){
+ int rc; /* The value return */
+ u64 y;
+ memcpy(&y,&x,sizeof(y));
+ rc = IsOvfl(y);
+ return rc;
+}
+#endif /* SQLITE_OMIT_FLOATING_POINT */
+
/*
** Compute a string length that is limited to what can be stored in
** lower 30 bits of a 32-bit signed integer.
@@ -33856,6 +35467,23 @@ SQLITE_PRIVATE void wx_sqlite3ErrorClear(wx_sqlite3 *db){
*/
SQLITE_PRIVATE void wx_sqlite3SystemError(wx_sqlite3 *db, int rc){
if( rc==SQLITE_IOERR_NOMEM ) return;
+#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
+ if( rc==SQLITE_IOERR_IN_PAGE ){
+ int ii;
+ int iErr;
+ wx_sqlite3BtreeEnterAll(db);
+ for(ii=0; ii<db->nDb; ii++){
+ if( db->aDb[ii].pBt ){
+ iErr = wx_sqlite3PagerWalSystemErrno(wx_sqlite3BtreePager(db->aDb[ii].pBt));
+ if( iErr ){
+ db->iSysErrno = iErr;
+ }
+ }
+ }
+ wx_sqlite3BtreeLeaveAll(db);
+ return;
+ }
+#endif
rc &= 0xff;
if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){
db->iSysErrno = wx_sqlite3OsGetLastError(db->pVfs);
@@ -33900,12 +35528,16 @@ SQLITE_PRIVATE void wx_sqlite3ProgressCheck(Parse *p){
p->rc = SQLITE_INTERRUPT;
}
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- if( db->xProgress && (++p->nProgressSteps)>=db->nProgressOps ){
- if( db->xProgress(db->pProgressArg) ){
- p->nErr++;
- p->rc = SQLITE_INTERRUPT;
+ if( db->xProgress ){
+ if( p->rc==SQLITE_INTERRUPT ){
+ p->nProgressSteps = 0;
+ }else if( (++p->nProgressSteps)>=db->nProgressOps ){
+ if( db->xProgress(db->pProgressArg) ){
+ p->nErr++;
+ p->rc = SQLITE_INTERRUPT;
+ }
+ p->nProgressSteps = 0;
}
- p->nProgressSteps = 0;
}
#endif
}
@@ -34006,6 +35638,44 @@ SQLITE_PRIVATE void wx_sqlite3DequoteExpr(Expr *p){
}
/*
+** Expression p is a QNUMBER (quoted number). Dequote the value in p->u.zToken
+** and set the type to INTEGER or FLOAT. "Quoted" integers or floats are those
+** that contain '_' characters that must be removed before further processing.
+*/
+SQLITE_PRIVATE void wx_sqlite3DequoteNumber(Parse *pParse, Expr *p){
+ assert( p!=0 || pParse->db->mallocFailed );
+ if( p ){
+ const char *pIn = p->u.zToken;
+ char *pOut = p->u.zToken;
+ int bHex = (pIn[0]=='0' && (pIn[1]=='x' || pIn[1]=='X'));
+ int iValue;
+ assert( p->op==TK_QNUMBER );
+ p->op = TK_INTEGER;
+ do {
+ if( *pIn!=SQLITE_DIGIT_SEPARATOR ){
+ *pOut++ = *pIn;
+ if( *pIn=='e' || *pIn=='E' || *pIn=='.' ) p->op = TK_FLOAT;
+ }else{
+ if( (bHex==0 && (!wx_sqlite3Isdigit(pIn[-1]) || !wx_sqlite3Isdigit(pIn[1])))
+ || (bHex==1 && (!wx_sqlite3Isxdigit(pIn[-1]) || !wx_sqlite3Isxdigit(pIn[1])))
+ ){
+ wx_sqlite3ErrorMsg(pParse, "unrecognized token: \"%s\"", p->u.zToken);
+ }
+ }
+ }while( *pIn++ );
+ if( bHex ) p->op = TK_INTEGER;
+
+ /* tag-20240227-a: If after dequoting, the number is an integer that
+ ** fits in 32 bits, then it must be converted into EP_IntValue. Other
+ ** parts of the code expect this. See also tag-20240227-b. */
+ if( p->op==TK_INTEGER && wx_sqlite3GetInt32(p->u.zToken, &iValue) ){
+ p->u.iValue = iValue;
+ p->flags |= EP_IntValue;
+ }
+ }
+}
+
+/*
** If the input token p is quoted, try to adjust the token to remove
** the quotes. This is not always possible:
**
@@ -34101,43 +35771,40 @@ SQLITE_PRIVATE u8 wx_sqlite3StrIHash(const char *z){
return h;
}
-/*
-** Compute 10 to the E-th power. Examples: E==1 results in 10.
-** E==2 results in 100. E==50 results in 1.0e50.
+/* Double-Double multiplication. (x[0],x[1]) *= (y,yy)
**
-** This routine only works for values of E between 1 and 341.
+** Reference:
+** T. J. Dekker, "A Floating-Point Technique for Extending the
+** Available Precision". 1971-07-26.
*/
-static LONGDOUBLE_TYPE wx_sqlite3Pow10(int E){
-#if defined(_MSC_VER)
- static const LONGDOUBLE_TYPE x[] = {
- 1.0e+001L,
- 1.0e+002L,
- 1.0e+004L,
- 1.0e+008L,
- 1.0e+016L,
- 1.0e+032L,
- 1.0e+064L,
- 1.0e+128L,
- 1.0e+256L
- };
- LONGDOUBLE_TYPE r = 1.0;
- int i;
- assert( E>=0 && E<=307 );
- for(i=0; E!=0; i++, E >>=1){
- if( E & 1 ) r *= x[i];
- }
- return r;
-#else
- LONGDOUBLE_TYPE x = 10.0;
- LONGDOUBLE_TYPE r = 1.0;
- while(1){
- if( E & 1 ) r *= x;
- E >>= 1;
- if( E==0 ) break;
- x *= x;
- }
- return r;
-#endif
+static void dekkerMul2(volatile double *x, double y, double yy){
+ /*
+ ** The "volatile" keywords on parameter x[] and on local variables
+ ** below are needed force intermediate results to be truncated to
+ ** binary64 rather than be carried around in an extended-precision
+ ** format. The truncation is necessary for the Dekker algorithm to
+ ** work. Intel x86 floating point might omit the truncation without
+ ** the use of volatile.
+ */
+ volatile double tx, ty, p, q, c, cc;
+ double hx, hy;
+ u64 m;
+ memcpy(&m, (void*)&x[0], 8);
+ m &= 0xfffffffffc000000LL;
+ memcpy(&hx, &m, 8);
+ tx = x[0] - hx;
+ memcpy(&m, &y, 8);
+ m &= 0xfffffffffc000000LL;
+ memcpy(&hy, &m, 8);
+ ty = y - hy;
+ p = hx*hy;
+ q = hx*ty + tx*hy;
+ c = p+q;
+ cc = p - c + q + tx*ty;
+ cc = x[0]*yy + x[1]*y + cc;
+ x[0] = c + cc;
+ x[1] = c - x[0];
+ x[1] += cc;
}
/*
@@ -34178,14 +35845,15 @@ SQLITE_PRIVATE int wx_sqlite3AtoF(const char *z, double *pResult, int length, u8
const char *zEnd;
/* sign * significand * (10 ^ (esign * exponent)) */
int sign = 1; /* sign of significand */
- i64 s = 0; /* significand */
+ u64 s = 0; /* significand */
int d = 0; /* adjust exponent for shifting decimal point */
int esign = 1; /* sign of exponent */
int e = 0; /* exponent */
int eValid = 1; /* True exponent is either not used or is well-formed */
- double result;
int nDigit = 0; /* Number of digits processed */
int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */
+ u64 s2; /* round-tripped significand */
+ double rr[2];
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
*pResult = 0.0; /* Default return value, in case of an error */
@@ -34223,7 +35891,7 @@ SQLITE_PRIVATE int wx_sqlite3AtoF(const char *z, double *pResult, int length, u8
while( z<zEnd && wx_sqlite3Isdigit(*z) ){
s = s*10 + (*z - '0');
z+=incr; nDigit++;
- if( s>=((LARGEST_INT64-9)/10) ){
+ if( s>=((LARGEST_UINT64-9)/10) ){
/* skip non-significant significand digits
** (increase exponent by d to shift decimal left) */
while( z<zEnd && wx_sqlite3Isdigit(*z) ){ z+=incr; d++; }
@@ -34238,7 +35906,7 @@ SQLITE_PRIVATE int wx_sqlite3AtoF(const char *z, double *pResult, int length, u8
/* copy digits from after decimal to significand
** (decrease exponent by d to shift decimal right) */
while( z<zEnd && wx_sqlite3Isdigit(*z) ){
- if( s<((LARGEST_INT64-9)/10) ){
+ if( s<((LARGEST_UINT64-9)/10) ){
s = s*10 + (*z - '0');
d--;
nDigit++;
@@ -34278,79 +35946,70 @@ SQLITE_PRIVATE int wx_sqlite3AtoF(const char *z, double *pResult, int length, u8
while( z<zEnd && wx_sqlite3Isspace(*z) ) z+=incr;
do_atof_calc:
+ /* Zero is a special case */
+ if( s==0 ){
+ *pResult = sign<0 ? -0.0 : +0.0;
+ goto atof_return;
+ }
+
/* adjust exponent by d, and update sign */
e = (e*esign) + d;
- if( e<0 ) {
- esign = -1;
- e *= -1;
- } else {
- esign = 1;
- }
- if( s==0 ) {
- /* In the IEEE 754 standard, zero is signed. */
- result = sign<0 ? -(double)0 : (double)0;
- } else {
- /* Attempt to reduce exponent.
- **
- ** Branches that are not required for the correct answer but which only
- ** help to obtain the correct answer faster are marked with special
- ** comments, as a hint to the mutation tester.
- */
- while( e>0 ){ /*OPTIMIZATION-IF-TRUE*/
- if( esign>0 ){
- if( s>=(LARGEST_INT64/10) ) break; /*OPTIMIZATION-IF-FALSE*/
- s *= 10;
- }else{
- if( s%10!=0 ) break; /*OPTIMIZATION-IF-FALSE*/
- s /= 10;
- }
- e--;
- }
+ /* Try to adjust the exponent to make it smaller */
+ while( e>0 && s<((LARGEST_UINT64-0x7ff)/10) ){
+ s *= 10;
+ e--;
+ }
+ while( e<0 && (s%10)==0 ){
+ s /= 10;
+ e++;
+ }
- /* adjust the sign of significand */
- s = sign<0 ? -s : s;
+ rr[0] = (double)s;
+ assert( sizeof(s2)==sizeof(rr[0]) );
+ memcpy(&s2, &rr[0], sizeof(s2));
+ if( s2<=0x43efffffffffffffLL ){
+ s2 = (u64)rr[0];
+ rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
+ }else{
+ rr[1] = 0.0;
+ }
+ assert( rr[1]<=1.0e-10*rr[0] ); /* Equal only when rr[0]==0.0 */
- if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/
- result = (double)s;
- }else{
- /* attempt to handle extremely small/large numbers better */
- if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/
- if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/
- LONGDOUBLE_TYPE scale = wx_sqlite3Pow10(e-308);
- if( esign<0 ){
- result = s / scale;
- result /= 1.0e+308;
- }else{
- result = s * scale;
- result *= 1.0e+308;
- }
- }else{ assert( e>=342 );
- if( esign<0 ){
- result = 0.0*s;
- }else{
-#ifdef INFINITY
- result = INFINITY*s;
-#else
- result = 1e308*1e308*s; /* Infinity */
-#endif
- }
- }
- }else{
- LONGDOUBLE_TYPE scale = wx_sqlite3Pow10(e);
- if( esign<0 ){
- result = s / scale;
- }else{
- result = s * scale;
- }
- }
+ if( e>0 ){
+ while( e>=100 ){
+ e -= 100;
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
+ }
+ while( e>=10 ){
+ e -= 10;
+ dekkerMul2(rr, 1.0e+10, 0.0);
+ }
+ while( e>=1 ){
+ e -= 1;
+ dekkerMul2(rr, 1.0e+01, 0.0);
+ }
+ }else{
+ while( e<=-100 ){
+ e += 100;
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
+ }
+ while( e<=-10 ){
+ e += 10;
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
+ }
+ while( e<=-1 ){
+ e += 1;
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
}
}
+ *pResult = rr[0]+rr[1];
+ if( wx_sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300;
+ if( sign<0 ) *pResult = -*pResult;
+ assert( !wx_sqlite3IsNaN(*pResult) );
- /* store the result */
- *pResult = result;
-
- /* return true if number and no extra non-whitespace chracters after */
+atof_return:
+ /* return true if number and no extra non-whitespace characters after */
if( z==zEnd && nDigit>0 && eValid && eType>0 ){
return eType;
}else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){
@@ -34385,13 +36044,15 @@ SQLITE_PRIVATE int wx_sqlite3Int64ToText(i64 v, char *zOut){
}
i = sizeof(zTemp)-2;
zTemp[sizeof(zTemp)-1] = 0;
- do{
- zTemp[i--] = (x%10) + '0';
+ while( 1 /*exit-by-break*/ ){
+ zTemp[i] = (x%10) + '0';
x = x/10;
- }while( x );
- if( v<0 ) zTemp[i--] = '-';
- memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
- return sizeof(zTemp)-2-i;
+ if( x==0 ) break;
+ i--;
+ };
+ if( v<0 ) zTemp[--i] = '-';
+ memcpy(zOut, &zTemp[i], sizeof(zTemp)-i);
+ return sizeof(zTemp)-1-i;
}
/*
@@ -34484,7 +36145,7 @@ SQLITE_PRIVATE int wx_sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8
/* This test and assignment is needed only to suppress UB warnings
** from clang and -fsanitize=undefined. This test and assignment make
** the code a little larger and slower, and no harm comes from omitting
- ** them, but we must appaise the undefined-behavior pharisees. */
+ ** them, but we must appease the undefined-behavior pharisees. */
*pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
}else if( neg ){
*pNum = -(i64)u;
@@ -34556,11 +36217,15 @@ SQLITE_PRIVATE int wx_sqlite3DecOrHexToI64(const char *z, i64 *pOut){
u = u*16 + wx_sqlite3HexToInt(z[k]);
}
memcpy(pOut, &u, 8);
- return (z[k]==0 && k-i<=16) ? 0 : 2;
+ if( k-i>16 ) return 2;
+ if( z[k]!=0 ) return 1;
+ return 0;
}else
#endif /* SQLITE_OMIT_HEX_INTEGER */
{
- return wx_sqlite3Atoi64(z, pOut, wx_sqlite3Strlen30(z), SQLITE_UTF8);
+ int n = (int)(0x3fffffff&strspn(z,"+- \n\t0123456789"));
+ if( z[n] ) n++;
+ return wx_sqlite3Atoi64(z, pOut, n, SQLITE_UTF8);
}
}
@@ -34592,7 +36257,7 @@ SQLITE_PRIVATE int wx_sqlite3GetInt32(const char *zNum, int *pValue){
u32 u = 0;
zNum += 2;
while( zNum[0]=='0' ) zNum++;
- for(i=0; wx_sqlite3Isxdigit(zNum[i]) && i<8; i++){
+ for(i=0; i<8 && wx_sqlite3Isxdigit(zNum[i]); i++){
u = u*16 + wx_sqlite3HexToInt(zNum[i]);
}
if( (u&0x80000000)==0 && wx_sqlite3Isxdigit(zNum[i])==0 ){
@@ -34640,6 +36305,142 @@ SQLITE_PRIVATE int wx_sqlite3Atoi(const char *z){
}
/*
+** Decode a floating-point value into an approximate decimal
+** representation.
+**
+** If iRound<=0 then round to -iRound significant digits to the
+** the left of the decimal point, or to a maximum of mxRound total
+** significant digits.
+**
+** If iRound>0 round to min(iRound,mxRound) significant digits total.
+**
+** mxRound must be positive.
+**
+** The significant digits of the decimal representation are
+** stored in p->z[] which is a often (but not always) a pointer
+** into the middle of p->zBuf[]. There are p->n significant digits.
+** The p->z[] array is *not* zero-terminated.
+*/
+SQLITE_PRIVATE void wx_sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
+ int i;
+ u64 v;
+ int e, exp = 0;
+ double rr[2];
+
+ p->isSpecial = 0;
+ p->z = p->zBuf;
+ assert( mxRound>0 );
+
+ /* Convert negative numbers to positive. Deal with Infinity, 0.0, and
+ ** NaN. */
+ if( r<0.0 ){
+ p->sign = '-';
+ r = -r;
+ }else if( r==0.0 ){
+ p->sign = '+';
+ p->n = 1;
+ p->iDP = 1;
+ p->z = "0";
+ return;
+ }else{
+ p->sign = '+';
+ }
+ memcpy(&v,&r,8);
+ e = v>>52;
+ if( (e&0x7ff)==0x7ff ){
+ p->isSpecial = 1 + (v!=0x7ff0000000000000LL);
+ p->n = 0;
+ p->iDP = 0;
+ return;
+ }
+
+ /* Multiply r by powers of ten until it lands somewhere in between
+ ** 1.0e+19 and 1.0e+17.
+ **
+ ** Use Dekker-style double-double computation to increase the
+ ** precision.
+ **
+ ** The error terms on constants like 1.0e+100 computed using the
+ ** decimal extension, for example as follows:
+ **
+ ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100)));
+ */
+ rr[0] = r;
+ rr[1] = 0.0;
+ if( rr[0]>9.223372036854774784e+18 ){
+ while( rr[0]>9.223372036854774784e+118 ){
+ exp += 100;
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
+ }
+ while( rr[0]>9.223372036854774784e+28 ){
+ exp += 10;
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
+ }
+ while( rr[0]>9.223372036854774784e+18 ){
+ exp += 1;
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
+ }
+ }else{
+ while( rr[0]<9.223372036854774784e-83 ){
+ exp -= 100;
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
+ }
+ while( rr[0]<9.223372036854774784e+07 ){
+ exp -= 10;
+ dekkerMul2(rr, 1.0e+10, 0.0);
+ }
+ while( rr[0]<9.22337203685477478e+17 ){
+ exp -= 1;
+ dekkerMul2(rr, 1.0e+01, 0.0);
+ }
+ }
+ v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1];
+
+ /* Extract significant digits. */
+ i = sizeof(p->zBuf)-1;
+ assert( v>0 );
+ while( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; }
+ assert( i>=0 && i<sizeof(p->zBuf)-1 );
+ p->n = sizeof(p->zBuf) - 1 - i;
+ assert( p->n>0 );
+ assert( p->n<sizeof(p->zBuf) );
+ p->iDP = p->n + exp;
+ if( iRound<=0 ){
+ iRound = p->iDP - iRound;
+ if( iRound==0 && p->zBuf[i+1]>='5' ){
+ iRound = 1;
+ p->zBuf[i--] = '0';
+ p->n++;
+ p->iDP++;
+ }
+ }
+ if( iRound>0 && (iRound<p->n || p->n>mxRound) ){
+ char *z = &p->zBuf[i+1];
+ if( iRound>mxRound ) iRound = mxRound;
+ p->n = iRound;
+ if( z[iRound]>='5' ){
+ int j = iRound-1;
+ while( 1 /*exit-by-break*/ ){
+ z[j]++;
+ if( z[j]<='9' ) break;
+ z[j] = '0';
+ if( j==0 ){
+ p->z[i--] = '1';
+ p->n++;
+ p->iDP++;
+ break;
+ }else{
+ j--;
+ }
+ }
+ }
+ }
+ p->z = &p->zBuf[i+1];
+ assert( i+p->n < sizeof(p->zBuf) );
+ while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; }
+}
+
+/*
** Try to convert z into an unsigned 32-bit integer. Return true on
** success and false if there is an error.
**
@@ -34902,121 +36703,32 @@ SQLITE_PRIVATE u8 wx_sqlite3GetVarint(const unsigned char *p, u64 *v){
** this function assumes the single-byte case has already been handled.
*/
SQLITE_PRIVATE u8 wx_sqlite3GetVarint32(const unsigned char *p, u32 *v){
- u32 a,b;
+ u64 v64;
+ u8 n;
- /* The 1-byte case. Overwhelmingly the most common. Handled inline
- ** by the getVarin32() macro */
- a = *p;
- /* a: p0 (unmasked) */
-#ifndef getVarint32
- if (!(a&0x80))
- {
- /* Values between 0 and 127 */
- *v = a;
- return 1;
- }
-#endif
+ /* Assume that the single-byte case has already been handled by
+ ** the getVarint32() macro */
+ assert( (p[0] & 0x80)!=0 );
- /* The 2-byte case */
- p++;
- b = *p;
- /* b: p1 (unmasked) */
- if (!(b&0x80))
- {
- /* Values between 128 and 16383 */
- a &= 0x7f;
- a = a<<7;
- *v = a | b;
+ if( (p[1] & 0x80)==0 ){
+ /* This is the two-byte case */
+ *v = ((p[0]&0x7f)<<7) | p[1];
return 2;
}
-
- /* The 3-byte case */
- p++;
- a = a<<14;
- a |= *p;
- /* a: p0<<14 | p2 (unmasked) */
- if (!(a&0x80))
- {
- /* Values between 16384 and 2097151 */
- a &= (0x7f<<14)|(0x7f);
- b &= 0x7f;
- b = b<<7;
- *v = a | b;
+ if( (p[2] & 0x80)==0 ){
+ /* This is the three-byte case */
+ *v = ((p[0]&0x7f)<<14) | ((p[1]&0x7f)<<7) | p[2];
return 3;
}
-
- /* A 32-bit varint is used to store size information in btrees.
- ** Objects are rarely larger than 2MiB limit of a 3-byte varint.
- ** A 3-byte varint is sufficient, for example, to record the size
- ** of a 1048569-byte BLOB or string.
- **
- ** We only unroll the first 1-, 2-, and 3- byte cases. The very
- ** rare larger cases can be handled by the slower 64-bit varint
- ** routine.
- */
-#if 1
- {
- u64 v64;
- u8 n;
-
- n = wx_sqlite3GetVarint(p-2, &v64);
- assert( n>3 && n<=9 );
- if( (v64 & SQLITE_MAX_U32)!=v64 ){
- *v = 0xffffffff;
- }else{
- *v = (u32)v64;
- }
- return n;
- }
-
-#else
- /* For following code (kept for historical record only) shows an
- ** unrolling for the 3- and 4-byte varint cases. This code is
- ** slightly faster, but it is also larger and much harder to test.
- */
- p++;
- b = b<<14;
- b |= *p;
- /* b: p1<<14 | p3 (unmasked) */
- if (!(b&0x80))
- {
- /* Values between 2097152 and 268435455 */
- b &= (0x7f<<14)|(0x7f);
- a &= (0x7f<<14)|(0x7f);
- a = a<<7;
- *v = a | b;
- return 4;
- }
-
- p++;
- a = a<<14;
- a |= *p;
- /* a: p0<<28 | p2<<14 | p4 (unmasked) */
- if (!(a&0x80))
- {
- /* Values between 268435456 and 34359738367 */
- a &= SLOT_4_2_0;
- b &= SLOT_4_2_0;
- b = b<<7;
- *v = a | b;
- return 5;
- }
-
- /* We can only reach this point when reading a corrupt database
- ** file. In that case we are not in any hurry. Use the (relatively
- ** slow) general-purpose wx_sqlite3GetVarint() routine to extract the
- ** value. */
- {
- u64 v64;
- u8 n;
-
- p -= 4;
- n = wx_sqlite3GetVarint(p, &v64);
- assert( n>5 && n<=9 );
+ /* four or more bytes */
+ n = wx_sqlite3GetVarint(p, &v64);
+ assert( n>3 && n<=9 );
+ if( (v64 & SQLITE_MAX_U32)!=v64 ){
+ *v = 0xffffffff;
+ }else{
*v = (u32)v64;
- return n;
}
-#endif
+ return n;
}
/*
@@ -35167,7 +36879,7 @@ SQLITE_PRIVATE int wx_sqlite3SafetyCheckSickOrOk(wx_sqlite3 *db){
}
/*
-** Attempt to add, substract, or multiply the 64-bit signed value iB against
+** Attempt to add, subtract, or multiply the 64-bit signed value iB against
** the other 64-bit signed integer at *pA and store the result in *pA.
** Return 0 on success. Or if the operation would have resulted in an
** overflow, leave *pA unchanged and return 1.
@@ -35453,104 +37165,6 @@ SQLITE_PRIVATE int wx_sqlite3VListNameToNum(VList *pIn, const char *zName, int n
return 0;
}
-/*
-** High-resolution hardware timer used for debugging and testing only.
-*/
-#if defined(VDBE_PROFILE) \
- || defined(SQLITE_PERFORMANCE_TRACE) \
- || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
-/************** Include hwtime.h in the middle of util.c *********************/
-/************** Begin file hwtime.h ******************************************/
-/*
-** 2008 May 27
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This file contains inline asm code for retrieving "high-performance"
-** counters for x86 and x86_64 class CPUs.
-*/
-#ifndef SQLITE_HWTIME_H
-#define SQLITE_HWTIME_H
-
-/*
-** The following routine only works on pentium-class (or newer) processors.
-** It uses the RDTSC opcode to read the cycle count value out of the
-** processor and returns that value. This can be used for high-res
-** profiling.
-*/
-#if !defined(__STRICT_ANSI__) && \
- (defined(__GNUC__) || defined(_MSC_VER)) && \
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
-
- #if defined(__GNUC__)
-
- __inline__ sqlite_uint64 wx_sqlite3Hwtime(void){
- unsigned int lo, hi;
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
- return (sqlite_uint64)hi << 32 | lo;
- }
-
- #elif defined(_MSC_VER)
-
- __declspec(naked) __inline sqlite_uint64 __cdecl wx_sqlite3Hwtime(void){
- __asm {
- rdtsc
- ret ; return value at EDX:EAX
- }
- }
-
- #endif
-
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
-
- __inline__ sqlite_uint64 wx_sqlite3Hwtime(void){
- unsigned int lo, hi;
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
- return (sqlite_uint64)hi << 32 | lo;
- }
-
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
-
- __inline__ sqlite_uint64 wx_sqlite3Hwtime(void){
- unsigned long long retval;
- unsigned long junk;
- __asm__ __volatile__ ("\n\
- 1: mftbu %1\n\
- mftb %L0\n\
- mftbu %0\n\
- cmpw %0,%1\n\
- bne 1b"
- : "=r" (retval), "=r" (junk));
- return retval;
- }
-
-#else
-
- /*
- ** asm() is needed for hardware timing support. Without asm(),
- ** disable the wx_sqlite3Hwtime() routine.
- **
- ** wx_sqlite3Hwtime() is only used for some obscure debugging
- ** and analysis configurations, not in any deliverable, so this
- ** should not be a great loss.
- */
-SQLITE_PRIVATE sqlite_uint64 wx_sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
-
-#endif
-
-#endif /* !defined(SQLITE_HWTIME_H) */
-
-/************** End of hwtime.h **********************************************/
-/************** Continuing where we left off in util.c ***********************/
-#endif
-
/************** End of util.c ************************************************/
/************** Begin file hash.c ********************************************/
/*
@@ -35652,7 +37266,7 @@ static void insertElement(
}
-/* Resize the hash table so that it cantains "new_size" buckets.
+/* Resize the hash table so that it contains "new_size" buckets.
**
** The hash table might fail to resize if wx_sqlite3_malloc() fails or
** if the new size is the same as the prior size.
@@ -35871,7 +37485,7 @@ SQLITE_PRIVATE const char *wx_sqlite3OpcodeName(int i){
/* 30 */ "SeekRowid" OpHelp("intkey=r[P3]"),
/* 31 */ "NotExists" OpHelp("intkey=r[P3]"),
/* 32 */ "Last" OpHelp(""),
- /* 33 */ "IfSmaller" OpHelp(""),
+ /* 33 */ "IfSizeBetween" OpHelp(""),
/* 34 */ "SorterSort" OpHelp(""),
/* 35 */ "Sort" OpHelp(""),
/* 36 */ "Rewind" OpHelp(""),
@@ -35888,16 +37502,16 @@ SQLITE_PRIVATE const char *wx_sqlite3OpcodeName(int i){
/* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
/* 48 */ "Program" OpHelp(""),
/* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
- /* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
- /* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
- /* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
- /* 53 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
- /* 54 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
- /* 55 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
- /* 56 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
- /* 57 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
- /* 58 */ "ElseEq" OpHelp(""),
- /* 59 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 50 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 51 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
+ /* 52 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
+ /* 53 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
+ /* 54 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
+ /* 55 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
+ /* 56 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
+ /* 57 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
+ /* 58 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
+ /* 59 */ "ElseEq" OpHelp(""),
/* 60 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
/* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
/* 62 */ "IncrVacuum" OpHelp(""),
@@ -35916,7 +37530,7 @@ SQLITE_PRIVATE const char *wx_sqlite3OpcodeName(int i){
/* 75 */ "Null" OpHelp("r[P2..P3]=NULL"),
/* 76 */ "SoftNull" OpHelp("r[P1]=NULL"),
/* 77 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
- /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
+ /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1)"),
/* 79 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
/* 80 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
/* 81 */ "SCopy" OpHelp("r[P2]=r[P1]"),
@@ -35940,23 +37554,23 @@ SQLITE_PRIVATE const char *wx_sqlite3OpcodeName(int i){
/* 99 */ "ReadCookie" OpHelp(""),
/* 100 */ "SetCookie" OpHelp(""),
/* 101 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
- /* 102 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
- /* 103 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
- /* 104 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
- /* 105 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
- /* 106 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
- /* 107 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
- /* 108 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
- /* 109 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
- /* 110 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
- /* 111 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
- /* 112 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
+ /* 102 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
+ /* 103 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
+ /* 104 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
+ /* 105 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
+ /* 106 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
+ /* 107 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
+ /* 108 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
+ /* 109 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
+ /* 110 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
+ /* 111 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
+ /* 112 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
/* 113 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
- /* 114 */ "BitNot" OpHelp("r[P2]= ~r[P1]"),
- /* 115 */ "OpenDup" OpHelp(""),
+ /* 114 */ "OpenDup" OpHelp(""),
+ /* 115 */ "BitNot" OpHelp("r[P2]= ~r[P1]"),
/* 116 */ "OpenAutoindex" OpHelp("nColumn=P2"),
- /* 117 */ "String8" OpHelp("r[P2]='P4'"),
- /* 118 */ "OpenEphemeral" OpHelp("nColumn=P2"),
+ /* 117 */ "OpenEphemeral" OpHelp("nColumn=P2"),
+ /* 118 */ "String8" OpHelp("r[P2]='P4'"),
/* 119 */ "SorterOpen" OpHelp(""),
/* 120 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
/* 121 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
@@ -35991,8 +37605,8 @@ SQLITE_PRIVATE const char *wx_sqlite3OpcodeName(int i){
/* 150 */ "LoadAnalysis" OpHelp(""),
/* 151 */ "DropTable" OpHelp(""),
/* 152 */ "DropIndex" OpHelp(""),
- /* 153 */ "Real" OpHelp("r[P2]=P4"),
- /* 154 */ "DropTrigger" OpHelp(""),
+ /* 153 */ "DropTrigger" OpHelp(""),
+ /* 154 */ "Real" OpHelp("r[P2]=P4"),
/* 155 */ "IntegrityCk" OpHelp(""),
/* 156 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
/* 157 */ "Param" OpHelp(""),
@@ -36012,19 +37626,22 @@ SQLITE_PRIVATE const char *wx_sqlite3OpcodeName(int i){
/* 171 */ "VCreate" OpHelp(""),
/* 172 */ "VDestroy" OpHelp(""),
/* 173 */ "VOpen" OpHelp(""),
- /* 174 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"),
- /* 175 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
- /* 176 */ "VRename" OpHelp(""),
- /* 177 */ "Pagecount" OpHelp(""),
- /* 178 */ "MaxPgcnt" OpHelp(""),
- /* 179 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"),
- /* 180 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"),
- /* 181 */ "Trace" OpHelp(""),
- /* 182 */ "CursorHint" OpHelp(""),
- /* 183 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
- /* 184 */ "Noop" OpHelp(""),
- /* 185 */ "Explain" OpHelp(""),
- /* 186 */ "Abortable" OpHelp(""),
+ /* 174 */ "VCheck" OpHelp(""),
+ /* 175 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"),
+ /* 176 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
+ /* 177 */ "VRename" OpHelp(""),
+ /* 178 */ "Pagecount" OpHelp(""),
+ /* 179 */ "MaxPgcnt" OpHelp(""),
+ /* 180 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"),
+ /* 181 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"),
+ /* 182 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"),
+ /* 183 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"),
+ /* 184 */ "Trace" OpHelp(""),
+ /* 185 */ "CursorHint" OpHelp(""),
+ /* 186 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
+ /* 187 */ "Noop" OpHelp(""),
+ /* 188 */ "Explain" OpHelp(""),
+ /* 189 */ "Abortable" OpHelp(""),
};
return azName[i];
}
@@ -37038,7 +38655,7 @@ SQLITE_PRIVATE int wx_sqlite3KvvfsInit(void){
** This source file is organized into divisions where the logic for various
** subfunctions is contained within the appropriate division. PLEASE
** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed
-** in the correct division and should be clearly labeled.
+** in the correct division and should be clearly labelled.
**
** The layout of divisions is as follows:
**
@@ -37088,7 +38705,7 @@ SQLITE_PRIVATE int wx_sqlite3KvvfsInit(void){
#endif
/* Use pread() and pwrite() if they are available */
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__linux__)
# define HAVE_PREAD 1
# define HAVE_PWRITE 1
#endif
@@ -37342,7 +38959,7 @@ static pid_t randomnessPid = 0;
#define UNIXFILE_EXCL 0x01 /* Connections from one process only */
#define UNIXFILE_RDONLY 0x02 /* Connection is read only */
#define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
-#ifndef SQLITE_DISABLE_DIRSYNC
+#if !defined(SQLITE_DISABLE_DIRSYNC) && !defined(_AIX)
# define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */
#else
# define UNIXFILE_DIRSYNC 0x00
@@ -37629,7 +39246,7 @@ static int robustFchown(int fd, uid_t uid, gid_t gid){
/*
** This is the xSetSystemCall() method of wx_sqlite3_vfs for all of the
-** "unix" VFSes. Return SQLITE_OK opon successfully updating the
+** "unix" VFSes. Return SQLITE_OK upon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
*/
@@ -38151,7 +39768,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
** If you close a file descriptor that points to a file that has locks,
** all locks on that file that are owned by the current process are
** released. To work around this problem, each unixInodeInfo object
-** maintains a count of the number of pending locks on tha inode.
+** maintains a count of the number of pending locks on the inode.
** When an attempt is made to close an unixFile, if there are
** other unixFile open on the same inode that are holding locks, the call
** to close() the file descriptor is deferred until all of the locks clear.
@@ -38165,7 +39782,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
** not posix compliant. Under LinuxThreads, a lock created by thread
** A cannot be modified or overridden by a different thread B.
** Only thread A can modify the lock. Locking behavior is correct
-** if the appliation uses the newer Native Posix Thread Library (NPTL)
+** if the application uses the newer Native Posix Thread Library (NPTL)
** on linux - with NPTL a lock created by thread A can override locks
** in thread B. But there is no way to know at compile-time which
** threading library is being used. So there is no way to know at
@@ -38315,8 +39932,12 @@ static int unixLogErrorAtLine(
** available, the error message will often be an empty string. Not a
** huge problem. Incorrectly concluding that the GNU version is available
** could lead to a segfault though.
+ **
+ ** Forum post 3f13857fa4062301 reports that the Android SDK may use
+ ** int-type return, depending on its version.
*/
-#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
+#if (defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)) \
+ && !defined(ANDROID) && !defined(__ANDROID__)
zErr =
# endif
strerror_r(iErrno, aErr, sizeof(aErr)-1);
@@ -38367,7 +39988,7 @@ static void storeLastErrno(unixFile *pFile, int error){
}
/*
-** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
+** Close all file descriptors accumulated in the unixInodeInfo->pUnused list.
*/
static void closePendingFds(unixFile *pFile){
unixInodeInfo *pInode = pFile->pInode;
@@ -38730,7 +40351,7 @@ static int unixLock(wx_sqlite3_file *id, int eFileLock){
** slightly in order to be compatible with Windows95 systems simultaneously
** accessing the same database file, in case that is ever required.
**
- ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
+ ** Symbols defined in os.h identify the 'pending byte' and the 'reserved
** byte', each single bytes at well known offsets, and the 'shared byte
** range', a range of 510 bytes at a well known offset.
**
@@ -38738,7 +40359,7 @@ static int unixLock(wx_sqlite3_file *id, int eFileLock){
** byte'. If this is successful, 'shared byte range' is read-locked
** and the lock on the 'pending byte' released. (Legacy note: When
** SQLite was first developed, Windows95 systems were still very common,
- ** and Widnows95 lacks a shared-lock capability. So on Windows95, a
+ ** and Windows95 lacks a shared-lock capability. So on Windows95, a
** single randomly selected by from the 'shared byte range' is locked.
** Windows95 is now pretty much extinct, but this work-around for the
** lack of shared-locks on Windows95 lives on, for backwards
@@ -38759,7 +40380,7 @@ static int unixLock(wx_sqlite3_file *id, int eFileLock){
** obtaining a write-lock on the 'pending byte'. This ensures that no new
** SHARED locks can be obtained, but existing SHARED locks are allowed to
** persist. If the call to this function fails to obtain the EXCLUSIVE
- ** lock in this case, it holds the PENDING lock intead. The client may
+ ** lock in this case, it holds the PENDING lock instead. The client may
** then re-attempt the EXCLUSIVE lock later on, after existing SHARED
** locks have cleared.
*/
@@ -38787,7 +40408,7 @@ static int unixLock(wx_sqlite3_file *id, int eFileLock){
/* Make sure the locking sequence is correct.
** (1) We never move from unlocked to anything higher than shared lock.
- ** (2) SQLite never explicitly requests a pendig lock.
+ ** (2) SQLite never explicitly requests a pending lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
@@ -39295,26 +40916,22 @@ static int nolockClose(wx_sqlite3_file *id) {
/*
** This routine checks if there is a RESERVED lock held on the specified
-** file by this or any other process. If such a lock is held, set *pResOut
-** to a non-zero value otherwise *pResOut is set to zero. The return value
-** is set to SQLITE_OK unless an I/O error occurs during lock checking.
-**
-** In dotfile locking, either a lock exists or it does not. So in this
-** variation of CheckReservedLock(), *pResOut is set to true if any lock
-** is held on the file and false if the file is unlocked.
+** file by this or any other process. If the caller holds a SHARED
+** or greater lock when it is called, then it is assumed that no other
+** client may hold RESERVED. Or, if the caller holds no lock, then it
+** is assumed another client holds RESERVED if the lock-file exists.
*/
static int dotlockCheckReservedLock(wx_sqlite3_file *id, int *pResOut) {
- int rc = SQLITE_OK;
- int reserved = 0;
unixFile *pFile = (unixFile*)id;
-
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
- assert( pFile );
- reserved = osAccess((const char*)pFile->lockingContext, 0)==0;
- OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
- *pResOut = reserved;
- return rc;
+ if( pFile->eFileLock>=SHARED_LOCK ){
+ *pResOut = 0;
+ }else{
+ *pResOut = osAccess((const char*)pFile->lockingContext, 0)==0;
+ }
+ OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, 0, *pResOut));
+ return SQLITE_OK;
}
/*
@@ -39484,54 +41101,33 @@ static int robust_flock(int fd, int op){
** is set to SQLITE_OK unless an I/O error occurs during lock checking.
*/
static int flockCheckReservedLock(wx_sqlite3_file *id, int *pResOut){
- int rc = SQLITE_OK;
- int reserved = 0;
+#ifdef SQLITE_DEBUG
unixFile *pFile = (unixFile*)id;
+#else
+ UNUSED_PARAMETER(id);
+#endif
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
assert( pFile );
+ assert( pFile->eFileLock<=SHARED_LOCK );
- /* Check if a thread in this process holds such a lock */
- if( pFile->eFileLock>SHARED_LOCK ){
- reserved = 1;
- }
-
- /* Otherwise see if some other process holds it. */
- if( !reserved ){
- /* attempt to get the lock */
- int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
- if( !lrc ){
- /* got the lock, unlock it */
- lrc = robust_flock(pFile->h, LOCK_UN);
- if ( lrc ) {
- int tErrno = errno;
- /* unlock failed with an error */
- lrc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
- rc = lrc;
- }
- } else {
- int tErrno = errno;
- reserved = 1;
- /* someone else might have it reserved */
- lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if( IS_LOCK_ERROR(lrc) ){
- storeLastErrno(pFile, tErrno);
- rc = lrc;
- }
- }
- }
- OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
+ /* The flock VFS only ever takes exclusive locks (see function flockLock).
+ ** Therefore, if this connection is holding any lock at all, no other
+ ** connection may be holding a RESERVED lock. So set *pResOut to 0
+ ** in this case.
+ **
+ ** Or, this connection may be holding no lock. In that case, set *pResOut to
+ ** 0 as well. The caller will then attempt to take an EXCLUSIVE lock on the
+ ** db in order to roll the hot journal back. If there is another connection
+ ** holding a lock, that attempt will fail and an SQLITE_BUSY returned to
+ ** the user. With other VFS, we try to avoid this, in order to allow a reader
+ ** to proceed while a writer is preparing its transaction. But that won't
+ ** work with the flock VFS - as it always takes EXCLUSIVE locks - so it is
+ ** not a problem in this case. */
+ *pResOut = 0;
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if( (rc & 0xff) == SQLITE_IOERR ){
- rc = SQLITE_OK;
- reserved=1;
- }
-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
- *pResOut = reserved;
- return rc;
+ return SQLITE_OK;
}
/*
@@ -40005,7 +41601,7 @@ static int afpLock(wx_sqlite3_file *id, int eFileLock){
/* Make sure the locking sequence is correct
** (1) We never move from unlocked to anything higher than shared lock.
- ** (2) SQLite never explicitly requests a pendig lock.
+ ** (2) SQLite never explicitly requests a pending lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
@@ -40121,7 +41717,7 @@ static int afpLock(wx_sqlite3_file *id, int eFileLock){
if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST +
pInode->sharedByte, 1, 0)) ){
int failed2 = SQLITE_OK;
- /* now attemmpt to get the exclusive lock range */
+ /* now attempt to get the exclusive lock range */
failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
SHARED_SIZE, 1);
if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
@@ -40170,9 +41766,6 @@ static int afpUnlock(wx_sqlite3_file *id, int eFileLock) {
unixInodeInfo *pInode;
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
int skipShared = 0;
-#ifdef SQLITE_TEST
- int h = pFile->h;
-#endif
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock,
@@ -40188,9 +41781,6 @@ static int afpUnlock(wx_sqlite3_file *id, int eFileLock) {
assert( pInode->nShared!=0 );
if( pFile->eFileLock>SHARED_LOCK ){
assert( pInode->eFileLock==pFile->eFileLock );
- SimulateIOErrorBenign(1);
- SimulateIOError( h=(-1) )
- SimulateIOErrorBenign(0);
#ifdef SQLITE_DEBUG
/* When reducing a lock such that other processes can start
@@ -40239,9 +41829,6 @@ static int afpUnlock(wx_sqlite3_file *id, int eFileLock) {
unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte;
pInode->nShared--;
if( pInode->nShared==0 ){
- SimulateIOErrorBenign(1);
- SimulateIOError( h=(-1) )
- SimulateIOErrorBenign(0);
if( !skipShared ){
rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0);
}
@@ -40342,12 +41929,6 @@ static int nfsUnlock(wx_sqlite3_file *id, int eFileLock){
** Seek to the offset passed as the second argument, then read cnt
** bytes into pBuf. Return the number of bytes actually read.
**
-** NB: If you define USE_PREAD or USE_PREAD64, then it might also
-** be necessary to define _XOPEN_SOURCE to be 500. This varies from
-** one system to another. Since SQLite does not define USE_PREAD
-** in any form by default, we will not attempt to define _XOPEN_SOURCE.
-** See tickets #2741 and #2681.
-**
** To avoid stomping the errno value on a failed read the lastErrno value
** is set before returning.
*/
@@ -40422,7 +42003,7 @@ static int unixRead(
#endif
#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
+ /* Deal with as much of this read request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -40574,7 +42155,7 @@ static int unixWrite(
#endif
#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
+ /* Deal with as much of this write request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -40696,7 +42277,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
/* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
** no-op. But go ahead and call fstat() to validate the file
** descriptor as we need a method to provoke a failure during
- ** coverate testing.
+ ** coverage testing.
*/
#ifdef SQLITE_NO_SYNC
{
@@ -41018,7 +42599,7 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
/* Forward declaration */
static int unixGetTempname(int nBuf, char *zBuf);
-#ifndef SQLITE_OMIT_WAL
+#if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL)
static int unixFcntlExternalReader(unixFile*, int*);
#endif
@@ -41089,7 +42670,13 @@ static int unixFileControl(wx_sqlite3_file *id, int op, void *pArg){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
case SQLITE_FCNTL_LOCK_TIMEOUT: {
int iOld = pFile->iBusyTimeout;
+#if SQLITE_ENABLE_SETLK_TIMEOUT==1
pFile->iBusyTimeout = *(int*)pArg;
+#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
+ pFile->iBusyTimeout = !!(*(int*)pArg);
+#else
+# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
+#endif
*(int*)pArg = iOld;
return SQLITE_OK;
}
@@ -41139,7 +42726,7 @@ static int unixFileControl(wx_sqlite3_file *id, int op, void *pArg){
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
case SQLITE_FCNTL_EXTERNAL_READER: {
-#ifndef SQLITE_OMIT_WAL
+#if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL)
return unixFcntlExternalReader((unixFile*)id, (int*)pArg);
#else
*(int*)pArg = 0;
@@ -41178,6 +42765,7 @@ static void setDeviceCharacteristics(unixFile *pFd){
if( pFd->ctrlFlags & UNIXFILE_PSOW ){
pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
}
+ pFd->deviceCharacteristics |= SQLITE_IOCAP_SUBPAGE_READ;
pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
}
@@ -41228,7 +42816,7 @@ static void setDeviceCharacteristics(unixFile *pFile){
pFile->sectorSize = fsInfo.f_bsize;
pFile->deviceCharacteristics =
/* full bitset of atomics from max sector size and smaller */
- ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
+ (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) |
SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
** so it is ordered */
0;
@@ -41236,7 +42824,7 @@ static void setDeviceCharacteristics(unixFile *pFile){
pFile->sectorSize = fsInfo.f_bsize;
pFile->deviceCharacteristics =
/* full bitset of atomics from max sector size and smaller */
- ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
+ (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) |
SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
** so it is ordered */
0;
@@ -41312,7 +42900,7 @@ static int unixGetpagesize(void){
#endif /* !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 */
-#ifndef SQLITE_OMIT_WAL
+#if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL)
/*
** Object used to represent an shared memory buffer.
@@ -41342,6 +42930,25 @@ static int unixGetpagesize(void){
** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and
** unixMutexHeld() is true when reading or writing any other field
** in this structure.
+**
+** aLock[SQLITE_SHM_NLOCK]:
+** This array records the various locks held by clients on each of the
+** SQLITE_SHM_NLOCK slots. If the aLock[] entry is set to 0, then no
+** locks are held by the process on this slot. If it is set to -1, then
+** some client holds an EXCLUSIVE lock on the locking slot. If the aLock[]
+** value is set to a positive value, then it is the number of shared
+** locks currently held on the slot.
+**
+** aMutex[SQLITE_SHM_NLOCK]:
+** Normally, when SQLITE_ENABLE_SETLK_TIMEOUT is not defined, mutex
+** pShmMutex is used to protect the aLock[] array and the right to
+** call fcntl() on unixShmNode.hShm to obtain or release locks.
+**
+** If SQLITE_ENABLE_SETLK_TIMEOUT is defined though, we use an array
+** of mutexes - one for each locking slot. To read or write locking
+** slot aLock[iSlot], the caller must hold the corresponding mutex
+** aMutex[iSlot]. Similarly, to call fcntl() to obtain or release a
+** lock corresponding to slot iSlot, mutex aMutex[iSlot] must be held.
*/
struct unixShmNode {
unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
@@ -41355,10 +42962,11 @@ struct unixShmNode {
char **apRegion; /* Array of mapped shared-memory regions */
int nRef; /* Number of unixShm objects pointing to this */
unixShm *pFirst; /* All unixShm objects pointing to this */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ wx_sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK];
+#endif
int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */
#ifdef SQLITE_DEBUG
- u8 exclMask; /* Mask of exclusive locks held */
- u8 sharedMask; /* Mask of shared locks held */
u8 nextShmId; /* Next available unixShm.id value */
#endif
};
@@ -41441,16 +43049,35 @@ static int unixShmSystemLock(
struct flock f; /* The posix advisory locking structure */
int rc = SQLITE_OK; /* Result code form fcntl() */
- /* Access to the unixShmNode object is serialized by the caller */
pShmNode = pFile->pInode->pShmNode;
- assert( pShmNode->nRef==0 || wx_sqlite3_mutex_held(pShmNode->pShmMutex) );
- assert( pShmNode->nRef>0 || unixMutexHeld() );
+
+ /* Assert that the parameters are within expected range and that the
+ ** correct mutex or mutexes are held. */
+ assert( pShmNode->nRef>=0 );
+ assert( (ofst==UNIX_SHM_DMS && n==1)
+ || (ofst>=UNIX_SHM_BASE && ofst+n<=(UNIX_SHM_BASE+SQLITE_SHM_NLOCK))
+ );
+ if( ofst==UNIX_SHM_DMS ){
+ assert( pShmNode->nRef>0 || unixMutexHeld() );
+ assert( pShmNode->nRef==0 || wx_sqlite3_mutex_held(pShmNode->pShmMutex) );
+ }else{
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ int ii;
+ for(ii=ofst-UNIX_SHM_BASE; ii<ofst-UNIX_SHM_BASE+n; ii++){
+ assert( wx_sqlite3_mutex_held(pShmNode->aMutex[ii]) );
+ }
+#else
+ assert( wx_sqlite3_mutex_held(pShmNode->pShmMutex) );
+ assert( pShmNode->nRef>0 );
+#endif
+ }
/* Shared locks never span more than one byte */
assert( n==1 || lockType!=F_RDLCK );
/* Locks are within range */
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
+ assert( ofst>=UNIX_SHM_BASE && ofst<=(UNIX_SHM_DMS+SQLITE_SHM_NLOCK) );
if( pShmNode->hShm>=0 ){
int res;
@@ -41461,7 +43088,7 @@ static int unixShmSystemLock(
f.l_len = n;
res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
if( res==-1 ){
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && SQLITE_ENABLE_SETLK_TIMEOUT==1
rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
#else
rc = SQLITE_BUSY;
@@ -41469,39 +43096,28 @@ static int unixShmSystemLock(
}
}
- /* Update the global lock state and do debug tracing */
+ /* Do debug tracing */
#ifdef SQLITE_DEBUG
- { u16 mask;
OSTRACE(("SHM-LOCK "));
- mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<<ofst);
if( rc==SQLITE_OK ){
if( lockType==F_UNLCK ){
- OSTRACE(("unlock %d ok", ofst));
- pShmNode->exclMask &= ~mask;
- pShmNode->sharedMask &= ~mask;
+ OSTRACE(("unlock %d..%d ok\n", ofst, ofst+n-1));
}else if( lockType==F_RDLCK ){
- OSTRACE(("read-lock %d ok", ofst));
- pShmNode->exclMask &= ~mask;
- pShmNode->sharedMask |= mask;
+ OSTRACE(("read-lock %d..%d ok\n", ofst, ofst+n-1));
}else{
assert( lockType==F_WRLCK );
- OSTRACE(("write-lock %d ok", ofst));
- pShmNode->exclMask |= mask;
- pShmNode->sharedMask &= ~mask;
+ OSTRACE(("write-lock %d..%d ok\n", ofst, ofst+n-1));
}
}else{
if( lockType==F_UNLCK ){
- OSTRACE(("unlock %d failed", ofst));
+ OSTRACE(("unlock %d..%d failed\n", ofst, ofst+n-1));
}else if( lockType==F_RDLCK ){
- OSTRACE(("read-lock failed"));
+ OSTRACE(("read-lock %d..%d failed\n", ofst, ofst+n-1));
}else{
assert( lockType==F_WRLCK );
- OSTRACE(("write-lock %d failed", ofst));
+ OSTRACE(("write-lock %d..%d failed\n", ofst, ofst+n-1));
}
}
- OSTRACE((" - afterwards %03x,%03x\n",
- pShmNode->sharedMask, pShmNode->exclMask));
- }
#endif
return rc;
@@ -41538,6 +43154,11 @@ static void unixShmPurge(unixFile *pFd){
int i;
assert( p->pInode==pFd->pInode );
wx_sqlite3_mutex_free(p->pShmMutex);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ for(i=0; i<SQLITE_SHM_NLOCK; i++){
+ wx_sqlite3_mutex_free(p->aMutex[i]);
+ }
+#endif
for(i=0; i<p->nRegion; i+=nShmPerMap){
if( p->hShm>=0 ){
osMunmap(p->apRegion[i], p->szRegion);
@@ -41597,7 +43218,20 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
pShmNode->isUnlocked = 1;
rc = SQLITE_READONLY_CANTINIT;
}else{
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ /* Do not use a blocking lock here. If the lock cannot be obtained
+ ** immediately, it means some other connection is truncating the
+ ** *-shm file. And after it has done so, it will not release its
+ ** lock, but only downgrade it to a shared lock. So no point in
+ ** blocking here. The call below to obtain the shared DMS lock may
+ ** use a blocking lock. */
+ int iSaveTimeout = pDbFd->iBusyTimeout;
+ pDbFd->iBusyTimeout = 0;
+#endif
rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ pDbFd->iBusyTimeout = iSaveTimeout;
+#endif
/* The first connection to attach must truncate the -shm file. We
** truncate to 3 bytes (an arbitrary small number, less than the
** -shm header size) rather than 0 as a system debugging aid, to
@@ -41718,6 +43352,18 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
rc = SQLITE_NOMEM_BKPT;
goto shm_open_err;
}
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ {
+ int ii;
+ for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
+ pShmNode->aMutex[ii] = wx_sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->aMutex[ii]==0 ){
+ rc = SQLITE_NOMEM_BKPT;
+ goto shm_open_err;
+ }
+ }
+ }
+#endif
}
if( pInode->bProcessLock==0 ){
@@ -41939,9 +43585,11 @@ shmpage_out:
*/
#ifdef SQLITE_DEBUG
static int assertLockingArrayOk(unixShmNode *pShmNode){
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ return 1;
+#else
unixShm *pX;
int aLock[SQLITE_SHM_NLOCK];
- assert( wx_sqlite3_mutex_held(pShmNode->pShmMutex) );
memset(aLock, 0, sizeof(aLock));
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
@@ -41959,13 +43607,14 @@ static int assertLockingArrayOk(unixShmNode *pShmNode){
assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) );
return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0);
+#endif
}
#endif
/*
** Change the lock state for a shared-memory segment.
**
-** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
+** Note that the relationship between SHARED and EXCLUSIVE locks is a little
** different here than in posix. In xShmLock(), one can go from unlocked
** to shared and back or from unlocked to exclusive and back. But one may
** not go from shared to exclusive or from exclusive to shared.
@@ -41980,7 +43629,7 @@ static int unixShmLock(
unixShm *p; /* The shared memory being locked */
unixShmNode *pShmNode; /* The underlying file iNode */
int rc = SQLITE_OK; /* Result code */
- u16 mask; /* Mask of locks to take or release */
+ u16 mask = (1<<(ofst+n)) - (1<<ofst); /* Mask of locks to take or release */
int *aLock;
p = pDbFd->pShm;
@@ -42015,88 +43664,151 @@ static int unixShmLock(
** It is not permitted to block on the RECOVER lock.
*/
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
- (ofst!=2) /* not RECOVER */
- && (ofst!=1 || (p->exclMask|p->sharedMask)==0)
- && (ofst!=0 || (p->exclMask|p->sharedMask)<3)
- && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
- ));
+ {
+ u16 lockMask = (p->exclMask|p->sharedMask);
+ assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
+ (ofst!=2) /* not RECOVER */
+ && (ofst!=1 || lockMask==0 || lockMask==2)
+ && (ofst!=0 || lockMask<3)
+ && (ofst<3 || lockMask<(1<<ofst))
+ ));
+ }
#endif
- mask = (1<<(ofst+n)) - (1<<ofst);
- assert( n>1 || mask==(1<<ofst) );
- wx_sqlite3_mutex_enter(pShmNode->pShmMutex);
- assert( assertLockingArrayOk(pShmNode) );
- if( flags & SQLITE_SHM_UNLOCK ){
- if( (p->exclMask|p->sharedMask) & mask ){
- int ii;
- int bUnlock = 1;
+ /* Check if there is any work to do. There are three cases:
+ **
+ ** a) An unlock operation where there are locks to unlock,
+ ** b) An shared lock where the requested lock is not already held
+ ** c) An exclusive lock where the requested lock is not already held
+ **
+ ** The SQLite core never requests an exclusive lock that it already holds.
+ ** This is assert()ed below.
+ */
+ assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)
+ || 0==(p->exclMask & mask)
+ );
+ if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask))
+ || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask))
+ || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK))
+ ){
- for(ii=ofst; ii<ofst+n; ii++){
- if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){
- bUnlock = 0;
- }
+ /* Take the required mutexes. In SETLK_TIMEOUT mode (blocking locks), if
+ ** this is an attempt on an exclusive lock use wx_sqlite3_mutex_try(). If any
+ ** other thread is holding this mutex, then it is either holding or about
+ ** to hold a lock exclusive to the one being requested, and we may
+ ** therefore return SQLITE_BUSY to the caller.
+ **
+ ** Doing this prevents some deadlock scenarios. For example, thread 1 may
+ ** be a checkpointer blocked waiting on the WRITER lock. And thread 2
+ ** may be a normal SQL client upgrading to a write transaction. In this
+ ** case thread 2 does a non-blocking request for the WRITER lock. But -
+ ** if it were to use wx_sqlite3_mutex_enter() then it would effectively
+ ** become a (doomed) blocking request, as thread 2 would block until thread
+ ** 1 obtained WRITER and released the mutex. Since thread 2 already holds
+ ** a lock on a read-locking slot at this point, this breaks the
+ ** anti-deadlock rules (see above). */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ int iMutex;
+ for(iMutex=ofst; iMutex<ofst+n; iMutex++){
+ if( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) ){
+ rc = wx_sqlite3_mutex_try(pShmNode->aMutex[iMutex]);
+ if( rc!=SQLITE_OK ) goto leave_shmnode_mutexes;
+ }else{
+ wx_sqlite3_mutex_enter(pShmNode->aMutex[iMutex]);
}
+ }
+#else
+ wx_sqlite3_mutex_enter(pShmNode->pShmMutex);
+#endif
- if( bUnlock ){
- rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
- if( rc==SQLITE_OK ){
- memset(&aLock[ofst], 0, sizeof(int)*n);
+ if( ALWAYS(rc==SQLITE_OK) ){
+ if( flags & SQLITE_SHM_UNLOCK ){
+ /* Case (a) - unlock. */
+ int bUnlock = 1;
+ assert( (p->exclMask & p->sharedMask)==0 );
+ assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask );
+ assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask );
+
+ /* If this is a SHARED lock being unlocked, it is possible that other
+ ** clients within this process are holding the same SHARED lock. In
+ ** this case, set bUnlock to 0 so that the posix lock is not removed
+ ** from the file-descriptor below. */
+ if( flags & SQLITE_SHM_SHARED ){
+ assert( n==1 );
+ assert( aLock[ofst]>=1 );
+ if( aLock[ofst]>1 ){
+ bUnlock = 0;
+ aLock[ofst]--;
+ p->sharedMask &= ~mask;
+ }
}
- }else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
- assert( n==1 && aLock[ofst]>1 );
- aLock[ofst]--;
- }
- /* Undo the local locks */
- if( rc==SQLITE_OK ){
- p->exclMask &= ~mask;
- p->sharedMask &= ~mask;
- }
- }
- }else if( flags & SQLITE_SHM_SHARED ){
- assert( n==1 );
- assert( (p->exclMask & (1<<ofst))==0 );
- if( (p->sharedMask & mask)==0 ){
- if( aLock[ofst]<0 ){
- rc = SQLITE_BUSY;
- }else if( aLock[ofst]==0 ){
- rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
- }
+ if( bUnlock ){
+ rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
+ if( rc==SQLITE_OK ){
+ memset(&aLock[ofst], 0, sizeof(int)*n);
+ p->sharedMask &= ~mask;
+ p->exclMask &= ~mask;
+ }
+ }
+ }else if( flags & SQLITE_SHM_SHARED ){
+ /* Case (b) - a shared lock. */
- /* Get the local shared locks */
- if( rc==SQLITE_OK ){
- p->sharedMask |= mask;
- aLock[ofst]++;
- }
- }
- }else{
- /* Make sure no sibling connections hold locks that will block this
- ** lock. If any do, return SQLITE_BUSY right away. */
- int ii;
- for(ii=ofst; ii<ofst+n; ii++){
- assert( (p->sharedMask & mask)==0 );
- if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
- rc = SQLITE_BUSY;
- break;
- }
- }
+ if( aLock[ofst]<0 ){
+ /* An exclusive lock is held by some other connection. BUSY. */
+ rc = SQLITE_BUSY;
+ }else if( aLock[ofst]==0 ){
+ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
+ }
- /* Get the exclusive locks at the system level. Then if successful
- ** also update the in-memory values. */
- if( rc==SQLITE_OK ){
- rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
- if( rc==SQLITE_OK ){
+ /* Get the local shared locks */
+ if( rc==SQLITE_OK ){
+ p->sharedMask |= mask;
+ aLock[ofst]++;
+ }
+ }else{
+ /* Case (c) - an exclusive lock. */
+ int ii;
+
+ assert( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) );
assert( (p->sharedMask & mask)==0 );
- p->exclMask |= mask;
+ assert( (p->exclMask & mask)==0 );
+
+ /* Make sure no sibling connections hold locks that will block this
+ ** lock. If any do, return SQLITE_BUSY right away. */
for(ii=ofst; ii<ofst+n; ii++){
- aLock[ii] = -1;
+ if( aLock[ii] ){
+ rc = SQLITE_BUSY;
+ break;
+ }
+ }
+
+ /* Get the exclusive locks at the system level. Then if successful
+ ** also update the in-memory values. */
+ if( rc==SQLITE_OK ){
+ rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
+ if( rc==SQLITE_OK ){
+ p->exclMask |= mask;
+ for(ii=ofst; ii<ofst+n; ii++){
+ aLock[ii] = -1;
+ }
+ }
}
}
+ assert( assertLockingArrayOk(pShmNode) );
+ }
+
+ /* Drop the mutexes acquired above. */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ leave_shmnode_mutexes:
+ for(iMutex--; iMutex>=ofst; iMutex--){
+ wx_sqlite3_mutex_leave(pShmNode->aMutex[iMutex]);
}
+#else
+ wx_sqlite3_mutex_leave(pShmNode->pShmMutex);
+#endif
}
- assert( assertLockingArrayOk(pShmNode) );
- wx_sqlite3_mutex_leave(pShmNode->pShmMutex);
+
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
p->id, osGetpid(0), p->sharedMask, p->exclMask));
return rc;
@@ -42346,11 +44058,16 @@ static int unixFetch(wx_sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
#if SQLITE_MAX_MMAP_SIZE>0
if( pFd->mmapSizeMax>0 ){
+ /* Ensure that there is always at least a 256 byte buffer of addressable
+ ** memory following the returned page. If the database is corrupt,
+ ** SQLite may overread the page slightly (in practice only a few bytes,
+ ** but 256 is safe, round, number). */
+ const int nEofBuffer = 256;
if( pFd->pMapRegion==0 ){
int rc = unixMapfile(pFd, -1);
if( rc!=SQLITE_OK ) return rc;
}
- if( pFd->mmapSize >= iOff+nAmt ){
+ if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){
*pp = &((u8 *)pFd->pMapRegion)[iOff];
pFd->nFetchOut++;
}
@@ -43294,12 +45011,19 @@ static int unixOpen(
rc = SQLITE_READONLY_DIRECTORY;
}else if( errno!=EISDIR && isReadWrite ){
/* Failed to open the file for read/write access. Try read-only. */
+ UnixUnusedFd *pReadonly = 0;
flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
openFlags &= ~(O_RDWR|O_CREAT);
flags |= SQLITE_OPEN_READONLY;
openFlags |= O_RDONLY;
isReadonly = 1;
- fd = robust_open(zName, openFlags, openMode);
+ pReadonly = findReusableFd(zName, flags);
+ if( pReadonly ){
+ fd = pReadonly->fd;
+ wx_sqlite3_free(pReadonly);
+ }else{
+ fd = robust_open(zName, openFlags, openMode);
+ }
}
}
if( fd<0 ){
@@ -43741,12 +45465,17 @@ static int unixRandomness(wx_sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
** than the argument.
*/
static int unixSleep(wx_sqlite3_vfs *NotUsed, int microseconds){
-#if OS_VXWORKS || _POSIX_C_SOURCE >= 199309L
+#if !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP+0
struct timespec sp;
-
sp.tv_sec = microseconds / 1000000;
sp.tv_nsec = (microseconds % 1000000) * 1000;
+
+ /* Almost all modern unix systems support nanosleep(). But if you are
+ ** compiling for one of the rare exceptions, you can use
+ ** -DHAVE_NANOSLEEP=0 (perhaps in conjuction with -DHAVE_USLEEP if
+ ** usleep() is available) in order to bypass the use of nanosleep() */
nanosleep(&sp, NULL);
+
UNUSED_PARAMETER(NotUsed);
return microseconds;
#elif defined(HAVE_USLEEP) && HAVE_USLEEP
@@ -46336,7 +48065,7 @@ static struct win_syscall {
/*
** This is the xSetSystemCall() method of wx_sqlite3_vfs for all of the
-** "win32" VFSes. Return SQLITE_OK opon successfully updating the
+** "win32" VFSes. Return SQLITE_OK upon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
*/
@@ -47916,7 +49645,7 @@ static int winRead(
pFile->h, pBuf, amt, offset, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
+ /* Deal with as much of this read request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -47994,7 +49723,7 @@ static int winWrite(
pFile->h, pBuf, amt, offset, pFile->locktype));
#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
+ /* Deal with as much of this write request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -48104,7 +49833,7 @@ static int winTruncate(wx_sqlite3_file *id, wx_sqlite3_int64 nByte){
** all references to memory-mapped content are closed. That is doable,
** but involves adding a few branches in the common write code path which
** could slow down normal operations slightly. Hence, we have decided for
- ** now to simply make trancations a no-op if there are pending reads. We
+ ** now to simply make transactions a no-op if there are pending reads. We
** can maybe revisit this decision in the future.
*/
return SQLITE_OK;
@@ -48163,7 +49892,7 @@ static int winTruncate(wx_sqlite3_file *id, wx_sqlite3_int64 nByte){
#ifdef SQLITE_TEST
/*
** Count the number of fullsyncs and normal syncs. This is used to test
-** that syncs and fullsyncs are occuring at the right times.
+** that syncs and fullsyncs are occurring at the right times.
*/
SQLITE_API int wx_sqlite3_sync_count = 0;
SQLITE_API int wx_sqlite3_fullsync_count = 0;
@@ -48520,7 +50249,7 @@ static int winLock(wx_sqlite3_file *id, int locktype){
*/
if( locktype==EXCLUSIVE_LOCK && res ){
assert( pFile->locktype>=SHARED_LOCK );
- res = winUnlockReadLock(pFile);
+ (void)winUnlockReadLock(pFile);
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
SHARED_SIZE, 0);
if( res ){
@@ -48837,7 +50566,7 @@ static int winSectorSize(wx_sqlite3_file *id){
*/
static int winDeviceCharacteristics(wx_sqlite3_file *id){
winFile *p = (winFile*)id;
- return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
+ return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | SQLITE_IOCAP_SUBPAGE_READ |
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
}
@@ -49698,6 +51427,11 @@ static int winFetch(wx_sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
#if SQLITE_MAX_MMAP_SIZE>0
if( pFd->mmapSizeMax>0 ){
+ /* Ensure that there is always at least a 256 byte buffer of addressable
+ ** memory following the returned page. If the database is corrupt,
+ ** SQLite may overread the page slightly (in practice only a few bytes,
+ ** but 256 is safe, round, number). */
+ const int nEofBuffer = 256;
if( pFd->pMapRegion==0 ){
int rc = winMapfile(pFd, -1);
if( rc!=SQLITE_OK ){
@@ -49706,7 +51440,7 @@ static int winFetch(wx_sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
return rc;
}
}
- if( pFd->mmapSize >= iOff+nAmt ){
+ if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){
assert( pFd->pMapRegion!=0 );
*pp = &((u8 *)pFd->pMapRegion)[iOff];
pFd->nFetchOut++;
@@ -49924,6 +51658,7 @@ static int winGetTempname(wx_sqlite3_vfs *pVfs, char **pzBuf){
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
size_t i, j;
+ DWORD pid;
int nPre = wx_sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX);
int nMax, nBuf, nDir, nLen;
char *zBuf;
@@ -50136,7 +51871,10 @@ static int winGetTempname(wx_sqlite3_vfs *pVfs, char **pzBuf){
j = wx_sqlite3Strlen30(zBuf);
wx_sqlite3_randomness(15, &zBuf[j]);
+ pid = osGetCurrentProcessId();
for(i=0; i<15; i++, j++){
+ zBuf[j] += pid & 0xff;
+ pid >>= 8;
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
@@ -50216,7 +51954,7 @@ static int winOpen(
int rc = SQLITE_OK; /* Function Return Code */
#if !defined(NDEBUG) || SQLITE_OS_WINCE
- int eType = flags&0xFFFFFF00; /* Type of file to open */
+ int eType = flags&0x0FFF00; /* Type of file to open */
#endif
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
@@ -50374,7 +52112,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
wx_sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
wx_sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -50391,7 +52129,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
wx_sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
wx_sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -50411,7 +52149,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
wx_sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
wx_sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -50634,6 +52372,13 @@ static int winAccess(
OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
zFilename, flags, pResOut));
+ if( zFilename==0 ){
+ *pResOut = 0;
+ OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+ zFilename, pResOut, *pResOut));
+ return SQLITE_OK;
+ }
+
zConverted = winConvertFromUtf8Filename(zFilename);
if( zConverted==0 ){
OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
@@ -52174,6 +53919,14 @@ SQLITE_API unsigned char *wx_sqlite3_serialize(
pOut = 0;
}else{
sz = wx_sqlite3_column_int64(pStmt, 0)*szPage;
+ if( sz==0 ){
+ wx_sqlite3_reset(pStmt);
+ wx_sqlite3_exec(db, "BEGIN IMMEDIATE; COMMIT;", 0, 0, 0);
+ rc = wx_sqlite3_step(pStmt);
+ if( rc==SQLITE_ROW ){
+ sz = wx_sqlite3_column_int64(pStmt, 0)*szPage;
+ }
+ }
if( piSize ) *piSize = sz;
if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
pOut = 0;
@@ -52494,7 +54247,7 @@ SQLITE_PRIVATE int wx_sqlite3BitvecSet(Bitvec *p, u32 i){
h = BITVEC_HASH(i++);
/* if there wasn't a hash collision, and this doesn't */
/* completely fill the hash, then just add it without */
- /* worring about sub-dividing and re-hashing. */
+ /* worrying about sub-dividing and re-hashing. */
if( !p->u.aHash[h] ){
if (p->nSet<(BITVEC_NINT-1)) {
goto bitvec_set_end;
@@ -52790,11 +54543,15 @@ struct PCache {
PgHdr *pPg;
unsigned char *a;
int j;
- pPg = (PgHdr*)pLower->pExtra;
- printf("%3lld: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
- a = (unsigned char *)pLower->pBuf;
- for(j=0; j<12; j++) printf("%02x", a[j]);
- printf(" ptr %p\n", pPg);
+ if( pLower==0 ){
+ printf("%3d: NULL\n", i);
+ }else{
+ pPg = (PgHdr*)pLower->pExtra;
+ printf("%3d: nRef %2lld flgs %02x data ", i, pPg->nRef, pPg->flags);
+ a = (unsigned char *)pLower->pBuf;
+ for(j=0; j<12; j++) printf("%02x", a[j]);
+ printf(" ptr %p\n", pPg);
+ }
}
static void pcacheDump(PCache *pCache){
int N;
@@ -52807,9 +54564,8 @@ struct PCache {
if( N>wx_sqlite3PcacheMxDump ) N = wx_sqlite3PcacheMxDump;
for(i=1; i<=N; i++){
pLower = wx_sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
- if( pLower==0 ) continue;
pcachePageTrace(i, pLower);
- if( ((PgHdr*)pLower)->pPage==0 ){
+ if( pLower && ((PgHdr*)pLower)->pPage==0 ){
wx_sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
}
}
@@ -52824,7 +54580,7 @@ struct PCache {
** Return 1 if pPg is on the dirty list for pCache. Return 0 if not.
** This routine runs inside of assert() statements only.
*/
-#ifdef SQLITE_DEBUG
+#if defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
PgHdr *p;
for(p=pCache->pDirty; p; p=p->pDirtyNext){
@@ -52832,6 +54588,16 @@ static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
}
return 0;
}
+static int pageNotOnDirtyList(PCache *pCache, PgHdr *pPg){
+ PgHdr *p;
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){
+ if( p==pPg ) return 0;
+ }
+ return 1;
+}
+#else
+# define pageOnDirtyList(A,B) 1
+# define pageNotOnDirtyList(A,B) 1
#endif
/*
@@ -52852,7 +54618,7 @@ SQLITE_PRIVATE int wx_sqlite3PcachePageSanity(PgHdr *pPg){
assert( pCache!=0 ); /* Every page has an associated PCache */
if( pPg->flags & PGHDR_CLEAN ){
assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
- assert( !pageOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirty list */
+ assert( pageNotOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirtylist */
}else{
assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */
assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg );
@@ -52988,7 +54754,7 @@ static int numberOfCachePages(PCache *p){
return p->szCache;
}else{
i64 n;
- /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
+ /* IMPLEMENTATION-OF: R-59858-46238 If the argument N is negative, then the
** number of cache pages is adjusted to be a number of pages that would
** use approximately abs(N*1024) bytes of memory based on the current
** page size. */
@@ -53219,6 +54985,7 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
pPgHdr->pData = pPage->pBuf;
pPgHdr->pExtra = (void *)&pPgHdr[1];
memset(pPgHdr->pExtra, 0, 8);
+ assert( EIGHT_BYTE_ALIGNMENT( pPgHdr->pExtra ) );
pPgHdr->pCache = pCache;
pPgHdr->pgno = pgno;
pPgHdr->flags = PGHDR_CLEAN;
@@ -53476,7 +55243,7 @@ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
}
/*
-** Sort the list of pages in accending order by pgno. Pages are
+** Sort the list of pages in ascending order by pgno. Pages are
** connected by pDirty pointers. The pDirtyPrev pointers are
** corrupted by this sort.
**
@@ -53716,7 +55483,7 @@ SQLITE_PRIVATE void wx_sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(P
** If N is positive, then N pages worth of memory are allocated using a single
** wx_sqlite3Malloc() call and that memory is used for the first N pages allocated.
** Or if N is negative, then -1024*N bytes of memory are allocated and used
-** for as many pages as can be accomodated.
+** for as many pages as can be accommodated.
**
** Only one of (2) or (3) can be used. Once the memory available to (2) or
** (3) is exhausted, subsequent allocations fail over to the general-purpose
@@ -53750,7 +55517,7 @@ typedef struct PGroup PGroup;
** in memory directly after the associated page data, if the database is
** corrupt, code at the b-tree layer may overread the page buffer and
** read part of this structure before the corruption is detected. This
-** can cause a valgrind error if the unitialized gap is accessed. Using u16
+** can cause a valgrind error if the uninitialized gap is accessed. Using u16
** ensures there is no such gap, and therefore no bytes of uninitialized
** memory in the structure.
**
@@ -53965,7 +55732,8 @@ static int pcache1InitBulk(PCache1 *pCache){
do{
PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage];
pX->page.pBuf = zBulk;
- pX->page.pExtra = &pX[1];
+ pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX));
+ assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) );
pX->isBulkLocal = 1;
pX->isAnchor = 0;
pX->pNext = pCache->pFree;
@@ -54102,7 +55870,8 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
if( pPg==0 ) return 0;
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
p->page.pBuf = pPg;
- p->page.pExtra = &p[1];
+ p->page.pExtra = (u8*)p + ROUND8(sizeof(*p));
+ assert( EIGHT_BYTE_ALIGNMENT( p->page.pExtra ) );
p->isBulkLocal = 0;
p->isAnchor = 0;
p->pLruPrev = 0; /* Initializing this saves a valgrind error */
@@ -54970,7 +56739,7 @@ SQLITE_PRIVATE void wx_sqlite3PcacheStats(
** The TEST primitive includes a "batch" number. The TEST primitive
** will only see elements that were inserted before the last change
** in the batch number. In other words, if an INSERT occurs between
-** two TESTs where the TESTs have the same batch nubmer, then the
+** two TESTs where the TESTs have the same batch number, then the
** value added by the INSERT will not be visible to the second TEST.
** The initial batch number is zero, so if the very first TEST contains
** a non-zero batch number, it will see all prior INSERTs.
@@ -55502,6 +57271,7 @@ SQLITE_PRIVATE int wx_sqlite3RowSetTest(RowSet *pRowSet, int iBatch, wx_sqlite3_
# define wx_sqlite3WalFramesize(z) 0
# define wx_sqlite3WalFindFrame(x,y,z) 0
# define wx_sqlite3WalFile(x) 0
+# undef SQLITE_USE_SEH
#else
#define WAL_SAVEPOINT_NDATA 4
@@ -55608,6 +57378,10 @@ SQLITE_PRIVATE int wx_sqlite3WalWriteLock(Wal *pWal, int bLock);
SQLITE_PRIVATE void wx_sqlite3WalDb(Wal *pWal, wx_sqlite3 *db);
#endif
+#ifdef SQLITE_USE_SEH
+SQLITE_PRIVATE int wx_sqlite3WalSystemErrno(Wal*);
+#endif
+
#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* SQLITE_WAL_H */
@@ -55893,7 +57667,7 @@ int wx_sqlite3PagerTrace=1; /* True to enable tracing */
** outstanding transactions have been abandoned, the pager is able to
** transition back to OPEN state, discarding the contents of the
** page-cache and any other in-memory state at the same time. Everything
-** is reloaded from disk (and, if necessary, hot-journal rollback peformed)
+** is reloaded from disk (and, if necessary, hot-journal rollback performed)
** when a read-transaction is next opened on the pager (transitioning
** the pager into READER state). At that point the system has recovered
** from the error.
@@ -56280,7 +58054,7 @@ struct Pager {
char *zJournal; /* Name of the journal file */
int (*xBusyHandler)(void*); /* Function to call when busy */
void *pBusyHandlerArg; /* Context argument for xBusyHandler */
- int aStat[4]; /* Total cache hits, misses, writes, spills */
+ u32 aStat[4]; /* Total cache hits, misses, writes, spills */
#ifdef SQLITE_TEST
int nRead; /* Database pages read */
#endif
@@ -56400,19 +58174,27 @@ static const unsigned char aJournalMagic[] = {
** Return true if page pgno can be read directly from the database file
** by the b-tree layer. This is the case if:
**
-** * the database file is open,
-** * there are no dirty pages in the cache, and
-** * the desired page is not currently in the wal file.
+** (1) the database file is open
+** (2) the VFS for the database is able to do unaligned sub-page reads
+** (3) there are no dirty pages in the cache, and
+** (4) the desired page is not currently in the wal file.
*/
SQLITE_PRIVATE int wx_sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
- if( pPager->fd->pMethods==0 ) return 0;
- if( wx_sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;
+ assert( pPager!=0 );
+ assert( pPager->fd!=0 );
+ if( pPager->fd->pMethods==0 ) return 0; /* Case (1) */
+ assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 );
+ if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd)
+ & SQLITE_IOCAP_SUBPAGE_READ)==0 ){
+ return 0; /* Case (2) */
+ }
+ if( wx_sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; /* Failed (3) */
+ if( wx_sqlite3mcPagerHasCodec(pPager) != 0 ) return 0;
#ifndef SQLITE_OMIT_WAL
if( pPager->pWal ){
u32 iRead = 0;
- int rc;
- rc = wx_sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
- return (rc==SQLITE_OK && iRead==0);
+ (void)wx_sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
+ return iRead==0; /* Condition (4) */
}
#endif
return 1;
@@ -56640,7 +58422,7 @@ static void setGetterMethod(Pager *pPager){
if( pPager->errCode ){
pPager->xGet = getPageError;
#if SQLITE_MAX_MMAP_SIZE>0
- }else if( USEFETCH(pPager) ){
+ }else if( USEFETCH(pPager) && wx_sqlite3mcPagerHasCodec(pPager) == 0 ){
pPager->xGet = getPageMMap;
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
}else{
@@ -57084,9 +58866,32 @@ static int writeJournalHdr(Pager *pPager){
memset(zHeader, 0, sizeof(aJournalMagic)+4);
}
+
+
/* The random check-hash initializer */
- wx_sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
+ if( pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){
+ wx_sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
+ }
+#ifdef SQLITE_DEBUG
+ else{
+ /* The Pager.cksumInit variable is usually randomized above to protect
+ ** against there being existing records in the journal file. This is
+ ** dangerous, as following a crash they may be mistaken for records
+ ** written by the current transaction and rolled back into the database
+ ** file, causing corruption. The following assert statements verify
+ ** that this is not required in "journal_mode=memory" mode, as in that
+ ** case the journal file is always 0 bytes in size at this point.
+ ** It is advantageous to avoid the wx_sqlite3_randomness() call if possible
+ ** as it takes the global PRNG mutex. */
+ i64 sz = 0;
+ wx_sqlite3OsFileSize(pPager->jfd, &sz);
+ assert( sz==0 );
+ assert( pPager->journalOff==journalHdrOffset(pPager) );
+ assert( wx_sqlite3JournalIsInMemory(pPager->jfd) );
+ }
+#endif
put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
+
/* The initial database size */
put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbOrigSize);
/* The assumed sector size for this process */
@@ -57266,7 +59071,7 @@ static int readJournalHdr(
** + 4 bytes: super-journal name checksum.
** + 8 bytes: aJournalMagic[].
**
-** The super-journal page checksum is the sum of the bytes in thesuper-journal
+** The super-journal page checksum is the sum of the bytes in the super-journal
** name, where each byte is interpreted as a signed 8-bit integer.
**
** If zSuper is a NULL pointer (occurs for a single database transaction),
@@ -57319,7 +59124,7 @@ static int writeSuperJournal(Pager *pPager, const char *zSuper){
}
pPager->journalOff += (nSuper+20);
- /* If the pager is in peristent-journal mode, then the physical
+ /* If the pager is in persistent-journal mode, then the physical
** journal-file may extend past the end of the super-journal name
** and 8 bytes of magic data just written to the file. This is
** dangerous because the code to rollback a hot-journal file
@@ -57489,7 +59294,7 @@ static void pager_unlock(Pager *pPager){
/*
** This function is called whenever an IOERR or FULL error that requires
-** the pager to transition into the ERROR state may ahve occurred.
+** the pager to transition into the ERROR state may have occurred.
** The first argument is a pointer to the pager structure, the second
** the error-code about to be returned by a pager API function. The
** value returned is a copy of the second argument to this function.
@@ -57730,6 +59535,9 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
return (rc==SQLITE_OK?rc2:rc);
}
+/* Forward reference */
+static int pager_playback(Pager *pPager, int isHot);
+
/*
** Execute a rollback if a transaction is active and unlock the
** database file.
@@ -57758,13 +59566,28 @@ static void pagerUnlockAndRollback(Pager *pPager){
assert( pPager->eState==PAGER_READER );
pager_end_transaction(pPager, 0, 0);
}
+ }else if( pPager->eState==PAGER_ERROR
+ && pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+ && isOpen(pPager->jfd)
+ ){
+ /* Special case for a ROLLBACK due to I/O error with an in-memory
+ ** journal: We have to rollback immediately, before the journal is
+ ** closed, because once it is closed, all content is forgotten. */
+ int errCode = pPager->errCode;
+ u8 eLock = pPager->eLock;
+ pPager->eState = PAGER_OPEN;
+ pPager->errCode = SQLITE_OK;
+ pPager->eLock = EXCLUSIVE_LOCK;
+ pager_playback(pPager, 1);
+ pPager->errCode = errCode;
+ pPager->eLock = eLock;
}
pager_unlock(pPager);
}
/*
** Parameter aData must point to a buffer of pPager->pageSize bytes
-** of data. Compute and return a checksum based ont the contents of the
+** of data. Compute and return a checksum based on the contents of the
** page of data and the current value of pPager->cksumInit.
**
** This is not a real checksum. It is really just the sum of the
@@ -58197,6 +60020,8 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
int rc = SQLITE_OK;
assert( pPager->eState!=PAGER_ERROR );
assert( pPager->eState!=PAGER_READER );
+ PAGERTRACE(("Truncate %d npage %u\n", PAGERID(pPager), nPage));
+
if( isOpen(pPager->fd)
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
@@ -58728,7 +60553,7 @@ static int pagerWalFrames(
assert( pPager->pWal );
assert( pList );
#ifdef SQLITE_DEBUG
- /* Verify that the page list is in accending order */
+ /* Verify that the page list is in ascending order */
for(p=pList; p && p->pDirty; p=p->pDirty){
assert( p->pgno < p->pDirty->pgno );
}
@@ -58859,7 +60684,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
#ifndef SQLITE_OMIT_WAL
/*
** Check if the *-wal file that corresponds to the database opened by pPager
-** exists if the database is not empy, or verify that the *-wal file does
+** exists if the database is not empty, or verify that the *-wal file does
** not exist (by deleting it) if the database file is empty.
**
** If the database is not empty and the *-wal file exists, open the pager
@@ -59614,6 +61439,7 @@ static int pagerAcquireMapPage(
return SQLITE_NOMEM_BKPT;
}
p->pExtra = (void *)&p[1];
+ assert( EIGHT_BYTE_ALIGNMENT( p->pExtra ) );
p->flags = PGHDR_MMAP;
p->nRef = 1;
p->pPager = pPager;
@@ -60269,11 +62095,7 @@ SQLITE_PRIVATE int wx_sqlite3PagerOpen(
int rc = SQLITE_OK; /* Return code */
int tempFile = 0; /* True for temp files (incl. in-memory files) */
int memDb = 0; /* True if this is an in-memory file */
-#ifndef SQLITE_OMIT_DESERIALIZE
int memJM = 0; /* Memory journal mode */
-#else
-# define memJM 0
-#endif
int readOnly = 0; /* True if this is a read-only file */
int journalFileSize; /* Bytes to allocate for each journal fd */
char *zPathname = 0; /* Full path to database file */
@@ -60392,12 +62214,13 @@ SQLITE_PRIVATE int wx_sqlite3PagerOpen(
** specific formatting and order of the various filenames, so if the format
** changes here, be sure to change it there as well.
*/
+ assert( SQLITE_PTRSIZE==sizeof(Pager*) );
pPtr = (u8 *)wx_sqlite3MallocZero(
ROUND8(sizeof(*pPager)) + /* Pager structure */
ROUND8(pcacheSize) + /* PCache object */
ROUND8(pVfs->szOsFile) + /* The main db file */
journalFileSize * 2 + /* The two journal files */
- sizeof(pPager) + /* Space to hold a pointer */
+ SQLITE_PTRSIZE + /* Space to hold a pointer */
4 + /* Database prefix */
nPathname + 1 + /* database filename */
nUriByte + /* query parameters */
@@ -60418,7 +62241,7 @@ SQLITE_PRIVATE int wx_sqlite3PagerOpen(
pPager->sjfd = (wx_sqlite3_file*)pPtr; pPtr += journalFileSize;
pPager->jfd = (wx_sqlite3_file*)pPtr; pPtr += journalFileSize;
assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );
- memcpy(pPtr, &pPager, sizeof(pPager)); pPtr += sizeof(pPager);
+ memcpy(pPtr, &pPager, SQLITE_PTRSIZE); pPtr += SQLITE_PTRSIZE;
/* Fill in the Pager.zFilename and pPager.zQueryParam fields */
pPtr += 4; /* Skip zero prefix */
@@ -60472,9 +62295,7 @@ SQLITE_PRIVATE int wx_sqlite3PagerOpen(
int fout = 0; /* VFS flags returned by xOpen() */
rc = wx_sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
assert( !memDb );
-#ifndef SQLITE_OMIT_DESERIALIZE
pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
-#endif
readOnly = (fout&SQLITE_OPEN_READONLY)!=0;
/* If the file was successfully opened for read/write access,
@@ -60611,15 +62432,18 @@ act_like_temp_file:
/*
** Return the wx_sqlite3_file for the main database given the name
-** of the corresonding WAL or Journal name as passed into
+** of the corresponding WAL or Journal name as passed into
** xOpen.
*/
SQLITE_API wx_sqlite3_file *wx_sqlite3_database_file_object(const char *zName){
Pager *pPager;
+ const char *p;
while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){
zName--;
}
- pPager = *(Pager**)(zName - 4 - sizeof(Pager*));
+ p = zName - 4 - sizeof(Pager*);
+ assert( EIGHT_BYTE_ALIGNMENT(p) );
+ pPager = *(Pager**)p;
return pPager->fd;
}
@@ -61114,6 +62938,10 @@ static int getPageNormal(
if( !isOpen(pPager->fd) || pPager->dbSize<pgno || noContent ){
if( pgno>pPager->mxPgno ){
rc = SQLITE_FULL;
+ if( pgno<=pPager->dbSize ){
+ wx_sqlite3PcacheRelease(pPg);
+ pPg = 0;
+ }
goto pager_acquire_err;
}
if( noContent ){
@@ -61249,8 +63077,20 @@ SQLITE_PRIVATE int wx_sqlite3PagerGet(
DbPage **ppPage, /* Write a pointer to the page here */
int flags /* PAGER_GET_XXX flags */
){
- /* printf("PAGE %u\n", pgno); fflush(stdout); */
+#if 0 /* Trace page fetch by setting to 1 */
+ int rc;
+ printf("PAGE %u\n", pgno);
+ fflush(stdout);
+ rc = pPager->xGet(pPager, pgno, ppPage, flags);
+ if( rc ){
+ printf("PAGE %u failed with 0x%02x\n", pgno, rc);
+ fflush(stdout);
+ }
+ return rc;
+#else
+ /* Normal, high-speed version of wx_sqlite3PagerGet() */
return pPager->xGet(pPager, pgno, ppPage, flags);
+#endif
}
/*
@@ -61278,10 +63118,12 @@ SQLITE_PRIVATE DbPage *wx_sqlite3PagerLookup(Pager *pPager, Pgno pgno){
/*
** Release a page reference.
**
-** The wx_sqlite3PagerUnref() and wx_sqlite3PagerUnrefNotNull() may only be
-** used if we know that the page being released is not the last page.
+** The wx_sqlite3PagerUnref() and wx_sqlite3PagerUnrefNotNull() may only be used
+** if we know that the page being released is not the last reference to page1.
** The btree layer always holds page1 open until the end, so these first
-** to routines can be used to release any page other than BtShared.pPage1.
+** two routines can be used to release any page other than BtShared.pPage1.
+** The assert() at tag-20230419-2 proves that this constraint is always
+** honored.
**
** Use wx_sqlite3PagerUnrefPageOne() to release page1. This latter routine
** checks the total number of outstanding pages and if the number of
@@ -61297,7 +63139,7 @@ SQLITE_PRIVATE void wx_sqlite3PagerUnrefNotNull(DbPage *pPg){
wx_sqlite3PcacheRelease(pPg);
}
/* Do not use this routine to release the last reference to page1 */
- assert( wx_sqlite3PcacheRefCount(pPager->pPCache)>0 );
+ assert( wx_sqlite3PcacheRefCount(pPager->pPCache)>0 ); /* tag-20230419-2 */
}
SQLITE_PRIVATE void wx_sqlite3PagerUnref(DbPage *pPg){
if( pPg ) wx_sqlite3PagerUnrefNotNull(pPg);
@@ -62124,6 +63966,13 @@ SQLITE_PRIVATE int wx_sqlite3PagerCommitPhaseOne(
rc = wx_sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
if( rc==SQLITE_OK ){
rc = pager_write_pagelist(pPager, pList);
+ if( rc==SQLITE_OK && pPager->dbSize>pPager->dbFileSize ){
+ char *pTmp = pPager->pTmpSpace;
+ int szPage = (int)pPager->pageSize;
+ memset(pTmp, 0, szPage);
+ rc = wx_sqlite3OsWrite(pPager->fd, pTmp, szPage,
+ ((i64)pPager->dbSize*pPager->pageSize)-szPage);
+ }
if( rc==SQLITE_OK ){
rc = wx_sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
}
@@ -62358,11 +64207,11 @@ SQLITE_PRIVATE int *wx_sqlite3PagerStats(Pager *pPager){
a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize;
a[4] = pPager->eState;
a[5] = pPager->errCode;
- a[6] = pPager->aStat[PAGER_STAT_HIT];
- a[7] = pPager->aStat[PAGER_STAT_MISS];
+ a[6] = (int)pPager->aStat[PAGER_STAT_HIT] & 0x7fffffff;
+ a[7] = (int)pPager->aStat[PAGER_STAT_MISS] & 0x7fffffff;
a[8] = 0; /* Used to be pPager->nOvfl */
a[9] = pPager->nRead;
- a[10] = pPager->aStat[PAGER_STAT_WRITE];
+ a[10] = (int)pPager->aStat[PAGER_STAT_WRITE] & 0x7fffffff;
return a;
}
#endif
@@ -62378,7 +64227,7 @@ SQLITE_PRIVATE int *wx_sqlite3PagerStats(Pager *pPager){
** reset parameter is non-zero, the cache hit or miss count is zeroed before
** returning.
*/
-SQLITE_PRIVATE void wx_sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
+SQLITE_PRIVATE void wx_sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, u64 *pnVal){
assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
|| eStat==SQLITE_DBSTATUS_CACHE_MISS
@@ -62614,7 +64463,7 @@ SQLITE_PRIVATE wx_sqlite3_file *wx_sqlite3PagerFile(Pager *pPager){
** This will be either the rollback journal or the WAL file.
*/
SQLITE_PRIVATE wx_sqlite3_file *wx_sqlite3PagerJrnlFile(Pager *pPager){
-#if SQLITE_OMIT_WAL
+#ifdef SQLITE_OMIT_WAL
return pPager->jfd;
#else
return pPager->pWal ? wx_sqlite3WalFile(pPager->pWal) : pPager->jfd;
@@ -62890,7 +64739,7 @@ SQLITE_PRIVATE int wx_sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
assert( pPager->eState!=PAGER_ERROR );
pPager->journalMode = (u8)eMode;
- /* When transistioning from TRUNCATE or PERSIST to any other journal
+ /* When transitioning from TRUNCATE or PERSIST to any other journal
** mode except WAL, unless the pager is in locking_mode=exclusive mode,
** delete the journal file.
*/
@@ -62935,7 +64784,7 @@ SQLITE_PRIVATE int wx_sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
}
assert( state==pPager->eState );
}
- }else if( eMode==PAGER_JOURNALMODE_OFF ){
+ }else if( eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_MEMORY ){
wx_sqlite3OsClose(pPager->jfd);
}
}
@@ -63057,13 +64906,15 @@ SQLITE_PRIVATE int wx_sqlite3PagerWalSupported(Pager *pPager){
*/
static int pagerExclusiveLock(Pager *pPager){
int rc; /* Return code */
+ u8 eOrigLock; /* Original lock */
- assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
+ assert( pPager->eLock>=SHARED_LOCK );
+ eOrigLock = pPager->eLock;
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
/* If the attempt to grab the exclusive lock failed, release the
** pending lock that may have been obtained instead. */
- pagerUnlockDb(pPager, SHARED_LOCK);
+ pagerUnlockDb(pPager, eOrigLock);
}
return rc;
@@ -63316,6 +65167,12 @@ SQLITE_PRIVATE int wx_sqlite3PagerWalFramesize(Pager *pPager){
}
#endif
+#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
+SQLITE_PRIVATE int wx_sqlite3PagerWalSystemErrno(Pager *pPager){
+ return wx_sqlite3WalSystemErrno(pPager->pWal);
+}
+#endif
+
#endif /* SQLITE_OMIT_DISKIO */
/************** End of pager.c ***********************************************/
@@ -63366,7 +65223,7 @@ SQLITE_PRIVATE int wx_sqlite3PagerWalFramesize(Pager *pPager){
** 28: Checksum-2 (second part of checksum for first 24 bytes of header).
**
** Immediately following the wal-header are zero or more frames. Each
-** frame consists of a 24-byte frame-header followed by a <page-size> bytes
+** frame consists of a 24-byte frame-header followed by <page-size> bytes
** of page data. The frame-header is six big-endian 32-bit unsigned
** integer values, as follows:
**
@@ -63606,7 +65463,7 @@ SQLITE_PRIVATE int wx_sqlite3WalTrace = 0;
**
** Technically, the various VFSes are free to implement these locks however
** they see fit. However, compatibility is encouraged so that VFSes can
-** interoperate. The standard implemention used on both unix and windows
+** interoperate. The standard implementation used on both unix and windows
** is for the index number to indicate a byte offset into the
** WalCkptInfo.aLock[] array in the wal-index header. In other words, all
** locks are on the shm file. The WALINDEX_LOCK_OFFSET constant (which
@@ -63682,7 +65539,7 @@ struct WalIndexHdr {
** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
** for any aReadMark[] means that entry is unused. aReadMark[0] is
** a special case; its value is never used and it exists as a place-holder
-** to avoid having to offset aReadMark[] indexs by one. Readers holding
+** to avoid having to offset aReadMark[] indexes by one. Readers holding
** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
** directly from the database.
**
@@ -63850,11 +65707,20 @@ struct Wal {
u32 iReCksum; /* On commit, recalculate checksums from here */
const char *zWalName; /* Name of WAL file */
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
+#ifdef SQLITE_USE_SEH
+ u32 lockMask; /* Mask of locks held */
+ void *pFree; /* Pointer to wx_sqlite3_free() if exception thrown */
+ u32 *pWiValue; /* Value to write into apWiData[iWiPg] */
+ int iWiPg; /* Write pWiValue into apWiData[iWiPg] */
+ int iSysErrno; /* System error code following exception */
+#endif
#ifdef SQLITE_DEBUG
+ int nSehTry; /* Number of nested SEH_TRY{} blocks */
u8 lockError; /* True if a locking error has occurred */
#endif
#ifdef SQLITE_ENABLE_SNAPSHOT
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
+ int bGetSnapshot; /* Transaction opened for wx_sqlite3_get_snapshot() */
#endif
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
wx_sqlite3 *db;
@@ -63933,6 +65799,113 @@ struct WalIterator {
)
/*
+** Structured Exception Handling (SEH) is a Windows-specific technique
+** for catching exceptions raised while accessing memory-mapped files.
+**
+** The -DSQLITE_USE_SEH compile-time option means to use SEH to catch and
+** deal with system-level errors that arise during WAL -shm file processing.
+** Without this compile-time option, any system-level faults that appear
+** while accessing the memory-mapped -shm file will cause a process-wide
+** signal to be deliver, which will more than likely cause the entire
+** process to exit.
+*/
+#ifdef SQLITE_USE_SEH
+#include <Windows.h>
+
+/* Beginning of a block of code in which an exception might occur */
+# define SEH_TRY __try { \
+ assert( walAssertLockmask(pWal) && pWal->nSehTry==0 ); \
+ VVA_ONLY(pWal->nSehTry++);
+
+/* The end of a block of code in which an exception might occur */
+# define SEH_EXCEPT(X) \
+ VVA_ONLY(pWal->nSehTry--); \
+ assert( pWal->nSehTry==0 ); \
+ } __except( sehExceptionFilter(pWal, GetExceptionCode(), GetExceptionInformation() ) ){ X }
+
+/* Simulate a memory-mapping fault in the -shm file for testing purposes */
+# define SEH_INJECT_FAULT sehInjectFault(pWal)
+
+/*
+** The second argument is the return value of GetExceptionCode() for the
+** current exception. Return EXCEPTION_EXECUTE_HANDLER if the exception code
+** indicates that the exception may have been caused by accessing the *-shm
+** file mapping. Or EXCEPTION_CONTINUE_SEARCH otherwise.
+*/
+static int sehExceptionFilter(Wal *pWal, int eCode, EXCEPTION_POINTERS *p){
+ VVA_ONLY(pWal->nSehTry--);
+ if( eCode==EXCEPTION_IN_PAGE_ERROR ){
+ if( p && p->ExceptionRecord && p->ExceptionRecord->NumberParameters>=3 ){
+ /* From MSDN: For this type of exception, the first element of the
+ ** ExceptionInformation[] array is a read-write flag - 0 if the exception
+ ** was thrown while reading, 1 if while writing. The second element is
+ ** the virtual address being accessed. The "third array element specifies
+ ** the underlying NTSTATUS code that resulted in the exception". */
+ pWal->iSysErrno = (int)p->ExceptionRecord->ExceptionInformation[2];
+ }
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+/*
+** If one is configured, invoke the xTestCallback callback with 650 as
+** the argument. If it returns true, throw the same exception that is
+** thrown by the system if the *-shm file mapping is accessed after it
+** has been invalidated.
+*/
+static void sehInjectFault(Wal *pWal){
+ int res;
+ assert( pWal->nSehTry>0 );
+
+ res = wx_sqlite3FaultSim(650);
+ if( res!=0 ){
+ ULONG_PTR aArg[3];
+ aArg[0] = 0;
+ aArg[1] = 0;
+ aArg[2] = (ULONG_PTR)res;
+ RaiseException(EXCEPTION_IN_PAGE_ERROR, 0, 3, (const ULONG_PTR*)aArg);
+ }
+}
+
+/*
+** There are two ways to use this macro. To set a pointer to be freed
+** if an exception is thrown:
+**
+** SEH_FREE_ON_ERROR(0, pPtr);
+**
+** and to cancel the same:
+**
+** SEH_FREE_ON_ERROR(pPtr, 0);
+**
+** In the first case, there must not already be a pointer registered to
+** be freed. In the second case, pPtr must be the registered pointer.
+*/
+#define SEH_FREE_ON_ERROR(X,Y) \
+ assert( (X==0 || Y==0) && pWal->pFree==X ); pWal->pFree = Y
+
+/*
+** There are two ways to use this macro. To arrange for pWal->apWiData[iPg]
+** to be set to pValue if an exception is thrown:
+**
+** SEH_SET_ON_ERROR(iPg, pValue);
+**
+** and to cancel the same:
+**
+** SEH_SET_ON_ERROR(0, 0);
+*/
+#define SEH_SET_ON_ERROR(X,Y) pWal->iWiPg = X; pWal->pWiValue = Y
+
+#else
+# define SEH_TRY VVA_ONLY(pWal->nSehTry++);
+# define SEH_EXCEPT(X) VVA_ONLY(pWal->nSehTry--); assert( pWal->nSehTry==0 );
+# define SEH_INJECT_FAULT assert( pWal->nSehTry>0 );
+# define SEH_FREE_ON_ERROR(X,Y)
+# define SEH_SET_ON_ERROR(X,Y)
+#endif /* ifdef SQLITE_USE_SEH */
+
+
+/*
** Obtain a pointer to the iPage'th page of the wal-index. The wal-index
** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are
** numbered from zero.
@@ -64004,6 +65977,7 @@ static int walIndexPage(
int iPage, /* The page we seek */
volatile u32 **ppPage /* Write the page pointer here */
){
+ SEH_INJECT_FAULT;
if( pWal->nWiData<=iPage || (*ppPage = pWal->apWiData[iPage])==0 ){
return walIndexPageRealloc(pWal, iPage, ppPage);
}
@@ -64015,6 +65989,7 @@ static int walIndexPage(
*/
static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ SEH_INJECT_FAULT;
return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
}
@@ -64023,6 +65998,7 @@ static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
*/
static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ SEH_INJECT_FAULT;
return (volatile WalIndexHdr*)pWal->apWiData[0];
}
@@ -64068,19 +66044,40 @@ static void walChecksumBytes(
assert( nByte>=8 );
assert( (nByte&0x00000007)==0 );
assert( nByte<=65536 );
+ assert( nByte%4==0 );
- if( nativeCksum ){
+ if( !nativeCksum ){
do {
+ s1 += BYTESWAP32(aData[0]) + s2;
+ s2 += BYTESWAP32(aData[1]) + s1;
+ aData += 2;
+ }while( aData<aEnd );
+ }else if( nByte%64==0 ){
+ do {
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
s1 += *aData++ + s2;
s2 += *aData++ + s1;
}while( aData<aEnd );
}else{
do {
- s1 += BYTESWAP32(aData[0]) + s2;
- s2 += BYTESWAP32(aData[1]) + s1;
- aData += 2;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
}while( aData<aEnd );
}
+ assert( aData==aEnd );
aOut[0] = s1;
aOut[1] = s2;
@@ -64191,7 +66188,7 @@ static int walDecodeFrame(
return 0;
}
- /* A frame is only valid if the page number is creater than zero.
+ /* A frame is only valid if the page number is greater than zero.
*/
pgno = wx_sqlite3Get4byte(&aFrame[0]);
if( pgno==0 ){
@@ -64199,7 +66196,7 @@ static int walDecodeFrame(
}
/* A frame is only valid if a checksum of the WAL header,
- ** all prior frams, the first 16 bytes of this frame-header,
+ ** all prior frames, the first 16 bytes of this frame-header,
** and the frame-data matches the checksum in the last 8
** bytes of this frame-header.
*/
@@ -64259,12 +66256,18 @@ static int walLockShared(Wal *pWal, int lockIdx){
WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
walLockName(lockIdx), rc ? "failed" : "ok"));
VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
+#ifdef SQLITE_USE_SEH
+ if( rc==SQLITE_OK ) pWal->lockMask |= (1 << lockIdx);
+#endif
return rc;
}
static void walUnlockShared(Wal *pWal, int lockIdx){
if( pWal->exclusiveMode ) return;
(void)wx_sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
+#ifdef SQLITE_USE_SEH
+ pWal->lockMask &= ~(1 << lockIdx);
+#endif
WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
}
static int walLockExclusive(Wal *pWal, int lockIdx, int n){
@@ -64275,12 +66278,20 @@ static int walLockExclusive(Wal *pWal, int lockIdx, int n){
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&0xFF)!=SQLITE_BUSY); )
+#ifdef SQLITE_USE_SEH
+ if( rc==SQLITE_OK ){
+ pWal->lockMask |= (((1<<n)-1) << (SQLITE_SHM_NLOCK+lockIdx));
+ }
+#endif
return rc;
}
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
if( pWal->exclusiveMode ) return;
(void)wx_sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
+#ifdef SQLITE_USE_SEH
+ pWal->lockMask &= ~(((1<<n)-1) << (SQLITE_SHM_NLOCK+lockIdx));
+#endif
WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
walLockName(lockIdx), n));
}
@@ -64372,6 +66383,7 @@ static int walFramePage(u32 iFrame){
*/
static u32 walFramePgno(Wal *pWal, u32 iFrame){
int iHash = walFramePage(iFrame);
+ SEH_INJECT_FAULT;
if( iHash==0 ){
return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
}
@@ -64631,6 +66643,7 @@ static int walIndexRecover(Wal *pWal){
/* Malloc a buffer to read frames into. */
szFrame = szPage + WAL_FRAME_HDRSIZE;
aFrame = (u8 *)wx_sqlite3_malloc64(szFrame + WALINDEX_PGSZ);
+ SEH_FREE_ON_ERROR(0, aFrame);
if( !aFrame ){
rc = SQLITE_NOMEM_BKPT;
goto recovery_error;
@@ -64649,6 +66662,7 @@ static int walIndexRecover(Wal *pWal){
rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare);
assert( aShare!=0 || rc!=SQLITE_OK );
if( aShare==0 ) break;
+ SEH_SET_ON_ERROR(iPg, aShare);
pWal->apWiData[iPg] = aPrivate;
for(iFrame=iFirst; iFrame<=iLast; iFrame++){
@@ -64676,6 +66690,7 @@ static int walIndexRecover(Wal *pWal){
}
}
pWal->apWiData[iPg] = aShare;
+ SEH_SET_ON_ERROR(0,0);
nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0);
nHdr32 = nHdr / sizeof(u32);
#ifndef SQLITE_SAFER_WALINDEX_RECOVERY
@@ -64706,9 +66721,11 @@ static int walIndexRecover(Wal *pWal){
}
}
#endif
+ SEH_INJECT_FAULT;
if( iFrame<=iLast ) break;
}
+ SEH_FREE_ON_ERROR(aFrame, 0);
wx_sqlite3_free(aFrame);
}
@@ -64736,6 +66753,7 @@ finished:
}else{
pInfo->aReadMark[i] = READMARK_NOT_USED;
}
+ SEH_INJECT_FAULT;
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
}else if( rc!=SQLITE_BUSY ){
goto recovery_error;
@@ -64893,7 +66911,7 @@ SQLITE_PRIVATE int wx_sqlite3WalOpen(
}
/*
-** Change the size to which the WAL file is trucated on each reset.
+** Change the size to which the WAL file is truncated on each reset.
*/
SQLITE_PRIVATE void wx_sqlite3WalLimit(Wal *pWal, i64 iLimit){
if( pWal ) pWal->mxWalSize = iLimit;
@@ -65119,23 +67137,16 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
nByte = sizeof(WalIterator)
+ (nSegment-1)*sizeof(struct WalSegment)
+ iLast*sizeof(ht_slot);
- p = (WalIterator *)wx_sqlite3_malloc64(nByte);
+ p = (WalIterator *)wx_sqlite3_malloc64(nByte
+ + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
+ );
if( !p ){
return SQLITE_NOMEM_BKPT;
}
memset(p, 0, nByte);
p->nSegment = nSegment;
-
- /* Allocate temporary space used by the merge-sort routine. This block
- ** of memory will be freed before this function returns.
- */
- aTmp = (ht_slot *)wx_sqlite3_malloc64(
- sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
- );
- if( !aTmp ){
- rc = SQLITE_NOMEM_BKPT;
- }
-
+ aTmp = (ht_slot*)&(((u8*)p)[nByte]);
+ SEH_FREE_ON_ERROR(0, p);
for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && i<nSegment; i++){
WalHashLoc sLoc;
@@ -65163,9 +67174,8 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
p->aSegment[i].aPgno = (u32 *)sLoc.aPgno;
}
}
- wx_sqlite3_free(aTmp);
-
if( rc!=SQLITE_OK ){
+ SEH_FREE_ON_ERROR(p, 0);
walIteratorFree(p);
p = 0;
}
@@ -65174,6 +67184,19 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
}
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+
+
+/*
+** Attempt to enable blocking locks that block for nMs ms. Return 1 if
+** blocking locks are successfully enabled, or 0 otherwise.
+*/
+static int walEnableBlockingMs(Wal *pWal, int nMs){
+ int rc = wx_sqlite3OsFileControl(
+ pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&nMs
+ );
+ return (rc==SQLITE_OK);
+}
+
/*
** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
** they are supported by the VFS, and (b) the database handle is configured
@@ -65185,11 +67208,7 @@ static int walEnableBlocking(Wal *pWal){
if( pWal->db ){
int tmout = pWal->db->busyTimeout;
if( tmout ){
- int rc;
- rc = wx_sqlite3OsFileControl(
- pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
- );
- res = (rc==SQLITE_OK);
+ res = walEnableBlockingMs(pWal, tmout);
}
}
return res;
@@ -65238,20 +67257,10 @@ SQLITE_PRIVATE void wx_sqlite3WalDb(Wal *pWal, wx_sqlite3 *db){
pWal->db = db;
}
-/*
-** Take an exclusive WRITE lock. Blocking if so configured.
-*/
-static int walLockWriter(Wal *pWal){
- int rc;
- walEnableBlocking(pWal);
- rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
- walDisableBlocking(pWal);
- return rc;
-}
#else
# define walEnableBlocking(x) 0
# define walDisableBlocking(x)
-# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
+# define walEnableBlockingMs(pWal, ms) 0
# define wx_sqlite3WalDb(pWal, db)
#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
@@ -65391,13 +67400,13 @@ static int walCheckpoint(
mxSafeFrame = pWal->hdr.mxFrame;
mxPage = pWal->hdr.nPage;
for(i=1; i<WAL_NREADER; i++){
- u32 y = AtomicLoad(pInfo->aReadMark+i);
+ u32 y = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
if( mxSafeFrame>y ){
assert( y<=pWal->hdr.mxFrame );
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
if( rc==SQLITE_OK ){
u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
- AtomicStore(pInfo->aReadMark+i, iMark);
+ AtomicStore(pInfo->aReadMark+i, iMark); SEH_INJECT_FAULT;
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
}else if( rc==SQLITE_BUSY ){
mxSafeFrame = y;
@@ -65418,8 +67427,7 @@ static int walCheckpoint(
&& (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK
){
u32 nBackfill = pInfo->nBackfill;
-
- pInfo->nBackfillAttempted = mxSafeFrame;
+ pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT;
/* Sync the WAL to disk */
rc = wx_sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
@@ -65450,6 +67458,7 @@ static int walCheckpoint(
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
i64 iOffset;
assert( walFramePgno(pWal, iFrame)==iDbpage );
+ SEH_INJECT_FAULT;
if( AtomicLoad(&db->u1.isInterrupted) ){
rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
break;
@@ -65479,7 +67488,7 @@ static int walCheckpoint(
}
}
if( rc==SQLITE_OK ){
- AtomicStore(&pInfo->nBackfill, mxSafeFrame);
+ AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT;
}
}
@@ -65501,6 +67510,7 @@ static int walCheckpoint(
*/
if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
assert( pWal->writeLock );
+ SEH_INJECT_FAULT;
if( pInfo->nBackfill<pWal->hdr.mxFrame ){
rc = SQLITE_BUSY;
}else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
@@ -65532,6 +67542,7 @@ static int walCheckpoint(
}
walcheckpoint_out:
+ SEH_FREE_ON_ERROR(pIter, 0);
walIteratorFree(pIter);
return rc;
}
@@ -65554,6 +67565,93 @@ static void walLimitSize(Wal *pWal, i64 nMax){
}
}
+#ifdef SQLITE_USE_SEH
+/*
+** This is the "standard" exception handler used in a few places to handle
+** an exception thrown by reading from the *-shm mapping after it has become
+** invalid in SQLITE_USE_SEH builds. It is used as follows:
+**
+** SEH_TRY { ... }
+** SEH_EXCEPT( rc = walHandleException(pWal); )
+**
+** This function does three things:
+**
+** 1) Determines the locks that should be held, based on the contents of
+** the Wal.readLock, Wal.writeLock and Wal.ckptLock variables. All other
+** held locks are assumed to be transient locks that would have been
+** released had the exception not been thrown and are dropped.
+**
+** 2) Frees the pointer at Wal.pFree, if any, using wx_sqlite3_free().
+**
+** 3) Set pWal->apWiData[pWal->iWiPg] to pWal->pWiValue if not NULL
+**
+** 4) Returns SQLITE_IOERR.
+*/
+static int walHandleException(Wal *pWal){
+ if( pWal->exclusiveMode==0 ){
+ static const int S = 1;
+ static const int E = (1<<SQLITE_SHM_NLOCK);
+ int ii;
+ u32 mUnlock = pWal->lockMask & ~(
+ (pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock)))
+ | (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0)
+ | (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0)
+ );
+ for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
+ if( (S<<ii) & mUnlock ) walUnlockShared(pWal, ii);
+ if( (E<<ii) & mUnlock ) walUnlockExclusive(pWal, ii, 1);
+ }
+ }
+ wx_sqlite3_free(pWal->pFree);
+ pWal->pFree = 0;
+ if( pWal->pWiValue ){
+ pWal->apWiData[pWal->iWiPg] = pWal->pWiValue;
+ pWal->pWiValue = 0;
+ }
+ return SQLITE_IOERR_IN_PAGE;
+}
+
+/*
+** Assert that the Wal.lockMask mask, which indicates the locks held
+** by the connection, is consistent with the Wal.readLock, Wal.writeLock
+** and Wal.ckptLock variables. To be used as:
+**
+** assert( walAssertLockmask(pWal) );
+*/
+static int walAssertLockmask(Wal *pWal){
+ if( pWal->exclusiveMode==0 ){
+ static const int S = 1;
+ static const int E = (1<<SQLITE_SHM_NLOCK);
+ u32 mExpect = (
+ (pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock)))
+ | (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0)
+ | (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0)
+#ifdef SQLITE_ENABLE_SNAPSHOT
+ | (pWal->pSnapshot ? (pWal->lockMask & (1 << WAL_CKPT_LOCK)) : 0)
+#endif
+ );
+ assert( mExpect==pWal->lockMask );
+ }
+ return 1;
+}
+
+/*
+** Return and zero the "system error" field set when an
+** EXCEPTION_IN_PAGE_ERROR exception is caught.
+*/
+SQLITE_PRIVATE int wx_sqlite3WalSystemErrno(Wal *pWal){
+ int iRet = 0;
+ if( pWal ){
+ iRet = pWal->iSysErrno;
+ pWal->iSysErrno = 0;
+ }
+ return iRet;
+}
+
+#else
+# define walAssertLockmask(x) 1
+#endif /* ifdef SQLITE_USE_SEH */
+
/*
** Close a connection to a log file.
*/
@@ -65568,6 +67666,8 @@ SQLITE_PRIVATE int wx_sqlite3WalClose(
if( pWal ){
int isDelete = 0; /* True to unlink wal and wal-index files */
+ assert( walAssertLockmask(pWal) );
+
/* 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
@@ -65592,7 +67692,7 @@ SQLITE_PRIVATE int wx_sqlite3WalClose(
);
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
+ ** fsynced (rc==SQLITE_OK) and if we are not in persistent-wal
** mode (!bPersist) */
isDelete = 1;
}else if( pWal->mxWalSize>=0 ){
@@ -65659,7 +67759,7 @@ static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){
** give false-positive warnings about these accesses because the tools do not
** account for the double-read and the memory barrier. The use of mutexes
** here would be problematic as the memory being accessed is potentially
- ** shared among multiple processes and not all mutex implementions work
+ ** shared among multiple processes and not all mutex implementations work
** reliably in that environment.
*/
aHdr = walIndexHdr(pWal);
@@ -65761,7 +67861,9 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
}
}else{
int bWriteLock = pWal->writeLock;
- if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
+ if( bWriteLock
+ || SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1))
+ ){
pWal->writeLock = 1;
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
badHdr = walIndexTryHdr(pWal, pChanged);
@@ -65769,7 +67871,8 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
/* 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.
- */
+ ** Disable blocking locks first. */
+ walDisableBlocking(pWal);
rc = walIndexRecover(pWal);
*pChanged = 1;
}
@@ -65980,6 +68083,37 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
}
/*
+** The final argument passed to walTryBeginRead() is of type (int*). The
+** caller should invoke walTryBeginRead as follows:
+**
+** int cnt = 0;
+** do {
+** rc = walTryBeginRead(..., &cnt);
+** }while( rc==WAL_RETRY );
+**
+** The final value of "cnt" is of no use to the caller. It is used by
+** the implementation of walTryBeginRead() as follows:
+**
+** + Each time walTryBeginRead() is called, it is incremented. Once
+** it reaches WAL_RETRY_PROTOCOL_LIMIT - indicating that walTryBeginRead()
+** has many times been invoked and failed with WAL_RETRY - walTryBeginRead()
+** returns SQLITE_PROTOCOL.
+**
+** + If SQLITE_ENABLE_SETLK_TIMEOUT is defined and walTryBeginRead() failed
+** because a blocking lock timed out (SQLITE_BUSY_TIMEOUT from the OS
+** layer), the WAL_RETRY_BLOCKED_MASK bit is set in "cnt". In this case
+** the next invocation of walTryBeginRead() may omit an expected call to
+** wx_sqlite3OsSleep(). There has already been a delay when the previous call
+** waited on a lock.
+*/
+#define WAL_RETRY_PROTOCOL_LIMIT 100
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+# define WAL_RETRY_BLOCKED_MASK 0x10000000
+#else
+# define WAL_RETRY_BLOCKED_MASK 0
+#endif
+
+/*
** 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.
@@ -66029,13 +68163,16 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
** 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){
+static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
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 */
u32 mxFrame; /* Wal frame to lock to */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ int nBlockTmout = 0;
+#endif
assert( pWal->readLock<0 ); /* Not currently locked */
@@ -66059,14 +68196,34 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** so that on the 100th (and last) RETRY we delay for 323 milliseconds.
** The total delay time before giving up is less than 10 seconds.
*/
- if( cnt>5 ){
+ (*pCnt)++;
+ if( *pCnt>5 ){
int nDelay = 1; /* Pause time in microseconds */
- if( cnt>100 ){
+ int cnt = (*pCnt & ~WAL_RETRY_BLOCKED_MASK);
+ if( cnt>WAL_RETRY_PROTOCOL_LIMIT ){
VVA_ONLY( pWal->lockError = 1; )
return SQLITE_PROTOCOL;
}
- if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
+ if( *pCnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ /* In SQLITE_ENABLE_SETLK_TIMEOUT builds, configure the file-descriptor
+ ** to block for locks for approximately nDelay us. This affects three
+ ** locks: (a) the shared lock taken on the DMS slot in os_unix.c (if
+ ** using os_unix.c), (b) the WRITER lock taken in walIndexReadHdr() if the
+ ** first attempted read fails, and (c) the shared lock taken on the
+ ** read-mark.
+ **
+ ** If the previous call failed due to an SQLITE_BUSY_TIMEOUT error,
+ ** then sleep for the minimum of 1us. The previous call already provided
+ ** an extra delay while it was blocking on the lock.
+ */
+ nBlockTmout = (nDelay+998) / 1000;
+ if( !useWal && walEnableBlockingMs(pWal, nBlockTmout) ){
+ if( *pCnt & WAL_RETRY_BLOCKED_MASK ) nDelay = 1;
+ }
+#endif
wx_sqlite3OsSleep(pWal->pVfs, nDelay);
+ *pCnt &= ~WAL_RETRY_BLOCKED_MASK;
}
if( !useWal ){
@@ -66074,6 +68231,13 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
if( pWal->bShmUnreliable==0 ){
rc = walIndexReadHdr(pWal, pChanged);
}
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ walDisableBlocking(pWal);
+ if( rc==SQLITE_BUSY_TIMEOUT ){
+ rc = SQLITE_BUSY;
+ *pCnt |= WAL_RETRY_BLOCKED_MASK;
+ }
+#endif
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
@@ -66110,9 +68274,10 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
assert( pWal->nWiData>0 );
assert( pWal->apWiData[0]!=0 );
pInfo = walCkptInfo(pWal);
+ SEH_INJECT_FAULT;
if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
#ifdef SQLITE_ENABLE_SNAPSHOT
- && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
+ && ((pWal->bGetSnapshot==0 && pWal->pSnapshot==0) || pWal->hdr.mxFrame==0)
#endif
){
/* The WAL has been completely backfilled (or it is empty).
@@ -66159,7 +68324,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}
#endif
for(i=1; i<WAL_NREADER; i++){
- u32 thisMark = AtomicLoad(pInfo->aReadMark+i);
+ u32 thisMark = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
if( mxReadMark<=thisMark && thisMark<=mxFrame ){
assert( thisMark!=READMARK_NOT_USED );
mxReadMark = thisMark;
@@ -66187,9 +68352,19 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
}
+ (void)walEnableBlockingMs(pWal, nBlockTmout);
rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+ walDisableBlocking(pWal);
if( rc ){
- return rc==SQLITE_BUSY ? WAL_RETRY : rc;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( rc==SQLITE_BUSY_TIMEOUT ){
+ *pCnt |= WAL_RETRY_BLOCKED_MASK;
+ }
+#else
+ assert( rc!=SQLITE_BUSY_TIMEOUT );
+#endif
+ assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT );
+ return (rc&0xFF)==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
@@ -66225,7 +68400,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** we can guarantee that the checkpointer that set nBackfill could not
** see any pages past pWal->hdr.mxFrame, this problem does not come up.
*/
- pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1;
+ pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; SEH_INJECT_FAULT;
walShmBarrier(pWal);
if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark
|| memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
@@ -66241,6 +68416,54 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
#ifdef SQLITE_ENABLE_SNAPSHOT
/*
+** This function does the work of wx_sqlite3WalSnapshotRecover().
+*/
+static int walSnapshotRecover(
+ Wal *pWal, /* WAL handle */
+ void *pBuf1, /* Temp buffer pWal->szPage bytes in size */
+ void *pBuf2 /* Temp buffer pWal->szPage bytes in size */
+){
+ int szPage = (int)pWal->szPage;
+ int rc;
+ i64 szDb; /* Size of db file in bytes */
+
+ rc = wx_sqlite3OsFileSize(pWal->pDbFd, &szDb);
+ if( rc==SQLITE_OK ){
+ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+ u32 i = pInfo->nBackfillAttempted;
+ for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
+ WalHashLoc sLoc; /* Hash table location */
+ u32 pgno; /* Page number in db file */
+ i64 iDbOff; /* Offset of db file entry */
+ i64 iWalOff; /* Offset of wal file entry */
+
+ rc = walHashGet(pWal, walFramePage(i), &sLoc);
+ if( rc!=SQLITE_OK ) break;
+ assert( i - sLoc.iZero - 1 >=0 );
+ pgno = sLoc.aPgno[i-sLoc.iZero-1];
+ iDbOff = (i64)(pgno-1) * szPage;
+
+ if( iDbOff+szPage<=szDb ){
+ iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
+ rc = wx_sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
+
+ if( rc==SQLITE_OK ){
+ rc = wx_sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
+ }
+
+ if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
+ break;
+ }
+ }
+
+ pInfo->nBackfillAttempted = i-1;
+ }
+ }
+
+ return rc;
+}
+
+/*
** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted
** variable so that older snapshots can be accessed. To do this, loop
** through all wal frames from nBackfillAttempted to (nBackfill+1),
@@ -66265,50 +68488,21 @@ SQLITE_PRIVATE int wx_sqlite3WalSnapshotRecover(Wal *pWal){
assert( pWal->readLock>=0 );
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
if( rc==SQLITE_OK ){
- volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
- int szPage = (int)pWal->szPage;
- i64 szDb; /* Size of db file in bytes */
-
- rc = wx_sqlite3OsFileSize(pWal->pDbFd, &szDb);
- if( rc==SQLITE_OK ){
- void *pBuf1 = wx_sqlite3_malloc(szPage);
- void *pBuf2 = wx_sqlite3_malloc(szPage);
- if( pBuf1==0 || pBuf2==0 ){
- rc = SQLITE_NOMEM;
- }else{
- u32 i = pInfo->nBackfillAttempted;
- for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
- WalHashLoc sLoc; /* Hash table location */
- u32 pgno; /* Page number in db file */
- i64 iDbOff; /* Offset of db file entry */
- i64 iWalOff; /* Offset of wal file entry */
-
- rc = walHashGet(pWal, walFramePage(i), &sLoc);
- if( rc!=SQLITE_OK ) break;
- assert( i - sLoc.iZero - 1 >=0 );
- pgno = sLoc.aPgno[i-sLoc.iZero-1];
- iDbOff = (i64)(pgno-1) * szPage;
-
- if( iDbOff+szPage<=szDb ){
- iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
- rc = wx_sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
-
- if( rc==SQLITE_OK ){
- rc = wx_sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
- }
-
- if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
- break;
- }
- }
-
- pInfo->nBackfillAttempted = i-1;
- }
+ void *pBuf1 = wx_sqlite3_malloc(pWal->szPage);
+ void *pBuf2 = wx_sqlite3_malloc(pWal->szPage);
+ if( pBuf1==0 || pBuf2==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pWal->ckptLock = 1;
+ SEH_TRY {
+ rc = walSnapshotRecover(pWal, pBuf1, pBuf2);
}
-
- wx_sqlite3_free(pBuf1);
- wx_sqlite3_free(pBuf2);
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+ pWal->ckptLock = 0;
}
+
+ wx_sqlite3_free(pBuf1);
+ wx_sqlite3_free(pBuf2);
walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
}
@@ -66317,28 +68511,20 @@ SQLITE_PRIVATE int wx_sqlite3WalSnapshotRecover(Wal *pWal){
#endif /* SQLITE_ENABLE_SNAPSHOT */
/*
-** Begin a read transaction on the database.
-**
-** This routine used to be called wx_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 its cache is stale and
-** needs to be flushed.
+** This function does the work of wx_sqlite3WalBeginReadTransaction() (see
+** below). That function simply calls this one inside an SEH_TRY{...} block.
*/
-SQLITE_PRIVATE int wx_sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+static int walBeginReadTransaction(Wal *pWal, int *pChanged){
int rc; /* Return code */
int cnt = 0; /* Number of TryBeginRead attempts */
#ifdef SQLITE_ENABLE_SNAPSHOT
+ int ckptLock = 0;
int bChanged = 0;
WalIndexHdr *pSnapshot = pWal->pSnapshot;
#endif
assert( pWal->ckptLock==0 );
+ assert( pWal->nSehTry>0 );
#ifdef SQLITE_ENABLE_SNAPSHOT
if( pSnapshot ){
@@ -66361,12 +68547,12 @@ SQLITE_PRIVATE int wx_sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
if( rc!=SQLITE_OK ){
return rc;
}
- pWal->ckptLock = 1;
+ ckptLock = 1;
}
#endif
do{
- rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
+ rc = walTryBeginRead(pWal, pChanged, 0, &cnt);
}while( rc==WAL_RETRY );
testcase( (rc&0xff)==SQLITE_BUSY );
testcase( (rc&0xff)==SQLITE_IOERR );
@@ -66425,16 +68611,38 @@ SQLITE_PRIVATE int wx_sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
}
/* Release the shared CKPT lock obtained above. */
- if( pWal->ckptLock ){
+ if( ckptLock ){
assert( pSnapshot );
walUnlockShared(pWal, WAL_CKPT_LOCK);
- pWal->ckptLock = 0;
}
#endif
return rc;
}
/*
+** Begin a read transaction on the database.
+**
+** This routine used to be called wx_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 its cache is stale and
+** needs to be flushed.
+*/
+SQLITE_PRIVATE int wx_sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+ int rc;
+ SEH_TRY {
+ rc = walBeginReadTransaction(pWal, pChanged);
+ }
+ SEH_EXCEPT( rc = walHandleException(pWal); )
+ return rc;
+}
+
+/*
** Finish with a read transaction. All this does is release the
** read-lock.
*/
@@ -66454,7 +68662,7 @@ SQLITE_PRIVATE void wx_sqlite3WalEndReadTransaction(Wal *pWal){
** Return SQLITE_OK if successful, or an error code if an error occurs. If an
** error does occur, the final value of *piRead is undefined.
*/
-SQLITE_PRIVATE int wx_sqlite3WalFindFrame(
+static int walFindFrame(
Wal *pWal, /* WAL handle */
Pgno pgno, /* Database page number to read data for */
u32 *piRead /* OUT: Frame number (or zero) */
@@ -66517,6 +68725,7 @@ SQLITE_PRIVATE int wx_sqlite3WalFindFrame(
}
nCollide = HASHTABLE_NSLOT;
iKey = walHash(pgno);
+ SEH_INJECT_FAULT;
while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
u32 iFrame = iH + sLoc.iZero;
if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){
@@ -66524,6 +68733,7 @@ SQLITE_PRIVATE int wx_sqlite3WalFindFrame(
iRead = iFrame;
}
if( (nCollide--)==0 ){
+ *piRead = 0;
return SQLITE_CORRUPT_BKPT;
}
iKey = walNextHash(iKey);
@@ -66554,6 +68764,30 @@ SQLITE_PRIVATE int wx_sqlite3WalFindFrame(
}
/*
+** Search the wal file for page pgno. If found, set *piRead to the frame that
+** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
+** to zero.
+**
+** Return SQLITE_OK if successful, or an error code if an error occurs. If an
+** error does occur, the final value of *piRead is undefined.
+**
+** The difference between this function and walFindFrame() is that this
+** function wraps walFindFrame() in an SEH_TRY{...} block.
+*/
+SQLITE_PRIVATE int wx_sqlite3WalFindFrame(
+ Wal *pWal, /* WAL handle */
+ Pgno pgno, /* Database page number to read data for */
+ u32 *piRead /* OUT: Frame number (or zero) */
+){
+ int rc;
+ SEH_TRY {
+ rc = walFindFrame(pWal, pgno, piRead);
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+ return rc;
+}
+
+/*
** Read the contents of frame iRead from the wal file into buffer pOut
** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
** error code otherwise.
@@ -66634,12 +68868,17 @@ SQLITE_PRIVATE int wx_sqlite3WalBeginWriteTransaction(Wal *pWal){
** time the read transaction on this connection was started, then
** the write is disallowed.
*/
- if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+ SEH_TRY {
+ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+ rc = SQLITE_BUSY_SNAPSHOT;
+ }
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+
+ if( rc!=SQLITE_OK ){
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
pWal->writeLock = 0;
- rc = SQLITE_BUSY_SNAPSHOT;
}
-
return rc;
}
@@ -66675,30 +68914,33 @@ SQLITE_PRIVATE int wx_sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void
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.
+ SEH_TRY {
+ /* Restore the clients cache of the wal-index header to the state it
+ ** was in before the client began writing to the database.
*/
- assert( walFramePgno(pWal, iFrame)!=1 );
- rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+ 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( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
}
- if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
}
return rc;
}
@@ -66742,7 +68984,10 @@ SQLITE_PRIVATE int wx_sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
pWal->hdr.mxFrame = aWalData[0];
pWal->hdr.aFrameCksum[0] = aWalData[1];
pWal->hdr.aFrameCksum[1] = aWalData[2];
- walCleanupHash(pWal);
+ SEH_TRY {
+ walCleanupHash(pWal);
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
}
return rc;
@@ -66792,7 +69037,7 @@ static int walRestartLog(Wal *pWal){
cnt = 0;
do{
int notUsed;
- rc = walTryBeginRead(pWal, &notUsed, 1, ++cnt);
+ rc = walTryBeginRead(pWal, &notUsed, 1, &cnt);
}while( rc==WAL_RETRY );
assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
testcase( (rc&0xff)==SQLITE_IOERR );
@@ -66923,7 +69168,7 @@ static int walRewriteChecksums(Wal *pWal, u32 iLast){
** Write a set of frames to the log. The caller must hold the write-lock
** on the log file (obtained using wx_sqlite3WalBeginWriteTransaction()).
*/
-SQLITE_PRIVATE int wx_sqlite3WalFrames(
+static int walFrames(
Wal *pWal, /* Wal handle to write to */
int szPage, /* Database page-size in bytes */
PgHdr *pList, /* List of dirty pages to write */
@@ -67011,7 +69256,9 @@ SQLITE_PRIVATE int wx_sqlite3WalFrames(
if( rc ) return rc;
}
}
- assert( (int)pWal->szPage==szPage );
+ if( (int)pWal->szPage!=szPage ){
+ return SQLITE_CORRUPT_BKPT; /* TH3 test case: cov1/corrupt155.test */
+ }
/* Setup information needed to write frames into the WAL */
w.pWal = pWal;
@@ -67032,7 +69279,7 @@ SQLITE_PRIVATE int wx_sqlite3WalFrames(
** checksums must be recomputed when the transaction is committed. */
if( iFirst && (p->pDirty || isCommit==0) ){
u32 iWrite = 0;
- VVA_ONLY(rc =) wx_sqlite3WalFindFrame(pWal, p->pgno, &iWrite);
+ VVA_ONLY(rc =) walFindFrame(pWal, p->pgno, &iWrite);
assert( rc==SQLITE_OK || iWrite==0 );
if( iWrite>=iFirst ){
i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
@@ -67152,6 +69399,29 @@ SQLITE_PRIVATE int wx_sqlite3WalFrames(
}
/*
+** Write a set of frames to the log. The caller must hold the write-lock
+** on the log file (obtained using wx_sqlite3WalBeginWriteTransaction()).
+**
+** The difference between this function and walFrames() is that this
+** function wraps walFrames() in an SEH_TRY{...} block.
+*/
+SQLITE_PRIVATE int wx_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;
+ SEH_TRY {
+ rc = walFrames(pWal, szPage, pList, nTruncate, isCommit, sync_flags);
+ }
+ SEH_EXCEPT( rc = walHandleException(pWal); )
+ return rc;
+}
+
+/*
** This routine is called to implement wx_sqlite3_wal_checkpoint() and
** related interfaces.
**
@@ -67188,10 +69458,9 @@ SQLITE_PRIVATE int wx_sqlite3WalCheckpoint(
if( pWal->readOnly ) return SQLITE_READONLY;
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
- /* Enable blocking locks, if possible. If blocking locks are successfully
- ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
+ /* Enable blocking locks, if possible. */
wx_sqlite3WalDb(pWal, db);
- (void)walEnableBlocking(pWal);
+ if( xBusy2 ) (void)walEnableBlocking(pWal);
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
** "checkpoint" lock on the database file.
@@ -67230,30 +69499,38 @@ SQLITE_PRIVATE int wx_sqlite3WalCheckpoint(
/* Read the wal-index header. */
- if( rc==SQLITE_OK ){
- walDisableBlocking(pWal);
- rc = walIndexReadHdr(pWal, &isChanged);
- (void)walEnableBlocking(pWal);
- if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
- wx_sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+ SEH_TRY {
+ if( rc==SQLITE_OK ){
+ /* For a passive checkpoint, do not re-enable blocking locks after
+ ** reading the wal-index header. A passive checkpoint should not block
+ ** or invoke the busy handler. The only lock such a checkpoint may
+ ** attempt to obtain is a lock on a read-slot, and it should give up
+ ** immediately and do a partial checkpoint if it cannot obtain it. */
+ walDisableBlocking(pWal);
+ rc = walIndexReadHdr(pWal, &isChanged);
+ if( eMode2!=SQLITE_CHECKPOINT_PASSIVE ) (void)walEnableBlocking(pWal);
+ if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
+ wx_sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+ }
}
- }
- /* 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, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
- }
+ /* 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, db, eMode2, xBusy2, pBusyArg, sync_flags,zBuf);
+ }
- /* If no error occurred, set the output variables. */
- if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
- if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
- if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+ /* If no error occurred, set the output variables. */
+ if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
+ if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
+ SEH_INJECT_FAULT;
+ if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+ }
}
}
+ SEH_EXCEPT( rc = walHandleException(pWal); )
if( isChanged ){
/* If a new wal-index header was loaded before the checkpoint was
@@ -67330,7 +69607,9 @@ SQLITE_PRIVATE int wx_sqlite3WalExclusiveMode(Wal *pWal, int op){
** locks are taken in this case). Nor should the pager attempt to
** upgrade to exclusive-mode following such an error.
*/
+#ifndef SQLITE_USE_SEH
assert( pWal->readLock>=0 || pWal->lockError );
+#endif
assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
if( op==0 ){
@@ -67398,7 +69677,20 @@ SQLITE_PRIVATE void wx_sqlite3WalSnapshotOpen(
Wal *pWal,
wx_sqlite3_snapshot *pSnapshot
){
- pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
+ if( pSnapshot && ((WalIndexHdr*)pSnapshot)->iVersion==0 ){
+ /* iVersion==0 means that this is a call to wx_sqlite3_snapshot_get(). In
+ ** this case set the bGetSnapshot flag so that if the call to
+ ** wx_sqlite3_snapshot_get() is about to read transaction on this wal
+ ** file, it does not take read-lock 0 if the wal file has been completely
+ ** checkpointed. Taking read-lock 0 would work, but then it would be
+ ** possible for a subsequent writer to destroy the snapshot even while
+ ** this connection is holding its read-transaction open. This is contrary
+ ** to user expectations, so we avoid it by not taking read-lock 0. */
+ pWal->bGetSnapshot = 1;
+ }else{
+ pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
+ pWal->bGetSnapshot = 0;
+ }
}
/*
@@ -67431,16 +69723,19 @@ SQLITE_API int wx_sqlite3_snapshot_cmp(wx_sqlite3_snapshot *p1, wx_sqlite3_snaps
*/
SQLITE_PRIVATE int wx_sqlite3WalSnapshotCheck(Wal *pWal, wx_sqlite3_snapshot *pSnapshot){
int rc;
- rc = walLockShared(pWal, WAL_CKPT_LOCK);
- if( rc==SQLITE_OK ){
- WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
- if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
- || pNew->mxFrame<walCkptInfo(pWal)->nBackfillAttempted
- ){
- rc = SQLITE_ERROR_SNAPSHOT;
- walUnlockShared(pWal, WAL_CKPT_LOCK);
+ SEH_TRY {
+ rc = walLockShared(pWal, WAL_CKPT_LOCK);
+ if( rc==SQLITE_OK ){
+ WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
+ if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
+ || pNew->mxFrame<walCkptInfo(pWal)->nBackfillAttempted
+ ){
+ rc = SQLITE_ERROR_SNAPSHOT;
+ walUnlockShared(pWal, WAL_CKPT_LOCK);
+ }
}
}
+ SEH_EXCEPT( rc = walHandleException(pWal); )
return rc;
}
@@ -67563,7 +69858,7 @@ SQLITE_PRIVATE wx_sqlite3_file *wx_sqlite3WalFile(Wal *pWal){
** 22 1 Min embedded payload fraction (must be 32)
** 23 1 Min leaf payload fraction (must be 32)
** 24 4 File change counter
-** 28 4 Reserved for future use
+** 28 4 The size of the database in pages
** 32 4 First freelist page
** 36 4 Number of freelist pages in the file
** 40 60 15 4-byte meta values passed to higher layers
@@ -67671,7 +69966,7 @@ SQLITE_PRIVATE wx_sqlite3_file *wx_sqlite3WalFile(Wal *pWal){
** byte are used. The integer consists of all bytes that have bit 8 set and
** the first byte with bit 8 clear. The most significant byte of the integer
** appears first. A variable-length integer may not be more than 9 bytes long.
-** As a special case, all 8 bytes of the 9th byte are used as data. This
+** As a special case, all 8 bits of the 9th byte are used as data. This
** allows a 64-bit integer to be encoded in 9 bytes.
**
** 0x00 becomes 0x00000000
@@ -67679,7 +69974,7 @@ SQLITE_PRIVATE wx_sqlite3_file *wx_sqlite3WalFile(Wal *pWal){
** 0x81 0x00 becomes 0x00000080
** 0x82 0x00 becomes 0x00000100
** 0x80 0x7f becomes 0x0000007f
-** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
+** 0x81 0x91 0xd1 0xac 0x78 becomes 0x12345678
** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
**
** Variable length integers are used for rowids and to hold the number of
@@ -67762,7 +70057,7 @@ typedef struct CellInfo CellInfo;
** page that has been loaded into memory. The information in this object
** is derived from the raw on-disk page content.
**
-** As each database page is loaded into memory, the pager allocats an
+** As each database page is loaded into memory, the pager allocates an
** instance of this object and zeros the first 8 bytes. (This is the
** "extra" information associated with each page of the pager.)
**
@@ -68055,7 +70350,7 @@ struct BtCursor {
#define BTCF_WriteFlag 0x01 /* True if a write cursor */
#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
-#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
+#define BTCF_AtLast 0x08 /* Cursor is pointing to the last entry */
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
#define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */
#define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */
@@ -68194,17 +70489,19 @@ 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 */
+ Pgno nCkPage; /* Pages in the database. 0 for partial check */
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
int rc; /* SQLITE_OK, SQLITE_NOMEM, or SQLITE_INTERRUPT */
u32 nStep; /* Number of steps into the integrity_check process */
const char *zPfx; /* Error message prefix */
- Pgno v1; /* Value for first %u substitution in zPfx */
- int v2; /* Value for second %d substitution in zPfx */
+ Pgno v0; /* Value for first %u substitution in zPfx (root page) */
+ Pgno v1; /* Value for second %u substitution in zPfx (current pg) */
+ int v2; /* Value for third %d substitution in zPfx */
StrAccum errMsg; /* Accumulate the error message text here */
u32 *heap; /* Min-heap used for analyzing cell coverage */
wx_sqlite3 *db; /* Database connection running the check */
+ i64 nRow; /* Number of rows visited in current tree */
};
/*
@@ -68217,7 +70514,7 @@ struct IntegrityCk {
/*
** get2byteAligned(), unlike get2byte(), requires that its argument point to a
-** two-byte aligned address. get2bytea() is only used for accessing the
+** two-byte aligned address. get2byteAligned() is only used for accessing the
** cell addresses in a btree header.
*/
#if SQLITE_BYTEORDER==4321
@@ -68394,7 +70691,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeHoldsMutex(Btree *p){
**
** There is a corresponding leave-all procedures.
**
-** Enter the mutexes in accending order by BtShared pointer address
+** Enter the mutexes in ascending order by BtShared pointer address
** to avoid the possibility of deadlock when two threads with
** two or more btrees in common both try to lock all their btrees
** at the same instant.
@@ -68664,8 +70961,8 @@ SQLITE_PRIVATE wx_sqlite3_uint64 wx_sqlite3BtreeSeekCount(Btree *pBt){
int corruptPageError(int lineno, MemPage *p){
char *zMsg;
wx_sqlite3BeginBenignMalloc();
- zMsg = wx_sqlite3_mprintf("database corruption page %d of %s",
- (int)p->pgno, wx_sqlite3PagerFilename(p->pBt->pPager, 0)
+ zMsg = wx_sqlite3_mprintf("database corruption page %u of %s",
+ p->pgno, wx_sqlite3PagerFilename(p->pBt->pPager, 0)
);
wx_sqlite3EndBenignMalloc();
if( zMsg ){
@@ -68679,8 +70976,47 @@ int corruptPageError(int lineno, MemPage *p){
# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno)
#endif
+/* Default value for SHARED_LOCK_TRACE macro if shared-cache is disabled
+** or if the lock tracking is disabled. This is always the value for
+** release builds.
+*/
+#define SHARED_LOCK_TRACE(X,MSG,TAB,TYPE) /*no-op*/
+
#ifndef SQLITE_OMIT_SHARED_CACHE
+#if 0
+/* ^---- Change to 1 and recompile to enable shared-lock tracing
+** for debugging purposes.
+**
+** Print all shared-cache locks on a BtShared. Debugging use only.
+*/
+static void sharedLockTrace(
+ BtShared *pBt,
+ const char *zMsg,
+ int iRoot,
+ int eLockType
+){
+ BtLock *pLock;
+ if( iRoot>0 ){
+ printf("%s-%p %u%s:", zMsg, pBt, iRoot, eLockType==READ_LOCK?"R":"W");
+ }else{
+ printf("%s-%p:", zMsg, pBt);
+ }
+ for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){
+ printf(" %p/%u%s", pLock->pBtree, pLock->iTable,
+ pLock->eLock==READ_LOCK ? "R" : "W");
+ while( pLock->pNext && pLock->pBtree==pLock->pNext->pBtree ){
+ pLock = pLock->pNext;
+ printf(",%u%s", pLock->iTable, pLock->eLock==READ_LOCK ? "R" : "W");
+ }
+ }
+ printf("\n");
+ fflush(stdout);
+}
+#undef SHARED_LOCK_TRACE
+#define SHARED_LOCK_TRACE(X,MSG,TAB,TYPE) sharedLockTrace(X,MSG,TAB,TYPE)
+#endif /* Shared-lock tracing */
+
#ifdef SQLITE_DEBUG
/*
**** This function is only used as part of an assert() statement. ***
@@ -68757,6 +71093,8 @@ static int hasSharedCacheTableLock(
iTab = iRoot;
}
+ SHARED_LOCK_TRACE(pBtree->pBt,"hasLock",iRoot,eLockType);
+
/* Search for the required lock. Either a write-lock on root-page iTab, a
** write-lock on the schema table, or (if the client is reading) a
** read-lock on iTab will suffice. Return 1 if any of these are found. */
@@ -68890,6 +71228,8 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
BtLock *pLock = 0;
BtLock *pIter;
+ SHARED_LOCK_TRACE(pBt,"setLock", iTable, eLock);
+
assert( wx_sqlite3BtreeHoldsMutex(p) );
assert( eLock==READ_LOCK || eLock==WRITE_LOCK );
assert( p->db!=0 );
@@ -68957,6 +71297,8 @@ static void clearAllSharedCacheTableLocks(Btree *p){
assert( p->sharable || 0==*ppIter );
assert( p->inTrans>0 );
+ SHARED_LOCK_TRACE(pBt, "clearAllLocks", 0, 0);
+
while( *ppIter ){
BtLock *pLock = *ppIter;
assert( (pBt->btsFlags & BTS_EXCLUSIVE)==0 || pBt->pWriter==pLock->pBtree );
@@ -68995,6 +71337,9 @@ static void clearAllSharedCacheTableLocks(Btree *p){
*/
static void downgradeAllSharedCacheTableLocks(Btree *p){
BtShared *pBt = p->pBt;
+
+ SHARED_LOCK_TRACE(pBt, "downgradeLocks", 0, 0);
+
if( pBt->pWriter==p ){
BtLock *pLock;
pBt->pWriter = 0;
@@ -69474,8 +71819,25 @@ SQLITE_PRIVATE int wx_sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentR
*/
SQLITE_PRIVATE void wx_sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){
/* Used only by system that substitute their own storage engine */
+#ifdef SQLITE_DEBUG
+ if( ALWAYS(eHintType==BTREE_HINT_RANGE) ){
+ va_list ap;
+ Expr *pExpr;
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = wx_sqlite3CursorRangeHintExprCheck;
+ va_start(ap, eHintType);
+ pExpr = va_arg(ap, Expr*);
+ w.u.aMem = va_arg(ap, Mem*);
+ va_end(ap);
+ assert( pExpr!=0 );
+ assert( w.u.aMem!=0 );
+ wx_sqlite3WalkExpr(&w, pExpr);
+ }
+#endif /* SQLITE_DEBUG */
}
-#endif
+#endif /* SQLITE_ENABLE_CURSOR_HINTS */
+
/*
** Provide flag hints to the cursor.
@@ -69560,7 +71922,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
pPtrmap = (u8 *)wx_sqlite3PagerGetData(pDbPage);
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
- TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
+ TRACE(("PTRMAP_UPDATE: %u->(%u,%u)\n", key, eType, parent));
*pRC= rc = wx_sqlite3PagerWrite(pDbPage);
if( rc==SQLITE_OK ){
pPtrmap[offset] = eType;
@@ -69759,27 +72121,31 @@ static void btreeParseCellPtr(
iKey = *pIter;
if( iKey>=0x80 ){
u8 x;
- iKey = ((iKey&0x7f)<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x =*++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x10204000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<8) | (*++pIter);
+ iKey = (iKey<<8) ^ 0x8000 ^ (*++pIter);
}
}
}
}
}
+ }else{
+ iKey ^= 0x204000;
}
+ }else{
+ iKey ^= 0x4000;
}
}
pIter++;
@@ -69856,10 +72222,11 @@ static void btreeParseCell(
**
** cellSizePtrNoPayload() => table internal nodes
** cellSizePtrTableLeaf() => table leaf nodes
-** cellSizePtr() => all index nodes & table leaf nodes
+** cellSizePtr() => index internal nodes
+** cellSizeIdxLeaf() => index leaf nodes
*/
static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
- u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */
+ u8 *pIter = pCell + 4; /* For looping over bytes of pCell */
u8 *pEnd; /* End mark for a varint */
u32 nSize; /* Size value to return */
@@ -69872,6 +72239,49 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
pPage->xParseCell(pPage, pCell, &debuginfo);
#endif
+ assert( pPage->childPtrSize==4 );
+ nSize = *pIter;
+ if( nSize>=0x80 ){
+ pEnd = &pIter[8];
+ nSize &= 0x7f;
+ do{
+ nSize = (nSize<<7) | (*++pIter & 0x7f);
+ }while( *(pIter)>=0x80 && pIter<pEnd );
+ }
+ pIter++;
+ testcase( nSize==pPage->maxLocal );
+ testcase( nSize==(u32)pPage->maxLocal+1 );
+ if( nSize<=pPage->maxLocal ){
+ nSize += (u32)(pIter - pCell);
+ assert( nSize>4 );
+ }else{
+ int minLocal = pPage->minLocal;
+ nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4);
+ testcase( nSize==pPage->maxLocal );
+ testcase( nSize==(u32)pPage->maxLocal+1 );
+ if( nSize>pPage->maxLocal ){
+ nSize = minLocal;
+ }
+ nSize += 4 + (u16)(pIter - pCell);
+ }
+ assert( nSize==debuginfo.nSize || CORRUPT_DB );
+ return (u16)nSize;
+}
+static u16 cellSizePtrIdxLeaf(MemPage *pPage, u8 *pCell){
+ u8 *pIter = pCell; /* For looping over bytes of pCell */
+ u8 *pEnd; /* End mark for a varint */
+ u32 nSize; /* Size value to return */
+
+#ifdef SQLITE_DEBUG
+ /* The value returned by this function should always be the same as
+ ** the (CellInfo.nSize) value found by doing a full parse of the
+ ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
+ ** this function verifies that this invariant is not violated. */
+ CellInfo debuginfo;
+ pPage->xParseCell(pPage, pCell, &debuginfo);
+#endif
+
+ assert( pPage->childPtrSize==0 );
nSize = *pIter;
if( nSize>=0x80 ){
pEnd = &pIter[8];
@@ -69996,7 +72406,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){
pPage->xParseCell(pPage, pCell, &info);
if( info.nLocal<info.nPayload ){
Pgno ovfl;
- if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){
+ if( SQLITE_OVERFLOW(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){
testcase( pSrc!=pPage );
*pRC = SQLITE_CORRUPT_BKPT;
return;
@@ -70097,7 +72507,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
iCellStart = get2byte(&data[hdr+5]);
if( nCell>0 ){
temp = wx_sqlite3PagerTempSpace(pPage->pBt->pPager);
- memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
+ memcpy(temp, data, usableSize);
src = temp;
for(i=0; i<nCell; i++){
u8 *pAddr; /* The i-th cell pointer */
@@ -70108,10 +72518,10 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
/* These conditions have already been verified in btreeInitPage()
** if PRAGMA cell_size_check=ON.
*/
- if( pc<iCellStart || pc>iCellLast ){
+ if( pc>iCellLast ){
return SQLITE_CORRUPT_PAGE(pPage);
}
- assert( pc>=iCellStart && pc<=iCellLast );
+ assert( pc>=0 && pc<=iCellLast );
size = pPage->xCellSize(pPage, &src[pc]);
cbrk -= size;
if( cbrk<iCellStart || pc+size>usableSize ){
@@ -70226,7 +72636,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
** allocation is being made in order to insert a new cell, so we will
** also end up needing a new cell pointer.
*/
-static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
+static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */
u8 * const data = pPage->aData; /* Local cache of pPage->aData */
int top; /* First byte of cell content area */
@@ -70252,13 +72662,14 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
** integer, so a value of 0 is used in its place. */
pTmp = &data[hdr+5];
top = get2byte(pTmp);
- assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */
if( gap>top ){
if( top==0 && pPage->pBt->usableSize==65536 ){
top = 65536;
}else{
return SQLITE_CORRUPT_PAGE(pPage);
}
+ }else if( top>(int)pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
}
/* If there is enough space between gap and top for one more cell pointer,
@@ -70320,7 +72731,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
**
** Even though the freeblock list was checked by btreeComputeFreeSpace(),
** that routine will not detect overlap between cells or freeblocks. Nor
-** does it detect cells or freeblocks that encrouch into the reserved bytes
+** does it detect cells or freeblocks that encroach into the reserved bytes
** at the end of the page. So do additional corruption checks inside this
** routine and return SQLITE_CORRUPT if any problems are found.
*/
@@ -70341,7 +72752,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
assert( wx_sqlite3_mutex_held(pPage->pBt->mutex) );
assert( iSize>=4 ); /* Minimum cell size is 4 */
- assert( iStart<=pPage->pBt->usableSize-4 );
+ assert( CORRUPT_DB || iStart<=pPage->pBt->usableSize-4 );
/* The list of freeblocks must be in ascending order. Find the
** spot on the list where iStart should be inserted.
@@ -70398,6 +72809,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}
pTmp = &data[hdr+5];
x = get2byte(pTmp);
+ if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
+ /* Overwrite deleted information with zeros when the secure_delete
+ ** option is enabled */
+ memset(&data[iStart], 0, iSize);
+ }
if( iStart<=x ){
/* The new freeblock is at the beginning of the cell content area,
** so just extend the cell content area rather than create another
@@ -70409,14 +72825,9 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}else{
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
+ put2byte(&data[iStart], iFreeBlk);
+ put2byte(&data[iStart+2], iSize);
}
- if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
- /* Overwrite deleted information with zeros when the secure_delete
- ** option is enabled */
- memset(&data[iStart], 0, iSize);
- }
- put2byte(&data[iStart], iFreeBlk);
- put2byte(&data[iStart+2], iSize);
pPage->nFree += iOrigSize;
return SQLITE_OK;
}
@@ -70453,14 +72864,14 @@ static int decodeFlags(MemPage *pPage, int flagByte){
}else if( flagByte==(PTF_ZERODATA | PTF_LEAF) ){
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
- pPage->xCellSize = cellSizePtr;
+ pPage->xCellSize = cellSizePtrIdxLeaf;
pPage->xParseCell = btreeParseCellPtrIndex;
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else{
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
- pPage->xCellSize = cellSizePtr;
+ pPage->xCellSize = cellSizePtrIdxLeaf;
pPage->xParseCell = btreeParseCellPtrIndex;
return SQLITE_CORRUPT_PAGE(pPage);
}
@@ -70779,68 +73190,41 @@ SQLITE_PRIVATE Pgno wx_sqlite3BtreeLastPage(Btree *p){
/*
** Get a page from the pager and initialize it.
-**
-** If pCur!=0 then the page is being fetched as part of a moveToChild()
-** call. Do additional sanity checking on the page in this case.
-** And if the fetch fails, this routine must decrement pCur->iPage.
-**
-** The page is fetched as read-write unless pCur is not NULL and is
-** a read-only cursor.
-**
-** If an error occurs, then *ppPage is undefined. It
-** may remain unchanged, or it may be set to an invalid value.
*/
static int getAndInitPage(
BtShared *pBt, /* The database file */
Pgno pgno, /* Number of the page to get */
MemPage **ppPage, /* Write the page pointer here */
- BtCursor *pCur, /* Cursor to receive the page, or NULL */
int bReadOnly /* True for a read-only page */
){
int rc;
DbPage *pDbPage;
+ MemPage *pPage;
assert( wx_sqlite3_mutex_held(pBt->mutex) );
- assert( pCur==0 || ppPage==&pCur->pPage );
- assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
- assert( pCur==0 || pCur->iPage>0 );
if( pgno>btreePagecount(pBt) ){
- rc = SQLITE_CORRUPT_BKPT;
- goto getAndInitPage_error1;
+ *ppPage = 0;
+ return SQLITE_CORRUPT_BKPT;
}
rc = wx_sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
if( rc ){
- goto getAndInitPage_error1;
+ *ppPage = 0;
+ return rc;
}
- *ppPage = (MemPage*)wx_sqlite3PagerGetExtra(pDbPage);
- if( (*ppPage)->isInit==0 ){
+ pPage = (MemPage*)wx_sqlite3PagerGetExtra(pDbPage);
+ if( pPage->isInit==0 ){
btreePageFromDbPage(pDbPage, pgno, pBt);
- rc = btreeInitPage(*ppPage);
+ rc = btreeInitPage(pPage);
if( rc!=SQLITE_OK ){
- goto getAndInitPage_error2;
+ releasePage(pPage);
+ *ppPage = 0;
+ return rc;
}
}
- assert( (*ppPage)->pgno==pgno || CORRUPT_DB );
- assert( (*ppPage)->aData==wx_sqlite3PagerGetData(pDbPage) );
-
- /* If obtaining a child page for a cursor, we must verify that the page is
- ** compatible with the root page. */
- if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
- rc = SQLITE_CORRUPT_PGNO(pgno);
- goto getAndInitPage_error2;
- }
+ assert( pPage->pgno==pgno || CORRUPT_DB );
+ assert( pPage->aData==wx_sqlite3PagerGetData(pDbPage) );
+ *ppPage = pPage;
return SQLITE_OK;
-
-getAndInitPage_error2:
- releasePage(*ppPage);
-getAndInitPage_error1:
- if( pCur ){
- pCur->iPage--;
- pCur->pPage = pCur->apPage[pCur->iPage];
- }
- testcase( pgno==0 );
- assert( pgno!=0 || rc!=SQLITE_OK );
- return rc;
}
/*
@@ -70923,7 +73307,7 @@ static void pageReinit(DbPage *pData){
** call to btreeInitPage() will likely return SQLITE_CORRUPT.
** But no harm is done by this. And it is very important that
** btreeInitPage() be called on every btree page so we make
- ** the call for every page that comes in for re-initing. */
+ ** the call for every page that comes in for re-initializing. */
btreeInitPage(pPage);
}
}
@@ -71102,6 +73486,9 @@ SQLITE_PRIVATE int wx_sqlite3BtreeOpen(
assert( sizeof(u16)==2 );
assert( sizeof(Pgno)==4 );
+ /* Suppress false-positive compiler warning from PVS-Studio */
+ memset(&zDbHeader[16], 0, 8);
+
pBt = wx_sqlite3MallocZero( sizeof(*pBt) );
if( pBt==0 ){
rc = SQLITE_NOMEM_BKPT;
@@ -71318,7 +73705,7 @@ static SQLITE_NOINLINE int allocateTempSpace(BtShared *pBt){
** can mean that fillInCell() only initializes the first 2 or 3
** bytes of pTmpSpace, but that the first 4 bytes are copied from
** it into a database page. This is not actually a problem, but it
- ** does cause a valgrind error when the 1 or 2 bytes of unitialized
+ ** does cause a valgrind error when the 1 or 2 bytes of uninitialized
** data is passed to system call write(). So to avoid this error,
** zero the first 4 bytes of temp space here.
**
@@ -71553,7 +73940,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeGetReserveNoMutex(Btree *p){
/*
** Return the number of bytes of space at the end of every page that
-** are intentually left unused. This is the "reserved" space that is
+** are intentionally left unused. This is the "reserved" space that is
** sometimes used by extensions.
**
** The value returned is the larger of the current reserve size and
@@ -71800,7 +74187,6 @@ static int lockBtree(BtShared *pBt){
){
goto page1_init_failed;
}
- pBt->btsFlags |= BTS_PAGESIZE_FIXED;
assert( (pageSize & 7)==0 );
/* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte
** integer at offset 20 is the number of bytes of space at the end of
@@ -71820,6 +74206,7 @@ static int lockBtree(BtShared *pBt){
releasePageOne(pPage1);
pBt->usableSize = usableSize;
pBt->pageSize = pageSize;
+ pBt->btsFlags |= BTS_PAGESIZE_FIXED;
freeTempSpace(pBt);
rc = wx_sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize,
pageSize-usableSize);
@@ -71839,6 +74226,7 @@ static int lockBtree(BtShared *pBt){
if( usableSize<480 ){
goto page1_init_failed;
}
+ pBt->btsFlags |= BTS_PAGESIZE_FIXED;
pBt->pageSize = pageSize;
pBt->usableSize = usableSize;
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -72017,7 +74405,11 @@ SQLITE_PRIVATE int wx_sqlite3BtreeNewDb(Btree *p){
** when A already has a read lock, we encourage A to give up and let B
** proceed.
*/
-SQLITE_PRIVATE int wx_sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
+static SQLITE_NOINLINE int btreeBeginTrans(
+ Btree *p, /* The btree in which to start the transaction */
+ int wrflag, /* True to start a write transaction */
+ int *pSchemaVersion /* Put schema version number here, if not NULL */
+){
BtShared *pBt = p->pBt;
Pager *pPager = pBt->pPager;
int rc = SQLITE_OK;
@@ -72189,6 +74581,28 @@ trans_begun:
wx_sqlite3BtreeLeave(p);
return rc;
}
+SQLITE_PRIVATE int wx_sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
+ BtShared *pBt;
+ if( p->sharable
+ || p->inTrans==TRANS_NONE
+ || (p->inTrans==TRANS_READ && wrflag!=0)
+ ){
+ return btreeBeginTrans(p,wrflag,pSchemaVersion);
+ }
+ pBt = p->pBt;
+ if( pSchemaVersion ){
+ *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]);
+ }
+ if( wrflag ){
+ /* This call makes sure that the pager has the correct number of
+ ** open savepoints. If the second parameter is greater than 0 and
+ ** the sub-journal is not already open, then it will be opened here.
+ */
+ return wx_sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
+ }else{
+ return SQLITE_OK;
+ }
+}
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -72326,7 +74740,7 @@ static int relocatePage(
if( iDbPage<3 ) return SQLITE_CORRUPT_BKPT;
/* Move page iDbPage from its current location to page number iFreePage */
- TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
+ TRACE(("AUTOVACUUM: Moving %u to free page %u (ptr page %u type %u)\n",
iDbPage, iFreePage, iPtrPage, eType));
rc = wx_sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit);
if( rc!=SQLITE_OK ){
@@ -73157,6 +75571,25 @@ SQLITE_PRIVATE int wx_sqlite3BtreeCursorSize(void){
return ROUND8(sizeof(BtCursor));
}
+#ifdef SQLITE_DEBUG
+/*
+** Return true if and only if the Btree object will be automatically
+** closed with the BtCursor closes. This is used within assert() statements
+** only.
+*/
+SQLITE_PRIVATE int wx_sqlite3BtreeClosesWithCursor(
+ Btree *pBtree, /* the btree object */
+ BtCursor *pCur /* Corresponding cursor */
+){
+ BtShared *pBt = pBtree->pBt;
+ if( (pBt->openFlags & BTREE_SINGLE)==0 ) return 0;
+ if( pBt->pCursor!=pCur ) return 0;
+ if( pCur->pNext!=0 ) return 0;
+ if( pCur->pBtree!=pBtree ) return 0;
+ return 1;
+}
+#endif
+
/*
** Initialize memory that will be converted into a BtCursor object.
**
@@ -73284,7 +75717,6 @@ SQLITE_PRIVATE void wx_sqlite3BtreeCursorUnpin(BtCursor *pCur){
pCur->curFlags &= ~BTCF_Pinned;
}
-#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
/*
** Return the offset into the database file for the start of the
** payload to which the cursor is pointing.
@@ -73296,7 +75728,6 @@ SQLITE_PRIVATE i64 wx_sqlite3BtreeOffset(BtCursor *pCur){
return (i64)pCur->pBt->pageSize*((i64)pCur->pPage->pgno - 1) +
(i64)(pCur->info.pPayload - pCur->pPage->aData);
}
-#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
/*
** Return the number of bytes of payload for the entry that pCur is
@@ -73322,7 +75753,7 @@ SQLITE_PRIVATE u32 wx_sqlite3BtreePayloadSize(BtCursor *pCur){
** routine always returns 2147483647 (which is the largest record
** that SQLite can handle) or more. But returning a smaller value might
** prevent large memory allocations when trying to interpret a
-** corrupt datrabase.
+** corrupt database.
**
** The current implementation merely returns the size of the underlying
** database file.
@@ -73541,9 +75972,12 @@ static int accessPayload(
if( pCur->aOverflow==0
|| nOvfl*(int)sizeof(Pgno) > wx_sqlite3MallocSize(pCur->aOverflow)
){
- Pgno *aNew = (Pgno*)wx_sqlite3Realloc(
- pCur->aOverflow, nOvfl*2*sizeof(Pgno)
- );
+ Pgno *aNew;
+ if( wx_sqlite3FaultSim(413) ){
+ aNew = 0;
+ }else{
+ aNew = (Pgno*)wx_sqlite3Realloc(pCur->aOverflow, nOvfl*2*sizeof(Pgno));
+ }
if( aNew==0 ){
return SQLITE_NOMEM_BKPT;
}else{
@@ -73553,6 +75987,12 @@ static int accessPayload(
memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
pCur->curFlags |= BTCF_ValidOvfl;
}else{
+ /* Sanity check the validity of the overflow page cache */
+ assert( pCur->aOverflow[0]==nextPage
+ || pCur->aOverflow[0]==0
+ || CORRUPT_DB );
+ assert( pCur->aOverflow[0]!=0 || pCur->aOverflow[offset/ovflSize]==0 );
+
/* If the overflow page-list cache has been allocated and the
** entry for the first required overflow page is valid, skip
** directly to it.
@@ -73622,7 +76062,6 @@ static int accessPayload(
assert( aWrite>=pBufStart ); /* due to (6) */
memcpy(aSave, aWrite, 4);
rc = wx_sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
- if( rc && nextPage>pBt->nPage ) rc = SQLITE_CORRUPT_BKPT;
nextPage = get4byte(aWrite);
memcpy(aWrite, aSave, 4);
}else
@@ -73784,6 +76223,7 @@ SQLITE_PRIVATE const void *wx_sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt
** vice-versa).
*/
static int moveToChild(BtCursor *pCur, u32 newPgno){
+ int rc;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
@@ -73797,8 +76237,18 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
pCur->apPage[pCur->iPage] = pCur->pPage;
pCur->ix = 0;
pCur->iPage++;
- return getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur,
- pCur->curPagerFlags);
+ rc = getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur->curPagerFlags);
+ assert( pCur->pPage!=0 || rc!=SQLITE_OK );
+ if( rc==SQLITE_OK
+ && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey)
+ ){
+ releasePage(pCur->pPage);
+ rc = SQLITE_CORRUPT_PGNO(newPgno);
+ }
+ if( rc ){
+ pCur->pPage = pCur->apPage[--pCur->iPage];
+ }
+ return rc;
}
#ifdef SQLITE_DEBUG
@@ -73905,7 +76355,7 @@ static int moveToRoot(BtCursor *pCur){
wx_sqlite3BtreeClearCursor(pCur);
}
rc = getAndInitPage(pCur->pBt, pCur->pgnoRoot, &pCur->pPage,
- 0, pCur->curPagerFlags);
+ pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
@@ -74017,13 +76467,30 @@ SQLITE_PRIVATE int wx_sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
*pRes = 0;
rc = moveToLeftmost(pCur);
}else if( rc==SQLITE_EMPTY ){
- assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ assert( pCur->pgnoRoot==0 || (pCur->pPage!=0 && pCur->pPage->nCell==0) );
*pRes = 1;
rc = SQLITE_OK;
}
return rc;
}
+#ifdef SQLITE_DEBUG
+/* The cursors is CURSOR_VALID and has BTCF_AtLast set. Verify that
+** this flags are true for a consistent database.
+**
+** This routine is is called from within assert() statements only.
+** It is an internal verification routine and does not appear in production
+** builds.
+*/
+static int cursorIsAtLastEntry(BtCursor *pCur){
+ int ii;
+ for(ii=0; ii<pCur->iPage; ii++){
+ if( pCur->aiIdx[ii]!=pCur->apPage[ii]->nCell ) return 0;
+ }
+ return pCur->ix==pCur->pPage->nCell-1 && pCur->pPage->leaf!=0;
+}
+#endif
+
/* Move the cursor to the last entry in the table. Return SQLITE_OK
** on success. Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty.
@@ -74052,18 +76519,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeLast(BtCursor *pCur, int *pRes){
/* If the cursor already points to the last entry, this is a no-op. */
if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
-#ifdef SQLITE_DEBUG
- /* This block serves to assert() that the cursor really does point
- ** to the last entry in the b-tree. */
- int ii;
- for(ii=0; ii<pCur->iPage; ii++){
- assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
- }
- assert( pCur->ix==pCur->pPage->nCell-1 || CORRUPT_DB );
- testcase( pCur->ix!=pCur->pPage->nCell-1 );
- /* ^-- dbsqlfuzz b92b72e4de80b5140c30ab71372ca719b8feb618 */
- assert( pCur->pPage->leaf );
-#endif
+ assert( cursorIsAtLastEntry(pCur) || CORRUPT_DB );
*pRes = 0;
return SQLITE_OK;
}
@@ -74116,13 +76572,14 @@ SQLITE_PRIVATE int wx_sqlite3BtreeTableMoveto(
}
if( pCur->info.nKey<intKey ){
if( (pCur->curFlags & BTCF_AtLast)!=0 ){
+ assert( cursorIsAtLastEntry(pCur) || CORRUPT_DB );
*pRes = -1;
return SQLITE_OK;
}
/* If the requested key is one more than the previous key, then
** try to get there using wx_sqlite3BtreeNext() rather than a full
** binary search. This is an optimization only. The correct answer
- ** is still obtained without this case, only a little more slowely */
+ ** is still obtained without this case, only a little more slowly. */
if( pCur->info.nKey+1==intKey ){
*pRes = 0;
rc = wx_sqlite3BtreeNext(pCur, 0);
@@ -74376,7 +76833,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeIndexMoveto(
&& indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0
&& pIdxKey->errCode==SQLITE_OK
){
- pCur->curFlags &= ~BTCF_ValidOvfl;
+ pCur->curFlags &= ~(BTCF_ValidOvfl|BTCF_AtLast);
if( !pCur->pPage->isInit ){
return SQLITE_CORRUPT_BKPT;
}
@@ -74518,10 +76975,36 @@ bypass_moveto_root:
}else{
chldPg = get4byte(findCell(pPage, lwr));
}
- pCur->ix = (u16)lwr;
- rc = moveToChild(pCur, chldPg);
- if( rc ) break;
- }
+
+ /* This block is similar to an in-lined version of:
+ **
+ ** pCur->ix = (u16)lwr;
+ ** rc = moveToChild(pCur, chldPg);
+ ** if( rc ) break;
+ */
+ pCur->info.nSize = 0;
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
+ if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ pCur->aiIdx[pCur->iPage] = (u16)lwr;
+ pCur->apPage[pCur->iPage] = pCur->pPage;
+ pCur->ix = 0;
+ pCur->iPage++;
+ rc = getAndInitPage(pCur->pBt, chldPg, &pCur->pPage, pCur->curPagerFlags);
+ if( rc==SQLITE_OK
+ && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey)
+ ){
+ releasePage(pCur->pPage);
+ rc = SQLITE_CORRUPT_PGNO(chldPg);
+ }
+ if( rc ){
+ pCur->pPage = pCur->apPage[--pCur->iPage];
+ break;
+ }
+ /*
+ ***** End of in-lined moveToChild() call */
+ }
moveto_index_finish:
pCur->info.nSize = 0;
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
@@ -74556,10 +77039,10 @@ SQLITE_PRIVATE i64 wx_sqlite3BtreeRowCountEst(BtCursor *pCur){
assert( cursorOwnsBtShared(pCur) );
assert( wx_sqlite3_mutex_held(pCur->pBtree->db->mutex) );
- /* Currently this interface is only called by the OP_IfSmaller
- ** opcode, and it that case the cursor will always be valid and
- ** will always point to a leaf node. */
- if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
+ /* Currently this interface is only called by the OP_IfSizeBetween
+ ** opcode and the OP_Count opcode with P3=1. In either case,
+ ** the cursor will always be valid unless the btree is empty. */
+ if( pCur->eState!=CURSOR_VALID ) return 0;
if( NEVER(pCur->pPage->leaf==0) ) return -1;
n = pCur->pPage->nCell;
@@ -74612,7 +77095,8 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
pPage = pCur->pPage;
idx = ++pCur->ix;
- if( !pPage->isInit || wx_sqlite3FaultSim(412) ){
+ if( wx_sqlite3FaultSim(412) ) pPage->isInit = 0;
+ if( !pPage->isInit ){
return SQLITE_CORRUPT_BKPT;
}
@@ -74704,7 +77188,10 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
}
pPage = pCur->pPage;
- assert( pPage->isInit );
+ if( wx_sqlite3FaultSim(412) ) pPage->isInit = 0;
+ if( !pPage->isInit ){
+ return SQLITE_CORRUPT_BKPT;
+ }
if( !pPage->leaf ){
int idx = pCur->ix;
rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
@@ -74875,7 +77362,7 @@ static int allocateBtreePage(
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
*ppPage = pTrunk;
pTrunk = 0;
- TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
+ TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
}else if( k>(u32)(pBt->usableSize/4 - 2) ){
/* Value of k is out of range. Database corruption */
rc = SQLITE_CORRUPT_PGNO(iTrunk);
@@ -74941,7 +77428,7 @@ static int allocateBtreePage(
}
}
pTrunk = 0;
- TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
+ TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
#endif
}else if( k>0 ){
/* Extract a leaf from the trunk */
@@ -74986,8 +77473,8 @@ static int allocateBtreePage(
){
int noContent;
*pPgno = iPage;
- TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
- ": %d more free pages\n",
+ TRACE(("ALLOCATE: %u was leaf %u of %u on trunk %u"
+ ": %u more free pages\n",
*pPgno, closest+1, k, pTrunk->pgno, n-1));
rc = wx_sqlite3PagerWrite(pTrunk->pDbPage);
if( rc ) goto end_allocate_page;
@@ -75043,7 +77530,7 @@ static int allocateBtreePage(
** becomes a new pointer-map page, the second is used by the caller.
*/
MemPage *pPg = 0;
- TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
+ TRACE(("ALLOCATE: %u from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetUnusedPage(pBt, pBt->nPage, &pPg, bNoContent);
if( rc==SQLITE_OK ){
@@ -75066,7 +77553,7 @@ static int allocateBtreePage(
releasePage(*ppPage);
*ppPage = 0;
}
- TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
+ TRACE(("ALLOCATE: %u from end of file\n", *pPgno));
}
assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) );
@@ -75194,7 +77681,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
}
rc = btreeSetHasContent(pBt, iPage);
}
- TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
+ TRACE(("FREE-PAGE: %u leaf on trunk page %u\n",pPage->pgno,pTrunk->pgno));
goto freepage_out;
}
}
@@ -75215,7 +77702,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
put4byte(pPage->aData, iTrunk);
put4byte(&pPage->aData[4], 0);
put4byte(&pPage1->aData[32], iPage);
- TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", pPage->pgno, iTrunk));
+ TRACE(("FREE-PAGE: %u new trunk page replacing %u\n", pPage->pgno, iTrunk));
freepage_out:
if( pPage ){
@@ -75304,7 +77791,7 @@ static SQLITE_NOINLINE int clearCellOverflow(
/* Call xParseCell to compute the size of a cell. If the cell contains
** overflow, then invoke cellClearOverflow to clear out that overflow.
-** STore the result code (SQLITE_OK or some error code) in rc.
+** Store the result code (SQLITE_OK or some error code) in rc.
**
** Implemented as macro to force inlining for performance.
*/
@@ -75377,7 +77864,10 @@ static int fillInCell(
n = nHeader + nPayload;
testcase( n==3 );
testcase( n==4 );
- if( n<4 ) n = 4;
+ if( n<4 ){
+ n = 4;
+ pPayload[nPayload] = 0;
+ }
*pnSize = n;
assert( nSrc<=nPayload );
testcase( nSrc<nPayload );
@@ -75574,6 +78064,14 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** in pTemp or the original pCell) and also record its index.
** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
+**
+** The insertCellFast() routine below works exactly the same as
+** insertCell() except that it lacks the pTemp and iChild parameters
+** which are assumed zero. Other than that, the two routines are the
+** same.
+**
+** Fixes or enhancements to this routine should be reflected in
+** insertCellFast()!
*/
static int insertCell(
MemPage *pPage, /* Page into which we are copying */
@@ -75596,14 +78094,103 @@ static int insertCell(
assert( wx_sqlite3_mutex_held(pPage->pBt->mutex) );
assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
assert( pPage->nFree>=0 );
+ assert( iChild>0 );
if( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){
memcpy(pTemp, pCell, sz);
pCell = pTemp;
}
- if( iChild ){
- put4byte(pCell, iChild);
+ put4byte(pCell, iChild);
+ j = pPage->nOverflow++;
+ /* Comparison against ArraySize-1 since we hold back one extra slot
+ ** as a contingency. In other words, never need more than 3 overflow
+ ** slots but 4 are allocated, just to be safe. */
+ assert( j < ArraySize(pPage->apOvfl)-1 );
+ pPage->apOvfl[j] = pCell;
+ pPage->aiOvfl[j] = (u16)i;
+
+ /* When multiple overflows occur, they are always sequential and in
+ ** sorted order. This invariants arise because multiple overflows can
+ ** only occur when inserting divider cells into the parent page during
+ ** balancing, and the dividers are adjacent and sorted.
+ */
+ assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */
+ assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */
+ }else{
+ int rc = wx_sqlite3PagerWrite(pPage->pDbPage);
+ if( NEVER(rc!=SQLITE_OK) ){
+ return rc;
+ }
+ assert( wx_sqlite3PagerIswriteable(pPage->pDbPage) );
+ data = pPage->aData;
+ assert( &data[pPage->cellOffset]==pPage->aCellIdx );
+ rc = allocateSpace(pPage, sz, &idx);
+ if( rc ){ return rc; }
+ /* The allocateSpace() routine guarantees the following properties
+ ** if it returns successfully */
+ assert( idx >= 0 );
+ assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
+ assert( idx+sz <= (int)pPage->pBt->usableSize );
+ pPage->nFree -= (u16)(2 + sz);
+ /* In a corrupt database where an entry in the cell index section of
+ ** a btree page has a value of 3 or less, the pCell value might point
+ ** as many as 4 bytes in front of the start of the aData buffer for
+ ** the source page. Make sure this does not cause problems by not
+ ** reading the first 4 bytes */
+ memcpy(&data[idx+4], pCell+4, sz-4);
+ put4byte(&data[idx], iChild);
+ pIns = pPage->aCellIdx + i*2;
+ memmove(pIns+2, pIns, 2*(pPage->nCell - i));
+ put2byte(pIns, idx);
+ pPage->nCell++;
+ /* increment the cell count */
+ if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++;
+ assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB );
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pPage->pBt->autoVacuum ){
+ int rc2 = SQLITE_OK;
+ /* The cell may contain a pointer to an overflow page. If so, write
+ ** the entry for the overflow page into the pointer map.
+ */
+ ptrmapPutOvflPtr(pPage, pPage, pCell, &rc2);
+ if( rc2 ) return rc2;
}
+#endif
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This variant of insertCell() assumes that the pTemp and iChild
+** parameters are both zero. Use this variant in wx_sqlite3BtreeInsert()
+** for performance improvement, and also so that this variant is only
+** called from that one place, and is thus inlined, and thus runs must
+** faster.
+**
+** Fixes or enhancements to this routine should be reflected into
+** the insertCell() routine.
+*/
+static int insertCellFast(
+ MemPage *pPage, /* Page into which we are copying */
+ int i, /* New cell becomes the i-th cell of the page */
+ u8 *pCell, /* Content of the new cell */
+ int sz /* Bytes of content in pCell */
+){
+ int idx = 0; /* Where to write new cell content in data[] */
+ int j; /* Loop counter */
+ u8 *data; /* The content of the whole page */
+ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
+
+ assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
+ assert( MX_CELL(pPage->pBt)<=10921 );
+ assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
+ assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
+ assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
+ assert( wx_sqlite3_mutex_held(pPage->pBt->mutex) );
+ assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
+ assert( pPage->nFree>=0 );
+ assert( pPage->nOverflow==0 );
+ if( sz+2>pPage->nFree ){
j = pPage->nOverflow++;
/* Comparison against ArraySize-1 since we hold back one extra slot
** as a contingency. In other words, never need more than 3 overflow
@@ -75635,17 +78222,7 @@ static int insertCell(
assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
assert( idx+sz <= (int)pPage->pBt->usableSize );
pPage->nFree -= (u16)(2 + sz);
- if( iChild ){
- /* In a corrupt database where an entry in the cell index section of
- ** a btree page has a value of 3 or less, the pCell value might point
- ** as many as 4 bytes in front of the start of the aData buffer for
- ** the source page. Make sure this does not cause problems by not
- ** reading the first 4 bytes */
- memcpy(&data[idx+4], pCell+4, sz-4);
- put4byte(&data[idx], iChild);
- }else{
- memcpy(&data[idx], pCell, sz);
- }
+ memcpy(&data[idx], pCell, sz);
pIns = pPage->aCellIdx + i*2;
memmove(pIns+2, pIns, 2*(pPage->nCell - i));
put2byte(pIns, idx);
@@ -75828,12 +78405,14 @@ static int rebuildPage(
int k; /* Current slot in pCArray->apEnd[] */
u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */
+ assert( nCell>0 );
assert( i<iEnd );
j = get2byte(&aData[hdr+5]);
if( j>(u32)usableSize ){ j = 0; }
memcpy(&pTmp[j], &aData[j], usableSize - j);
- for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
+ assert( pCArray->ixNx[NB*2-1]>i );
+ for(k=0; pCArray->ixNx[k]<=i; k++){}
pSrcEnd = pCArray->apEnd[k];
pData = pEnd;
@@ -75896,7 +78475,7 @@ static int rebuildPage(
** Finally, argument pBegin points to the byte immediately following the
** end of the space required by this page for the cell-pointer area (for
** all cells - not just those inserted by the current call). If the content
-** area must be extended to before this point in order to accomodate all
+** area must be extended to before this point in order to accommodate all
** cells in apCell[], then the cells do not fit and non-zero is returned.
*/
static int pageInsertArray(
@@ -75916,7 +78495,8 @@ static int pageInsertArray(
u8 *pEnd; /* Maximum extent of cell data */
assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
if( iEnd<=iFirst ) return 0;
- for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
+ assert( pCArray->ixNx[NB*2-1]>i );
+ for(k=0; pCArray->ixNx[k]<=i ; k++){}
pEnd = pCArray->apEnd[k];
while( 1 /*Exit by break*/ ){
int sz, rc;
@@ -75974,42 +78554,50 @@ static int pageFreeArray(
u8 * const pEnd = &aData[pPg->pBt->usableSize];
u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize];
int nRet = 0;
- int i;
+ int i, j;
int iEnd = iFirst + nCell;
- u8 *pFree = 0; /* \__ Parameters for pending call to */
- int szFree = 0; /* / freeSpace() */
+ int nFree = 0;
+ int aOfst[10];
+ int aAfter[10];
for(i=iFirst; i<iEnd; i++){
u8 *pCell = pCArray->apCell[i];
if( SQLITE_WITHIN(pCell, pStart, pEnd) ){
int sz;
+ int iAfter;
+ int iOfst;
/* No need to use cachedCellSize() here. The sizes of all cells that
** are to be freed have already been computing while deciding which
** cells need freeing */
sz = pCArray->szCell[i]; assert( sz>0 );
- if( pFree!=(pCell + sz) ){
- if( pFree ){
- assert( pFree>aData && (pFree - aData)<65536 );
- freeSpace(pPg, (u16)(pFree - aData), szFree);
- }
- pFree = pCell;
- szFree = sz;
- if( pFree+sz>pEnd ){
- return 0;
+ iOfst = (u16)(pCell - aData);
+ iAfter = iOfst+sz;
+ for(j=0; j<nFree; j++){
+ if( aOfst[j]==iAfter ){
+ aOfst[j] = iOfst;
+ break;
+ }else if( aAfter[j]==iOfst ){
+ aAfter[j] = iAfter;
+ break;
}
- }else{
- /* The current cell is adjacent to and before the pFree cell.
- ** Combine the two regions into one to reduce the number of calls
- ** to freeSpace(). */
- pFree = pCell;
- szFree += sz;
+ }
+ if( j>=nFree ){
+ if( nFree>=(int)(sizeof(aOfst)/sizeof(aOfst[0])) ){
+ for(j=0; j<nFree; j++){
+ freeSpace(pPg, aOfst[j], aAfter[j]-aOfst[j]);
+ }
+ nFree = 0;
+ }
+ aOfst[nFree] = iOfst;
+ aAfter[nFree] = iAfter;
+ if( &aData[iAfter]>pEnd ) return 0;
+ nFree++;
}
nRet++;
}
}
- if( pFree ){
- assert( pFree>aData && (pFree - aData)<65536 );
- freeSpace(pPg, (u16)(pFree - aData), szFree);
+ for(j=0; j<nFree; j++){
+ freeSpace(pPg, aOfst[j], aAfter[j]-aOfst[j]);
}
return nRet;
}
@@ -76062,9 +78650,9 @@ static int editPage(
nCell -= nTail;
}
- pData = &aData[get2byteNotZero(&aData[hdr+5])];
+ pData = &aData[get2byte(&aData[hdr+5])];
if( pData<pBegin ) goto editpage_fail;
- if( pData>pPg->aDataEnd ) goto editpage_fail;
+ if( NEVER(pData>pPg->aDataEnd) ) goto editpage_fail;
/* Add cells to the start of the page */
if( iNew<iOld ){
@@ -76126,6 +78714,7 @@ static int editPage(
return SQLITE_OK;
editpage_fail:
/* Unable to edit this page. Rebuild it from scratch instead. */
+ if( nNew<1 ) return SQLITE_CORRUPT_BKPT;
populateCellCache(pCArray, iNew, nNew);
return rebuildPage(pCArray, iNew, nNew, pPg);
}
@@ -76192,6 +78781,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
b.szCell = &szCell;
b.apEnd[0] = pPage->aDataEnd;
b.ixNx[0] = 2;
+ b.ixNx[NB*2-1] = 0x7fffffff;
rc = rebuildPage(&b, 0, 1, pNew);
if( NEVER(rc) ){
releasePage(pNew);
@@ -76203,7 +78793,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
** with entries for the new page, and any pointer from the
** cell on the page to an overflow page. If either of these
** operations fails, the return code is set, but the contents
- ** of the parent page are still manipulated by thh code below.
+ ** of the parent page are still manipulated by the code below.
** That is Ok, at this point the parent page is guaranteed to
** be marked as dirty. Returning an error code will cause a
** rollback, undoing any changes made to the parent page.
@@ -76427,7 +79017,9 @@ static int balance_nonroot(
CellArray b; /* Parsed information on cells being balanced */
memset(abDone, 0, sizeof(abDone));
- memset(&b, 0, sizeof(b));
+ assert( sizeof(b) - sizeof(b.ixNx) == offsetof(CellArray,ixNx) );
+ memset(&b, 0, sizeof(b)-sizeof(b.ixNx[0]));
+ b.ixNx[NB*2-1] = 0x7fffffff;
pBt = pParent->pBt;
assert( wx_sqlite3_mutex_held(pBt->mutex) );
assert( wx_sqlite3PagerIswriteable(pParent->pDbPage) );
@@ -76479,7 +79071,7 @@ static int balance_nonroot(
pgno = get4byte(pRight);
while( 1 ){
if( rc==SQLITE_OK ){
- rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0);
+ rc = getAndInitPage(pBt, pgno, &apOld[i], 0);
}
if( rc ){
memset(apOld, 0, (i+1)*sizeof(MemPage*));
@@ -76586,7 +79178,7 @@ static int balance_nonroot(
** table-interior, index-leaf, or index-interior).
*/
if( pOld->aData[0]!=apOld[0]->aData[0] ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PAGE(pOld);
goto balance_cleanup;
}
@@ -76610,7 +79202,7 @@ static int balance_nonroot(
memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow));
if( pOld->nOverflow>0 ){
if( NEVER(limit<pOld->aiOvfl[0]) ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PAGE(pOld);
goto balance_cleanup;
}
limit = pOld->aiOvfl[0];
@@ -76793,7 +79385,7 @@ static int balance_nonroot(
}
}
- /* Sanity check: For a non-corrupt database file one of the follwing
+ /* Sanity check: For a non-corrupt database file one of the following
** must be true:
** (1) We found one or more cells (cntNew[0])>0), or
** (2) pPage is a virtual root page. A virtual root page is when
@@ -76801,7 +79393,7 @@ static int balance_nonroot(
** that page.
*/
assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB);
- TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\n",
+ TRACE(("BALANCE: old: %u(nc=%u) %u(nc=%u) %u(nc=%u)\n",
apOld[0]->pgno, apOld[0]->nCell,
nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0,
nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0
@@ -76885,8 +79477,8 @@ static int balance_nonroot(
}
}
- TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) "
- "%d(%d nc=%d) %d(%d nc=%d)\n",
+ TRACE(("BALANCE: new: %u(%u nc=%u) %u(%u nc=%u) %u(%u nc=%u) "
+ "%u(%u nc=%u) %u(%u nc=%u)\n",
apNew[0]->pgno, szNew[0], cntNew[0],
nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0,
nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0,
@@ -77018,9 +79610,10 @@ static int balance_nonroot(
iOvflSpace += sz;
assert( sz<=pBt->maxLocal+23 );
assert( iOvflSpace <= (int)pBt->pageSize );
- for(k=0; b.ixNx[k]<=j && ALWAYS(k<NB*2); k++){}
+ assert( b.ixNx[NB*2-1]>j );
+ for(k=0; b.ixNx[k]<=j; k++){}
pSrcEnd = b.apEnd[k];
- if( SQLITE_WITHIN(pSrcEnd, pCell, pCell+sz) ){
+ if( SQLITE_OVERFLOW(pSrcEnd, pCell, pCell+sz) ){
rc = SQLITE_CORRUPT_BKPT;
goto balance_cleanup;
}
@@ -77054,6 +79647,8 @@ static int balance_nonroot(
for(i=1-nNew; i<nNew; i++){
int iPg = i<0 ? -i : i;
assert( iPg>=0 && iPg<nNew );
+ assert( iPg>=1 || i>=0 );
+ assert( iPg<ArraySize(cntOld) );
if( abDone[iPg] ) continue; /* Skip pages already processed */
if( i>=0 /* On the upwards pass, or... */
|| cntOld[iPg-1]>=cntNew[iPg-1] /* Condition (1) is true */
@@ -77131,7 +79726,7 @@ static int balance_nonroot(
}
assert( pParent->isInit );
- TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n",
+ TRACE(("BALANCE: finished: old=%u new=%u cells=%u\n",
nOld, nNew, b.nCell));
/* Free any old pages that were not reused as new pages.
@@ -77216,7 +79811,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
assert( wx_sqlite3PagerIswriteable(pRoot->pDbPage) );
assert( pChild->nCell==pRoot->nCell || CORRUPT_DB );
- TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));
+ TRACE(("BALANCE: copy root %u into %u\n", pRoot->pgno, pChild->pgno));
/* Copy the overflow cells from pRoot to pChild */
memcpy(pChild->aiOvfl, pRoot->aiOvfl,
@@ -77251,7 +79846,7 @@ static int anotherValidCursor(BtCursor *pCur){
&& pOther->eState==CURSOR_VALID
&& pOther->pPage==pCur->pPage
){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pCur->pPage);
}
}
return SQLITE_OK;
@@ -77311,7 +79906,7 @@ static int balance(BtCursor *pCur){
/* The page being written is not a root page, and there is currently
** more than one reference to it. This only happens if the page is one
** of its own ancestor pages. Corruption. */
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PAGE(pPage);
}else{
MemPage * const pParent = pCur->apPage[iPage-1];
int const iIdx = pCur->aiIdx[iPage-1];
@@ -77410,7 +80005,7 @@ static int btreeOverwriteContent(
){
int nData = pX->nData - iOffset;
if( nData<=0 ){
- /* Overwritting with zeros */
+ /* Overwriting with zeros */
int i;
for(i=0; i<iAmt && pDest[i]==0; i++){}
if( i<iAmt ){
@@ -77446,7 +80041,7 @@ static int btreeOverwriteContent(
** cell.
*/
static SQLITE_NOINLINE int btreeOverwriteOverflowCell(
- BtCursor *pCur, /* Cursor pointing to cell to ovewrite */
+ BtCursor *pCur, /* Cursor pointing to cell to overwrite */
const BtreePayload *pX /* Content to write into the cell */
){
int iOffset; /* Next byte of pX->pData to write */
@@ -77475,7 +80070,7 @@ static SQLITE_NOINLINE int btreeOverwriteOverflowCell(
rc = btreeGetPage(pBt, ovflPgno, &pPage, 0);
if( rc ) return rc;
if( wx_sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PAGE(pPage);
}else{
if( iOffset+ovflPageSize<(u32)nTotal ){
ovflPgno = get4byte(pPage->aData);
@@ -77503,7 +80098,7 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
|| pCur->info.pPayload < pPage->aData + pPage->cellOffset
){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
if( pCur->info.nLocal==nTotal ){
/* The entire cell is local */
@@ -77584,7 +80179,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeInsert(
** Which can only happen if the SQLITE_NoSchemaError flag was set when
** the schema was loaded. This cannot be asserted though, as a user might
** set the flag, load the schema, and then unset the flag. */
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot);
}
}
@@ -77699,7 +80294,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeInsert(
}
}
assert( pCur->eState==CURSOR_VALID
- || (pCur->eState==CURSOR_INVALID && loc) );
+ || (pCur->eState==CURSOR_INVALID && loc) || CORRUPT_DB );
pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );
@@ -77707,14 +80302,14 @@ SQLITE_PRIVATE int wx_sqlite3BtreeInsert(
if( pPage->nFree<0 ){
if( NEVER(pCur->eState>CURSOR_INVALID) ){
/* ^^^^^--- due to the moveToRoot() call above */
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PAGE(pPage);
}else{
rc = btreeComputeFreeSpace(pPage);
}
if( rc ) return rc;
}
- TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
+ TRACE(("INSERT: table=%u nkey=%lld ndata=%u page=%u %s\n",
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit || CORRUPT_DB );
@@ -77724,7 +80319,10 @@ SQLITE_PRIVATE int wx_sqlite3BtreeInsert(
if( flags & BTREE_PREFORMAT ){
rc = SQLITE_OK;
szNew = p->pBt->nPreformatSize;
- if( szNew<4 ) szNew = 4;
+ if( szNew<4 ){
+ szNew = 4;
+ newCell[3] = 0;
+ }
if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
CellInfo info;
pPage->xParseCell(pPage, newCell, &info);
@@ -77746,7 +80344,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeInsert(
CellInfo info;
assert( idx>=0 );
if( idx>=pPage->nCell ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
rc = wx_sqlite3PagerWrite(pPage->pDbPage);
if( rc ){
@@ -77773,10 +80371,10 @@ SQLITE_PRIVATE int wx_sqlite3BtreeInsert(
** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */
assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */
if( oldCell < pPage->aData+pPage->hdrOffset+10 ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
if( oldCell+szNew > pPage->aDataEnd ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
memcpy(oldCell, newCell, szNew);
return SQLITE_OK;
@@ -77786,11 +80384,11 @@ SQLITE_PRIVATE int wx_sqlite3BtreeInsert(
}else if( loc<0 && pPage->nCell>0 ){
assert( pPage->leaf );
idx = ++pCur->ix;
- pCur->curFlags &= ~BTCF_ValidNKey;
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
}else{
assert( pPage->leaf );
}
- rc = insertCell(pPage, idx, newCell, szNew, 0, 0);
+ rc = insertCellFast(pPage, idx, newCell, szNew);
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
@@ -77816,7 +80414,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeInsert(
*/
if( pPage->nOverflow ){
assert( rc==SQLITE_OK );
- pCur->curFlags &= ~(BTCF_ValidNKey);
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
rc = balance(pCur);
/* Must make sure nOverflow is reset to zero even if the balance()
@@ -77878,7 +80476,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i
nIn = pSrc->info.nLocal;
aIn = pSrc->info.pPayload;
if( aIn+nIn>pSrc->pPage->aDataEnd ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pSrc->pPage);
}
nRem = pSrc->info.nPayload;
if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
@@ -77903,7 +80501,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i
if( nRem>nIn ){
if( aIn+nIn+4>pSrc->pPage->aDataEnd ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pSrc->pPage);
}
ovflIn = get4byte(&pSrc->info.pPayload[nIn]);
}
@@ -77999,7 +80597,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID );
if( rc || pCur->eState!=CURSOR_VALID ) return rc;
}else{
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot);
}
}
assert( pCur->eState==CURSOR_VALID );
@@ -78008,11 +80606,14 @@ SQLITE_PRIVATE int wx_sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
iCellIdx = pCur->ix;
pPage = pCur->pPage;
if( pPage->nCell<=iCellIdx ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
pCell = findCell(pPage, iCellIdx);
if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ if( pCell<&pPage->aCellIdx[pPage->nCell] ){
+ return SQLITE_CORRUPT_PAGE(pPage);
}
/* If the BTREE_SAVEPOSITION bit is on, then the cursor position must
@@ -78103,7 +80704,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
n = pCur->pPage->pgno;
}
pCell = findCell(pLeaf, pLeaf->nCell-1);
- if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
+ if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_PAGE(pLeaf);
nCell = pLeaf->xCellSize(pLeaf, pCell);
assert( MX_CELL_SIZE(pBt) >= nCell );
pTmp = pBt->pTmpSpace;
@@ -78190,7 +80791,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
MemPage *pRoot;
Pgno pgnoRoot;
int rc;
- int ptfFlags; /* Page-type flage for the root page of new table */
+ int ptfFlags; /* Page-type flags for the root page of new table */
assert( wx_sqlite3BtreeHoldsMutex(p) );
assert( pBt->inTransaction==TRANS_WRITE );
@@ -78219,7 +80820,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
*/
wx_sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot);
if( pgnoRoot>btreePagecount(pBt) ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pgnoRoot);
}
pgnoRoot++;
@@ -78267,7 +80868,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
}
rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage);
if( eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(pgnoRoot);
}
if( rc!=SQLITE_OK ){
releasePage(pRoot);
@@ -78357,14 +80958,14 @@ static int clearDatabasePage(
assert( wx_sqlite3_mutex_held(pBt->mutex) );
if( pgno>btreePagecount(pBt) ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pgno);
}
- rc = getAndInitPage(pBt, pgno, &pPage, 0, 0);
+ rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc;
if( (pBt->openFlags & BTREE_SINGLE)==0
&& wx_sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1))
){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PAGE(pPage);
goto cleardatabasepage_out;
}
hdr = pPage->hdrOffset;
@@ -78468,7 +81069,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
assert( p->inTrans==TRANS_WRITE );
assert( iTable>=2 );
if( iTable>btreePagecount(pBt) ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(iTable);
}
rc = wx_sqlite3BtreeClearTable(p, iTable, 0);
@@ -78762,7 +81363,8 @@ static void checkAppendMsg(
wx_sqlite3_str_append(&pCheck->errMsg, "\n", 1);
}
if( pCheck->zPfx ){
- wx_sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2);
+ wx_sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx,
+ pCheck->v0, pCheck->v1, pCheck->v2);
}
wx_sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
va_end(ap);
@@ -78779,7 +81381,8 @@ static void checkAppendMsg(
** corresponds to page iPg is already set.
*/
static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){
- assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 );
+ assert( pCheck->aPgRef!=0 );
+ assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 );
return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07)));
}
@@ -78787,7 +81390,8 @@ static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){
** 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 );
+ assert( pCheck->aPgRef!=0 );
+ assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 );
pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07));
}
@@ -78801,12 +81405,12 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
** Also check that the page number is in bounds.
*/
static int checkRef(IntegrityCk *pCheck, Pgno iPage){
- if( iPage>pCheck->nPage || iPage==0 ){
- checkAppendMsg(pCheck, "invalid page number %d", iPage);
+ if( iPage>pCheck->nCkPage || iPage==0 ){
+ checkAppendMsg(pCheck, "invalid page number %u", iPage);
return 1;
}
if( getPageReferenced(pCheck, iPage) ){
- checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
+ checkAppendMsg(pCheck, "2nd reference to page %u", iPage);
return 1;
}
setPageReferenced(pCheck, iPage);
@@ -78832,13 +81436,13 @@ static void checkPtrmap(
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) checkOom(pCheck);
- checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
+ checkAppendMsg(pCheck, "Failed to read ptrmap key=%u", iChild);
return;
}
if( ePtrmapType!=eType || iPtrmapParent!=iParent ){
checkAppendMsg(pCheck,
- "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)",
+ "Bad ptr map entry key=%u expected=(%u,%u) got=(%u,%u)",
iChild, eType, iParent, ePtrmapType, iPtrmapParent);
}
}
@@ -78863,7 +81467,7 @@ static void checkList(
if( checkRef(pCheck, iPage) ) break;
N--;
if( wx_sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
- checkAppendMsg(pCheck, "failed to get page %d", iPage);
+ checkAppendMsg(pCheck, "failed to get page %u", iPage);
break;
}
pOvflData = (unsigned char *)wx_sqlite3PagerGetData(pOvflPage);
@@ -78876,7 +81480,7 @@ static void checkList(
#endif
if( n>pCheck->pBt->usableSize/4-2 ){
checkAppendMsg(pCheck,
- "freelist leaf count too big on page %d", iPage);
+ "freelist leaf count too big on page %u", iPage);
N--;
}else{
for(i=0; i<(int)n; i++){
@@ -78908,7 +81512,7 @@ static void checkList(
}
if( N && nErrAtStart==pCheck->nErr ){
checkAppendMsg(pCheck,
- "%s is %d but should be %d",
+ "%s is %u but should be %u",
isFreeList ? "size" : "overflow list length",
expected-N, expected);
}
@@ -79023,11 +81627,12 @@ static int checkTreePage(
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage) ) return 0;
- pCheck->zPfx = "Page %u: ";
+ pCheck->zPfx = "Tree %u page %u: ";
pCheck->v1 = iPage;
if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck,
"unable to get the page. error code=%d", rc);
+ if( rc==SQLITE_IOERR_NOMEM ) pCheck->rc = SQLITE_NOMEM;
goto end_of_check;
}
@@ -79050,7 +81655,7 @@ static int checkTreePage(
hdr = pPage->hdrOffset;
/* Set up for cell analysis */
- pCheck->zPfx = "On tree page %u cell %d: ";
+ pCheck->zPfx = "Tree %u page %u cell %u: ";
contentOffset = get2byteNotZero(&data[hdr+5]);
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
@@ -79058,6 +81663,9 @@ static int checkTreePage(
** number of cells on the page. */
nCell = get2byte(&data[hdr+3]);
assert( pPage->nCell==nCell );
+ if( pPage->leaf || pPage->intKey==0 ){
+ pCheck->nRow += nCell;
+ }
/* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
** immediately follows the b-tree page header. */
@@ -79070,7 +81678,7 @@ static int checkTreePage(
pgno = get4byte(&data[hdr+8]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
- pCheck->zPfx = "On page %u at right child: ";
+ pCheck->zPfx = "Tree %u page %u right child: ";
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
@@ -79094,7 +81702,7 @@ static int checkTreePage(
pc = get2byteAligned(pCellIdx);
pCellIdx -= 2;
if( pc<contentOffset || pc>usableSize-4 ){
- checkAppendMsg(pCheck, "Offset %d out of range %d..%d",
+ checkAppendMsg(pCheck, "Offset %u out of range %u..%u",
pc, contentOffset, usableSize-4);
doCoverageCheck = 0;
continue;
@@ -79169,6 +81777,7 @@ static int checkTreePage(
btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
}
}
+ assert( heap!=0 );
/* Add the freeblocks to the min-heap
**
** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
@@ -79226,7 +81835,7 @@ static int checkTreePage(
*/
if( heap[0]==0 && nFrag!=data[hdr+7] ){
checkAppendMsg(pCheck,
- "Fragmentation of %d bytes reported as %d on page %u",
+ "Fragmentation of %u bytes reported as %u on page %u",
nFrag, data[hdr+7], iPage);
}
}
@@ -79268,6 +81877,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeIntegrityCheck(
wx_sqlite3 *db, /* Database connection that is running the check */
Btree *p, /* The btree to be checked */
Pgno *aRoot, /* An array of root pages numbers for individual trees */
+ Mem *aCnt, /* Memory cells to write counts for each tree to */
int nRoot, /* Number of entries in aRoot[] */
int mxErr, /* Stop reporting errors after this many */
int *pnErr, /* OUT: Write number of errors seen to this variable */
@@ -79281,7 +81891,9 @@ SQLITE_PRIVATE int wx_sqlite3BtreeIntegrityCheck(
int bPartial = 0; /* True if not checking all btrees */
int bCkFreelist = 1; /* True to scan the freelist */
VVA_ONLY( int nRef );
+
assert( nRoot>0 );
+ assert( aCnt!=0 );
/* aRoot[0]==0 means this is a partial check */
if( aRoot[0]==0 ){
@@ -79298,15 +81910,15 @@ SQLITE_PRIVATE int wx_sqlite3BtreeIntegrityCheck(
sCheck.db = db;
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
- sCheck.nPage = btreePagecount(sCheck.pBt);
+ sCheck.nCkPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
wx_sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL;
- if( sCheck.nPage==0 ){
+ if( sCheck.nCkPage==0 ){
goto integrity_ck_cleanup;
}
- sCheck.aPgRef = wx_sqlite3MallocZero((sCheck.nPage / 8)+ 1);
+ sCheck.aPgRef = wx_sqlite3MallocZero((sCheck.nCkPage / 8)+ 1);
if( !sCheck.aPgRef ){
checkOom(&sCheck);
goto integrity_ck_cleanup;
@@ -79318,12 +81930,12 @@ SQLITE_PRIVATE int wx_sqlite3BtreeIntegrityCheck(
}
i = PENDING_BYTE_PAGE(pBt);
- if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
+ if( i<=sCheck.nCkPage ) setPageReferenced(&sCheck, i);
/* Check the integrity of the freelist
*/
if( bCkFreelist ){
- sCheck.zPfx = "Main freelist: ";
+ sCheck.zPfx = "Freelist: ";
checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
get4byte(&pBt->pPage1->aData[36]));
sCheck.zPfx = 0;
@@ -79340,7 +81952,7 @@ SQLITE_PRIVATE int wx_sqlite3BtreeIntegrityCheck(
mxInHdr = get4byte(&pBt->pPage1->aData[52]);
if( mx!=mxInHdr ){
checkAppendMsg(&sCheck,
- "max rootpage (%d) disagrees with header (%d)",
+ "max rootpage (%u) disagrees with header (%u)",
mx, mxInHdr
);
}
@@ -79354,24 +81966,28 @@ SQLITE_PRIVATE int wx_sqlite3BtreeIntegrityCheck(
testcase( pBt->db->flags & SQLITE_CellSizeCk );
pBt->db->flags &= ~(u64)SQLITE_CellSizeCk;
for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
- i64 notUsed;
- if( aRoot[i]==0 ) continue;
+ sCheck.nRow = 0;
+ if( aRoot[i] ){
+ i64 notUsed;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
- checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
- }
+ if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
+ checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
+ }
#endif
- checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
+ sCheck.v0 = aRoot[i];
+ checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
+ }
+ wx_sqlite3MemSetArrayInt64(aCnt, i, sCheck.nRow);
}
pBt->db->flags = savedDbFlags;
/* Make sure every page in the file is referenced
*/
if( !bPartial ){
- for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
+ for(i=1; i<=sCheck.nCkPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
if( getPageReferenced(&sCheck, i)==0 ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %u: never used", i);
}
#else
/* If the database supports auto-vacuum, make sure no tables contain
@@ -79379,11 +81995,11 @@ SQLITE_PRIVATE int wx_sqlite3BtreeIntegrityCheck(
*/
if( getPageReferenced(&sCheck, i)==0 &&
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %u: never used", i);
}
if( getPageReferenced(&sCheck, i)!=0 &&
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
+ checkAppendMsg(&sCheck, "Page %u: pointer map referenced", i);
}
#endif
}
@@ -79855,6 +82471,12 @@ SQLITE_API wx_sqlite3_backup *wx_sqlite3_backup_init(
}
#endif
+ /* Check whether databases are compatible with backup */
+ if (!wx_sqlite3mcIsBackupSupported(pSrcDb, zSrcDb, pDestDb, zDestDb)){
+ wx_sqlite3ErrorWithMsg(pDestDb, SQLITE_ERROR, "backup is not supported with incompatible source and target databases");
+ return NULL;
+ }
+
/* Lock the source database handle. The destination database
** handle is not locked in this routine, but it is locked in
** wx_sqlite3_backup_step(). The user is required to ensure that no
@@ -79945,13 +82567,7 @@ static int backupOnePage(
assert( !isFatalError(p->rc) );
assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
assert( zSrcData );
-
- /* Catch the case where the destination is an in-memory database and the
- ** page sizes of the source and destination differ.
- */
- if( nSrcPgsz!=nDestPgsz && wx_sqlite3PagerIsMemdb(pDestPager) ){
- rc = SQLITE_READONLY;
- }
+ assert( nSrcPgsz==nDestPgsz || wx_sqlite3PagerIsMemdb(pDestPager)==0 );
/* This loop runs once for each destination page spanned by the source
** page. For each iteration, variable iOff is set to the byte offset
@@ -80084,7 +82700,10 @@ SQLITE_API int wx_sqlite3_backup_step(wx_sqlite3_backup *p, int nPage){
pgszSrc = wx_sqlite3BtreeGetPageSize(p->pSrc);
pgszDest = wx_sqlite3BtreeGetPageSize(p->pDest);
destMode = wx_sqlite3PagerGetJournalMode(wx_sqlite3BtreePager(p->pDest));
- if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
+ if( SQLITE_OK==rc
+ && (destMode==PAGER_JOURNALMODE_WAL || wx_sqlite3PagerIsMemdb(pDestPager))
+ && pgszSrc!=pgszDest
+ ){
rc = SQLITE_READONLY;
}
@@ -80633,6 +83252,7 @@ SQLITE_PRIVATE int wx_sqlite3VdbeMemValidStrRep(Mem *p){
char *z;
int i, j, incr;
if( (p->flags & MEM_Str)==0 ) return 1;
+ if( p->db && p->db->mallocFailed ) return 1;
if( p->flags & MEM_Term ){
/* Insure that the string is properly zero-terminated. Pay particular
** attention to the case where p->n is odd */
@@ -80790,6 +83410,40 @@ SQLITE_PRIVATE int wx_sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
}
/*
+** If pMem is already a string, detect if it is a zero-terminated
+** string, or make it into one if possible, and mark it as such.
+**
+** This is an optimization. Correct operation continues even if
+** this routine is a no-op.
+*/
+SQLITE_PRIVATE void wx_sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){
+ if( (pMem->flags & (MEM_Str|MEM_Term|MEM_Ephem|MEM_Static))!=MEM_Str ){
+ /* pMem must be a string, and it cannot be an ephemeral or static string */
+ return;
+ }
+ if( pMem->enc!=SQLITE_UTF8 ) return;
+ if( NEVER(pMem->z==0) ) return;
+ if( pMem->flags & MEM_Dyn ){
+ if( pMem->xDel==wx_sqlite3_free
+ && wx_sqlite3_msize(pMem->z) >= (u64)(pMem->n+1)
+ ){
+ pMem->z[pMem->n] = 0;
+ pMem->flags |= MEM_Term;
+ return;
+ }
+ if( pMem->xDel==wx_sqlite3RCStrUnref ){
+ /* Blindly assume that all RCStr objects are zero-terminated */
+ pMem->flags |= MEM_Term;
+ return;
+ }
+ }else if( pMem->szMalloc >= pMem->n+1 ){
+ pMem->z[pMem->n] = 0;
+ pMem->flags |= MEM_Term;
+ return;
+ }
+}
+
+/*
** It is already known that pMem contains an unterminated string.
** Add the zero terminator.
**
@@ -80915,7 +83569,7 @@ SQLITE_PRIVATE int wx_sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
vdbeMemRenderNum(nByte, pMem->z, pMem);
assert( pMem->z!=0 );
- assert( pMem->n==wx_sqlite3Strlen30NN(pMem->z) );
+ assert( pMem->n==(int)wx_sqlite3Strlen30NN(pMem->z) );
pMem->enc = SQLITE_UTF8;
pMem->flags |= MEM_Str|MEM_Term;
if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
@@ -81051,36 +83705,6 @@ SQLITE_PRIVATE void wx_sqlite3VdbeMemReleaseMalloc(Mem *p){
}
/*
-** Convert a 64-bit IEEE double into a 64-bit signed integer.
-** If the double is out of range of a 64-bit signed integer then
-** return the closest available 64-bit signed integer.
-*/
-static SQLITE_NOINLINE i64 doubleToInt64(double r){
-#ifdef SQLITE_OMIT_FLOATING_POINT
- /* When floating-point is omitted, double and int64 are the same thing */
- return r;
-#else
- /*
- ** Many compilers we encounter do not define constants for the
- ** minimum and maximum 64-bit integers, or they define them
- ** inconsistently. And many do not understand the "LL" notation.
- ** So we define our own static constants here using nothing
- ** larger than a 32-bit integer constant.
- */
- static const i64 maxInt = LARGEST_INT64;
- static const i64 minInt = SMALLEST_INT64;
-
- if( r<=(double)minInt ){
- return minInt;
- }else if( r>=(double)maxInt ){
- return maxInt;
- }else{
- return (i64)r;
- }
-#endif
-}
-
-/*
** Return some kind of integer value which is the best we can do
** at representing the value that *pMem describes as an integer.
** If pMem is an integer, then the value is exact. If pMem is
@@ -81106,7 +83730,7 @@ SQLITE_PRIVATE i64 wx_sqlite3VdbeIntValue(const Mem *pMem){
testcase( flags & MEM_IntReal );
return pMem->u.i;
}else if( flags & MEM_Real ){
- return doubleToInt64(pMem->u.r);
+ return wx_sqlite3RealToI64(pMem->u.r);
}else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){
return memIntValue(pMem);
}else{
@@ -81168,7 +83792,7 @@ SQLITE_PRIVATE void wx_sqlite3VdbeIntegerAffinity(Mem *pMem){
if( pMem->flags & MEM_IntReal ){
MemSetTypeFlag(pMem, MEM_Int);
}else{
- i64 ix = doubleToInt64(pMem->u.r);
+ i64 ix = wx_sqlite3RealToI64(pMem->u.r);
/* Only mark the value as an integer if
**
@@ -81236,8 +83860,8 @@ SQLITE_PRIVATE int wx_sqlite3RealSameAsInt(double r1, wx_sqlite3_int64 i){
** from UBSAN.
*/
SQLITE_PRIVATE i64 wx_sqlite3RealToI64(double r){
- if( r<=(double)SMALLEST_INT64 ) return SMALLEST_INT64;
- if( r>=(double)LARGEST_INT64) return LARGEST_INT64;
+ if( r<-9223372036854774784.0 ) return SMALLEST_INT64;
+ if( r>+9223372036854774784.0 ) return LARGEST_INT64;
return (i64)r;
}
@@ -81308,6 +83932,7 @@ SQLITE_PRIVATE int wx_sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
break;
}
default: {
+ int rc;
assert( aff==SQLITE_AFF_TEXT );
assert( MEM_Str==(MEM_Blob>>3) );
pMem->flags |= (pMem->flags&MEM_Blob)>>3;
@@ -81315,7 +83940,9 @@ SQLITE_PRIVATE int wx_sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1;
- return wx_sqlite3VdbeChangeEncoding(pMem, encoding);
+ rc = wx_sqlite3VdbeChangeEncoding(pMem, encoding);
+ if( rc ) return rc;
+ wx_sqlite3VdbeMemZeroTerminateIfAble(pMem);
}
}
return SQLITE_OK;
@@ -81411,6 +84038,13 @@ SQLITE_PRIVATE void wx_sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
}
}
+/*
+** Set the iIdx'th entry of array aMem[] to contain integer value val.
+*/
+SQLITE_PRIVATE void wx_sqlite3MemSetArrayInt64(wx_sqlite3_value *aMem, int iIdx, i64 val){
+ wx_sqlite3VdbeMemSetInt64(&aMem[iIdx], val);
+}
+
/* A no-op destructor */
SQLITE_PRIVATE void wx_sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
@@ -81839,6 +84473,24 @@ SQLITE_PRIVATE const void *wx_sqlite3ValueText(wx_sqlite3_value* pVal, u8 enc){
return valueToText(pVal, enc);
}
+/* Return true if sqlit3_value object pVal is a string or blob value
+** that uses the destructor specified in the second argument.
+**
+** TODO: Maybe someday promote this interface into a published API so
+** that third-party extensions can get access to it?
+*/
+SQLITE_PRIVATE int wx_sqlite3ValueIsOfClass(const wx_sqlite3_value *pVal, void(*xFree)(void*)){
+ if( ALWAYS(pVal!=0)
+ && ALWAYS((pVal->flags & (MEM_Str|MEM_Blob))!=0)
+ && (pVal->flags & MEM_Dyn)!=0
+ && pVal->xDel==xFree
+ ){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
/*
** Create a new wx_sqlite3_value object.
*/
@@ -81906,6 +84558,7 @@ static wx_sqlite3_value *valueNew(wx_sqlite3 *db, struct ValueNewStat4Ctx *p){
}
pRec->nField = p->iVal+1;
+ wx_sqlite3VdbeMemSetNull(&pRec->aMem[p->iVal]);
return &pRec->aMem[p->iVal];
}
#else
@@ -81959,9 +84612,12 @@ static int valueFromFunction(
if( pList ) nVal = pList->nExpr;
assert( !ExprHasProperty(p, EP_IntValue) );
pFunc = wx_sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ if( pFunc==0 ) return SQLITE_OK;
+#endif
assert( pFunc );
if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
- || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
+ || (pFunc->funcFlags & (SQLITE_FUNC_NEEDCOLL|SQLITE_FUNC_RUNONLY))!=0
){
return SQLITE_OK;
}
@@ -81973,7 +84629,8 @@ static int valueFromFunction(
goto value_from_function_out;
}
for(i=0; i<nVal; i++){
- rc = wx_sqlite3ValueFromExpr(db, pList->a[i].pExpr, enc, aff, &apVal[i]);
+ rc = wx_sqlite3Stat4ValueFromExpr(pCtx->pParse, pList->a[i].pExpr, aff,
+ &apVal[i]);
if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out;
}
}
@@ -81995,16 +84652,11 @@ static int valueFromFunction(
}else{
wx_sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
assert( rc==SQLITE_OK );
- assert( enc==pVal->enc
- || (pVal->flags & MEM_Str)==0
- || db->mallocFailed );
-#if 0 /* Not reachable except after a prior failure */
rc = wx_sqlite3VdbeChangeEncoding(pVal, enc);
- if( rc==SQLITE_OK && wx_sqlite3VdbeMemTooBig(pVal) ){
+ if( NEVER(rc==SQLITE_OK && wx_sqlite3VdbeMemTooBig(pVal)) ){
rc = SQLITE_TOOBIG;
pCtx->pParse->nErr++;
}
-#endif
}
value_from_function_out:
@@ -82068,6 +84720,13 @@ static int valueFromExpr(
rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
testcase( rc!=SQLITE_OK );
if( *ppVal ){
+#ifdef SQLITE_ENABLE_STAT4
+ rc = ExpandBlob(*ppVal);
+#else
+ /* zero-blobs only come from functions, not literal values. And
+ ** functions are only processed under STAT4 */
+ assert( (ppVal[0][0].flags & MEM_Zero)==0 );
+#endif
wx_sqlite3VdbeMemCast(*ppVal, aff, enc);
wx_sqlite3ValueApplyAffinity(*ppVal, affinity, enc);
}
@@ -82075,14 +84734,20 @@ static int valueFromExpr(
}
/* Handle negative integers in a single step. This is needed in the
- ** case when the value is -9223372036854775808.
- */
- if( op==TK_UMINUS
- && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){
- pExpr = pExpr->pLeft;
- op = pExpr->op;
- negInt = -1;
- zNeg = "-";
+ ** case when the value is -9223372036854775808. Except - do not do this
+ ** for hexadecimal literals. */
+ if( op==TK_UMINUS ){
+ Expr *pLeft = pExpr->pLeft;
+ if( (pLeft->op==TK_INTEGER || pLeft->op==TK_FLOAT) ){
+ if( ExprHasProperty(pLeft, EP_IntValue)
+ || pLeft->u.zToken[0]!='0' || (pLeft->u.zToken[1] & ~0x20)!='X'
+ ){
+ pExpr = pLeft;
+ op = pExpr->op;
+ negInt = -1;
+ zNeg = "-";
+ }
+ }
}
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
@@ -82091,12 +84756,26 @@ static int valueFromExpr(
if( ExprHasProperty(pExpr, EP_IntValue) ){
wx_sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt);
}else{
- zVal = wx_sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
- if( zVal==0 ) goto no_mem;
- wx_sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
+ i64 iVal;
+ if( op==TK_INTEGER && 0==wx_sqlite3DecOrHexToI64(pExpr->u.zToken, &iVal) ){
+ wx_sqlite3VdbeMemSetInt64(pVal, iVal*negInt);
+ }else{
+ zVal = wx_sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
+ if( zVal==0 ) goto no_mem;
+ wx_sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
+ }
}
- if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_BLOB ){
- wx_sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
+ if( affinity==SQLITE_AFF_BLOB ){
+ if( op==TK_FLOAT ){
+ assert( pVal && pVal->z && pVal->flags==(MEM_Str|MEM_Term) );
+ wx_sqlite3AtoF(pVal->z, &pVal->u.r, pVal->n, SQLITE_UTF8);
+ pVal->flags = MEM_Real;
+ }else if( op==TK_INTEGER ){
+ /* This case is required by -9223372036854775808 and other strings
+ ** that look like integers but cannot be handled by the
+ ** wx_sqlite3DecOrHexToI64() call above. */
+ wx_sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
+ }
}else{
wx_sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
}
@@ -82160,6 +84839,7 @@ static int valueFromExpr(
if( pVal ){
pVal->flags = MEM_Int;
pVal->u.i = pExpr->u.zToken[4]==0;
+ wx_sqlite3ValueApplyAffinity(pVal, affinity, enc);
}
}
@@ -82365,17 +85045,17 @@ SQLITE_PRIVATE int wx_sqlite3Stat4Column(
wx_sqlite3_value **ppVal /* OUT: Extracted value */
){
u32 t = 0; /* a column type code */
- int nHdr; /* Size of the header in the record */
- int iHdr; /* Next unread header byte */
- int iField; /* Next unread data byte */
- int szField = 0; /* Size of the current data field */
+ u32 nHdr; /* Size of the header in the record */
+ u32 iHdr; /* Next unread header byte */
+ i64 iField; /* Next unread data byte */
+ u32 szField = 0; /* Size of the current data field */
int i; /* Column index */
u8 *a = (u8*)pRec; /* Typecast byte array */
Mem *pMem = *ppVal; /* Write result into this Mem object */
assert( iCol>0 );
iHdr = getVarint32(a, nHdr);
- if( nHdr>nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT;
+ if( nHdr>(u32)nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT;
iField = nHdr;
for(i=0; i<=iCol; i++){
iHdr += getVarint32(&a[iHdr], t);
@@ -82682,14 +85362,44 @@ static int growOpArray(Vdbe *v, int nOp){
** wx_sqlite3CantopenError(lineno)
*/
static void test_addop_breakpoint(int pc, Op *pOp){
- static int n = 0;
+ static u64 n = 0;
(void)pc;
(void)pOp;
n++;
+ if( n==LARGEST_UINT64 ) abort(); /* so that n is used, preventing a warning */
}
#endif
/*
+** Slow paths for wx_sqlite3VdbeAddOp3() and wx_sqlite3VdbeAddOp4Int() for the
+** unusual case when we need to increase the size of the Vdbe.aOp[] array
+** before adding the new opcode.
+*/
+static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
+ assert( p->nOpAlloc<=p->nOp );
+ if( growOpArray(p, 1) ) return 1;
+ assert( p->nOpAlloc>p->nOp );
+ return wx_sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+}
+static SQLITE_NOINLINE int addOp4IntSlow(
+ Vdbe *p, /* Add the opcode to this VM */
+ int op, /* The new opcode */
+ int p1, /* The P1 operand */
+ int p2, /* The P2 operand */
+ int p3, /* The P3 operand */
+ int p4 /* The P4 operand as an integer */
+){
+ int addr = wx_sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+ if( p->db->mallocFailed==0 ){
+ VdbeOp *pOp = &p->aOp[addr];
+ pOp->p4type = P4_INT32;
+ pOp->p4.i = p4;
+ }
+ return addr;
+}
+
+
+/*
** Add a new instruction to the list of instructions current in the
** VDBE. Return the address of the new instruction.
**
@@ -82699,17 +85409,16 @@ static void test_addop_breakpoint(int pc, Op *pOp){
**
** op The opcode for this instruction
**
-** p1, p2, p3 Operands
-**
-** Use the wx_sqlite3VdbeResolveLabel() function to fix an address and
-** the wx_sqlite3VdbeChangeP4() function to change the value of the P4
-** operand.
+** p1, p2, p3, p4 Operands
*/
-static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
- assert( p->nOpAlloc<=p->nOp );
- if( growOpArray(p, 1) ) return 1;
- assert( p->nOpAlloc>p->nOp );
- return wx_sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+SQLITE_PRIVATE int wx_sqlite3VdbeAddOp0(Vdbe *p, int op){
+ return wx_sqlite3VdbeAddOp3(p, op, 0, 0, 0);
+}
+SQLITE_PRIVATE int wx_sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){
+ return wx_sqlite3VdbeAddOp3(p, op, p1, 0, 0);
+}
+SQLITE_PRIVATE int wx_sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
+ return wx_sqlite3VdbeAddOp3(p, op, p1, p2, 0);
}
SQLITE_PRIVATE int wx_sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
int i;
@@ -82732,6 +85441,9 @@ SQLITE_PRIVATE int wx_sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3)
pOp->p3 = p3;
pOp->p4.p = 0;
pOp->p4type = P4_NOTUSED;
+
+ /* Replicate this logic in wx_sqlite3VdbeAddOp4Int()
+ ** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
pOp->zComment = 0;
#endif
@@ -82748,16 +85460,59 @@ SQLITE_PRIVATE int wx_sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3)
#ifdef SQLITE_VDBE_COVERAGE
pOp->iSrcLine = 0;
#endif
+ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ** Replicate in wx_sqlite3VdbeAddOp4Int() */
+
return i;
}
-SQLITE_PRIVATE int wx_sqlite3VdbeAddOp0(Vdbe *p, int op){
- return wx_sqlite3VdbeAddOp3(p, op, 0, 0, 0);
-}
-SQLITE_PRIVATE int wx_sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){
- return wx_sqlite3VdbeAddOp3(p, op, p1, 0, 0);
-}
-SQLITE_PRIVATE int wx_sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
- return wx_sqlite3VdbeAddOp3(p, op, p1, p2, 0);
+SQLITE_PRIVATE int wx_sqlite3VdbeAddOp4Int(
+ Vdbe *p, /* Add the opcode to this VM */
+ int op, /* The new opcode */
+ int p1, /* The P1 operand */
+ int p2, /* The P2 operand */
+ int p3, /* The P3 operand */
+ int p4 /* The P4 operand as an integer */
+){
+ int i;
+ VdbeOp *pOp;
+
+ i = p->nOp;
+ if( p->nOpAlloc<=i ){
+ return addOp4IntSlow(p, op, p1, p2, p3, p4);
+ }
+ p->nOp++;
+ pOp = &p->aOp[i];
+ assert( pOp!=0 );
+ pOp->opcode = (u8)op;
+ pOp->p5 = 0;
+ pOp->p1 = p1;
+ pOp->p2 = p2;
+ pOp->p3 = p3;
+ pOp->p4.i = p4;
+ pOp->p4type = P4_INT32;
+
+ /* Replicate this logic in wx_sqlite3VdbeAddOp3()
+ ** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ pOp->zComment = 0;
+#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+ pOp->nExec = 0;
+ pOp->nCycle = 0;
+#endif
+#ifdef SQLITE_DEBUG
+ if( p->db->flags & SQLITE_VdbeAddopTrace ){
+ wx_sqlite3VdbePrintOp(0, i, &p->aOp[i]);
+ test_addop_breakpoint(i, &p->aOp[i]);
+ }
+#endif
+#ifdef SQLITE_VDBE_COVERAGE
+ pOp->iSrcLine = 0;
+#endif
+ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ** Replicate in wx_sqlite3VdbeAddOp3() */
+
+ return i;
}
/* Generate code for an unconditional jump to instruction iDest
@@ -82914,10 +85669,10 @@ SQLITE_PRIVATE void wx_sqlite3ExplainBreakpoint(const char *z1, const char *z2){
*/
SQLITE_PRIVATE int wx_sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
int addr = 0;
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+#if !defined(SQLITE_DEBUG)
/* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined.
** But omit them (for performance) during production builds */
- if( pParse->explain==2 )
+ if( pParse->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
#endif
{
char *zMsg;
@@ -82935,7 +85690,7 @@ SQLITE_PRIVATE int wx_sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zF
if( bPush){
pParse->addrExplain = iThis;
}
- wx_sqlite3VdbeScanStatus(v, iThis, 0, 0, 0, 0);
+ wx_sqlite3VdbeScanStatus(v, iThis, -1, -1, 0, 0);
}
return addr;
}
@@ -82965,26 +85720,6 @@ SQLITE_PRIVATE void wx_sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWher
wx_sqlite3MayAbort(p->pParse);
}
-/*
-** Add an opcode that includes the p4 value as an integer.
-*/
-SQLITE_PRIVATE int wx_sqlite3VdbeAddOp4Int(
- Vdbe *p, /* Add the opcode to this VM */
- int op, /* The new opcode */
- int p1, /* The P1 operand */
- int p2, /* The P2 operand */
- int p3, /* The P3 operand */
- int p4 /* The P4 operand as an integer */
-){
- int addr = wx_sqlite3VdbeAddOp3(p, op, p1, p2, p3);
- if( p->db->mallocFailed==0 ){
- VdbeOp *pOp = &p->aOp[addr];
- pOp->p4type = P4_INT32;
- pOp->p4.i = p4;
- }
- return addr;
-}
-
/* Insert the end of a co-routine
*/
SQLITE_PRIVATE void wx_sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){
@@ -83291,11 +86026,13 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
Op *pOp;
Parse *pParse = p->pParse;
int *aLabel = pParse->aLabel;
+
+ assert( pParse->db->mallocFailed==0 ); /* tag-20230419-1 */
p->readOnly = 1;
p->bIsReader = 0;
pOp = &p->aOp[p->nOp-1];
assert( p->aOp[0].opcode==OP_Init );
- while( 1 /* Loop termates when it reaches the OP_Init opcode */ ){
+ while( 1 /* Loop terminates when it reaches the OP_Init opcode */ ){
/* Only JUMP opcodes and the short list of special opcodes in the switch
** below need to be considered. The mkopcodeh.tcl generator script groups
** all these opcodes together near the front of the opcode list. Skip
@@ -83350,8 +86087,18 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
** have non-negative values for P2. */
assert( (wx_sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
assert( ADDR(pOp->p2)<-pParse->nLabel );
+ assert( aLabel!=0 ); /* True because of tag-20230419-1 */
pOp->p2 = aLabel[ADDR(pOp->p2)];
}
+
+ /* OPFLG_JUMP opcodes never have P2==0, though OPFLG_JUMP0 opcodes
+ ** might */
+ assert( pOp->p2>0
+ || (wx_sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP0)!=0 );
+
+ /* Jumps never go off the end of the bytecode array */
+ assert( pOp->p2<p->nOp
+ || (wx_sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)==0 );
break;
}
}
@@ -83416,6 +86163,10 @@ SQLITE_PRIVATE void wx_sqlite3VdbeNoJumpsOutsideSubrtn(
int iDest = pOp->p2; /* Jump destination */
if( iDest==0 ) continue;
if( pOp->opcode==OP_Gosub ) continue;
+ if( pOp->p3==20230325 && pOp->opcode==OP_NotNull ){
+ /* This is a deliberately taken illegal branch. tag-20230325-2 */
+ continue;
+ }
if( iDest<0 ){
int j = ADDR(iDest);
assert( j>=0 );
@@ -83593,18 +86344,20 @@ SQLITE_PRIVATE void wx_sqlite3VdbeScanStatus(
LogEst nEst, /* Estimated number of output rows */
const char *zName /* Name of table or index being scanned */
){
- wx_sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus);
- ScanStatus *aNew;
- aNew = (ScanStatus*)wx_sqlite3DbRealloc(p->db, p->aScan, nByte);
- if( aNew ){
- ScanStatus *pNew = &aNew[p->nScan++];
- memset(pNew, 0, sizeof(ScanStatus));
- pNew->addrExplain = addrExplain;
- pNew->addrLoop = addrLoop;
- pNew->addrVisit = addrVisit;
- pNew->nEst = nEst;
- pNew->zName = wx_sqlite3DbStrDup(p->db, zName);
- p->aScan = aNew;
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ wx_sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus);
+ ScanStatus *aNew;
+ aNew = (ScanStatus*)wx_sqlite3DbRealloc(p->db, p->aScan, nByte);
+ if( aNew ){
+ ScanStatus *pNew = &aNew[p->nScan++];
+ memset(pNew, 0, sizeof(ScanStatus));
+ pNew->addrExplain = addrExplain;
+ pNew->addrLoop = addrLoop;
+ pNew->addrVisit = addrVisit;
+ pNew->nEst = nEst;
+ pNew->zName = wx_sqlite3DbStrDup(p->db, zName);
+ p->aScan = aNew;
+ }
}
}
@@ -83621,20 +86374,22 @@ SQLITE_PRIVATE void wx_sqlite3VdbeScanStatusRange(
int addrStart,
int addrEnd
){
- ScanStatus *pScan = 0;
- int ii;
- for(ii=p->nScan-1; ii>=0; ii--){
- pScan = &p->aScan[ii];
- if( pScan->addrExplain==addrExplain ) break;
- pScan = 0;
- }
- if( pScan ){
- if( addrEnd<0 ) addrEnd = wx_sqlite3VdbeCurrentAddr(p)-1;
- for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
- if( pScan->aAddrRange[ii]==0 ){
- pScan->aAddrRange[ii] = addrStart;
- pScan->aAddrRange[ii+1] = addrEnd;
- break;
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ ScanStatus *pScan = 0;
+ int ii;
+ for(ii=p->nScan-1; ii>=0; ii--){
+ pScan = &p->aScan[ii];
+ if( pScan->addrExplain==addrExplain ) break;
+ pScan = 0;
+ }
+ if( pScan ){
+ if( addrEnd<0 ) addrEnd = wx_sqlite3VdbeCurrentAddr(p)-1;
+ for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
+ if( pScan->aAddrRange[ii]==0 ){
+ pScan->aAddrRange[ii] = addrStart;
+ pScan->aAddrRange[ii+1] = addrEnd;
+ break;
+ }
}
}
}
@@ -83651,19 +86406,21 @@ SQLITE_PRIVATE void wx_sqlite3VdbeScanStatusCounters(
int addrLoop,
int addrVisit
){
- ScanStatus *pScan = 0;
- int ii;
- for(ii=p->nScan-1; ii>=0; ii--){
- pScan = &p->aScan[ii];
- if( pScan->addrExplain==addrExplain ) break;
- pScan = 0;
- }
- if( pScan ){
- pScan->addrLoop = addrLoop;
- pScan->addrVisit = addrVisit;
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ ScanStatus *pScan = 0;
+ int ii;
+ for(ii=p->nScan-1; ii>=0; ii--){
+ pScan = &p->aScan[ii];
+ if( pScan->addrExplain==addrExplain ) break;
+ pScan = 0;
+ }
+ if( pScan ){
+ if( addrLoop>0 ) pScan->addrLoop = addrLoop;
+ if( addrVisit>0 ) pScan->addrVisit = addrVisit;
+ }
}
}
-#endif
+#endif /* defined(SQLITE_ENABLE_STMT_SCANSTATUS) */
/*
@@ -83742,7 +86499,7 @@ SQLITE_PRIVATE void wx_sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
/*
** If the input FuncDef structure is ephemeral, then free it. If
-** the FuncDef is not ephermal, then do nothing.
+** the FuncDef is not ephemeral, then do nothing.
*/
static void freeEphemeralFunction(wx_sqlite3 *db, FuncDef *pDef){
assert( db!=0 );
@@ -83803,6 +86560,16 @@ static void freeP4(wx_sqlite3 *db, int p4type, void *p4){
if( db->pnBytesFreed==0 ) wx_sqlite3VtabUnlock((VTable *)p4);
break;
}
+ case P4_TABLEREF: {
+ if( db->pnBytesFreed==0 ) wx_sqlite3DeleteTable(db, (Table*)p4);
+ break;
+ }
+ case P4_SUBRTNSIG: {
+ SubrtnSig *pSig = (SubrtnSig*)p4;
+ wx_sqlite3DbFree(db, pSig->zAff);
+ wx_sqlite3DbFree(db, pSig);
+ break;
+ }
}
}
@@ -83906,7 +86673,6 @@ SQLITE_PRIVATE void wx_sqlite3VdbeReleaseRegisters(
}
#endif /* SQLITE_DEBUG */
-
/*
** Change the value of the P4 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
@@ -83931,7 +86697,7 @@ static void SQLITE_NOINLINE vdbeChangeP4Full(
int n
){
if( pOp->p4type ){
- freeP4(p->db, pOp->p4type, pOp->p4.p);
+ assert( pOp->p4type > P4_FREE_IF_LE );
pOp->p4type = 0;
pOp->p4.p = 0;
}
@@ -84087,7 +86853,7 @@ SQLITE_PRIVATE VdbeOp *wx_sqlite3VdbeGetOp(Vdbe *p, int addr){
/* Return the most recently added opcode
*/
-VdbeOp * wx_sqlite3VdbeGetLastOp(Vdbe *p){
+SQLITE_PRIVATE VdbeOp *wx_sqlite3VdbeGetLastOp(Vdbe *p){
return wx_sqlite3VdbeGetOp(p, p->nOp - 1);
}
@@ -84383,6 +87149,11 @@ SQLITE_PRIVATE char *wx_sqlite3VdbeDisplayP4(wx_sqlite3 *db, Op *pOp){
zP4 = pOp->p4.pTab->zName;
break;
}
+ case P4_SUBRTNSIG: {
+ SubrtnSig *pSig = pOp->p4.pSubrtnSig;
+ wx_sqlite3_str_appendf(&x, "subrtnsig:%d,%s", pSig->selId, pSig->zAff);
+ break;
+ }
default: {
zP4 = pOp->p4.z;
}
@@ -84827,7 +87598,7 @@ SQLITE_PRIVATE int wx_sqlite3VdbeList(
wx_sqlite3VdbeMemSetInt64(pMem+1, pOp->p2);
wx_sqlite3VdbeMemSetInt64(pMem+2, pOp->p3);
wx_sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, wx_sqlite3_free);
- p->nResColumn = 4;
+ assert( p->nResColumn==4 );
}else{
wx_sqlite3VdbeMemSetInt64(pMem+0, i);
wx_sqlite3VdbeMemSetStr(pMem+1, (char*)wx_sqlite3OpcodeName(pOp->opcode),
@@ -84846,7 +87617,7 @@ SQLITE_PRIVATE int wx_sqlite3VdbeList(
wx_sqlite3VdbeMemSetNull(pMem+7);
#endif
wx_sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, wx_sqlite3_free);
- p->nResColumn = 8;
+ assert( p->nResColumn==8 );
}
p->pResultRow = pMem;
if( db->mallocFailed ){
@@ -85060,26 +87831,9 @@ SQLITE_PRIVATE void wx_sqlite3VdbeMakeReady(
resolveP2Values(p, &nArg);
p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
if( pParse->explain ){
- static const char * const azColName[] = {
- "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
- "id", "parent", "notused", "detail"
- };
- int iFirst, mx, i;
if( nMem<10 ) nMem = 10;
p->explain = pParse->explain;
- if( pParse->explain==2 ){
- wx_sqlite3VdbeSetNumCols(p, 4);
- iFirst = 8;
- mx = 12;
- }else{
- wx_sqlite3VdbeSetNumCols(p, 8);
- iFirst = 0;
- mx = 8;
- }
- for(i=iFirst; i<mx; i++){
- wx_sqlite3VdbeSetColName(p, i-iFirst, COLNAME_NAME,
- azColName[i], SQLITE_STATIC);
- }
+ p->nResColumn = 12 - 4*p->explain;
}
p->expired = 0;
@@ -85131,7 +87885,23 @@ SQLITE_PRIVATE void wx_sqlite3VdbeMakeReady(
SQLITE_PRIVATE void wx_sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx ) wx_sqlite3VdbeFreeCursorNN(p,pCx);
}
+static SQLITE_NOINLINE void freeCursorWithCache(Vdbe *p, VdbeCursor *pCx){
+ VdbeTxtBlbCache *pCache = pCx->pCache;
+ assert( pCx->colCache );
+ pCx->colCache = 0;
+ pCx->pCache = 0;
+ if( pCache->pCValue ){
+ wx_sqlite3RCStrUnref(pCache->pCValue);
+ pCache->pCValue = 0;
+ }
+ wx_sqlite3DbFree(p->db, pCache);
+ wx_sqlite3VdbeFreeCursorNN(p, pCx);
+}
SQLITE_PRIVATE void wx_sqlite3VdbeFreeCursorNN(Vdbe *p, VdbeCursor *pCx){
+ if( pCx->colCache ){
+ freeCursorWithCache(p, pCx);
+ return;
+ }
switch( pCx->eCurType ){
case CURTYPE_SORTER: {
wx_sqlite3VdbeSorterClose(p->db, pCx);
@@ -85232,12 +88002,12 @@ SQLITE_PRIVATE void wx_sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
int n;
wx_sqlite3 *db = p->db;
- if( p->nResColumn ){
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ if( p->nResAlloc ){
+ releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N);
wx_sqlite3DbFree(db, p->aColName);
}
n = nResColumn*COLNAME_N;
- p->nResColumn = (u16)nResColumn;
+ p->nResColumn = p->nResAlloc = (u16)nResColumn;
p->aColName = (Mem*)wx_sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
initMemArray(p->aColName, n, db, MEM_Null);
@@ -85262,14 +88032,14 @@ SQLITE_PRIVATE int wx_sqlite3VdbeSetColName(
){
int rc;
Mem *pColName;
- assert( idx<p->nResColumn );
+ assert( idx<p->nResAlloc );
assert( var<COLNAME_N );
if( p->db->mallocFailed ){
assert( !zName || xDel!=SQLITE_DYNAMIC );
return SQLITE_NOMEM_BKPT;
}
assert( p->aColName!=0 );
- pColName = &(p->aColName[idx+var*p->nResColumn]);
+ pColName = &(p->aColName[idx+var*p->nResAlloc]);
rc = wx_sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, xDel);
assert( rc!=0 || !zName || (pColName->flags&MEM_Term)!=0 );
return rc;
@@ -85747,7 +88517,7 @@ SQLITE_PRIVATE int wx_sqlite3VdbeHalt(Vdbe *p){
/* Check for immediate foreign key violations. */
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
- wx_sqlite3VdbeCheckFk(p, 0);
+ (void)wx_sqlite3VdbeCheckFk(p, 0);
}
/* If the auto-commit flag is set and this is the only active writer
@@ -85782,6 +88552,7 @@ SQLITE_PRIVATE int wx_sqlite3VdbeHalt(Vdbe *p){
wx_sqlite3VdbeLeave(p);
return SQLITE_BUSY;
}else if( rc!=SQLITE_OK ){
+ wx_sqlite3SystemError(db, rc);
p->rc = rc;
wx_sqlite3RollbackAll(db, SQLITE_OK);
p->nChange = 0;
@@ -85791,6 +88562,8 @@ SQLITE_PRIVATE int wx_sqlite3VdbeHalt(Vdbe *p){
db->flags &= ~(u64)SQLITE_DeferFKs;
wx_sqlite3CommitInternalChanges(db);
}
+ }else if( p->rc==SQLITE_SCHEMA && db->nVdbeActive>1 ){
+ p->nChange = 0;
}else{
wx_sqlite3RollbackAll(db, SQLITE_OK);
p->nChange = 0;
@@ -86091,7 +88864,7 @@ static void wx_sqlite3VdbeClearObject(wx_sqlite3 *db, Vdbe *p){
assert( db!=0 );
assert( p->db==0 || p->db==db );
if( p->aColName ){
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N);
wx_sqlite3DbNNFreeNN(db, p->aColName);
}
for(pSub=p->pProgram; pSub; pSub=pNext){
@@ -86109,9 +88882,9 @@ static void wx_sqlite3VdbeClearObject(wx_sqlite3 *db, Vdbe *p){
#ifdef SQLITE_ENABLE_NORMALIZE
wx_sqlite3DbFree(db, p->zNormSql);
{
- DblquoteStr *pThis, *pNext;
- for(pThis=p->pDblStr; pThis; pThis=pNext){
- pNext = pThis->pNextStr;
+ DblquoteStr *pThis, *pNxt;
+ for(pThis=p->pDblStr; pThis; pThis=pNxt){
+ pNxt = pThis->pNextStr;
wx_sqlite3DbFree(db, pThis);
}
}
@@ -86458,6 +89231,23 @@ static void serialGet(
pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
}
}
+static int serialGet7(
+ const unsigned char *buf, /* Buffer to deserialize from */
+ Mem *pMem /* Memory cell to write value into */
+){
+ u64 x = FOUR_BYTE_UINT(buf);
+ u32 y = FOUR_BYTE_UINT(buf+4);
+ x = (x<<32) + y;
+ assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
+ swapMixedEndianFloat(x);
+ memcpy(&pMem->u.r, &x, sizeof(x));
+ if( IsNaN(x) ){
+ pMem->flags = MEM_Null;
+ return 1;
+ }
+ pMem->flags = MEM_Real;
+ return 0;
+}
SQLITE_PRIVATE void wx_sqlite3VdbeSerialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
@@ -86691,6 +89481,15 @@ static int vdbeRecordCompareDebug(
if( d1+(u64)serial_type1+2>(u64)nKey1
&& d1+(u64)wx_sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1
){
+ if( serial_type1>=1
+ && serial_type1<=7
+ && d1+(u64)wx_sqlite3VdbeSerialTypeLen(serial_type1)<=(u64)nKey1+8
+ && CORRUPT_DB
+ ){
+ return 1; /* corrupt record not detected by
+ ** wx_sqlite3VdbeRecordCompareWithSkip(). Return true
+ ** to avoid firing the assert() */
+ }
break;
}
@@ -86859,32 +89658,37 @@ SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3BlobCompare(const Mem *pB1, const M
return n1 - n2;
}
+/* The following two functions are used only within testcase() to prove
+** test coverage. These functions do no exist for production builds.
+** We must use separate SQLITE_NOINLINE functions here, since otherwise
+** optimizer code movement causes gcov to become very confused.
+*/
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
+static int SQLITE_NOINLINE doubleLt(double a, double b){ return a<b; }
+static int SQLITE_NOINLINE doubleEq(double a, double b){ return a==b; }
+#endif
+
/*
** Do a comparison between a 64-bit signed integer and a 64-bit floating-point
** number. Return negative, zero, or positive if the first (i64) is less than,
** equal to, or greater than the second (double).
*/
SQLITE_PRIVATE int wx_sqlite3IntFloatCompare(i64 i, double r){
- if( sizeof(LONGDOUBLE_TYPE)>8 ){
- LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
- testcase( x<r );
- testcase( x>r );
- testcase( x==r );
- if( x<r ) return -1;
- if( x>r ) return +1; /*NO_TEST*/ /* work around bugs in gcov */
- return 0; /*NO_TEST*/ /* work around bugs in gcov */
+ if( wx_sqlite3IsNaN(r) ){
+ /* SQLite considers NaN to be a NULL. And all integer values are greater
+ ** than NULL */
+ return 1;
}else{
i64 y;
- double s;
if( r<-9223372036854775808.0 ) return +1;
if( r>=9223372036854775808.0 ) return -1;
y = (i64)r;
if( i<y ) return -1;
if( i>y ) return +1;
- s = (double)i;
- if( s<r ) return -1;
- if( s>r ) return +1;
- return 0;
+ testcase( doubleLt(((double)i),r) );
+ testcase( doubleLt(r,((double)i)) );
+ testcase( doubleEq(r,((double)i)) );
+ return (((double)i)<r) ? -1 : (((double)i)>r);
}
}
@@ -87114,7 +89918,7 @@ SQLITE_PRIVATE int wx_sqlite3VdbeRecordCompareWithSkip(
}else if( serial_type==0 ){
rc = -1;
}else if( serial_type==7 ){
- wx_sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
+ serialGet7(&aKey1[d1], &mem1);
rc = -wx_sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
}else{
i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
@@ -87134,19 +89938,23 @@ SQLITE_PRIVATE int wx_sqlite3VdbeRecordCompareWithSkip(
/* Serial types 12 or greater are strings and blobs (greater than
** numbers). Types 10 and 11 are currently "reserved for future
** use", so it doesn't really matter what the results of comparing
- ** them to numberic values are. */
+ ** them to numeric values are. */
rc = serial_type==10 ? -1 : +1;
}else if( serial_type==0 ){
rc = -1;
}else{
- wx_sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
if( serial_type==7 ){
- if( mem1.u.r<pRhs->u.r ){
+ if( serialGet7(&aKey1[d1], &mem1) ){
+ rc = -1; /* mem1 is a NaN */
+ }else if( mem1.u.r<pRhs->u.r ){
rc = -1;
}else if( mem1.u.r>pRhs->u.r ){
rc = +1;
+ }else{
+ assert( rc==0 );
}
}else{
+ wx_sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
rc = wx_sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
}
}
@@ -87216,7 +90024,14 @@ SQLITE_PRIVATE int wx_sqlite3VdbeRecordCompareWithSkip(
/* RHS is null */
else{
serial_type = aKey1[idx1];
- rc = (serial_type!=0 && serial_type!=10);
+ if( serial_type==0
+ || serial_type==10
+ || (serial_type==7 && serialGet7(&aKey1[d1], &mem1)!=0)
+ ){
+ assert( rc==0 );
+ }else{
+ rc = 1;
+ }
}
if( rc!=0 ){
@@ -87676,7 +90491,8 @@ SQLITE_PRIVATE wx_sqlite3_value *wx_sqlite3VdbeGetBoundValue(Vdbe *v, int iVar,
assert( iVar>0 );
if( v ){
Mem *pMem = &v->aVar[iVar-1];
- assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
+ assert( (v->db->flags & SQLITE_EnableQPSG)==0
+ || (v->db->mDbFlags & DBFLAG_InternalFunc)!=0 );
if( 0==(pMem->flags & MEM_Null) ){
wx_sqlite3_value *pRet = wx_sqlite3ValueNew(v->db);
if( pRet ){
@@ -87696,7 +90512,8 @@ SQLITE_PRIVATE wx_sqlite3_value *wx_sqlite3VdbeGetBoundValue(Vdbe *v, int iVar,
*/
SQLITE_PRIVATE void wx_sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
assert( iVar>0 );
- assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
+ assert( (v->db->flags & SQLITE_EnableQPSG)==0
+ || (v->db->mDbFlags & DBFLAG_InternalFunc)!=0 );
if( iVar>=32 ){
v->expmask |= 0x80000000;
}else{
@@ -87738,6 +90555,20 @@ SQLITE_PRIVATE int wx_sqlite3NotPureFunc(wx_sqlite3_context *pCtx){
return 1;
}
+#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
+/*
+** This Walker callback is used to help verify that calls to
+** wx_sqlite3BtreeCursorHint() with opcode BTREE_HINT_RANGE have
+** byte-code register values correctly initialized.
+*/
+SQLITE_PRIVATE int wx_sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_REGISTER ){
+ assert( (pWalker->u.aMem[pExpr->iTable].flags & MEM_Undefined)==0 );
+ }
+ return WRC_Continue;
+}
+#endif /* SQLITE_ENABLE_CURSOR_HINTS && SQLITE_DEBUG */
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Transfer error message text from an wx_sqlite3_vtab.zErrMsg (text stored
@@ -87800,6 +90631,16 @@ SQLITE_PRIVATE void wx_sqlite3VdbePreUpdateHook(
PreUpdate preupdate;
const char *zTbl = pTab->zName;
static const u8 fakeSortOrder = 0;
+#ifdef SQLITE_DEBUG
+ int nRealCol;
+ if( pTab->tabFlags & TF_WithoutRowid ){
+ nRealCol = wx_sqlite3PrimaryKeyIndex(pTab)->nColumn;
+ }else if( pTab->tabFlags & TF_HasVirtual ){
+ nRealCol = pTab->nNVCol;
+ }else{
+ nRealCol = pTab->nCol;
+ }
+#endif
assert( db->pPreUpdate==0 );
memset(&preupdate, 0, sizeof(PreUpdate));
@@ -87816,8 +90657,8 @@ SQLITE_PRIVATE void wx_sqlite3VdbePreUpdateHook(
assert( pCsr!=0 );
assert( pCsr->eCurType==CURTYPE_BTREE );
- assert( pCsr->nField==pTab->nCol
- || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
+ assert( pCsr->nField==nRealCol
+ || (pCsr->nField==nRealCol+1 && op==SQLITE_DELETE && iReg==-1)
);
preupdate.v = v;
@@ -87846,6 +90687,13 @@ SQLITE_PRIVATE void wx_sqlite3VdbePreUpdateHook(
}
wx_sqlite3DbNNFreeNN(db, preupdate.aNew);
}
+ if( preupdate.apDflt ){
+ int i;
+ for(i=0; i<pTab->nCol; i++){
+ wx_sqlite3ValueFree(preupdate.apDflt[i]);
+ }
+ wx_sqlite3DbFree(db, preupdate.apDflt);
+ }
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -88005,7 +90853,15 @@ SQLITE_API int wx_sqlite3_clear_bindings(wx_sqlite3_stmt *pStmt){
int rc = SQLITE_OK;
Vdbe *p = (Vdbe*)pStmt;
#if SQLITE_THREADSAFE
- wx_sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex;
+ wx_sqlite3_mutex *mutex;
+#endif
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pStmt==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+#if SQLITE_THREADSAFE
+ mutex = p->db->mutex;
#endif
wx_sqlite3_mutex_enter(mutex);
for(i=0; i<p->nVar; i++){
@@ -88124,7 +90980,7 @@ SQLITE_API int wx_sqlite3_value_type(wx_sqlite3_value* pVal){
SQLITE_NULL, /* 0x1f (not possible) */
SQLITE_FLOAT, /* 0x20 INTREAL */
SQLITE_NULL, /* 0x21 (not possible) */
- SQLITE_TEXT, /* 0x22 INTREAL + TEXT */
+ SQLITE_FLOAT, /* 0x22 INTREAL + TEXT */
SQLITE_NULL, /* 0x23 (not possible) */
SQLITE_FLOAT, /* 0x24 (not possible) */
SQLITE_NULL, /* 0x25 (not possible) */
@@ -88228,7 +91084,7 @@ SQLITE_API void wx_sqlite3_value_free(wx_sqlite3_value *pOld){
** is too big or if an OOM occurs.
**
** The invokeValueDestructor(P,X) routine invokes destructor function X()
-** on value P is not going to be used and need to be destroyed.
+** on value P if P is not going to be used and need to be destroyed.
*/
static void setResultStrOrError(
wx_sqlite3_context *pCtx, /* Function context */
@@ -88258,7 +91114,7 @@ static void setResultStrOrError(
static int invokeValueDestructor(
const void *p, /* Value to destroy */
void (*xDel)(void*), /* The destructor */
- wx_sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */
+ wx_sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if not NULL */
){
assert( xDel!=SQLITE_DYNAMIC );
if( xDel==0 ){
@@ -88268,7 +91124,14 @@ static int invokeValueDestructor(
}else{
xDel((void*)p);
}
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx!=0 ){
+ wx_sqlite3_result_error_toobig(pCtx);
+ }
+#else
+ assert( pCtx!=0 );
wx_sqlite3_result_error_toobig(pCtx);
+#endif
return SQLITE_TOOBIG;
}
SQLITE_API void wx_sqlite3_result_blob(
@@ -88277,6 +91140,12 @@ SQLITE_API void wx_sqlite3_result_blob(
int n,
void (*xDel)(void *)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 || n<0 ){
+ invokeValueDestructor(z, xDel, pCtx);
+ return;
+ }
+#endif
assert( n>=0 );
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, 0, xDel);
@@ -88287,8 +91156,14 @@ SQLITE_API void wx_sqlite3_result_blob64(
wx_sqlite3_uint64 n,
void (*xDel)(void *)
){
- assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
assert( xDel!=SQLITE_DYNAMIC );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
+ assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
if( n>0x7fffffff ){
(void)invokeValueDestructor(z, xDel, pCtx);
}else{
@@ -88296,30 +91171,48 @@ SQLITE_API void wx_sqlite3_result_blob64(
}
}
SQLITE_API void wx_sqlite3_result_double(wx_sqlite3_context *pCtx, double rVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
wx_sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
}
SQLITE_API void wx_sqlite3_result_error(wx_sqlite3_context *pCtx, const char *z, int n){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
wx_sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API void wx_sqlite3_result_error16(wx_sqlite3_context *pCtx, const void *z, int n){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
wx_sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
SQLITE_API void wx_sqlite3_result_int(wx_sqlite3_context *pCtx, int iVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
wx_sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal);
}
SQLITE_API void wx_sqlite3_result_int64(wx_sqlite3_context *pCtx, i64 iVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
wx_sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
}
SQLITE_API void wx_sqlite3_result_null(wx_sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
wx_sqlite3VdbeMemSetNull(pCtx->pOut);
}
@@ -88329,14 +91222,37 @@ SQLITE_API void wx_sqlite3_result_pointer(
const char *zPType,
void (*xDestructor)(void*)
){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(pPtr, xDestructor, 0);
+ return;
+ }
+#endif
+ pOut = pCtx->pOut;
assert( wx_sqlite3_mutex_held(pOut->db->mutex) );
wx_sqlite3VdbeMemRelease(pOut);
pOut->flags = MEM_Null;
wx_sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor);
}
SQLITE_API void wx_sqlite3_result_subtype(wx_sqlite3_context *pCtx, unsigned int eSubtype){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
+#if defined(SQLITE_STRICT_SUBTYPE) && SQLITE_STRICT_SUBTYPE+0!=0
+ if( pCtx->pFunc!=0
+ && (pCtx->pFunc->funcFlags & SQLITE_RESULT_SUBTYPE)==0
+ ){
+ char zErr[200];
+ wx_sqlite3_snprintf(sizeof(zErr), zErr,
+ "misuse of wx_sqlite3_result_subtype() by %s()",
+ pCtx->pFunc->zName);
+ wx_sqlite3_result_error(pCtx, zErr, -1);
+ return;
+ }
+#endif /* SQLITE_STRICT_SUBTYPE */
+ pOut = pCtx->pOut;
assert( wx_sqlite3_mutex_held(pOut->db->mutex) );
pOut->eSubtype = eSubtype & 0xff;
pOut->flags |= MEM_Subtype;
@@ -88347,6 +91263,12 @@ SQLITE_API void wx_sqlite3_result_text(
int n,
void (*xDel)(void *)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
}
@@ -88357,6 +91279,12 @@ SQLITE_API void wx_sqlite3_result_text64(
void (*xDel)(void *),
unsigned char enc
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
assert( xDel!=SQLITE_DYNAMIC );
if( enc!=SQLITE_UTF8 ){
@@ -88367,6 +91295,7 @@ SQLITE_API void wx_sqlite3_result_text64(
(void)invokeValueDestructor(z, xDel, pCtx);
}else{
setResultStrOrError(pCtx, z, (int)n, enc, xDel);
+ wx_sqlite3VdbeMemZeroTerminateIfAble(pCtx->pOut);
}
}
#ifndef SQLITE_OMIT_UTF16
@@ -88399,7 +91328,16 @@ SQLITE_API void wx_sqlite3_result_text16le(
}
#endif /* SQLITE_OMIT_UTF16 */
SQLITE_API void wx_sqlite3_result_value(wx_sqlite3_context *pCtx, wx_sqlite3_value *pValue){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+ if( pValue==0 ){
+ wx_sqlite3_result_null(pCtx);
+ return;
+ }
+#endif
+ pOut = pCtx->pOut;
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
wx_sqlite3VdbeMemCopy(pOut, pValue);
wx_sqlite3VdbeChangeEncoding(pOut, pCtx->enc);
@@ -88411,7 +91349,12 @@ SQLITE_API void wx_sqlite3_result_zeroblob(wx_sqlite3_context *pCtx, int n){
wx_sqlite3_result_zeroblob64(pCtx, n>0 ? n : 0);
}
SQLITE_API int wx_sqlite3_result_zeroblob64(wx_sqlite3_context *pCtx, u64 n){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ pOut = pCtx->pOut;
assert( wx_sqlite3_mutex_held(pOut->db->mutex) );
if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
wx_sqlite3_result_error_toobig(pCtx);
@@ -88425,6 +91368,9 @@ SQLITE_API int wx_sqlite3_result_zeroblob64(wx_sqlite3_context *pCtx, u64 n){
#endif
}
SQLITE_API void wx_sqlite3_result_error_code(wx_sqlite3_context *pCtx, int errCode){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
pCtx->isError = errCode ? errCode : -1;
#ifdef SQLITE_DEBUG
if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
@@ -88437,6 +91383,9 @@ SQLITE_API void wx_sqlite3_result_error_code(wx_sqlite3_context *pCtx, int errCo
/* Force an SQLITE_TOOBIG error. */
SQLITE_API void wx_sqlite3_result_error_toobig(wx_sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_TOOBIG;
wx_sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1,
@@ -88445,6 +91394,9 @@ SQLITE_API void wx_sqlite3_result_error_toobig(wx_sqlite3_context *pCtx){
/* An SQLITE_NOMEM error. */
SQLITE_API void wx_sqlite3_result_error_nomem(wx_sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
wx_sqlite3VdbeMemSetNull(pCtx->pOut);
pCtx->isError = SQLITE_NOMEM_BKPT;
@@ -88697,6 +91649,9 @@ SQLITE_API int wx_sqlite3_step(wx_sqlite3_stmt *pStmt){
** pointer to it.
*/
SQLITE_API void *wx_sqlite3_user_data(wx_sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#endif
assert( p && p->pFunc );
return p->pFunc->pUserData;
}
@@ -88712,7 +91667,11 @@ SQLITE_API void *wx_sqlite3_user_data(wx_sqlite3_context *p){
** application defined function.
*/
SQLITE_API wx_sqlite3 *wx_sqlite3_context_db_handle(wx_sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#else
assert( p && p->pOut );
+#endif
return p->pOut->db;
}
@@ -88731,7 +91690,11 @@ SQLITE_API wx_sqlite3 *wx_sqlite3_context_db_handle(wx_sqlite3_context *p){
** value, as a signal to the xUpdate routine that the column is unchanged.
*/
SQLITE_API int wx_sqlite3_vtab_nochange(wx_sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#else
assert( p );
+#endif
return wx_sqlite3_value_nochange(p->pOut);
}
@@ -88739,7 +91702,7 @@ SQLITE_API int wx_sqlite3_vtab_nochange(wx_sqlite3_context *p){
** The destructor function for a ValueList object. This needs to be
** a separate function, unknowable to the application, to ensure that
** calls to wx_sqlite3_vtab_in_first()/wx_sqlite3_vtab_in_next() that are not
-** preceeded by activation of IN processing via wx_sqlite3_vtab_int() do not
+** preceded by activation of IN processing via wx_sqlite3_vtab_int() do not
** try to access a fake ValueList object inserted by a hostile extension.
*/
SQLITE_PRIVATE void wx_sqlite3VdbeValueListFree(void *pToDelete){
@@ -88759,7 +91722,7 @@ static int valueFromValueList(
ValueList *pRhs;
*ppOut = 0;
- if( pVal==0 ) return SQLITE_MISUSE;
+ if( pVal==0 ) return SQLITE_MISUSE_BKPT;
if( (pVal->flags & MEM_Dyn)==0 || pVal->xDel!=wx_sqlite3VdbeValueListFree ){
return SQLITE_ERROR;
}else{
@@ -88890,6 +91853,9 @@ SQLITE_API void *wx_sqlite3_aggregate_context(wx_sqlite3_context *p, int nByte){
SQLITE_API void *wx_sqlite3_get_auxdata(wx_sqlite3_context *pCtx, int iArg){
AuxData *pAuxData;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return 0;
+#endif
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
#if SQLITE_ENABLE_STAT4
if( pCtx->pVdbe==0 ) return 0;
@@ -88922,8 +91888,12 @@ SQLITE_API void wx_sqlite3_set_auxdata(
void (*xDelete)(void*)
){
AuxData *pAuxData;
- Vdbe *pVdbe = pCtx->pVdbe;
+ Vdbe *pVdbe;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
+ pVdbe= pCtx->pVdbe;
assert( wx_sqlite3_mutex_held(pCtx->pOut->db->mutex) );
#ifdef SQLITE_ENABLE_STAT4
if( pVdbe==0 ) goto failed;
@@ -88979,7 +91949,8 @@ SQLITE_API int wx_sqlite3_aggregate_count(wx_sqlite3_context *p){
*/
SQLITE_API int wx_sqlite3_column_count(wx_sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
- return pVm ? pVm->nResColumn : 0;
+ if( pVm==0 ) return 0;
+ return pVm->nResColumn;
}
/*
@@ -89068,7 +92039,7 @@ static Mem *columnMem(wx_sqlite3_stmt *pStmt, int i){
** wx_sqlite3_column_real()
** wx_sqlite3_column_bytes()
** wx_sqlite3_column_bytes16()
-** sqiite3_column_blob()
+** wx_sqlite3_column_blob()
*/
static void columnMallocFailure(wx_sqlite3_stmt *pStmt)
{
@@ -89153,6 +92124,32 @@ SQLITE_API int wx_sqlite3_column_type(wx_sqlite3_stmt *pStmt, int i){
}
/*
+** Column names appropriate for EXPLAIN or EXPLAIN QUERY PLAN.
+*/
+static const char * const azExplainColNames8[] = {
+ "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", /* EXPLAIN */
+ "id", "parent", "notused", "detail" /* EQP */
+};
+static const u16 azExplainColNames16data[] = {
+ /* 0 */ 'a', 'd', 'd', 'r', 0,
+ /* 5 */ 'o', 'p', 'c', 'o', 'd', 'e', 0,
+ /* 12 */ 'p', '1', 0,
+ /* 15 */ 'p', '2', 0,
+ /* 18 */ 'p', '3', 0,
+ /* 21 */ 'p', '4', 0,
+ /* 24 */ 'p', '5', 0,
+ /* 27 */ 'c', 'o', 'm', 'm', 'e', 'n', 't', 0,
+ /* 35 */ 'i', 'd', 0,
+ /* 38 */ 'p', 'a', 'r', 'e', 'n', 't', 0,
+ /* 45 */ 'n', 'o', 't', 'u', 's', 'e', 'd', 0,
+ /* 53 */ 'd', 'e', 't', 'a', 'i', 'l', 0
+};
+static const u8 iExplainColNames16[] = {
+ 0, 5, 12, 15, 18, 21, 24, 27,
+ 35, 38, 45, 53
+};
+
+/*
** Convert the N-th element of pStmt->pColName[] into a string using
** xFunc() then return that string. If N is out of range, return 0.
**
@@ -89184,15 +92181,29 @@ static const void *columnName(
return 0;
}
#endif
+ if( N<0 ) return 0;
ret = 0;
p = (Vdbe *)pStmt;
db = p->db;
assert( db!=0 );
- n = wx_sqlite3_column_count(pStmt);
- if( N<n && N>=0 ){
+ wx_sqlite3_mutex_enter(db->mutex);
+
+ if( p->explain ){
+ if( useType>0 ) goto columnName_end;
+ n = p->explain==1 ? 8 : 4;
+ if( N>=n ) goto columnName_end;
+ if( useUtf16 ){
+ int i = iExplainColNames16[N + 8*p->explain - 8];
+ ret = (void*)&azExplainColNames16data[i];
+ }else{
+ ret = (void*)azExplainColNames8[N + 8*p->explain - 8];
+ }
+ goto columnName_end;
+ }
+ n = p->nResColumn;
+ if( N<n ){
+ u8 prior_mallocFailed = db->mallocFailed;
N += useType*n;
- wx_sqlite3_mutex_enter(db->mutex);
- assert( db->mallocFailed==0 );
#ifndef SQLITE_OMIT_UTF16
if( useUtf16 ){
ret = wx_sqlite3_value_text16((wx_sqlite3_value*)&p->aColName[N]);
@@ -89204,12 +92215,14 @@ static const void *columnName(
/* A malloc may have failed inside of the _text() call. If this
** is the case, clear the mallocFailed flag and return NULL.
*/
- if( db->mallocFailed ){
+ assert( db->mallocFailed==0 || db->mallocFailed==1 );
+ if( db->mallocFailed > prior_mallocFailed ){
wx_sqlite3OomClear(db);
ret = 0;
}
- wx_sqlite3_mutex_leave(db->mutex);
}
+columnName_end:
+ wx_sqlite3_mutex_leave(db->mutex);
return ret;
}
@@ -89302,13 +92315,24 @@ SQLITE_API const void *wx_sqlite3_column_origin_name16(wx_sqlite3_stmt *pStmt, i
/*
** Unbind the value bound to variable i in virtual machine p. This is the
** the same as binding a NULL value to the column. If the "i" parameter is
-** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK.
+** out of range, then SQLITE_RANGE is returned. Otherwise SQLITE_OK.
**
** A successful evaluation of this routine acquires the mutex on p.
** the mutex is released if any kind of error occurs.
**
** The error code stored in database p->db is overwritten with the return
** value in any case.
+**
+** (tag-20240917-01) If vdbeUnbind(p,(u32)(i-1)) returns SQLITE_OK,
+** that means all of the the following will be true:
+**
+** p!=0
+** p->pVar!=0
+** i>0
+** i<=p->nVar
+**
+** An assert() is normally added after vdbeUnbind() to help static analyzers
+** realize this.
*/
static int vdbeUnbind(Vdbe *p, unsigned int i){
Mem *pVar;
@@ -89317,7 +92341,7 @@ static int vdbeUnbind(Vdbe *p, unsigned int i){
}
wx_sqlite3_mutex_enter(p->db->mutex);
if( p->eVdbeState!=VDBE_READY_STATE ){
- wx_sqlite3Error(p->db, SQLITE_MISUSE);
+ wx_sqlite3Error(p->db, SQLITE_MISUSE_BKPT);
wx_sqlite3_mutex_leave(p->db->mutex);
wx_sqlite3_log(SQLITE_MISUSE,
"bind on a busy prepared statement: [%s]", p->zSql);
@@ -89366,6 +92390,7 @@ static int bindText(
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
if( zData!=0 ){
pVar = &p->aVar[i-1];
rc = wx_sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
@@ -89415,6 +92440,7 @@ SQLITE_API int wx_sqlite3_bind_double(wx_sqlite3_stmt *pStmt, int i, double rVal
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
wx_sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
wx_sqlite3_mutex_leave(p->db->mutex);
}
@@ -89428,6 +92454,7 @@ SQLITE_API int wx_sqlite3_bind_int64(wx_sqlite3_stmt *pStmt, int i, sqlite_int64
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
wx_sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
wx_sqlite3_mutex_leave(p->db->mutex);
}
@@ -89438,6 +92465,7 @@ SQLITE_API int wx_sqlite3_bind_null(wx_sqlite3_stmt *pStmt, int i){
Vdbe *p = (Vdbe*)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
wx_sqlite3_mutex_leave(p->db->mutex);
}
return rc;
@@ -89453,6 +92481,7 @@ SQLITE_API int wx_sqlite3_bind_pointer(
Vdbe *p = (Vdbe*)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
wx_sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
wx_sqlite3_mutex_leave(p->db->mutex);
}else if( xDestructor ){
@@ -89534,6 +92563,7 @@ SQLITE_API int wx_sqlite3_bind_zeroblob(wx_sqlite3_stmt *pStmt, int i, int n){
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
#ifndef SQLITE_OMIT_INCRBLOB
wx_sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
#else
@@ -89546,6 +92576,9 @@ SQLITE_API int wx_sqlite3_bind_zeroblob(wx_sqlite3_stmt *pStmt, int i, int n){
SQLITE_API int wx_sqlite3_bind_zeroblob64(wx_sqlite3_stmt *pStmt, int i, wx_sqlite3_uint64 n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return SQLITE_MISUSE_BKPT;
+#endif
wx_sqlite3_mutex_enter(p->db->mutex);
if( n>(u64)p->db->aLimit[SQLITE_LIMIT_LENGTH] ){
rc = SQLITE_TOOBIG;
@@ -89667,6 +92700,42 @@ SQLITE_API int wx_sqlite3_stmt_isexplain(wx_sqlite3_stmt *pStmt){
}
/*
+** Set the explain mode for a statement.
+*/
+SQLITE_API int wx_sqlite3_stmt_explain(wx_sqlite3_stmt *pStmt, int eMode){
+ Vdbe *v = (Vdbe*)pStmt;
+ int rc;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pStmt==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ wx_sqlite3_mutex_enter(v->db->mutex);
+ if( ((int)v->explain)==eMode ){
+ rc = SQLITE_OK;
+ }else if( eMode<0 || eMode>2 ){
+ rc = SQLITE_ERROR;
+ }else if( (v->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){
+ rc = SQLITE_ERROR;
+ }else if( v->eVdbeState!=VDBE_READY_STATE ){
+ rc = SQLITE_BUSY;
+ }else if( v->nMem>=10 && (eMode!=2 || v->haveEqpOps) ){
+ /* No reprepare necessary */
+ v->explain = eMode;
+ rc = SQLITE_OK;
+ }else{
+ v->explain = eMode;
+ rc = wx_sqlite3Reprepare(v);
+ v->haveEqpOps = eMode==2;
+ }
+ if( v->explain ){
+ v->nResColumn = 12 - 4*v->explain;
+ }else{
+ v->nResColumn = v->nResAlloc;
+ }
+ wx_sqlite3_mutex_leave(v->db->mutex);
+ return rc;
+}
+
+/*
** Return true if the prepared statement is in need of being reset.
*/
SQLITE_API int wx_sqlite3_stmt_busy(wx_sqlite3_stmt *pStmt){
@@ -89805,10 +92874,16 @@ static UnpackedRecord *vdbeUnpackRecord(
** a field of the row currently being updated or deleted.
*/
SQLITE_API int wx_sqlite3_preupdate_old(wx_sqlite3 *db, int iIdx, wx_sqlite3_value **ppValue){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
Mem *pMem;
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 || ppValue==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ p = db->pPreUpdate;
/* Test that this call is being made from within an SQLITE_DELETE or
** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
if( !p || p->op==SQLITE_INSERT ){
@@ -89848,7 +92923,30 @@ SQLITE_API int wx_sqlite3_preupdate_old(wx_sqlite3 *db, int iIdx, wx_sqlite3_val
if( iIdx==p->pTab->iPKey ){
wx_sqlite3VdbeMemSetInt64(pMem, p->iKey1);
}else if( iIdx>=p->pUnpacked->nField ){
- *ppValue = (wx_sqlite3_value *)columnNullValue();
+ /* This occurs when the table has been extended using ALTER TABLE
+ ** ADD COLUMN. The value to return is the default value of the column. */
+ Column *pCol = &p->pTab->aCol[iIdx];
+ if( pCol->iDflt>0 ){
+ if( p->apDflt==0 ){
+ int nByte = sizeof(wx_sqlite3_value*)*p->pTab->nCol;
+ p->apDflt = (wx_sqlite3_value**)wx_sqlite3DbMallocZero(db, nByte);
+ if( p->apDflt==0 ) goto preupdate_old_out;
+ }
+ if( p->apDflt[iIdx]==0 ){
+ wx_sqlite3_value *pVal = 0;
+ Expr *pDflt;
+ assert( p->pTab!=0 && IsOrdinaryTable(p->pTab) );
+ pDflt = p->pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
+ rc = wx_sqlite3ValueFromExpr(db, pDflt, ENC(db), pCol->affinity, &pVal);
+ if( rc==SQLITE_OK && pVal==0 ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }
+ p->apDflt[iIdx] = pVal;
+ }
+ *ppValue = p->apDflt[iIdx];
+ }else{
+ *ppValue = (wx_sqlite3_value *)columnNullValue();
+ }
}else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
if( pMem->flags & (MEM_Int|MEM_IntReal) ){
testcase( pMem->flags & MEM_Int );
@@ -89869,7 +92967,12 @@ SQLITE_API int wx_sqlite3_preupdate_old(wx_sqlite3 *db, int iIdx, wx_sqlite3_val
** the number of columns in the row being updated, deleted or inserted.
*/
SQLITE_API int wx_sqlite3_preupdate_count(wx_sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->keyinfo.nKeyField : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -89887,7 +92990,12 @@ SQLITE_API int wx_sqlite3_preupdate_count(wx_sqlite3 *db){
** or SET DEFAULT action is considered a trigger.
*/
SQLITE_API int wx_sqlite3_preupdate_depth(wx_sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->v->nFrame : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -89898,7 +93006,12 @@ SQLITE_API int wx_sqlite3_preupdate_depth(wx_sqlite3 *db){
** only.
*/
SQLITE_API int wx_sqlite3_preupdate_blobwrite(wx_sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->iBlobWrite : -1);
}
#endif
@@ -89909,10 +93022,16 @@ SQLITE_API int wx_sqlite3_preupdate_blobwrite(wx_sqlite3 *db){
** a field of the row currently being updated or inserted.
*/
SQLITE_API int wx_sqlite3_preupdate_new(wx_sqlite3 *db, int iIdx, wx_sqlite3_value **ppValue){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
int rc = SQLITE_OK;
Mem *pMem;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 || ppValue==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ p = db->pPreUpdate;
if( !p || p->op==SQLITE_DELETE ){
rc = SQLITE_MISUSE_BKPT;
goto preupdate_new_out;
@@ -89991,15 +93110,33 @@ SQLITE_API int wx_sqlite3_stmt_scanstatus_v2(
void *pOut /* OUT: Write the answer here */
){
Vdbe *p = (Vdbe*)pStmt;
- ScanStatus *pScan;
+ VdbeOp *aOp;
+ int nOp;
+ ScanStatus *pScan = 0;
int idx;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 || pOut==0
+ || iScanStatusOp<SQLITE_SCANSTAT_NLOOP
+ || iScanStatusOp>SQLITE_SCANSTAT_NCYCLE ){
+ return 1;
+ }
+#endif
+ aOp = p->aOp;
+ nOp = p->nOp;
+ if( p->pFrame ){
+ VdbeFrame *pFrame;
+ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
+ aOp = pFrame->aOp;
+ nOp = pFrame->nOp;
+ }
+
if( iScan<0 ){
int ii;
if( iScanStatusOp==SQLITE_SCANSTAT_NCYCLE ){
i64 res = 0;
- for(ii=0; ii<p->nOp; ii++){
- res += p->aOp[ii].nCycle;
+ for(ii=0; ii<nOp; ii++){
+ res += aOp[ii].nCycle;
}
*(i64*)pOut = res;
return 0;
@@ -90008,7 +93145,6 @@ SQLITE_API int wx_sqlite3_stmt_scanstatus_v2(
}
if( flags & SQLITE_SCANSTAT_COMPLEX ){
idx = iScan;
- pScan = &p->aScan[idx];
}else{
/* If the COMPLEX flag is clear, then this function must ignore any
** ScanStatus structures with ScanStatus.addrLoop set to 0. */
@@ -90021,11 +93157,13 @@ SQLITE_API int wx_sqlite3_stmt_scanstatus_v2(
}
}
if( idx>=p->nScan ) return 1;
+ assert( pScan==0 || pScan==&p->aScan[idx] );
+ pScan = &p->aScan[idx];
switch( iScanStatusOp ){
case SQLITE_SCANSTAT_NLOOP: {
if( pScan->addrLoop>0 ){
- *(wx_sqlite3_int64*)pOut = p->aOp[pScan->addrLoop].nExec;
+ *(wx_sqlite3_int64*)pOut = aOp[pScan->addrLoop].nExec;
}else{
*(wx_sqlite3_int64*)pOut = -1;
}
@@ -90033,7 +93171,7 @@ SQLITE_API int wx_sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_NVISIT: {
if( pScan->addrVisit>0 ){
- *(wx_sqlite3_int64*)pOut = p->aOp[pScan->addrVisit].nExec;
+ *(wx_sqlite3_int64*)pOut = aOp[pScan->addrVisit].nExec;
}else{
*(wx_sqlite3_int64*)pOut = -1;
}
@@ -90055,7 +93193,7 @@ SQLITE_API int wx_sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_EXPLAIN: {
if( pScan->addrExplain ){
- *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z;
+ *(const char**)pOut = aOp[ pScan->addrExplain ].p4.z;
}else{
*(const char**)pOut = 0;
}
@@ -90063,7 +93201,7 @@ SQLITE_API int wx_sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_SELECTID: {
if( pScan->addrExplain ){
- *(int*)pOut = p->aOp[ pScan->addrExplain ].p1;
+ *(int*)pOut = aOp[ pScan->addrExplain ].p1;
}else{
*(int*)pOut = -1;
}
@@ -90071,7 +93209,7 @@ SQLITE_API int wx_sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_PARENTID: {
if( pScan->addrExplain ){
- *(int*)pOut = p->aOp[ pScan->addrExplain ].p2;
+ *(int*)pOut = aOp[ pScan->addrExplain ].p2;
}else{
*(int*)pOut = -1;
}
@@ -90089,18 +93227,18 @@ SQLITE_API int wx_sqlite3_stmt_scanstatus_v2(
if( iIns==0 ) break;
if( iIns>0 ){
while( iIns<=iEnd ){
- res += p->aOp[iIns].nCycle;
+ res += aOp[iIns].nCycle;
iIns++;
}
}else{
int iOp;
- for(iOp=0; iOp<p->nOp; iOp++){
- Op *pOp = &p->aOp[iOp];
+ for(iOp=0; iOp<nOp; iOp++){
+ Op *pOp = &aOp[iOp];
if( pOp->p1!=iEnd ) continue;
if( (wx_sqlite3OpcodeProperty[pOp->opcode] & OPFLG_NCYCLE)==0 ){
continue;
}
- res += p->aOp[iOp].nCycle;
+ res += aOp[iOp].nCycle;
}
}
}
@@ -90133,7 +93271,7 @@ SQLITE_API int wx_sqlite3_stmt_scanstatus(
SQLITE_API void wx_sqlite3_stmt_scanstatus_reset(wx_sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
int ii;
- for(ii=0; ii<p->nOp; ii++){
+ for(ii=0; p!=0 && ii<p->nOp; ii++){
Op *pOp = &p->aOp[ii];
pOp->nExec = 0;
pOp->nCycle = 0;
@@ -90362,6 +93500,104 @@ SQLITE_PRIVATE char *wx_sqlite3VdbeExpandSql(
/* #include "vdbeInt.h" */
/*
+** High-resolution hardware timer used for debugging and testing only.
+*/
+#if defined(VDBE_PROFILE) \
+ || defined(SQLITE_PERFORMANCE_TRACE) \
+ || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+/************** Include hwtime.h in the middle of vdbe.c *********************/
+/************** Begin file hwtime.h ******************************************/
+/*
+** 2008 May 27
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains inline asm code for retrieving "high-performance"
+** counters for x86 and x86_64 class CPUs.
+*/
+#ifndef SQLITE_HWTIME_H
+#define SQLITE_HWTIME_H
+
+/*
+** The following routine only works on Pentium-class (or newer) processors.
+** It uses the RDTSC opcode to read the cycle count value out of the
+** processor and returns that value. This can be used for high-res
+** profiling.
+*/
+#if !defined(__STRICT_ANSI__) && \
+ (defined(__GNUC__) || defined(_MSC_VER)) && \
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
+
+ #if defined(__GNUC__)
+
+ __inline__ sqlite_uint64 wx_sqlite3Hwtime(void){
+ unsigned int lo, hi;
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
+ return (sqlite_uint64)hi << 32 | lo;
+ }
+
+ #elif defined(_MSC_VER)
+
+ __declspec(naked) __inline sqlite_uint64 __cdecl wx_sqlite3Hwtime(void){
+ __asm {
+ rdtsc
+ ret ; return value at EDX:EAX
+ }
+ }
+
+ #endif
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
+
+ __inline__ sqlite_uint64 wx_sqlite3Hwtime(void){
+ unsigned int lo, hi;
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
+ return (sqlite_uint64)hi << 32 | lo;
+ }
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
+
+ __inline__ sqlite_uint64 wx_sqlite3Hwtime(void){
+ unsigned long long retval;
+ unsigned long junk;
+ __asm__ __volatile__ ("\n\
+ 1: mftbu %1\n\
+ mftb %L0\n\
+ mftbu %0\n\
+ cmpw %0,%1\n\
+ bne 1b"
+ : "=r" (retval), "=r" (junk));
+ return retval;
+ }
+
+#else
+
+ /*
+ ** asm() is needed for hardware timing support. Without asm(),
+ ** disable the wx_sqlite3Hwtime() routine.
+ **
+ ** wx_sqlite3Hwtime() is only used for some obscure debugging
+ ** and analysis configurations, not in any deliverable, so this
+ ** should not be a great loss.
+ */
+SQLITE_PRIVATE sqlite_uint64 wx_sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
+
+#endif
+
+#endif /* !defined(SQLITE_HWTIME_H) */
+
+/************** End of hwtime.h **********************************************/
+/************** Continuing where we left off in vdbe.c ***********************/
+#endif
+
+/*
** Invoke this macro on memory cells just prior to changing the
** value of the cell. This macro verifies that shallow copies are
** not misused. A shallow copy of a string or blob just copies a
@@ -90472,11 +93708,12 @@ SQLITE_API int wx_sqlite3_found_count = 0;
** wx_sqlite3CantopenError(lineno)
*/
static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){
- static int n = 0;
+ static u64 n = 0;
(void)pc;
(void)pOp;
(void)v;
n++;
+ if( n==LARGEST_UINT64 ) abort(); /* So that n is used, preventing a warning */
}
#endif
@@ -90896,6 +94133,9 @@ SQLITE_PRIVATE void wx_sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){
wx_sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.');
}
wx_sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]);
+ if( f & MEM_Term ){
+ wx_sqlite3_str_appendf(pStr, "(0-term)");
+ }
}
}
#endif
@@ -91023,12 +94263,102 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){
}else if( p->flags & MEM_Real ){
h += wx_sqlite3VdbeIntValue(p);
}else if( p->flags & (MEM_Str|MEM_Blob) ){
- /* no-op */
+ /* All strings have the same hash and all blobs have the same hash,
+ ** though, at least, those hashes are different from each other and
+ ** from NULL. */
+ h += 4093 + (p->flags & (MEM_Str|MEM_Blob));
}
}
return h;
}
+
+/*
+** For OP_Column, factor out the case where content is loaded from
+** overflow pages, so that the code to implement this case is separate
+** the common case where all content fits on the page. Factoring out
+** the code reduces register pressure and helps the common case
+** to run faster.
+*/
+static SQLITE_NOINLINE int vdbeColumnFromOverflow(
+ VdbeCursor *pC, /* The BTree cursor from which we are reading */
+ int iCol, /* The column to read */
+ int t, /* The serial-type code for the column value */
+ i64 iOffset, /* Offset to the start of the content value */
+ u32 cacheStatus, /* Current Vdbe.cacheCtr value */
+ u32 colCacheCtr, /* Current value of the column cache counter */
+ Mem *pDest /* Store the value into this register. */
+){
+ int rc;
+ wx_sqlite3 *db = pDest->db;
+ int encoding = pDest->enc;
+ int len = wx_sqlite3VdbeSerialTypeLen(t);
+ assert( pC->eCurType==CURTYPE_BTREE );
+ if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) return SQLITE_TOOBIG;
+ if( len > 4000 && pC->pKeyInfo==0 ){
+ /* Cache large column values that are on overflow pages using
+ ** an RCStr (reference counted string) so that if they are reloaded,
+ ** that do not have to be copied a second time. The overhead of
+ ** creating and managing the cache is such that this is only
+ ** profitable for larger TEXT and BLOB values.
+ **
+ ** Only do this on table-btrees so that writes to index-btrees do not
+ ** need to clear the cache. This buys performance in the common case
+ ** in exchange for generality.
+ */
+ VdbeTxtBlbCache *pCache;
+ char *pBuf;
+ if( pC->colCache==0 ){
+ pC->pCache = wx_sqlite3DbMallocZero(db, sizeof(VdbeTxtBlbCache) );
+ if( pC->pCache==0 ) return SQLITE_NOMEM;
+ pC->colCache = 1;
+ }
+ pCache = pC->pCache;
+ if( pCache->pCValue==0
+ || pCache->iCol!=iCol
+ || pCache->cacheStatus!=cacheStatus
+ || pCache->colCacheCtr!=colCacheCtr
+ || pCache->iOffset!=wx_sqlite3BtreeOffset(pC->uc.pCursor)
+ ){
+ if( pCache->pCValue ) wx_sqlite3RCStrUnref(pCache->pCValue);
+ pBuf = pCache->pCValue = wx_sqlite3RCStrNew( len+3 );
+ if( pBuf==0 ) return SQLITE_NOMEM;
+ rc = wx_sqlite3BtreePayload(pC->uc.pCursor, iOffset, len, pBuf);
+ if( rc ) return rc;
+ pBuf[len] = 0;
+ pBuf[len+1] = 0;
+ pBuf[len+2] = 0;
+ pCache->iCol = iCol;
+ pCache->cacheStatus = cacheStatus;
+ pCache->colCacheCtr = colCacheCtr;
+ pCache->iOffset = wx_sqlite3BtreeOffset(pC->uc.pCursor);
+ }else{
+ pBuf = pCache->pCValue;
+ }
+ assert( t>=12 );
+ wx_sqlite3RCStrRef(pBuf);
+ if( t&1 ){
+ rc = wx_sqlite3VdbeMemSetStr(pDest, pBuf, len, encoding,
+ wx_sqlite3RCStrUnref);
+ pDest->flags |= MEM_Term;
+ }else{
+ rc = wx_sqlite3VdbeMemSetStr(pDest, pBuf, len, 0,
+ wx_sqlite3RCStrUnref);
+ }
+ }else{
+ rc = wx_sqlite3VdbeMemFromBtree(pC->uc.pCursor, iOffset, len, pDest);
+ if( rc ) return rc;
+ wx_sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
+ if( (t&1)!=0 && encoding==SQLITE_UTF8 ){
+ pDest->z[len] = 0;
+ pDest->flags |= MEM_Term;
+ }
+ }
+ pDest->flags &= ~MEM_Ephem;
+ return rc;
+}
+
+
/*
** Return the symbolic name for the data type of a pMem
*/
@@ -91071,8 +94401,10 @@ SQLITE_PRIVATE int wx_sqlite3VdbeExec(
Mem *pIn2 = 0; /* 2nd input operand */
Mem *pIn3 = 0; /* 3rd input operand */
Mem *pOut = 0; /* Output operand */
+ u32 colCacheCtr = 0; /* Column cache counter */
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
u64 *pnCycle = 0;
+ int bStmtScanStatus = IS_STMT_SCANSTATUS(db)!=0;
#endif
/*** INSERT STACK UNION HERE ***/
@@ -91137,13 +94469,17 @@ SQLITE_PRIVATE int wx_sqlite3VdbeExec(
assert( pOp>=aOp && pOp<&aOp[p->nOp]);
nVmStep++;
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+
+#if defined(VDBE_PROFILE)
pOp->nExec++;
pnCycle = &pOp->nCycle;
-# ifdef VDBE_PROFILE
- if( wx_sqlite3NProfileCnt==0 )
-# endif
+ if( wx_sqlite3NProfileCnt==0 ) *pnCycle -= wx_sqlite3Hwtime();
+#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ if( bStmtScanStatus ){
+ pOp->nExec++;
+ pnCycle = &pOp->nCycle;
*pnCycle -= wx_sqlite3Hwtime();
+ }
#endif
/* Only allow tracing if SQLITE_DEBUG is defined.
@@ -91261,8 +94597,8 @@ SQLITE_PRIVATE int wx_sqlite3VdbeExec(
case OP_Goto: { /* jump */
#ifdef SQLITE_DEBUG
- /* In debuggging mode, when the p5 flags is set on an OP_Goto, that
- ** means we should really jump back to the preceeding OP_ReleaseReg
+ /* In debugging mode, when the p5 flags is set on an OP_Goto, that
+ ** means we should really jump back to the preceding OP_ReleaseReg
** instruction. */
if( pOp->p5 ){
assert( pOp->p2 < (int)(pOp - aOp) );
@@ -91369,7 +94705,7 @@ case OP_Return: { /* in1 */
**
** See also: EndCoroutine
*/
-case OP_InitCoroutine: { /* jump */
+case OP_InitCoroutine: { /* jump0 */
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
assert( pOp->p2>=0 && pOp->p2<p->nOp );
assert( pOp->p3>=0 && pOp->p3<p->nOp );
@@ -91392,7 +94728,9 @@ jump_to_p2:
**
** The instruction at the address in register P1 is a Yield.
** Jump to the P2 parameter of that Yield.
-** After the jump, register P1 becomes undefined.
+** After the jump, the value register P1 is left with a value
+** such that subsequent OP_Yields go back to the this same
+** OP_EndCoroutine instruction.
**
** See also: InitCoroutine
*/
@@ -91404,8 +94742,8 @@ case OP_EndCoroutine: { /* in1 */
pCaller = &aOp[pIn1->u.i];
assert( pCaller->opcode==OP_Yield );
assert( pCaller->p2>=0 && pCaller->p2<p->nOp );
+ pIn1->u.i = (int)(pOp - p->aOp) - 1;
pOp = &aOp[pCaller->p2 - 1];
- pIn1->flags = MEM_Undefined;
break;
}
@@ -91422,7 +94760,7 @@ case OP_EndCoroutine: { /* in1 */
**
** See also: InitCoroutine
*/
-case OP_Yield: { /* in1, jump */
+case OP_Yield: { /* in1, jump0 */
int pcDest;
pIn1 = &aMem[pOp->p1];
assert( VdbeMemDynamic(pIn1)==0 );
@@ -91452,7 +94790,7 @@ case OP_HaltIfNull: { /* in3 */
/* no break */ deliberate_fall_through
}
-/* Opcode: Halt P1 P2 * P4 P5
+/* Opcode: Halt P1 P2 P3 P4 P5
**
** Exit immediately. All open cursors, etc are closed
** automatically.
@@ -91465,18 +94803,22 @@ case OP_HaltIfNull: { /* in3 */
** then back out all changes that have occurred during this execution of the
** VDBE, but do not rollback the transaction.
**
-** If P4 is not null then it is an error message string.
+** If P3 is not zero and P4 is NULL, then P3 is a register that holds the
+** text of an error message.
+**
+** If P3 is zero and P4 is not null then the error message string is held
+** in P4.
**
-** P5 is a value between 0 and 4, inclusive, that modifies the P4 string.
+** P5 is a value between 1 and 4, inclusive, then the P4 error message
+** string is modified as follows:
**
-** 0: (no change)
-** 1: NOT NULL contraint failed: P4
+** 1: NOT NULL constraint failed: P4
** 2: UNIQUE constraint failed: P4
** 3: CHECK constraint failed: P4
** 4: FOREIGN KEY constraint failed: P4
**
-** If P5 is not zero and P4 is NULL, then everything after the ":" is
-** omitted.
+** If P3 is zero and P5 is not zero and P4 is NULL, then everything after
+** the ":" is omitted.
**
** There is an implied "Halt 0 0 0" instruction inserted at the very end of
** every program. So a jump past the last instruction of the program
@@ -91489,6 +94831,9 @@ case OP_Halt: {
#ifdef SQLITE_DEBUG
if( pOp->p2==OE_Abort ){ wx_sqlite3VdbeAssertAbortable(p); }
#endif
+ assert( pOp->p4type==P4_NOTUSED
+ || pOp->p4type==P4_STATIC
+ || pOp->p4type==P4_DYNAMIC );
/* A deliberately coded "OP_Halt SQLITE_INTERNAL * * * *" opcode indicates
** something is wrong with the code generator. Raise an assertion in order
@@ -91519,7 +94864,12 @@ case OP_Halt: {
p->errorAction = (u8)pOp->p2;
assert( pOp->p5<=4 );
if( p->rc ){
- if( pOp->p5 ){
+ if( pOp->p3>0 && pOp->p4type==P4_NOTUSED ){
+ const char *zErr;
+ assert( pOp->p3<=(p->nMem + 1 - p->nCursor) );
+ zErr = wx_sqlite3ValueText(&aMem[pOp->p3], SQLITE_UTF8);
+ wx_sqlite3VdbeError(p, "%s", zErr);
+ }else if( pOp->p5 ){
static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
"FOREIGN KEY" };
testcase( pOp->p5==1 );
@@ -91752,19 +95102,15 @@ case OP_Blob: { /* out2 */
break;
}
-/* Opcode: Variable P1 P2 * P4 *
-** Synopsis: r[P2]=parameter(P1,P4)
+/* Opcode: Variable P1 P2 * * *
+** Synopsis: r[P2]=parameter(P1)
**
** Transfer the values of bound parameter P1 into register P2
-**
-** If the parameter is named, then its name appears in P4.
-** The P4 value is used by wx_sqlite3_bind_parameter_name().
*/
case OP_Variable: { /* out2 */
Mem *pVar; /* Value being transferred */
assert( pOp->p1>0 && pOp->p1<=p->nVar );
- assert( pOp->p4.z==0 || pOp->p4.z==wx_sqlite3VListNumToName(p->pVList,pOp->p1) );
pVar = &p->aVar[pOp->p1 - 1];
if( wx_sqlite3VdbeMemTooBig(pVar) ){
goto too_big;
@@ -92274,7 +95620,7 @@ case OP_AddImm: { /* in1 */
pIn1 = &aMem[pOp->p1];
memAboutToChange(p, pIn1);
wx_sqlite3VdbeMemIntegerify(pIn1);
- pIn1->u.i += pOp->p2;
+ *(u64*)&pIn1->u.i += (u64)pOp->p2;
break;
}
@@ -92285,7 +95631,7 @@ case OP_AddImm: { /* in1 */
** without data loss, then jump immediately to P2, or if P2==0
** raise an SQLITE_MISMATCH exception.
*/
-case OP_MustBeInt: { /* jump, in1 */
+case OP_MustBeInt: { /* jump0, in1 */
pIn1 = &aMem[pOp->p1];
if( (pIn1->flags & MEM_Int)==0 ){
applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
@@ -92326,7 +95672,7 @@ case OP_RealAffinity: { /* in1 */
}
#endif
-#ifndef SQLITE_OMIT_CAST
+#if !defined(SQLITE_OMIT_CAST) || !defined(SQLITE_OMIT_ANALYZE)
/* Opcode: Cast P1 P2 * * *
** Synopsis: affinity(r[P1])
**
@@ -92541,7 +95887,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
}
}
}else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){
- if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
+ if( (flags1 & MEM_Str)!=0 ){
+ pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
+ }else if( (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn1->flags & MEM_Int );
testcase( pIn1->flags & MEM_Real );
testcase( pIn1->flags & MEM_IntReal );
@@ -92550,7 +95898,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str;
}
- if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
+ if( (flags3 & MEM_Str)!=0 ){
+ pIn3->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
+ }else if( (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn3->flags & MEM_Int );
testcase( pIn3->flags & MEM_Real );
testcase( pIn3->flags & MEM_IntReal );
@@ -92601,10 +95951,10 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** opcodes are allowed to occur between this instruction and the previous
** OP_Lt or OP_Gt.
**
-** If result of an OP_Eq comparison on the same two operands as the
-** prior OP_Lt or OP_Gt would have been true, then jump to P2.
-** If the result of an OP_Eq comparison on the two previous
-** operands would have been false or NULL, then fall through.
+** If the result of an OP_Eq comparison on the same two operands as
+** the prior OP_Lt or OP_Gt would have been true, then jump to P2. If
+** the result of an OP_Eq comparison on the two previous operands
+** would have been false or NULL, then fall through.
*/
case OP_ElseEq: { /* same as TK_ESCAPE, jump */
@@ -92731,7 +96081,7 @@ case OP_Compare: {
/* Opcode: Jump P1 P2 P3 * *
**
** Jump to the instruction at address P1, P2, or P3 depending on whether
-** in the most recent OP_Compare instruction the P1 vector was less than
+** in the most recent OP_Compare instruction the P1 vector was less than,
** equal to, or greater than the P2 vector, respectively.
**
** This opcode must immediately follow an OP_Compare opcode.
@@ -92958,6 +96308,12 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04.
** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10.
**
+** WARNING: This opcode does not reliably distinguish between NULL and REAL
+** when P1>=0. If the database contains a NaN value, this opcode will think
+** that the datatype is REAL when it should be NULL. When P1<0 and the value
+** is already stored in register P3, then this opcode does reliably
+** distinguish between NULL and REAL. The problem only arises then P1>=0.
+**
** Take the jump to address P2 if and only if the datatype of the
** value determined by P1 and P3 corresponds to one of the bits in the
** P5 bitmask.
@@ -93028,7 +96384,7 @@ case OP_IsType: { /* jump */
/* Opcode: ZeroOrNull P1 P2 P3 * *
** Synopsis: r[P2] = 0 OR NULL
**
-** If all both registers P1 and P3 are NOT NULL, then store a zero in
+** If both registers P1 and P3 are NOT NULL, then store a zero in
** register P2. If either registers P1 or P3 are NULL then put
** a NULL in register P2.
*/
@@ -93071,7 +96427,7 @@ case OP_IfNullRow: { /* jump */
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
- if( ALWAYS(pC) && pC->nullRow ){
+ if( pC && pC->nullRow ){
wx_sqlite3VdbeMemSetNull(aMem + pOp->p3);
goto jump_to_p2;
}
@@ -93382,11 +96738,16 @@ op_column_restart:
pDest->flags = aFlag[t&1];
}
}else{
+ u8 p5;
pDest->enc = encoding;
+ assert( pDest->db==db );
/* This branch happens only when content is on overflow pages */
- if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
- && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
- || (len = wx_sqlite3VdbeSerialTypeLen(t))==0
+ if( ((p5 = (pOp->p5 & OPFLAG_BYTELENARG))!=0
+ && (p5==OPFLAG_TYPEOFARG
+ || (t>=12 && ((t&1)==0 || p5==OPFLAG_BYTELENARG))
+ )
+ )
+ || wx_sqlite3VdbeSerialTypeLen(t)==0
){
/* Content is irrelevant for
** 1. the typeof() function,
@@ -93403,11 +96764,13 @@ op_column_restart:
*/
wx_sqlite3VdbeSerialGet((u8*)wx_sqlite3CtypeMap, t, pDest);
}else{
- if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) goto too_big;
- rc = wx_sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
- wx_sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
- pDest->flags &= ~MEM_Ephem;
+ rc = vdbeColumnFromOverflow(pC, p2, t, aOffset[p2],
+ p->cacheCtr, colCacheCtr, pDest);
+ if( rc ){
+ if( rc==SQLITE_NOMEM ) goto no_mem;
+ if( rc==SQLITE_TOOBIG ) goto too_big;
+ goto abort_due_to_error;
+ }
}
}
@@ -93566,7 +96929,7 @@ case OP_Affinity: {
}else{
pIn1->u.r = (double)pIn1->u.i;
pIn1->flags |= MEM_Real;
- pIn1->flags &= ~MEM_Int;
+ pIn1->flags &= ~(MEM_Int|MEM_Str);
}
}
REGISTER_TRACE((int)(pIn1-aMem), pIn1);
@@ -93869,7 +97232,6 @@ case OP_MakeRecord: {
/* NULL value. No change in zPayload */
}else{
u64 v;
- u32 i;
if( serial_type==7 ){
assert( sizeof(v)==sizeof(pRec->u.r) );
memcpy(&v, &pRec->u.r, sizeof(v));
@@ -93877,12 +97239,22 @@ case OP_MakeRecord: {
}else{
v = pRec->u.i;
}
- len = i = wx_sqlite3SmallTypeSizes[serial_type];
- assert( i>0 );
- while( 1 /*exit-by-break*/ ){
- zPayload[--i] = (u8)(v&0xFF);
- if( i==0 ) break;
- v >>= 8;
+ len = wx_sqlite3SmallTypeSizes[serial_type];
+ assert( len>=1 && len<=8 && len!=5 && len!=7 );
+ switch( len ){
+ default: zPayload[7] = (u8)(v&0xff); v >>= 8;
+ zPayload[6] = (u8)(v&0xff); v >>= 8;
+ /* no break */ deliberate_fall_through
+ case 6: zPayload[5] = (u8)(v&0xff); v >>= 8;
+ zPayload[4] = (u8)(v&0xff); v >>= 8;
+ /* no break */ deliberate_fall_through
+ case 4: zPayload[3] = (u8)(v&0xff); v >>= 8;
+ /* no break */ deliberate_fall_through
+ case 3: zPayload[2] = (u8)(v&0xff); v >>= 8;
+ /* no break */ deliberate_fall_through
+ case 2: zPayload[1] = (u8)(v&0xff); v >>= 8;
+ /* no break */ deliberate_fall_through
+ case 1: zPayload[0] = (u8)(v&0xff);
}
zPayload += len;
}
@@ -94540,23 +97912,23 @@ case OP_OpenWrite:
if( pDb->pSchema->file_format < p->minWriteFileFormat ){
p->minWriteFileFormat = pDb->pSchema->file_format;
}
+ if( pOp->p5 & OPFLAG_P2ISREG ){
+ assert( p2>0 );
+ assert( p2<=(u32)(p->nMem+1 - p->nCursor) );
+ pIn2 = &aMem[p2];
+ assert( memIsValid(pIn2) );
+ assert( (pIn2->flags & MEM_Int)!=0 );
+ wx_sqlite3VdbeMemIntegerify(pIn2);
+ p2 = (int)pIn2->u.i;
+ /* The p2 value always comes from a prior OP_CreateBtree opcode and
+ ** that opcode will always set the p2 value to 2 or more or else fail.
+ ** If there were a failure, the prepared statement would have halted
+ ** before reaching this instruction. */
+ assert( p2>=2 );
+ }
}else{
wrFlag = 0;
- }
- if( pOp->p5 & OPFLAG_P2ISREG ){
- assert( p2>0 );
- assert( p2<=(u32)(p->nMem+1 - p->nCursor) );
- assert( pOp->opcode==OP_OpenWrite );
- pIn2 = &aMem[p2];
- assert( memIsValid(pIn2) );
- assert( (pIn2->flags & MEM_Int)!=0 );
- wx_sqlite3VdbeMemIntegerify(pIn2);
- p2 = (int)pIn2->u.i;
- /* The p2 value always comes from a prior OP_CreateBtree opcode and
- ** that opcode will always set the p2 value to 2 or more or else fail.
- ** If there were a failure, the prepared statement would have halted
- ** before reaching this instruction. */
- assert( p2>=2 );
+ assert( (pOp->p5 & OPFLAG_P2ISREG)==0 );
}
if( pOp->p4type==P4_KEYINFO ){
pKeyInfo = pOp->p4.pKeyInfo;
@@ -94691,7 +98063,7 @@ case OP_OpenEphemeral: { /* ncycle */
}
pCx = p->apCsr[pOp->p1];
if( pCx && !pCx->noReuse && ALWAYS(pOp->p2<=pCx->nField) ){
- /* If the ephermeral table is already open and has no duplicates from
+ /* If the ephemeral table is already open and has no duplicates from
** OP_OpenDup, then erase all existing content so that the table is
** empty again, rather than creating a new table. */
assert( pCx->isEphemeral );
@@ -94734,7 +98106,10 @@ case OP_OpenEphemeral: { /* ncycle */
}
pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
if( rc ){
+ assert( !wx_sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) );
wx_sqlite3BtreeClose(pCx->ub.pBtx);
+ }else{
+ assert( wx_sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) );
}
}
}
@@ -94800,7 +98175,8 @@ case OP_SequenceTest: {
** is the only cursor opcode that works with a pseudo-table.
**
** P3 is the number of fields in the records that will be stored by
-** the pseudo-table.
+** the pseudo-table. If P2 is 0 or negative then the pseudo-cursor
+** will return NULL for every column.
*/
case OP_OpenPseudo: {
VdbeCursor *pCx;
@@ -94943,10 +98319,10 @@ case OP_ColumnsUsed: {
**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
*/
-case OP_SeekLT: /* jump, in3, group, ncycle */
-case OP_SeekLE: /* jump, in3, group, ncycle */
-case OP_SeekGE: /* jump, in3, group, ncycle */
-case OP_SeekGT: { /* jump, in3, group, ncycle */
+case OP_SeekLT: /* jump0, in3, group, ncycle */
+case OP_SeekLE: /* jump0, in3, group, ncycle */
+case OP_SeekGE: /* jump0, in3, group, ncycle */
+case OP_SeekGT: { /* jump0, in3, group, ncycle */
int res; /* Comparison result */
int oc; /* Opcode */
VdbeCursor *pC; /* The cursor to seek */
@@ -95182,7 +98558,7 @@ seek_not_found:
** row. If This.P5 is false (0) then a jump is made to SeekGE.P2. If
** This.P5 is true (non-zero) then a jump is made to This.P2. The P5==0
** case occurs when there are no inequality constraints to the right of
-** the IN constraing. The jump to SeekGE.P2 ends the loop. The P5!=0 case
+** the IN constraint. The jump to SeekGE.P2 ends the loop. The P5!=0 case
** occurs when there are inequality constraints to the right of the IN
** operator. In that case, the This.P2 will point either directly to or
** to setup code prior to the OP_IdxGT or OP_IdxGE opcode that checks for
@@ -95190,7 +98566,7 @@ seek_not_found:
**
** Possible outcomes from this opcode:<ol>
**
-** <li> If the cursor is initally not pointed to any valid row, then
+** <li> If the cursor is initially not pointed to any valid row, then
** fall through into the subsequent OP_SeekGE opcode.
**
** <li> If the cursor is left pointing to a row that is before the target
@@ -95305,6 +98681,7 @@ case OP_SeekScan: { /* ncycle */
break;
}
nStep--;
+ pC->cacheStatus = CACHE_STALE;
rc = wx_sqlite3BtreeNext(pC->uc.pCursor, 0);
if( rc ){
if( rc==SQLITE_DONE ){
@@ -95421,13 +98798,13 @@ case OP_IfNotOpen: { /* jump */
** operands to OP_NotFound and OP_IdxGT.
**
** This opcode is an optimization attempt only. If this opcode always
-** falls through, the correct answer is still obtained, but extra works
+** falls through, the correct answer is still obtained, but extra work
** is performed.
**
** A value of N in the seekHit flag of cursor P1 means that there exists
** a key P3:N that will match some record in the index. We want to know
** if it is possible for a record P3:P4 to match some record in the
-** index. If it is not possible, we can skips some work. So if seekHit
+** index. If it is not possible, we can skip some work. So if seekHit
** is less than P4, attempt to find out if a match is possible by running
** OP_NotFound.
**
@@ -95510,6 +98887,7 @@ case OP_Found: { /* jump, in3, ncycle */
r.pKeyInfo = pC->pKeyInfo;
r.default_rc = 0;
#ifdef SQLITE_DEBUG
+ (void)wx_sqlite3FaultSim(50); /* For use by --counter in TH3 */
for(ii=0; ii<r.nField; ii++){
assert( memIsValid(&r.aMem[ii]) );
assert( (r.aMem[ii].flags & MEM_Zero)==0 || r.aMem[ii].n==0 );
@@ -95612,7 +98990,7 @@ case OP_Found: { /* jump, in3, ncycle */
**
** See also: Found, NotFound, NoConflict, SeekRowid
*/
-case OP_SeekRowid: { /* jump, in3, ncycle */
+case OP_SeekRowid: { /* jump0, in3, ncycle */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
@@ -95939,6 +99317,7 @@ case OP_Insert: {
);
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
+ colCacheCtr++;
/* Invoke the update-hook if required. */
if( rc ) goto abort_due_to_error;
@@ -95992,13 +99371,18 @@ case OP_RowCell: {
** left in an undefined state.
**
** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this
-** delete one of several associated with deleting a table row and all its
-** associated index entries. Exactly one of those deletes is the "primary"
-** delete. The others are all on OPFLAG_FORDELETE cursors or else are
-** marked with the AUXDELETE flag.
+** delete is one of several associated with deleting a table row and
+** all its associated index entries. Exactly one of those deletes is
+** the "primary" delete. The others are all on OPFLAG_FORDELETE
+** cursors or else are marked with the AUXDELETE flag.
+**
+** If the OPFLAG_NCHANGE (0x01) flag of P2 (NB: P2 not P5) is set, then
+** the row change count is incremented (otherwise not).
**
-** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row
-** change count is incremented (otherwise not).
+** If the OPFLAG_ISNOOP (0x40) flag of P2 (not P5!) is set, then the
+** pre-update-hook for deletes is run, but the btree is otherwise unchanged.
+** This happens when the OP_Delete is to be shortly followed by an OP_Insert
+** with the same key, causing the btree entry to be overwritten.
**
** P1 must not be pseudo-table. It has to be a real table with
** multiple rows.
@@ -96099,6 +99483,7 @@ case OP_Delete: {
rc = wx_sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
pC->cacheStatus = CACHE_STALE;
+ colCacheCtr++;
pC->seekResult = 0;
if( rc ) goto abort_due_to_error;
@@ -96166,13 +99551,13 @@ case OP_SorterCompare: {
** Write into register P2 the current sorter data for sorter cursor P1.
** Then clear the column header cache on cursor P3.
**
-** This opcode is normally use to move a record out of the sorter and into
+** This opcode is normally used to move a record out of the sorter and into
** a register that is the source for a pseudo-table cursor created using
** OpenPseudo. That pseudo-table cursor is the one that is identified by
** parameter P3. Clearing the P3 column cache as part of this opcode saves
** us from having to issue a separate NullRow instruction to clear that cache.
*/
-case OP_SorterData: {
+case OP_SorterData: { /* ncycle */
VdbeCursor *pC;
pOut = &aMem[pOp->p2];
@@ -96364,7 +99749,7 @@ case OP_NullRow: {
** configured to use Prev, not Next.
*/
case OP_SeekEnd: /* ncycle */
-case OP_Last: { /* jump, ncycle */
+case OP_Last: { /* jump0, ncycle */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
@@ -96398,28 +99783,38 @@ case OP_Last: { /* jump, ncycle */
break;
}
-/* Opcode: IfSmaller P1 P2 P3 * *
+/* Opcode: IfSizeBetween P1 P2 P3 P4 *
**
-** Estimate the number of rows in the table P1. Jump to P2 if that
-** estimate is less than approximately 2**(0.1*P3).
+** Let N be the approximate number of rows in the table or index
+** with cursor P1 and let X be 10*log2(N) if N is positive or -1
+** if N is zero.
+**
+** Jump to P2 if X is in between P3 and P4, inclusive.
*/
-case OP_IfSmaller: { /* jump */
+case OP_IfSizeBetween: { /* jump */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
i64 sz;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ assert( pOp->p4type==P4_INT32 );
+ assert( pOp->p3>=-1 && pOp->p3<=640*2 );
+ assert( pOp->p4.i>=-1 && pOp->p4.i<=640*2 );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
pCrsr = pC->uc.pCursor;
assert( pCrsr );
rc = wx_sqlite3BtreeFirst(pCrsr, &res);
if( rc ) goto abort_due_to_error;
- if( res==0 ){
+ if( res!=0 ){
+ sz = -1; /* -Infinity encoding */
+ }else{
sz = wx_sqlite3BtreeRowCountEst(pCrsr);
- if( ALWAYS(sz>=0) && wx_sqlite3LogEst((u64)sz)<pOp->p3 ) res = 1;
+ assert( sz>0 );
+ sz = wx_sqlite3LogEst((u64)sz);
}
+ res = sz>=pOp->p3 && sz<=pOp->p4.i;
VdbeBranchTaken(res!=0,2);
if( res ) goto jump_to_p2;
break;
@@ -96447,8 +99842,8 @@ case OP_IfSmaller: { /* jump */
** regression tests can determine whether or not the optimizer is
** correctly optimizing out sorts.
*/
-case OP_SorterSort: /* jump */
-case OP_Sort: { /* jump */
+case OP_SorterSort: /* jump ncycle */
+case OP_Sort: { /* jump ncycle */
#ifdef SQLITE_TEST
wx_sqlite3_sort_count++;
wx_sqlite3_search_count--;
@@ -96472,7 +99867,7 @@ case OP_Sort: { /* jump */
** from the beginning toward the end. In other words, the cursor is
** configured to use Next, not Prev.
*/
-case OP_Rewind: { /* jump, ncycle */
+case OP_Rewind: { /* jump0, ncycle */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
@@ -96975,7 +100370,7 @@ case OP_IdxGE: { /* jump, ncycle */
** file is given by P1.
**
** The table being destroyed is in the main database file if P3==0. If
-** P3==1 then the table to be clear is in the auxiliary database file
+** P3==1 then the table to be destroyed is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If AUTOVACUUM is enabled then it is possible that another root page
@@ -97035,8 +100430,8 @@ case OP_Destroy: { /* out2 */
** in the database file is given by P1. But, unlike Destroy, do not
** remove the table or index from the database file.
**
-** The table being clear is in the main database file if P2==0. If
-** P2==1 then the table to be clear is in the auxiliary database file
+** The table being cleared is in the main database file if P2==0. If
+** P2==1 then the table to be cleared is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If the P3 value is non-zero, then the row change count is incremented
@@ -97119,16 +100514,57 @@ case OP_CreateBtree: { /* out2 */
break;
}
-/* Opcode: SqlExec * * * P4 *
+/* Opcode: SqlExec P1 P2 * P4 *
**
** Run the SQL statement or statements specified in the P4 string.
+**
+** The P1 parameter is a bitmask of options:
+**
+** 0x0001 Disable Auth and Trace callbacks while the statements
+** in P4 are running.
+**
+** 0x0002 Set db->nAnalysisLimit to P2 while the statements in
+** P4 are running.
+**
*/
case OP_SqlExec: {
+ char *zErr;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ wx_sqlite3_xauth xAuth;
+#endif
+ u8 mTrace;
+ int savedAnalysisLimit;
+
wx_sqlite3VdbeIncrWriteCounter(p, 0);
db->nSqlExec++;
- rc = wx_sqlite3_exec(db, pOp->p4.z, 0, 0, 0);
+ zErr = 0;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ xAuth = db->xAuth;
+#endif
+ mTrace = db->mTrace;
+ savedAnalysisLimit = db->nAnalysisLimit;
+ if( pOp->p1 & 0x0001 ){
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = 0;
+#endif
+ db->mTrace = 0;
+ }
+ if( pOp->p1 & 0x0002 ){
+ db->nAnalysisLimit = pOp->p2;
+ }
+ rc = wx_sqlite3_exec(db, pOp->p4.z, 0, 0, &zErr);
db->nSqlExec--;
- if( rc ) goto abort_due_to_error;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = xAuth;
+#endif
+ db->mTrace = mTrace;
+ db->nAnalysisLimit = savedAnalysisLimit;
+ if( zErr || rc ){
+ wx_sqlite3VdbeError(p, "%s", zErr);
+ wx_sqlite3_free(zErr);
+ if( rc==SQLITE_NOMEM ) goto no_mem;
+ goto abort_due_to_error;
+ }
break;
}
@@ -97274,11 +100710,11 @@ case OP_DropTrigger: {
/* Opcode: IntegrityCk P1 P2 P3 P4 P5
**
** Do an analysis of the currently open database. Store in
-** register P1 the text of an error message describing any problems.
-** If no problems are found, store a NULL in register P1.
+** register (P1+1) the text of an error message describing any problems.
+** If no problems are found, store a NULL in register (P1+1).
**
-** The register P3 contains one less than the maximum number of allowed errors.
-** At most reg(P3) errors will be reported.
+** The register (P1) contains one less than the maximum number of allowed
+** errors. At most reg(P1) errors will be reported.
** In other words, the analysis stops as soon as reg(P1) errors are
** seen. Reg(P1) is updated with the number of errors remaining.
**
@@ -97298,19 +100734,21 @@ case OP_IntegrityCk: {
Mem *pnErr; /* Register keeping track of errors remaining */
assert( p->bIsReader );
+ assert( pOp->p4type==P4_INTARRAY );
nRoot = pOp->p2;
aRoot = pOp->p4.ai;
assert( nRoot>0 );
+ assert( aRoot!=0 );
assert( aRoot[0]==(Pgno)nRoot );
- assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
- pnErr = &aMem[pOp->p3];
+ assert( pOp->p1>0 && (pOp->p1+1)<=(p->nMem+1 - p->nCursor) );
+ pnErr = &aMem[pOp->p1];
assert( (pnErr->flags & MEM_Int)!=0 );
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
- pIn1 = &aMem[pOp->p1];
+ pIn1 = &aMem[pOp->p1+1];
assert( pOp->p5<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p5) );
- rc = wx_sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
- (int)pnErr->u.i+1, &nErr, &z);
+ rc = wx_sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1],
+ &aMem[pOp->p3], nRoot, (int)pnErr->u.i+1, &nErr, &z);
wx_sqlite3VdbeMemSetNull(pIn1);
if( nErr==0 ){
assert( z==0 );
@@ -97437,7 +100875,9 @@ case OP_RowSetTest: { /* jump, in1, in3 */
** P1 contains the address of the memory cell that contains the first memory
** cell in an array of values used as arguments to the sub-program. P2
** contains the address to jump to if the sub-program throws an IGNORE
-** exception using the RAISE() function. Register P3 contains the address
+** exception using the RAISE() function. P2 might be zero, if there is
+** no possibility that an IGNORE exception will be raised.
+** Register P3 contains the address
** of a memory cell in this (the parent) VM that is used to allocate the
** memory required by the sub-vdbe at runtime.
**
@@ -97445,7 +100885,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
**
** If P5 is non-zero, then recursive program invocation is enabled.
*/
-case OP_Program: { /* jump */
+case OP_Program: { /* jump0 */
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 */
@@ -97810,18 +101250,29 @@ case OP_AggInverse:
case OP_AggStep: {
int n;
wx_sqlite3_context *pCtx;
+ u64 nAlloc;
assert( pOp->p4type==P4_FUNCDEF );
n = pOp->p5;
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
- pCtx = wx_sqlite3DbMallocRawNN(db, n*sizeof(wx_sqlite3_value*) +
- (sizeof(pCtx[0]) + sizeof(Mem) - sizeof(wx_sqlite3_value*)));
+
+ /* Allocate space for (a) the context object and (n-1) extra pointers
+ ** to append to the wx_sqlite3_context.argv[1] array, and (b) a memory
+ ** cell in which to store the accumulation. Be careful that the memory
+ ** cell is 8-byte aligned, even on platforms where a pointer is 32-bits.
+ **
+ ** Note: We could avoid this by using a regular memory cell from aMem[] for
+ ** the accumulator, instead of allocating one here. */
+ nAlloc = ROUND8P( sizeof(pCtx[0]) + (n-1)*sizeof(wx_sqlite3_value*) );
+ pCtx = wx_sqlite3DbMallocRawNN(db, nAlloc + sizeof(Mem));
if( pCtx==0 ) goto no_mem;
- pCtx->pMem = 0;
- pCtx->pOut = (Mem*)&(pCtx->argv[n]);
+ pCtx->pOut = (Mem*)((u8*)pCtx + nAlloc);
+ assert( EIGHT_BYTE_ALIGNMENT(pCtx->pOut) );
+
wx_sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null);
+ pCtx->pMem = 0;
pCtx->pFunc = pOp->p4.pFunc;
pCtx->iOp = (int)(pOp - aOp);
pCtx->pVdbe = p;
@@ -97862,7 +101313,7 @@ case OP_AggStep1: {
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
- ** reinitializes the relavant parts of the wx_sqlite3_context object */
+ ** reinitializes the relevant parts of the wx_sqlite3_context object */
if( pCtx->pMem != pMem ){
pCtx->pMem = pMem;
for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
@@ -97957,6 +101408,7 @@ case OP_AggFinal: {
}
wx_sqlite3VdbeChangeEncoding(pMem, encoding);
UPDATE_MAX_BLOBSIZE(pMem);
+ REGISTER_TRACE((int)(pMem-aMem), pMem);
break;
}
@@ -98349,6 +101801,52 @@ case OP_VOpen: { /* ncycle */
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VCheck P1 P2 P3 P4 *
+**
+** P4 is a pointer to a Table object that is a virtual table in schema P1
+** that supports the xIntegrity() method. This opcode runs the xIntegrity()
+** method for that virtual table, using P3 as the integer argument. If
+** an error is reported back, the table name is prepended to the error
+** message and that message is stored in P2. If no errors are seen,
+** register P2 is set to NULL.
+*/
+case OP_VCheck: { /* out2 */
+ Table *pTab;
+ wx_sqlite3_vtab *pVtab;
+ const wx_sqlite3_module *pModule;
+ char *zErr = 0;
+
+ pOut = &aMem[pOp->p2];
+ wx_sqlite3VdbeMemSetNull(pOut); /* Innocent until proven guilty */
+ assert( pOp->p4type==P4_TABLEREF );
+ pTab = pOp->p4.pTab;
+ assert( pTab!=0 );
+ assert( pTab->nTabRef>0 );
+ assert( IsVirtual(pTab) );
+ if( pTab->u.vtab.p==0 ) break;
+ pVtab = pTab->u.vtab.p->pVtab;
+ assert( pVtab!=0 );
+ pModule = pVtab->pModule;
+ assert( pModule!=0 );
+ assert( pModule->iVersion>=4 );
+ assert( pModule->xIntegrity!=0 );
+ wx_sqlite3VtabLock(pTab->u.vtab.p);
+ assert( pOp->p1>=0 && pOp->p1<db->nDb );
+ rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName,
+ pOp->p3, &zErr);
+ wx_sqlite3VtabUnlock(pTab->u.vtab.p);
+ if( rc ){
+ wx_sqlite3_free(zErr);
+ goto abort_due_to_error;
+ }
+ if( zErr ){
+ wx_sqlite3VdbeMemSetStr(pOut, zErr, -1, SQLITE_UTF8, wx_sqlite3_free);
+ }
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VInitIn P1 P2 P3 * *
** Synopsis: r[P2]=ValueList(P1,P3)
**
@@ -98461,6 +101959,7 @@ case OP_VColumn: { /* ncycle */
const wx_sqlite3_module *pModule;
Mem *pDest;
wx_sqlite3_context sContext;
+ FuncDef nullFunc;
VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur!=0 );
@@ -98478,6 +101977,9 @@ case OP_VColumn: { /* ncycle */
memset(&sContext, 0, sizeof(sContext));
sContext.pOut = pDest;
sContext.enc = encoding;
+ nullFunc.pUserData = 0;
+ nullFunc.funcFlags = SQLITE_RESULT_SUBTYPE;
+ sContext.pFunc = &nullFunc;
assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 );
if( pOp->p5 & OPFLAG_NOCHNG ){
wx_sqlite3VdbeMemSetNull(pDest);
@@ -98739,7 +102241,7 @@ case OP_MaxPgcnt: { /* out2 */
** This opcode works exactly like OP_Function. The only difference is in
** its name. This opcode is used in places where the function must be
** purely non-deterministic. Some built-in date/time functions can be
-** either determinitic of non-deterministic, depending on their arguments.
+** either deterministic of non-deterministic, depending on their arguments.
** When those function are used in a non-deterministic way, they will check
** to see if they were called using OP_PureFunc instead of OP_Function, and
** if they were, they throw an error.
@@ -98757,7 +102259,7 @@ case OP_Function: { /* group */
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
- ** reinitializes the relavant parts of the wx_sqlite3_context object */
+ ** reinitializes the relevant parts of the wx_sqlite3_context object */
pOut = &aMem[pOp->p3];
if( pCtx->pOut != pOut ){
pCtx->pVdbe = p;
@@ -98810,6 +102312,42 @@ case OP_ClrSubtype: { /* in1 */
break;
}
+/* Opcode: GetSubtype P1 P2 * * *
+** Synopsis: r[P2] = r[P1].subtype
+**
+** Extract the subtype value from register P1 and write that subtype
+** into register P2. If P1 has no subtype, then P1 gets a NULL.
+*/
+case OP_GetSubtype: { /* in1 out2 */
+ pIn1 = &aMem[pOp->p1];
+ pOut = &aMem[pOp->p2];
+ if( pIn1->flags & MEM_Subtype ){
+ wx_sqlite3VdbeMemSetInt64(pOut, pIn1->eSubtype);
+ }else{
+ wx_sqlite3VdbeMemSetNull(pOut);
+ }
+ break;
+}
+
+/* Opcode: SetSubtype P1 P2 * * *
+** Synopsis: r[P2].subtype = r[P1]
+**
+** Set the subtype value of register P2 to the integer from register P1.
+** If P1 is NULL, clear the subtype from p2.
+*/
+case OP_SetSubtype: { /* in1 out2 */
+ pIn1 = &aMem[pOp->p1];
+ pOut = &aMem[pOp->p2];
+ if( pIn1->flags & MEM_Null ){
+ pOut->flags &= ~MEM_Subtype;
+ }else{
+ assert( pIn1->flags & MEM_Int );
+ pOut->flags |= MEM_Subtype;
+ pOut->eSubtype = (u8)(pIn1->u.i & 0xff);
+ }
+ break;
+}
+
/* Opcode: FilterAdd P1 * P3 P4 *
** Synopsis: filter(P1) += key(P3@P4)
**
@@ -98833,7 +102371,7 @@ case OP_FilterAdd: {
printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
}
#endif
- h %= pIn1->n;
+ h %= (pIn1->n*8);
pIn1->z[h/8] |= 1<<(h&7);
break;
}
@@ -98869,7 +102407,7 @@ case OP_Filter: { /* jump */
printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
}
#endif
- h %= pIn1->n;
+ h %= (pIn1->n*8);
if( (pIn1->z[h/8] & (1<<(h&7)))==0 ){
VdbeBranchTaken(1, 2);
p->aCounter[SQLITE_STMTSTATUS_FILTER_HIT]++;
@@ -98907,7 +102445,7 @@ case OP_Filter: { /* jump */
** error is encountered.
*/
case OP_Trace:
-case OP_Init: { /* jump */
+case OP_Init: { /* jump0 */
int i;
#ifndef SQLITE_OMIT_TRACE
char *zTrace;
@@ -99068,14 +102606,29 @@ case OP_ReleaseReg: {
/* Opcode: Noop * * * * *
**
-** Do nothing. This instruction is often useful as a jump
-** destination.
+** Do nothing. Continue downward to the next opcode.
*/
-/*
-** The magic Explain opcode are only inserted when explain==2 (which
-** is to say when the EXPLAIN QUERY PLAN syntax is used.)
-** This opcode records information from the optimizer. It is the
-** the same as a no-op. This opcodesnever appears in a real VM program.
+/* Opcode: Explain P1 P2 P3 P4 *
+**
+** This is the same as OP_Noop during normal query execution. The
+** purpose of this opcode is to hold information about the query
+** plan for the purpose of EXPLAIN QUERY PLAN output.
+**
+** The P4 value is human-readable text that describes the query plan
+** element. Something like "SCAN t1" or "SEARCH t2 USING INDEX t2x1".
+**
+** The P1 value is the ID of the current element and P2 is the parent
+** element for the case of nested query plan elements. If P2 is zero
+** then this element is a top-level element.
+**
+** For loop elements, P3 is the estimated code of each invocation of this
+** element.
+**
+** As with all opcodes, the meanings of the parameters for OP_Explain
+** are subject to change from one release to the next. Applications
+** should not attempt to interpret or use any of the information
+** contained in the OP_Explain opcode. The information provided by this
+** opcode is intended for testing and debugging use only.
*/
default: { /* This is really OP_Noop, OP_Explain */
assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain );
@@ -99095,8 +102648,10 @@ default: { /* This is really OP_Noop, OP_Explain */
*pnCycle += wx_sqlite3NProfileCnt ? wx_sqlite3NProfileCnt : wx_sqlite3Hwtime();
pnCycle = 0;
#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
- *pnCycle += wx_sqlite3Hwtime();
- pnCycle = 0;
+ if( pnCycle ){
+ *pnCycle += wx_sqlite3Hwtime();
+ pnCycle = 0;
+ }
#endif
/* The following code adds nothing to the actual functionality
@@ -99119,7 +102674,7 @@ default: { /* This is really OP_Noop, OP_Explain */
}
if( opProperty==0xff ){
/* Never happens. This code exists to avoid a harmless linkage
- ** warning aboud wx_sqlite3VdbeRegisterDump() being defined but not
+ ** warning about wx_sqlite3VdbeRegisterDump() being defined but not
** used. */
wx_sqlite3VdbeRegisterDump(p);
}
@@ -99292,8 +102847,7 @@ static int blobSeekToRow(Incrblob *p, wx_sqlite3_int64 iRow, char **pzErr){
/* Set the value of register r[1] in the SQL statement to integer iRow.
** This is done directly as a performance optimization
*/
- v->aMem[1].flags = MEM_Int;
- v->aMem[1].u.i = iRow;
+ wx_sqlite3VdbeMemSetInt64(&v->aMem[1], iRow);
/* If the statement has been run before (and is paused at the OP_ResultRow)
** then back it up to the point where it does the OP_NotExists. This could
@@ -99376,7 +102930,7 @@ SQLITE_API int wx_sqlite3_blob_open(
#endif
*ppBlob = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !wx_sqlite3SafetyCheckOk(db) || zTable==0 ){
+ if( !wx_sqlite3SafetyCheckOk(db) || zTable==0 || zColumn==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
@@ -99401,6 +102955,11 @@ SQLITE_API int wx_sqlite3_blob_open(
pTab = 0;
wx_sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
}
+ if( pTab && (pTab->tabFlags&TF_HasGenerated)!=0 ){
+ pTab = 0;
+ wx_sqlite3ErrorMsg(&sParse, "cannot open table with generated columns: %s",
+ zTable);
+ }
#ifndef SQLITE_OMIT_VIEW
if( pTab && IsView(pTab) ){
pTab = 0;
@@ -99575,7 +103134,7 @@ blob_open_out:
if( pBlob && pBlob->pStmt ) wx_sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
wx_sqlite3DbFree(db, pBlob);
}
- wx_sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
+ wx_sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr);
wx_sqlite3DbFree(db, zErr);
wx_sqlite3ParseObjectReset(&sParse);
rc = wx_sqlite3ApiExit(db, rc);
@@ -99734,7 +103293,7 @@ SQLITE_API int wx_sqlite3_blob_reopen(wx_sqlite3_blob *pBlob, wx_sqlite3_int64 i
((Vdbe*)p->pStmt)->rc = SQLITE_OK;
rc = blobSeekToRow(p, iRow, &zErr);
if( rc!=SQLITE_OK ){
- wx_sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
+ wx_sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr);
wx_sqlite3DbFree(db, zErr);
}
assert( rc!=SQLITE_SCHEMA );
@@ -99837,7 +103396,7 @@ SQLITE_API int wx_sqlite3_blob_reopen(wx_sqlite3_blob *pBlob, wx_sqlite3_int64 i
** The threshold for the amount of main memory to use before flushing
** records to a PMA is roughly the same as the limit configured for the
** page-cache of the main database. Specifically, the threshold is set to
-** the value returned by "PRAGMA main.page_size" multipled by
+** the value returned by "PRAGMA main.page_size" multiplied by
** that returned by "PRAGMA main.cache_size", in bytes.
**
** If the sorter is running in single-threaded mode, then all PMAs generated
@@ -99860,7 +103419,7 @@ SQLITE_API int wx_sqlite3_blob_reopen(wx_sqlite3_blob *pBlob, wx_sqlite3_int64 i
**
** If there are fewer than SORTER_MAX_MERGE_COUNT PMAs in total and the
** sorter is running in single-threaded mode, then these PMAs are merged
-** incrementally as keys are retreived from the sorter by the VDBE. The
+** incrementally as keys are retrieved from the sorter by the VDBE. The
** MergeEngine object, described in further detail below, performs this
** merge.
**
@@ -99938,7 +103497,7 @@ struct SorterFile {
struct SorterList {
SorterRecord *pList; /* Linked list of records */
u8 *aMemory; /* If non-NULL, bulk memory to hold pList */
- int szPMA; /* Size of pList as PMA in bytes */
+ i64 szPMA; /* Size of pList as PMA in bytes */
};
/*
@@ -100023,7 +103582,7 @@ struct MergeEngine {
**
** Essentially, this structure contains all those fields of the VdbeSorter
** structure for which each thread requires a separate instance. For example,
-** each thread requries its own UnpackedRecord object to unpack records in
+** each thread requeries its own UnpackedRecord object to unpack records in
** as part of comparison operations.
**
** Before a background thread is launched, variable bDone is set to 0. Then,
@@ -100047,10 +103606,10 @@ typedef int (*SorterCompare)(SortSubtask*,int*,const void*,int,const void*,int);
struct SortSubtask {
SQLiteThread *pThread; /* Background thread, if any */
int bDone; /* Set if thread is finished but not joined */
+ int nPMA; /* Number of PMAs currently in file */
VdbeSorter *pSorter; /* Sorter that owns this sub-task */
UnpackedRecord *pUnpacked; /* Space to unpack a record */
SorterList list; /* List for thread to write to a PMA */
- int nPMA; /* Number of PMAs currently in file */
SorterCompare xCompare; /* Compare function to use */
SorterFile file; /* Temp file for level-0 PMAs */
SorterFile file2; /* Space for other PMAs */
@@ -100095,7 +103654,7 @@ struct VdbeSorter {
** PMA, in sorted order. The next key to be read is cached in nKey/aKey.
** aKey might point into aMap or into aBuffer. If neither of those locations
** contain a contiguous representation of the key, then aAlloc is allocated
-** and the key is copied into aAlloc and aKey is made to poitn to aAlloc.
+** and the key is copied into aAlloc and aKey is made to point to aAlloc.
**
** pFd==0 at EOF.
*/
@@ -100308,13 +103867,14 @@ static int vdbePmaReadBlob(
while( nRem>0 ){
int rc; /* vdbePmaReadBlob() return code */
int nCopy; /* Number of bytes to copy */
- u8 *aNext; /* Pointer to buffer to copy data from */
+ u8 *aNext = 0; /* Pointer to buffer to copy data from */
nCopy = nRem;
if( nRem>p->nBuffer ) nCopy = p->nBuffer;
rc = vdbePmaReadBlob(p, nCopy, &aNext);
if( rc!=SQLITE_OK ) return rc;
assert( aNext!=p->aAlloc );
+ assert( aNext!=0 );
memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy);
nRem -= nCopy;
}
@@ -101466,7 +105026,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
** the background thread from a sub-tasks previous turn is still running,
** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy,
** fall back to using the final sub-task. The first (pSorter->nTask-1)
- ** sub-tasks are prefered as they use background threads - the final
+ ** sub-tasks are preferred as they use background threads - the final
** sub-task uses the main thread. */
for(i=0; i<nWorker; i++){
int iTest = (pSorter->iPrev + i + 1) % nWorker;
@@ -101524,8 +105084,8 @@ SQLITE_PRIVATE int wx_sqlite3VdbeSorterWrite(
int rc = SQLITE_OK; /* Return Code */
SorterRecord *pNew; /* New list element */
int bFlush; /* True to flush contents of memory to PMA */
- int nReq; /* Bytes of memory required */
- int nPMA; /* Bytes of PMA space required */
+ i64 nReq; /* Bytes of memory required */
+ i64 nPMA; /* Bytes of PMA space required */
int t; /* serial type of first record field */
assert( pCsr->eCurType==CURTYPE_SORTER );
@@ -101950,7 +105510,7 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode);
- /* Set up the required files for pIncr. A multi-theaded IncrMerge object
+ /* Set up the required files for pIncr. A multi-threaded IncrMerge object
** requires two temp files to itself, whereas a single-threaded object
** only requires a region of pTask->file2. */
if( rc==SQLITE_OK ){
@@ -102590,6 +106150,8 @@ static int bytecodevtabConnect(
"p5 INT,"
"comment TEXT,"
"subprog TEXT,"
+ "nexec INT,"
+ "ncycle INT,"
"stmt HIDDEN"
");",
@@ -102752,7 +106314,7 @@ static int bytecodevtabColumn(
}
}
}
- i += 10;
+ i += 20;
}
}
switch( i ){
@@ -102802,16 +106364,31 @@ static int bytecodevtabColumn(
}
break;
}
- case 10: /* tables_used.type */
+
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ case 9: /* nexec */
+ wx_sqlite3_result_int64(ctx, pOp->nExec);
+ break;
+ case 10: /* ncycle */
+ wx_sqlite3_result_int64(ctx, pOp->nCycle);
+ break;
+#else
+ case 9: /* nexec */
+ case 10: /* ncycle */
+ wx_sqlite3_result_int(ctx, 0);
+ break;
+#endif
+
+ case 20: /* tables_used.type */
wx_sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
break;
- case 11: /* tables_used.schema */
+ case 21: /* tables_used.schema */
wx_sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
break;
- case 12: /* tables_used.name */
+ case 22: /* tables_used.name */
wx_sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
break;
- case 13: /* tables_used.wr */
+ case 23: /* tables_used.wr */
wx_sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
break;
}
@@ -102885,7 +106462,7 @@ static int bytecodevtabBestIndex(
int rc = SQLITE_CONSTRAINT;
struct wx_sqlite3_index_constraint *p;
bytecodevtab *pVTab = (bytecodevtab*)tab;
- int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
+ int iBaseCol = pVTab->bTablesUsed ? 4 : 10;
pIdxInfo->estimatedCost = (double)100;
pIdxInfo->estimatedRows = 100;
pIdxInfo->idxNum = 0;
@@ -102932,7 +106509,8 @@ static wx_sqlite3_module bytecodevtabModule = {
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
- /* xShadowName */ 0
+ /* xShadowName */ 0,
+ /* xIntegrity */ 0
};
@@ -103456,7 +107034,7 @@ static int walkWindowList(Walker *pWalker, Window *pList, int bOneOnly){
** The return value from this routine is WRC_Abort to abandon the tree walk
** and WRC_Continue to continue.
*/
-static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
+SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3WalkExprNN(Walker *pWalker, Expr *pExpr){
int rc;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
@@ -103465,7 +107043,9 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
if( rc ) return rc & WRC_Abort;
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
assert( pExpr->x.pList==0 || pExpr->pRight==0 );
- if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
+ if( pExpr->pLeft && wx_sqlite3WalkExprNN(pWalker, pExpr->pLeft) ){
+ return WRC_Abort;
+ }
if( pExpr->pRight ){
assert( !ExprHasProperty(pExpr, EP_WinFunc) );
pExpr = pExpr->pRight;
@@ -103489,7 +107069,7 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
SQLITE_PRIVATE int wx_sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
- return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;
+ return pExpr ? wx_sqlite3WalkExprNN(pWalker,pExpr) : WRC_Continue;
}
/*
@@ -103564,7 +107144,9 @@ SQLITE_PRIVATE int wx_sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
pSrc = p->pSrc;
if( ALWAYS(pSrc) ){
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
- if( pItem->pSelect && wx_sqlite3WalkSelect(pWalker, pItem->pSelect) ){
+ if( pItem->fg.isSubquery
+ && wx_sqlite3WalkSelect(pWalker, pItem->u4.pSubq->pSelect)
+ ){
return WRC_Abort;
}
if( pItem->fg.isTabFunc
@@ -103615,7 +107197,7 @@ SQLITE_PRIVATE int wx_sqlite3WalkSelect(Walker *pWalker, Select *p){
}
/* Increase the walkerDepth when entering a subquery, and
-** descrease when leaving the subquery.
+** decrease when leaving the subquery.
*/
SQLITE_PRIVATE int wx_sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){
UNUSED_PARAMETER(pSelect);
@@ -103734,6 +107316,8 @@ static void resolveAlias(
assert( iCol>=0 && iCol<pEList->nExpr );
pOrig = pEList->a[iCol].pExpr;
assert( pOrig!=0 );
+ assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) );
+ if( pExpr->pAggInfo ) return;
db = pParse->db;
pDup = wx_sqlite3ExprDup(db, pOrig, 0);
if( db->mallocFailed ){
@@ -103759,21 +107343,36 @@ static void resolveAlias(
}
/*
-** Subqueries stores the original database, table and column names for their
-** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
-** Check to see if the zSpan given to this routine matches the zDb, zTab,
-** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
-** match anything.
+** Subqueries store the original database, table and column names for their
+** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN",
+** and mark the expression-list item by setting ExprList.a[].fg.eEName
+** to ENAME_TAB.
+**
+** Check to see if the zSpan/eEName of the expression-list item passed to this
+** routine matches the zDb, zTab, and zCol. If any of zDb, zTab, and zCol are
+** NULL then those fields will match anything. Return true if there is a match,
+** or false otherwise.
+**
+** SF_NestedFrom subqueries also store an entry for the implicit rowid (or
+** _rowid_, or oid) column by setting ExprList.a[].fg.eEName to ENAME_ROWID,
+** and setting zSpan to "DATABASE.TABLE.<rowid-alias>". This type of pItem
+** argument matches if zCol is a rowid alias. If it is not NULL, (*pbRowid)
+** is set to 1 if there is this kind of match.
*/
SQLITE_PRIVATE int wx_sqlite3MatchEName(
const struct ExprList_item *pItem,
const char *zCol,
const char *zTab,
- const char *zDb
+ const char *zDb,
+ int *pbRowid
){
int n;
const char *zSpan;
- if( pItem->fg.eEName!=ENAME_TAB ) return 0;
+ int eEName = pItem->fg.eEName;
+ if( eEName!=ENAME_TAB && (eEName!=ENAME_ROWID || NEVER(pbRowid==0)) ){
+ return 0;
+ }
+ assert( pbRowid==0 || *pbRowid==0 );
zSpan = pItem->zEName;
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
if( zDb && (wx_sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
@@ -103785,9 +107384,11 @@ SQLITE_PRIVATE int wx_sqlite3MatchEName(
return 0;
}
zSpan += n+1;
- if( zCol && wx_sqlite3StrICmp(zSpan, zCol)!=0 ){
- return 0;
+ if( zCol ){
+ if( eEName==ENAME_TAB && wx_sqlite3StrICmp(zSpan, zCol)!=0 ) return 0;
+ if( eEName==ENAME_ROWID && wx_sqlite3IsRowid(zCol)==0 ) return 0;
}
+ if( eEName==ENAME_ROWID ) *pbRowid = 1;
return 1;
}
@@ -103820,6 +107421,7 @@ SQLITE_PRIVATE Bitmask wx_sqlite3ExprColUsed(Expr *pExpr){
assert( ExprUseYTab(pExpr) );
pExTab = pExpr->y.pTab;
assert( pExTab!=0 );
+ assert( n < pExTab->nCol );
if( (pExTab->tabFlags & TF_HasGenerated)!=0
&& (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0
){
@@ -103850,7 +107452,7 @@ static void extendFJMatch(
if( pNew ){
pNew->iTable = pMatch->iCursor;
pNew->iColumn = iColumn;
- pNew->y.pTab = pMatch->pTab;
+ pNew->y.pTab = pMatch->pSTab;
assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 );
ExprSetProperty(pNew, EP_CanBeNull);
*ppList = wx_sqlite3ExprListAppend(pParse, *ppList, pNew);
@@ -103863,7 +107465,7 @@ static void extendFJMatch(
static SQLITE_NOINLINE int isValidSchemaTableName(
const char *zTab, /* Name as it appears in the SQL */
Table *pTab, /* The schema table we are trying to match */
- Schema *pSchema /* non-NULL if a database qualifier is present */
+ const char *zDb /* non-NULL if a database qualifier is present */
){
const char *zLegacy;
assert( pTab!=0 );
@@ -103874,7 +107476,7 @@ static SQLITE_NOINLINE int isValidSchemaTableName(
if( wx_sqlite3StrICmp(zTab+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){
return 1;
}
- if( pSchema==0 ) return 0;
+ if( zDb==0 ) return 0;
if( wx_sqlite3StrICmp(zTab+7, &LEGACY_SCHEMA_TABLE[7])==0 ) return 1;
if( wx_sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1;
}else{
@@ -103914,13 +107516,13 @@ static int lookupName(
Parse *pParse, /* The parsing context */
const char *zDb, /* Name of the database containing table, or NULL */
const char *zTab, /* Name of table containing column, or NULL */
- const char *zCol, /* Name of the column. */
+ const Expr *pRight, /* Name of the column. */
NameContext *pNC, /* The name context used to resolve the name */
Expr *pExpr /* Make this EXPR node point to the selected column */
){
int i, j; /* Loop counters */
int cnt = 0; /* Number of matching column names */
- int cntTab = 0; /* Number of matching table names */
+ int cntTab = 0; /* Number of potential "rowid" matches */
int nSubquery = 0; /* How many levels of subquery */
wx_sqlite3 *db = pParse->db; /* The database connection */
SrcItem *pItem; /* Use for looping over pSrcList items */
@@ -103931,6 +107533,7 @@ static int lookupName(
Table *pTab = 0; /* Table holding the row */
Column *pCol; /* A column of pTab */
ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */
+ const char *zCol = pRight->u.zToken;
assert( pNC ); /* the name context cannot be NULL. */
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
@@ -103980,10 +107583,10 @@ static int lookupName(
if( pSrcList ){
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
u8 hCol;
- pTab = pItem->pTab;
+ pTab = pItem->pSTab;
assert( pTab!=0 && pTab->zName!=0 );
assert( pTab->nCol>0 || pParse->nErr );
- assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem));
if( pItem->fg.isNestedFrom ){
/* In this case, pItem is a subquery that has been formed from a
** parenthesized subset of the FROM clause terms. Example:
@@ -103992,44 +107595,58 @@ static int lookupName(
** This pItem -------------^
*/
int hit = 0;
- assert( pItem->pSelect!=0 );
- pEList = pItem->pSelect->pEList;
+ Select *pSel;
+ assert( pItem->fg.isSubquery );
+ assert( pItem->u4.pSubq!=0 );
+ pSel = pItem->u4.pSubq->pSelect;
+ assert( pSel!=0 );
+ pEList = pSel->pEList;
assert( pEList!=0 );
assert( pEList->nExpr==pTab->nCol );
for(j=0; j<pEList->nExpr; j++){
- if( !wx_sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
+ int bRowid = 0; /* True if possible rowid match */
+ if( !wx_sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){
continue;
}
- if( cnt>0 ){
- if( pItem->fg.isUsing==0
- || wx_sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
- ){
- /* Two or more tables have the same column name which is
- ** not joined by USING. This is an error. Signal as much
- ** by clearing pFJMatch and letting cnt go above 1. */
- wx_sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else
- if( (pItem->fg.jointype & JT_RIGHT)==0 ){
- /* An INNER or LEFT JOIN. Use the left-most table */
- continue;
- }else
- if( (pItem->fg.jointype & JT_LEFT)==0 ){
- /* A RIGHT JOIN. Use the right-most table */
- cnt = 0;
- wx_sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else{
- /* For a FULL JOIN, we must construct a coalesce() func */
- extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
+ if( bRowid==0 ){
+ if( cnt>0 ){
+ if( pItem->fg.isUsing==0
+ || wx_sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
+ ){
+ /* Two or more tables have the same column name which is
+ ** not joined by USING. This is an error. Signal as much
+ ** by clearing pFJMatch and letting cnt go above 1. */
+ wx_sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else
+ if( (pItem->fg.jointype & JT_RIGHT)==0 ){
+ /* An INNER or LEFT JOIN. Use the left-most table */
+ continue;
+ }else
+ if( (pItem->fg.jointype & JT_LEFT)==0 ){
+ /* A RIGHT JOIN. Use the right-most table */
+ cnt = 0;
+ wx_sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else{
+ /* For a FULL JOIN, we must construct a coalesce() func */
+ extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
+ }
}
+ cnt++;
+ hit = 1;
+ }else if( cnt>0 ){
+ /* This is a potential rowid match, but there has already been
+ ** a real match found. So this can be ignored. */
+ continue;
}
- cnt++;
- cntTab = 2;
+ cntTab++;
pMatch = pItem;
pExpr->iColumn = j;
pEList->a[j].fg.bUsed = 1;
- hit = 1;
+
+ /* rowid cannot be part of a USING clause - assert() this. */
+ assert( bRowid==0 || pEList->a[j].fg.bUsingTerm==0 );
if( pEList->a[j].fg.bUsingTerm ) break;
}
if( hit || zTab==0 ) continue;
@@ -104046,7 +107663,7 @@ static int lookupName(
}
}else if( wx_sqlite3StrICmp(zTab, pTab->zName)!=0 ){
if( pTab->tnum!=1 ) continue;
- if( !isValidSchemaTableName(zTab, pTab, pSchema) ) continue;
+ if( !isValidSchemaTableName(zTab, pTab, zDb) ) continue;
}
assert( ExprUseYTab(pExpr) );
if( IN_RENAME_OBJECT && pItem->zAlias ){
@@ -104093,14 +107710,43 @@ static int lookupName(
}
}
if( 0==cnt && VisibleRowid(pTab) ){
+ /* pTab is a potential ROWID match. Keep track of it and match
+ ** the ROWID later if that seems appropriate. (Search for "cntTab"
+ ** to find related code.) Only allow a ROWID match if there is
+ ** a single ROWID match candidate.
+ */
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ /* In SQLITE_ALLOW_ROWID_IN_VIEW mode, allow a ROWID match
+ ** if there is a single VIEW candidate or if there is a single
+ ** non-VIEW candidate plus multiple VIEW candidates. In other
+ ** words non-VIEW candidate terms take precedence over VIEWs.
+ */
+ if( cntTab==0
+ || (cntTab==1
+ && pMatch!=0
+ && ALWAYS(pMatch->pSTab!=0)
+ && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0
+ && (pTab->tabFlags & TF_Ephemeral)==0)
+ ){
+ cntTab = 1;
+ pMatch = pItem;
+ }else{
+ cntTab++;
+ }
+#else
+ /* The (much more common) non-SQLITE_ALLOW_ROWID_IN_VIEW case is
+ ** simpler since we require exactly one candidate, which will
+ ** always be a non-VIEW
+ */
cntTab++;
pMatch = pItem;
+#endif
}
}
if( pMatch ){
pExpr->iTable = pMatch->iCursor;
assert( ExprUseYTab(pExpr) );
- pExpr->y.pTab = pMatch->pTab;
+ pExpr->y.pTab = pMatch->pSTab;
if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){
ExprSetProperty(pExpr, EP_CanBeNull);
}
@@ -104122,7 +107768,9 @@ static int lookupName(
assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
if( pParse->bReturning ){
if( (pNC->ncFlags & NC_UBaseReg)!=0
- && (zTab==0 || wx_sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0)
+ && ALWAYS(zTab==0
+ || wx_sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0
+ || isValidSchemaTableName(zTab, pParse->pTriggerTab, 0))
){
pExpr->iTable = op!=TK_DELETE;
pTab = pParse->pTriggerTab;
@@ -104140,7 +107788,7 @@ static int lookupName(
if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){
Upsert *pUpsert = pNC->uNC.pUpsert;
if( pUpsert && wx_sqlite3StrICmp("excluded",zTab)==0 ){
- pTab = pUpsert->pUpsertSrc->a[0].pTab;
+ pTab = pUpsert->pUpsertSrc->a[0].pSTab;
pExpr->iTable = EXCLUDED_TABLE_NUMBER;
}
}
@@ -104219,14 +107867,19 @@ static int lookupName(
** Perhaps the name is a reference to the ROWID
*/
if( cnt==0
- && cntTab==1
+ && cntTab>=1
&& pMatch
&& (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
&& wx_sqlite3IsRowid(zCol)
- && ALWAYS(VisibleRowid(pMatch->pTab))
+ && ALWAYS(VisibleRowid(pMatch->pSTab) || pMatch->fg.isNestedFrom)
){
- cnt = 1;
- pExpr->iColumn = -1;
+ cnt = cntTab;
+#if SQLITE_ALLOW_ROWID_IN_VIEW+0==2
+ if( pMatch->pSTab!=0 && IsView(pMatch->pSTab) ){
+ eNewExprOp = TK_NULL;
+ }
+#endif
+ if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1;
pExpr->affExpr = SQLITE_AFF_INTEGER;
}
@@ -104379,12 +108032,17 @@ static int lookupName(
wx_sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol);
}else if( zTab ){
wx_sqlite3ErrorMsg(pParse, "%s: %s.%s", zErr, zTab, zCol);
+ }else if( cnt==0 && ExprHasProperty(pRight,EP_DblQuoted) ){
+ wx_sqlite3ErrorMsg(pParse, "%s: \"%s\" - should this be a"
+ " string literal in single-quotes?",
+ zErr, zCol);
}else{
wx_sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol);
}
wx_sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr);
pParse->checkSchema = 1;
pTopNC->nNcErr++;
+ eNewExprOp = TK_NULL;
}
assert( pFJMatch==0 );
@@ -104411,8 +108069,12 @@ static int lookupName(
** If a generated column is referenced, set bits for every column
** of the table.
*/
- if( pExpr->iColumn>=0 && pMatch!=0 ){
- pMatch->colUsed |= wx_sqlite3ExprColUsed(pExpr);
+ if( pMatch ){
+ if( pExpr->iColumn>=0 ){
+ pMatch->colUsed |= wx_sqlite3ExprColUsed(pExpr);
+ }else{
+ pMatch->fg.rowidUsed = 1;
+ }
}
pExpr->op = eNewExprOp;
@@ -104450,7 +108112,7 @@ SQLITE_PRIVATE Expr *wx_sqlite3CreateColumnExpr(wx_sqlite3 *db, SrcList *pSrc, i
SrcItem *pItem = &pSrc->a[iSrc];
Table *pTab;
assert( ExprUseYTab(p) );
- pTab = p->y.pTab = pItem->pTab;
+ pTab = p->y.pTab = pItem->pSTab;
p->iTable = pItem->iCursor;
if( p->y.pTab->iPKey==iCol ){
p->iColumn = -1;
@@ -104569,7 +108231,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pItem = pSrcList->a;
pExpr->op = TK_COLUMN;
assert( ExprUseYTab(pExpr) );
- pExpr->y.pTab = pItem->pTab;
+ pExpr->y.pTab = pItem->pSTab;
pExpr->iTable = pItem->iCursor;
pExpr->iColumn--;
pExpr->affExpr = SQLITE_AFF_INTEGER;
@@ -104589,6 +108251,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
** resolved. This prevents "column" from being counted as having been
** referenced, which might prevent a SELECT from being erroneously
** marked as correlated.
+ **
+ ** 2024-03-28: Beware of aggregates. A bare column of aggregated table
+ ** can still evaluate to NULL even though it is marked as NOT NULL.
+ ** Example:
+ **
+ ** CREATE TABLE t1(a INT NOT NULL);
+ ** SELECT a, a IS NULL, a IS NOT NULL, count(*) FROM t1;
+ **
+ ** The "a IS NULL" and "a IS NOT NULL" expressions cannot be optimized
+ ** here because at the time this case is hit, we do not yet know whether
+ ** or not t1 is being aggregated. We have to assume the worst and omit
+ ** the optimization. The only time it is safe to apply this optimization
+ ** is within the WHERE clause.
*/
case TK_NOTNULL:
case TK_ISNULL: {
@@ -104599,19 +108274,36 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
anRef[i] = p->nRef;
}
wx_sqlite3WalkExpr(pWalker, pExpr->pLeft);
- if( 0==wx_sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){
- testcase( ExprHasProperty(pExpr, EP_OuterON) );
- assert( !ExprHasProperty(pExpr, EP_IntValue) );
- pExpr->u.iValue = (pExpr->op==TK_NOTNULL);
- pExpr->flags |= EP_IntValue;
- pExpr->op = TK_INTEGER;
+ if( IN_RENAME_OBJECT ) return WRC_Prune;
+ if( wx_sqlite3ExprCanBeNull(pExpr->pLeft) ){
+ /* The expression can be NULL. So the optimization does not apply */
+ return WRC_Prune;
+ }
- for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
- p->nRef = anRef[i];
+ for(i=0, p=pNC; p; p=p->pNext, i++){
+ if( (p->ncFlags & NC_Where)==0 ){
+ return WRC_Prune; /* Not in a WHERE clause. Unsafe to optimize. */
}
- wx_sqlite3ExprDelete(pParse->db, pExpr->pLeft);
- pExpr->pLeft = 0;
}
+ testcase( ExprHasProperty(pExpr, EP_OuterON) );
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+#if TREETRACE_ENABLED
+ if( wx_sqlite3TreeTrace & 0x80000 ){
+ wx_sqlite3DebugPrintf(
+ "NOT NULL strength reduction converts the following to %d:\n",
+ pExpr->op==TK_NOTNULL
+ );
+ wx_sqlite3ShowExpr(pExpr);
+ }
+#endif /* TREETRACE_ENABLED */
+ pExpr->u.iValue = (pExpr->op==TK_NOTNULL);
+ pExpr->flags |= EP_IntValue;
+ pExpr->op = TK_INTEGER;
+ for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
+ p->nRef = anRef[i];
+ }
+ wx_sqlite3ExprDelete(pParse->db, pExpr->pLeft);
+ pExpr->pLeft = 0;
return WRC_Prune;
}
@@ -104625,7 +108317,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
*/
case TK_ID:
case TK_DOT: {
- const char *zColumn;
const char *zTable;
const char *zDb;
Expr *pRight;
@@ -104634,7 +108325,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
zDb = 0;
zTable = 0;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- zColumn = pExpr->u.zToken;
+ pRight = pExpr;
}else{
Expr *pLeft = pExpr->pLeft;
testcase( pNC->ncFlags & NC_IdxExpr );
@@ -104653,21 +108344,20 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
assert( ExprUseUToken(pLeft) && ExprUseUToken(pRight) );
zTable = pLeft->u.zToken;
- zColumn = pRight->u.zToken;
assert( ExprUseYTab(pExpr) );
if( IN_RENAME_OBJECT ){
wx_sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight);
wx_sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft);
}
}
- return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
+ return lookupName(pParse, zDb, zTable, pRight, pNC, pExpr);
}
/* Resolve function names
*/
case TK_FUNCTION: {
- ExprList *pList = pExpr->x.pList; /* The argument list */
- int n = pList ? pList->nExpr : 0; /* Number of arguments */
+ ExprList *pList; /* The argument list */
+ int n; /* Number of arguments */
int no_such_func = 0; /* True if no such function exists */
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
@@ -104679,6 +108369,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0);
#endif
assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
+ assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER );
+ pList = pExpr->x.pList;
+ n = pList ? pList->nExpr : 0;
zId = pExpr->u.zToken;
pDef = wx_sqlite3FindFunction(pParse->db, zId, n, enc, 0);
if( pDef==0 ){
@@ -104727,6 +108420,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
}
#endif
+
+ /* If the function may call wx_sqlite3_value_subtype(), then set the
+ ** EP_SubtArg flag on all of its argument expressions. This prevents
+ ** where.c from replacing the expression with a value read from an
+ ** index on the same expression, which will not have the correct
+ ** subtype. Also set the flag if the function expression itself is
+ ** an EP_SubtArg expression. In this case subtypes are required as
+ ** the function may return a value with a subtype back to its
+ ** caller using wx_sqlite3_result_value(). */
+ if( (pDef->funcFlags & SQLITE_SUBTYPE)
+ || ExprHasProperty(pExpr, EP_SubtArg)
+ ){
+ int ii;
+ for(ii=0; ii<n; ii++){
+ ExprSetProperty(pList->a[ii].pExpr, EP_SubtArg);
+ }
+ }
+
if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
/* For the purposes of the EP_ConstFunc flag, date and time
** functions and other functions that change slowly are considered
@@ -104820,6 +108531,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pNC->nNcErr++;
}
#endif
+ else if( is_agg==0 && pExpr->pLeft ){
+ wx_sqlite3ExprOrderByAggregateError(pParse, pExpr);
+ pNC->nNcErr++;
+ }
if( is_agg ){
/* Window functions may not be arguments of aggregate functions.
** Or arguments of other window functions. But aggregate functions
@@ -104831,17 +108546,20 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
#endif
}
}
-#ifndef SQLITE_OMIT_WINDOWFUNC
- else if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ else if( ExprHasProperty(pExpr, EP_WinFunc) || pExpr->pLeft ){
is_agg = 1;
}
-#endif
wx_sqlite3WalkExprList(pWalker, pList);
if( is_agg ){
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ wx_sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList);
+ }
#ifndef SQLITE_OMIT_WINDOWFUNC
- if( pWin ){
+ if( pWin && pParse->nErr==0 ){
Select *pSel = pNC->pWinSelect;
- assert( pWin==0 || (ExprUseYWin(pExpr) && pWin==pExpr->y.pWin) );
+ assert( ExprUseYWin(pExpr) && pWin==pExpr->y.pWin );
if( IN_RENAME_OBJECT==0 ){
wx_sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef);
if( pParse->db->mallocFailed ) break;
@@ -104866,11 +108584,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
while( pNC2
&& wx_sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0
){
- pExpr->op2++;
+ pExpr->op2 += (1 + pNC2->nNestedSelect);
pNC2 = pNC2->pNext;
}
assert( pDef!=0 || IN_RENAME_OBJECT );
if( pNC2 && pDef ){
+ pExpr->op2 += pNC2->nNestedSelect;
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg );
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
@@ -104899,6 +108618,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
testcase( pNC->ncFlags & NC_PartIdx );
testcase( pNC->ncFlags & NC_IdxExpr );
testcase( pNC->ncFlags & NC_GenCol );
+ assert( pExpr->x.pSelect );
if( pNC->ncFlags & NC_SelfRef ){
notValidImpl(pParse, pNC, "subqueries", pExpr, pExpr);
}else{
@@ -104907,6 +108627,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
+ pExpr->x.pSelect->selFlags |= SF_Correlated;
}
pNC->ncFlags |= NC_Subquery;
}
@@ -105045,7 +108766,7 @@ static int resolveOrderByTermToExprList(
int rc; /* Return code from subprocedures */
u8 savedSuppErr; /* Saved value of db->suppressErr */
- assert( wx_sqlite3ExprIsInteger(pE, &i)==0 );
+ assert( wx_sqlite3ExprIsInteger(pE, &i, 0)==0 );
pEList = pSelect->pEList;
/* Resolve all names in the ORDER BY term expression
@@ -105144,7 +108865,7 @@ static int resolveCompoundOrderBy(
if( pItem->fg.done ) continue;
pE = wx_sqlite3ExprSkipCollateAndLikely(pItem->pExpr);
if( NEVER(pE==0) ) continue;
- if( wx_sqlite3ExprIsInteger(pE, &iCol) ){
+ if( wx_sqlite3ExprIsInteger(pE, &iCol, 0) ){
if( iCol<=0 || iCol>pEList->nExpr ){
resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr, pE);
return 1;
@@ -105329,7 +109050,7 @@ static int resolveOrderGroupBy(
continue;
}
}
- if( wx_sqlite3ExprIsInteger(pE2, &iCol) ){
+ if( wx_sqlite3ExprIsInteger(pE2, &iCol, 0) ){
/* The ORDER BY term is an integer constant. Again, set the column
** number so that wx_sqlite3ResolveOrderGroupBy() will convert the
** order-by term to a copy of the result-set expression */
@@ -105348,7 +109069,7 @@ static int resolveOrderGroupBy(
}
for(j=0; j<pSelect->pEList->nExpr; j++){
if( wx_sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
- /* Since this expresion is being changed into a reference
+ /* Since this expression is being changed into a reference
** to an identical expression in the result set, remove all Window
** objects belonging to the expression from the Select.pWin list. */
windowRemoveExprFromSelect(pSelect, pE);
@@ -105401,10 +109122,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
while( p ){
assert( (p->selFlags & SF_Expanded)!=0 );
assert( (p->selFlags & SF_Resolved)==0 );
- assert( db->suppressErr==0 ); /* SF_Resolved not set if errors suppressed */
p->selFlags |= SF_Resolved;
-
/* Resolve the expressions in the LIMIT and OFFSET clauses. These
** are not allowed to refer to any names, so pass an empty NameContext.
*/
@@ -105422,7 +109141,11 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** moves the pOrderBy down to the sub-query. It will be moved back
** after the names have been resolved. */
if( p->selFlags & SF_Converted ){
- Select *pSub = p->pSrc->a[0].pSelect;
+ Select *pSub;
+ assert( p->pSrc->a[0].fg.isSubquery );
+ assert( p->pSrc->a[0].u4.pSubq!=0 );
+ pSub = p->pSrc->a[0].u4.pSubq->pSelect;
+ assert( pSub!=0 );
assert( p->pSrc->nSrc==1 && p->pOrderBy );
assert( pSub->pPrior && pSub->pOrderBy==0 );
pSub->pOrderBy = p->pOrderBy;
@@ -105431,14 +109154,19 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
/* Recursively resolve names in all subqueries in the FROM clause
*/
+ if( pOuterNC ) pOuterNC->nNestedSelect++;
for(i=0; i<p->pSrc->nSrc; i++){
SrcItem *pItem = &p->pSrc->a[i];
- if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
+ assert( pItem->zName!=0
+ || pItem->fg.isSubquery ); /* Test of tag-20240424-1*/
+ if( pItem->fg.isSubquery
+ && (pItem->u4.pSubq->pSelect->selFlags & SF_Resolved)==0
+ ){
int nRef = pOuterNC ? pOuterNC->nRef : 0;
const char *zSavedContext = pParse->zAuthContext;
if( pItem->zName ) pParse->zAuthContext = pItem->zName;
- wx_sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC);
+ wx_sqlite3ResolveSelectNames(pParse, pItem->u4.pSubq->pSelect, pOuterNC);
pParse->zAuthContext = zSavedContext;
if( pParse->nErr ) return WRC_Abort;
assert( db->mallocFailed==0 );
@@ -105455,6 +109183,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
}
}
+ if( pOuterNC && ALWAYS(pOuterNC->nNestedSelect>0) ){
+ pOuterNC->nNestedSelect--;
+ }
/* Set up the local name-context to pass to wx_sqlite3ResolveExprNames() to
** resolve the result-set expression list.
@@ -105498,7 +109229,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
if( wx_sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
}
+ sNC.ncFlags |= NC_Where;
if( wx_sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
+ sNC.ncFlags &= ~NC_Where;
/* Resolve names in table-valued-function arguments */
for(i=0; i<p->pSrc->nSrc; i++){
@@ -105535,7 +109268,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** These integers will be replaced by copies of the corresponding result
** set expressions by the call to resolveOrderGroupBy() below. */
if( p->selFlags & SF_Converted ){
- Select *pSub = p->pSrc->a[0].pSelect;
+ Select *pSub;
+ assert( p->pSrc->a[0].fg.isSubquery );
+ pSub = p->pSrc->a[0].u4.pSubq->pSelect;
+ assert( pSub!=0 );
p->pOrderBy = pSub->pOrderBy;
pSub->pOrderBy = 0;
}
@@ -105671,7 +109407,8 @@ SQLITE_PRIVATE int wx_sqlite3ResolveExprNames(
return SQLITE_ERROR;
}
#endif
- wx_sqlite3WalkExpr(&w, pExpr);
+ assert( pExpr!=0 );
+ wx_sqlite3WalkExprNN(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
w.pParse->nHeight -= pExpr->nHeight;
#endif
@@ -105688,6 +109425,9 @@ SQLITE_PRIVATE int wx_sqlite3ResolveExprNames(
** Resolve all names for all expression in an expression list. This is
** just like wx_sqlite3ResolveExprNames() except that it works for an expression
** list rather than a single expression.
+**
+** The return value is SQLITE_OK (0) for success or SQLITE_ERROR (1) for a
+** failure.
*/
SQLITE_PRIVATE int wx_sqlite3ResolveExprListNames(
NameContext *pNC, /* Namespace to resolve expressions in. */
@@ -105696,7 +109436,7 @@ SQLITE_PRIVATE int wx_sqlite3ResolveExprListNames(
int i;
int savedHasAgg = 0;
Walker w;
- if( pList==0 ) return WRC_Continue;
+ if( pList==0 ) return SQLITE_OK;
w.pParse = pNC->pParse;
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
@@ -105710,10 +109450,10 @@ SQLITE_PRIVATE int wx_sqlite3ResolveExprListNames(
#if SQLITE_MAX_EXPR_DEPTH>0
w.pParse->nHeight += pExpr->nHeight;
if( wx_sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
- return WRC_Abort;
+ return SQLITE_ERROR;
}
#endif
- wx_sqlite3WalkExpr(&w, pExpr);
+ wx_sqlite3WalkExprNN(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
w.pParse->nHeight -= pExpr->nHeight;
#endif
@@ -105727,15 +109467,15 @@ SQLITE_PRIVATE int wx_sqlite3ResolveExprListNames(
(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
}
- if( w.pParse->nErr>0 ) return WRC_Abort;
+ if( w.pParse->nErr>0 ) return SQLITE_ERROR;
}
pNC->ncFlags |= savedHasAgg;
- return WRC_Continue;
+ return SQLITE_OK;
}
/*
** Resolve all names in all expressions of a SELECT and in all
-** decendents of the SELECT, including compounds off of p->pPrior,
+** descendants of the SELECT, including compounds off of p->pPrior,
** subqueries in expressions, and subqueries used as FROM clause
** terms.
**
@@ -105798,7 +109538,7 @@ SQLITE_PRIVATE int wx_sqlite3ResolveSelfReference(
if( pTab ){
sSrc.nSrc = 1;
sSrc.a[0].zName = pTab->zName;
- sSrc.a[0].pTab = pTab;
+ sSrc.a[0].pSTab = pTab;
sSrc.a[0].iCursor = -1;
if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
/* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP
@@ -105885,6 +109625,7 @@ SQLITE_PRIVATE char wx_sqlite3ExprAffinity(const Expr *pExpr){
if( op==TK_SELECT_COLUMN ){
assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) );
assert( pExpr->iColumn < pExpr->iTable );
+ assert( pExpr->iColumn >= 0 );
assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr );
return wx_sqlite3ExprAffinity(
pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
@@ -105902,7 +109643,9 @@ SQLITE_PRIVATE char wx_sqlite3ExprAffinity(const Expr *pExpr){
op = pExpr->op;
continue;
}
- if( op!=TK_REGISTER || (op = pExpr->op2)==TK_REGISTER ) break;
+ if( op!=TK_REGISTER ) break;
+ op = pExpr->op2;
+ if( NEVER( op==TK_REGISTER ) ) break;
}
return pExpr->affExpr;
}
@@ -106035,9 +109778,10 @@ SQLITE_PRIVATE Expr *wx_sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
assert( pExpr->x.pList->nExpr>0 );
assert( pExpr->op==TK_FUNCTION );
pExpr = pExpr->x.pList->a[0].pExpr;
- }else{
- assert( pExpr->op==TK_COLLATE );
+ }else if( pExpr->op==TK_COLLATE ){
pExpr = pExpr->pLeft;
+ }else{
+ break;
}
}
return pExpr;
@@ -106096,11 +109840,10 @@ SQLITE_PRIVATE CollSeq *wx_sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
}else{
Expr *pNext = p->pRight;
/* The Expr.x union is never used at the same time as Expr.pRight */
- assert( ExprUseXList(p) );
- assert( p->x.pList==0 || p->pRight==0 );
- if( p->x.pList!=0 && !db->mallocFailed ){
+ assert( !ExprUseXList(p) || p->x.pList==0 || p->pRight==0 );
+ if( ExprUseXList(p) && p->x.pList!=0 && !db->mallocFailed ){
int i;
- for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
+ for(i=0; i<p->x.pList->nExpr; i++){
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
pNext = p->x.pList->a[i].pExpr;
break;
@@ -106122,7 +109865,7 @@ SQLITE_PRIVATE CollSeq *wx_sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
/*
** Return the collation sequence for the expression pExpr. If
** there is no defined collating sequence, return a pointer to the
-** defautl collation sequence.
+** default collation sequence.
**
** See also: wx_sqlite3ExprCollSeq()
**
@@ -106252,7 +109995,7 @@ SQLITE_PRIVATE CollSeq *wx_sqlite3BinaryCompareCollSeq(
return pColl;
}
-/* Expresssion p is a comparison operator. Return a collation sequence
+/* Expression p is a comparison operator. Return a collation sequence
** appropriate for the comparison operator.
**
** This is normally just a wrapper around wx_sqlite3BinaryCompareCollSeq().
@@ -106409,6 +110152,7 @@ SQLITE_PRIVATE Expr *wx_sqlite3ExprForVectorField(
*/
pRet = wx_sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0);
if( pRet ){
+ ExprSetProperty(pRet, EP_FullSize);
pRet->iTable = nField;
pRet->iColumn = iField;
pRet->pLeft = pVector;
@@ -106709,6 +110453,15 @@ SQLITE_PRIVATE void wx_sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
#endif /* SQLITE_MAX_EXPR_DEPTH>0 */
/*
+** Set the error offset for an Expr node, if possible.
+*/
+SQLITE_PRIVATE void wx_sqlite3ExprSetErrorOffset(Expr *pExpr, int iOfst){
+ if( pExpr==0 ) return;
+ if( NEVER(ExprUseWJoin(pExpr)) ) return;
+ pExpr->w.iOfst = iOfst;
+}
+
+/*
** This routine is the core allocator for Expr nodes.
**
** Construct a new expression node and return a pointer to it. Memory
@@ -106722,11 +110475,12 @@ SQLITE_PRIVATE void wx_sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
** appear to be quoted. If the quotes were of the form "..." (double-quotes)
** then the EP_DblQuoted flag is set on the expression node.
**
-** Special case: If op==TK_INTEGER and pToken points to a string that
-** can be translated into a 32-bit integer, then the token is not
-** stored in u.zToken. Instead, the integer values is written
-** into u.iValue and the EP_IntValue flag is set. No extra storage
+** Special case (tag-20240227-a): If op==TK_INTEGER and pToken points to
+** a string that can be translated into a 32-bit integer, then the token is
+** not stored in u.zToken. Instead, the integer values is written
+** into u.iValue and the EP_IntValue flag is set. No extra storage
** is allocated to hold the integer text and the dequote flag is ignored.
+** See also tag-20240227-b.
*/
SQLITE_PRIVATE Expr *wx_sqlite3ExprAlloc(
wx_sqlite3 *db, /* Handle for wx_sqlite3DbMallocRawNN() */
@@ -106742,7 +110496,7 @@ SQLITE_PRIVATE Expr *wx_sqlite3ExprAlloc(
if( pToken ){
if( op!=TK_INTEGER || pToken->z==0
|| wx_sqlite3GetInt32(pToken->z, &iValue)==0 ){
- nExtra = pToken->n+1;
+ nExtra = pToken->n+1; /* tag-20240227-a */
assert( iValue>=0 );
}
}
@@ -106932,9 +110686,9 @@ SQLITE_PRIVATE Select *wx_sqlite3ExprListToValues(Parse *pParse, int nElem, Expr
** 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.
+** If one side or the other of the AND is known to be false, and neither side
+** is part of an ON clause, then instead of returning an AND expression,
+** just return a constant expression with a value of false.
*/
SQLITE_PRIVATE Expr *wx_sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
wx_sqlite3 *db = pParse->db;
@@ -106942,14 +110696,17 @@ SQLITE_PRIVATE Expr *wx_sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight)
return pRight;
}else if( pRight==0 ){
return pLeft;
- }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight))
- && !IN_RENAME_OBJECT
- ){
- wx_sqlite3ExprDeferredDelete(pParse, pLeft);
- wx_sqlite3ExprDeferredDelete(pParse, pRight);
- return wx_sqlite3Expr(db, TK_INTEGER, "0");
}else{
- return wx_sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
+ u32 f = pLeft->flags | pRight->flags;
+ if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse))==EP_IsFalse
+ && !IN_RENAME_OBJECT
+ ){
+ wx_sqlite3ExprDeferredDelete(pParse, pLeft);
+ wx_sqlite3ExprDeferredDelete(pParse, pRight);
+ return wx_sqlite3Expr(db, TK_INTEGER, "0");
+ }else{
+ return wx_sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
+ }
}
}
@@ -106988,6 +110745,67 @@ SQLITE_PRIVATE Expr *wx_sqlite3ExprFunction(
}
/*
+** Report an error when attempting to use an ORDER BY clause within
+** the arguments of a non-aggregate function.
+*/
+SQLITE_PRIVATE void wx_sqlite3ExprOrderByAggregateError(Parse *pParse, Expr *p){
+ wx_sqlite3ErrorMsg(pParse,
+ "ORDER BY may not be used with non-aggregate %#T()", p
+ );
+}
+
+/*
+** Attach an ORDER BY clause to a function call.
+**
+** functionname( arguments ORDER BY sortlist )
+** \_____________________/ \______/
+** pExpr pOrderBy
+**
+** The ORDER BY clause is inserted into a new Expr node of type TK_ORDER
+** and added to the Expr.pLeft field of the parent TK_FUNCTION node.
+*/
+SQLITE_PRIVATE void wx_sqlite3ExprAddFunctionOrderBy(
+ Parse *pParse, /* Parsing context */
+ Expr *pExpr, /* The function call to which ORDER BY is to be added */
+ ExprList *pOrderBy /* The ORDER BY clause to add */
+){
+ Expr *pOB;
+ wx_sqlite3 *db = pParse->db;
+ if( NEVER(pOrderBy==0) ){
+ assert( db->mallocFailed );
+ return;
+ }
+ if( pExpr==0 ){
+ assert( db->mallocFailed );
+ wx_sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+ assert( pExpr->op==TK_FUNCTION );
+ assert( pExpr->pLeft==0 );
+ assert( ExprUseXList(pExpr) );
+ if( pExpr->x.pList==0 || NEVER(pExpr->x.pList->nExpr==0) ){
+ /* Ignore ORDER BY on zero-argument aggregates */
+ wx_sqlite3ParserAddCleanup(pParse, wx_sqlite3ExprListDeleteGeneric, pOrderBy);
+ return;
+ }
+ if( IsWindowFunc(pExpr) ){
+ wx_sqlite3ExprOrderByAggregateError(pParse, pExpr);
+ wx_sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+
+ pOB = wx_sqlite3ExprAlloc(db, TK_ORDER, 0, 0);
+ if( pOB==0 ){
+ wx_sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+ pOB->x.pList = pOrderBy;
+ assert( ExprUseXList(pOB) );
+ pExpr->pLeft = pOB;
+ ExprSetProperty(pOB, EP_FullSize);
+}
+
+/*
** Check to see if a function is usable according to current access
** rules:
**
@@ -107110,6 +110928,7 @@ SQLITE_PRIVATE void wx_sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u3
static SQLITE_NOINLINE void wx_sqlite3ExprDeleteNN(wx_sqlite3 *db, Expr *p){
assert( p!=0 );
assert( db!=0 );
+exprDeleteRestart:
assert( !ExprUseUValue(p) || p->u.iValue>=0 );
assert( !ExprUseYWin(p) || !ExprUseYSub(p) );
assert( !ExprUseYWin(p) || p->y.pWin!=0 || db->mallocFailed );
@@ -107125,7 +110944,6 @@ static SQLITE_NOINLINE void wx_sqlite3ExprDeleteNN(wx_sqlite3 *db, Expr *p){
if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){
/* The Expr.x union is never used at the same time as Expr.pRight */
assert( (ExprUseXList(p) && p->x.pList==0) || p->pRight==0 );
- if( p->pLeft && p->op!=TK_SELECT_COLUMN ) wx_sqlite3ExprDeleteNN(db, p->pLeft);
if( p->pRight ){
assert( !ExprHasProperty(p, EP_WinFunc) );
wx_sqlite3ExprDeleteNN(db, p->pRight);
@@ -107140,6 +110958,19 @@ static SQLITE_NOINLINE void wx_sqlite3ExprDeleteNN(wx_sqlite3 *db, Expr *p){
}
#endif
}
+ if( p->pLeft && p->op!=TK_SELECT_COLUMN ){
+ Expr *pLeft = p->pLeft;
+ if( !ExprHasProperty(p, EP_Static)
+ && !ExprHasProperty(pLeft, EP_Static)
+ ){
+ /* Avoid unnecessary recursion on unary operators */
+ wx_sqlite3DbNNFreeNN(db, p);
+ p = pLeft;
+ goto exprDeleteRestart;
+ }else{
+ wx_sqlite3ExprDeleteNN(db, pLeft);
+ }
+ }
}
if( !ExprHasProperty(p, EP_Static) ){
wx_sqlite3DbNNFreeNN(db, p);
@@ -107148,6 +110979,9 @@ static SQLITE_NOINLINE void wx_sqlite3ExprDeleteNN(wx_sqlite3 *db, Expr *p){
SQLITE_PRIVATE void wx_sqlite3ExprDelete(wx_sqlite3 *db, Expr *p){
if( p ) wx_sqlite3ExprDeleteNN(db, p);
}
+SQLITE_PRIVATE void wx_sqlite3ExprDeleteGeneric(wx_sqlite3 *db, void *p){
+ if( ALWAYS(p) ) wx_sqlite3ExprDeleteNN(db, (Expr*)p);
+}
/*
** Clear both elements of an OnOrUsing object
@@ -107165,17 +110999,15 @@ SQLITE_PRIVATE void wx_sqlite3ClearOnOrUsing(wx_sqlite3 *db, OnOrUsing *p){
/*
** Arrange to cause pExpr to be deleted when the pParse is deleted.
** This is similar to wx_sqlite3ExprDelete() except that the delete is
-** deferred untilthe pParse is deleted.
+** deferred until the pParse is deleted.
**
** The pExpr might be deleted immediately on an OOM error.
**
-** The deferred delete is (currently) implemented by adding the
-** pExpr to the pParse->pConstExpr list with a register number of 0.
+** Return 0 if the delete was successfully deferred. Return non-zero
+** if the delete happened immediately because of an OOM.
*/
-SQLITE_PRIVATE void wx_sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
- wx_sqlite3ParserAddCleanup(pParse,
- (void(*)(wx_sqlite3*,void*))wx_sqlite3ExprDelete,
- pExpr);
+SQLITE_PRIVATE int wx_sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
+ return 0==wx_sqlite3ParserAddCleanup(pParse, wx_sqlite3ExprDeleteGeneric, pExpr);
}
/* Invoke wx_sqlite3RenameExprUnmap() and wx_sqlite3ExprDelete() on the
@@ -107240,11 +111072,7 @@ static int dupedExprStructSize(const Expr *p, int flags){
assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
assert( EXPR_FULLSIZE<=0xfff );
assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
- if( 0==flags || p->op==TK_SELECT_COLUMN
-#ifndef SQLITE_OMIT_WINDOWFUNC
- || ExprHasProperty(p, EP_WinFunc)
-#endif
- ){
+ if( 0==flags || ExprHasProperty(p, EP_FullSize) ){
nSize = EXPR_FULLSIZE;
}else{
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
@@ -107275,56 +111103,93 @@ static int dupedExprNodeSize(const Expr *p, int flags){
/*
** Return the number of bytes required to create a duplicate of the
-** expression passed as the first argument. The second argument is a
-** mask containing EXPRDUP_XXX flags.
+** expression passed as the first argument.
**
** The value returned includes space to create a copy of the Expr struct
** itself and the buffer referred to by Expr.u.zToken, if any.
**
-** If the EXPRDUP_REDUCE flag is set, then the return value includes
-** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
-** and Expr.pRight variables (but not for any structures pointed to or
-** descended from the Expr.x.pList or Expr.x.pSelect variables).
+** The return value includes space to duplicate all Expr nodes in the
+** tree formed by Expr.pLeft and Expr.pRight, but not any other
+** substructure such as Expr.x.pList, Expr.x.pSelect, and Expr.y.pWin.
*/
-static int dupedExprSize(const Expr *p, int flags){
- int nByte = 0;
- if( p ){
- nByte = dupedExprNodeSize(p, flags);
- if( flags&EXPRDUP_REDUCE ){
- nByte += dupedExprSize(p->pLeft, flags) + dupedExprSize(p->pRight, flags);
- }
- }
+static int dupedExprSize(const Expr *p){
+ int nByte;
+ assert( p!=0 );
+ nByte = dupedExprNodeSize(p, EXPRDUP_REDUCE);
+ if( p->pLeft ) nByte += dupedExprSize(p->pLeft);
+ if( p->pRight ) nByte += dupedExprSize(p->pRight);
+ assert( nByte==ROUND8(nByte) );
return nByte;
}
/*
-** This function is similar to wx_sqlite3ExprDup(), except that if pzBuffer
-** is not NULL then *pzBuffer is assumed to point to a buffer large enough
-** to store the copy of expression p, the copies of p->u.zToken
-** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
-** if any. Before returning, *pzBuffer is set to the first byte past the
-** portion of the buffer copied into by this function.
+** An EdupBuf is a memory allocation used to stored multiple Expr objects
+** together with their Expr.zToken content. This is used to help implement
+** compression while doing wx_sqlite3ExprDup(). The top-level Expr does the
+** allocation for itself and many of its decendents, then passes an instance
+** of the structure down into exprDup() so that they decendents can have
+** access to that memory.
*/
-static Expr *exprDup(wx_sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
+typedef struct EdupBuf EdupBuf;
+struct EdupBuf {
+ u8 *zAlloc; /* Memory space available for storage */
+#ifdef SQLITE_DEBUG
+ u8 *zEnd; /* First byte past the end of memory */
+#endif
+};
+
+/*
+** This function is similar to wx_sqlite3ExprDup(), except that if pEdupBuf
+** is not NULL then it points to memory that can be used to store a copy
+** of the input Expr p together with its p->u.zToken (if any). pEdupBuf
+** is updated with the new buffer tail prior to returning.
+*/
+static Expr *exprDup(
+ wx_sqlite3 *db, /* Database connection (for memory allocation) */
+ const Expr *p, /* Expr tree to be duplicated */
+ int dupFlags, /* EXPRDUP_REDUCE for compression. 0 if not */
+ EdupBuf *pEdupBuf /* Preallocated storage space, or NULL */
+){
Expr *pNew; /* Value to return */
- u8 *zAlloc; /* Memory space from which to build Expr object */
+ EdupBuf sEdupBuf; /* Memory space from which to build Expr object */
u32 staticFlag; /* EP_Static if space not obtained from malloc */
+ int nToken = -1; /* Space needed for p->u.zToken. -1 means unknown */
assert( db!=0 );
assert( p );
assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE );
- assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE );
+ assert( pEdupBuf==0 || dupFlags==EXPRDUP_REDUCE );
/* Figure out where to write the new Expr structure. */
- if( pzBuffer ){
- zAlloc = *pzBuffer;
+ if( pEdupBuf ){
+ sEdupBuf.zAlloc = pEdupBuf->zAlloc;
+#ifdef SQLITE_DEBUG
+ sEdupBuf.zEnd = pEdupBuf->zEnd;
+#endif
staticFlag = EP_Static;
- assert( zAlloc!=0 );
+ assert( sEdupBuf.zAlloc!=0 );
+ assert( dupFlags==EXPRDUP_REDUCE );
}else{
- zAlloc = wx_sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags));
+ int nAlloc;
+ if( dupFlags ){
+ nAlloc = dupedExprSize(p);
+ }else if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nToken = wx_sqlite3Strlen30NN(p->u.zToken)+1;
+ nAlloc = ROUND8(EXPR_FULLSIZE + nToken);
+ }else{
+ nToken = 0;
+ nAlloc = ROUND8(EXPR_FULLSIZE);
+ }
+ assert( nAlloc==ROUND8(nAlloc) );
+ sEdupBuf.zAlloc = wx_sqlite3DbMallocRawNN(db, nAlloc);
+#ifdef SQLITE_DEBUG
+ sEdupBuf.zEnd = sEdupBuf.zAlloc ? sEdupBuf.zAlloc+nAlloc : 0;
+#endif
+
staticFlag = 0;
}
- pNew = (Expr *)zAlloc;
+ pNew = (Expr *)sEdupBuf.zAlloc;
+ assert( EIGHT_BYTE_ALIGNMENT(pNew) );
if( pNew ){
/* Set nNewSize to the size allocated for the structure pointed to
@@ -107333,22 +111198,27 @@ static Expr *exprDup(wx_sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer)
** by the copy of the p->u.zToken string (if any).
*/
const unsigned nStructSize = dupedExprStructSize(p, dupFlags);
- const int nNewSize = nStructSize & 0xfff;
- int nToken;
- if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
- nToken = wx_sqlite3Strlen30(p->u.zToken) + 1;
- }else{
- nToken = 0;
+ int nNewSize = nStructSize & 0xfff;
+ if( nToken<0 ){
+ if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nToken = wx_sqlite3Strlen30(p->u.zToken) + 1;
+ }else{
+ nToken = 0;
+ }
}
if( dupFlags ){
+ assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >= nNewSize+nToken );
assert( ExprHasProperty(p, EP_Reduced)==0 );
- memcpy(zAlloc, p, nNewSize);
+ memcpy(sEdupBuf.zAlloc, p, nNewSize);
}else{
u32 nSize = (u32)exprStructSize(p);
- memcpy(zAlloc, p, nSize);
+ assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >=
+ (int)EXPR_FULLSIZE+nToken );
+ memcpy(sEdupBuf.zAlloc, p, nSize);
if( nSize<EXPR_FULLSIZE ){
- memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
+ memset(&sEdupBuf.zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
}
+ nNewSize = EXPR_FULLSIZE;
}
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
@@ -107361,44 +111231,50 @@ static Expr *exprDup(wx_sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer)
}
/* Copy the p->u.zToken string, if any. */
- if( nToken ){
- char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
+ assert( nToken>=0 );
+ if( nToken>0 ){
+ char *zToken = pNew->u.zToken = (char*)&sEdupBuf.zAlloc[nNewSize];
memcpy(zToken, p->u.zToken, nToken);
+ nNewSize += nToken;
}
+ sEdupBuf.zAlloc += ROUND8(nNewSize);
+
+ if( ((p->flags|pNew->flags)&(EP_TokenOnly|EP_Leaf))==0 ){
- if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
if( ExprUseXSelect(p) ){
pNew->x.pSelect = wx_sqlite3SelectDup(db, p->x.pSelect, dupFlags);
}else{
- pNew->x.pList = wx_sqlite3ExprListDup(db, p->x.pList, dupFlags);
+ pNew->x.pList = wx_sqlite3ExprListDup(db, p->x.pList,
+ p->op!=TK_ORDER ? dupFlags : 0);
}
- }
- /* Fill in pNew->pLeft and pNew->pRight. */
- if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){
- zAlloc += dupedExprNodeSize(p, dupFlags);
- if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){
- pNew->pLeft = p->pLeft ?
- exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0;
- pNew->pRight = p->pRight ?
- exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0;
- }
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(p, EP_WinFunc) ){
pNew->y.pWin = wx_sqlite3WindowDup(db, pNew, p->y.pWin);
assert( ExprHasProperty(pNew, EP_WinFunc) );
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
- if( pzBuffer ){
- *pzBuffer = zAlloc;
- }
- }else{
- if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
- if( pNew->op==TK_SELECT_COLUMN ){
+
+ /* Fill in pNew->pLeft and pNew->pRight. */
+ if( dupFlags ){
+ if( p->op==TK_SELECT_COLUMN ){
+ pNew->pLeft = p->pLeft;
+ assert( p->pRight==0
+ || p->pRight==p->pLeft
+ || ExprHasProperty(p->pLeft, EP_Subquery) );
+ }else{
+ pNew->pLeft = p->pLeft ?
+ exprDup(db, p->pLeft, EXPRDUP_REDUCE, &sEdupBuf) : 0;
+ }
+ pNew->pRight = p->pRight ?
+ exprDup(db, p->pRight, EXPRDUP_REDUCE, &sEdupBuf) : 0;
+ }else{
+ if( p->op==TK_SELECT_COLUMN ){
pNew->pLeft = p->pLeft;
- assert( p->pRight==0 || p->pRight==p->pLeft
- || ExprHasProperty(p->pLeft, EP_Subquery) );
+ assert( p->pRight==0
+ || p->pRight==p->pLeft
+ || ExprHasProperty(p->pLeft, EP_Subquery) );
}else{
pNew->pLeft = wx_sqlite3ExprDup(db, p->pLeft, 0);
}
@@ -107406,6 +111282,8 @@ static Expr *exprDup(wx_sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer)
}
}
}
+ if( pEdupBuf ) memcpy(pEdupBuf, &sEdupBuf, sizeof(sEdupBuf));
+ assert( sEdupBuf.zAlloc <= sEdupBuf.zEnd );
return pNew;
}
@@ -107557,30 +111435,46 @@ SQLITE_PRIVATE SrcList *wx_sqlite3SrcListDup(wx_sqlite3 *db, const SrcList *p, i
SrcItem *pNewItem = &pNew->a[i];
const SrcItem *pOldItem = &p->a[i];
Table *pTab;
- pNewItem->pSchema = pOldItem->pSchema;
- pNewItem->zDatabase = wx_sqlite3DbStrDup(db, pOldItem->zDatabase);
+ pNewItem->fg = pOldItem->fg;
+ if( pOldItem->fg.isSubquery ){
+ Subquery *pNewSubq = wx_sqlite3DbMallocRaw(db, sizeof(Subquery));
+ if( pNewSubq==0 ){
+ assert( db->mallocFailed );
+ pNewItem->fg.isSubquery = 0;
+ }else{
+ memcpy(pNewSubq, pOldItem->u4.pSubq, sizeof(*pNewSubq));
+ pNewSubq->pSelect = wx_sqlite3SelectDup(db, pNewSubq->pSelect, flags);
+ if( pNewSubq->pSelect==0 ){
+ wx_sqlite3DbFree(db, pNewSubq);
+ pNewSubq = 0;
+ pNewItem->fg.isSubquery = 0;
+ }
+ }
+ pNewItem->u4.pSubq = pNewSubq;
+ }else if( pOldItem->fg.fixedSchema ){
+ pNewItem->u4.pSchema = pOldItem->u4.pSchema;
+ }else{
+ pNewItem->u4.zDatabase = wx_sqlite3DbStrDup(db, pOldItem->u4.zDatabase);
+ }
pNewItem->zName = wx_sqlite3DbStrDup(db, pOldItem->zName);
pNewItem->zAlias = wx_sqlite3DbStrDup(db, pOldItem->zAlias);
- pNewItem->fg = pOldItem->fg;
pNewItem->iCursor = pOldItem->iCursor;
- pNewItem->addrFillSub = pOldItem->addrFillSub;
- pNewItem->regReturn = pOldItem->regReturn;
if( pNewItem->fg.isIndexedBy ){
pNewItem->u1.zIndexedBy = wx_sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
+ }else if( pNewItem->fg.isTabFunc ){
+ pNewItem->u1.pFuncArg =
+ wx_sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
+ }else{
+ pNewItem->u1.nRow = pOldItem->u1.nRow;
}
pNewItem->u2 = pOldItem->u2;
if( pNewItem->fg.isCte ){
pNewItem->u2.pCteUse->nUse++;
}
- if( pNewItem->fg.isTabFunc ){
- pNewItem->u1.pFuncArg =
- wx_sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
- }
- pTab = pNewItem->pTab = pOldItem->pTab;
+ pTab = pNewItem->pSTab = pOldItem->pSTab;
if( pTab ){
pTab->nTabRef++;
}
- pNewItem->pSelect = wx_sqlite3SelectDup(db, pOldItem->pSelect, flags);
if( pOldItem->fg.isUsing ){
assert( pNewItem->fg.isUsing );
pNewItem->u3.pUsing = wx_sqlite3IdListDup(db, pOldItem->u3.pUsing);
@@ -107654,7 +111548,6 @@ SQLITE_PRIVATE Select *wx_sqlite3SelectDup(wx_sqlite3 *db, const Select *pDup, i
pp = &pNew->pPrior;
pNext = pNew;
}
-
return pRet;
}
#else
@@ -107670,11 +111563,7 @@ SQLITE_PRIVATE Select *wx_sqlite3SelectDup(wx_sqlite3 *db, const Select *p, int
** initially NULL, then create a new expression list.
**
** The pList argument must be either NULL or a pointer to an ExprList
-** obtained from a prior call to wx_sqlite3ExprListAppend(). This routine
-** may not be used with an ExprList obtained from wx_sqlite3ExprListDup().
-** Reason: This routine assumes that the number of slots in pList->a[]
-** is a power of two. That is true for wx_sqlite3ExprListAppend() returns
-** but is not necessarily true from the return value of wx_sqlite3ExprListDup().
+** obtained from a prior call to wx_sqlite3ExprListAppend().
**
** If a memory allocation error occurs, the entire list is freed and
** NULL is returned. If non-NULL is returned, then it is guaranteed
@@ -107939,6 +111828,9 @@ static SQLITE_NOINLINE void exprListDeleteNN(wx_sqlite3 *db, ExprList *pList){
SQLITE_PRIVATE void wx_sqlite3ExprListDelete(wx_sqlite3 *db, ExprList *pList){
if( pList ) exprListDeleteNN(db, pList);
}
+SQLITE_PRIVATE void wx_sqlite3ExprListDeleteGeneric(wx_sqlite3 *db, void *pList){
+ if( ALWAYS(pList) ) exprListDeleteNN(db, (ExprList*)pList);
+}
/*
** Return the bitwise-OR of all Expr.flags fields in the given
@@ -108007,7 +111899,7 @@ SQLITE_PRIVATE int wx_sqlite3ExprIdToTrueFalse(Expr *pExpr){
** and 0 if it is FALSE.
*/
SQLITE_PRIVATE int wx_sqlite3ExprTruthValue(const Expr *pExpr){
- pExpr = wx_sqlite3ExprSkipCollate((Expr*)pExpr);
+ pExpr = wx_sqlite3ExprSkipCollateAndLikely((Expr*)pExpr);
assert( pExpr->op==TK_TRUEFALSE );
assert( !ExprHasProperty(pExpr, EP_IntValue) );
assert( wx_sqlite3StrICmp(pExpr->u.zToken,"true")==0
@@ -108042,6 +111934,54 @@ SQLITE_PRIVATE Expr *wx_sqlite3ExprSimplifiedAndOr(Expr *pExpr){
return pExpr;
}
+/*
+** pExpr is a TK_FUNCTION node. Try to determine whether or not the
+** function is a constant function. A function is constant if all of
+** the following are true:
+**
+** (1) It is a scalar function (not an aggregate or window function)
+** (2) It has either the SQLITE_FUNC_CONSTANT or SQLITE_FUNC_SLOCHNG
+** property.
+** (3) All of its arguments are constants
+**
+** This routine sets pWalker->eCode to 0 if pExpr is not a constant.
+** It makes no changes to pWalker->eCode if pExpr is constant. In
+** every case, it returns WRC_Abort.
+**
+** Called as a service subroutine from exprNodeIsConstant().
+*/
+static SQLITE_NOINLINE int exprNodeIsConstantFunction(
+ Walker *pWalker,
+ Expr *pExpr
+){
+ int n; /* Number of arguments */
+ ExprList *pList; /* List of arguments */
+ FuncDef *pDef; /* The function */
+ wx_sqlite3 *db; /* The database */
+
+ assert( pExpr->op==TK_FUNCTION );
+ if( ExprHasProperty(pExpr, EP_TokenOnly)
+ || (pList = pExpr->x.pList)==0
+ ){;
+ n = 0;
+ }else{
+ n = pList->nExpr;
+ wx_sqlite3WalkExprList(pWalker, pList);
+ if( pWalker->eCode==0 ) return WRC_Abort;
+ }
+ db = pWalker->pParse->db;
+ pDef = wx_sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
+ if( pDef==0
+ || pDef->xFinalize!=0
+ || (pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
+ || ExprHasProperty(pExpr, EP_WinFunc)
+ ){
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+ return WRC_Prune;
+}
+
/*
** These routines are Walker callbacks used to check expressions to
@@ -108070,6 +112010,7 @@ SQLITE_PRIVATE Expr *wx_sqlite3ExprSimplifiedAndOr(Expr *pExpr){
** malformed schema error.
*/
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
+ assert( pWalker->eCode>0 );
/* If pWalker->eCode is 2 then any term of the expression that comes from
** the ON or USING clauses of an outer join disqualifies the expression
@@ -108089,6 +112030,8 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
){
if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL);
return WRC_Continue;
+ }else if( pWalker->pParse ){
+ return exprNodeIsConstantFunction(pWalker, pExpr);
}else{
pWalker->eCode = 0;
return WRC_Abort;
@@ -108117,9 +112060,11 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
case TK_IF_NULL_ROW:
case TK_REGISTER:
case TK_DOT:
+ case TK_RAISE:
testcase( pExpr->op==TK_REGISTER );
testcase( pExpr->op==TK_IF_NULL_ROW );
testcase( pExpr->op==TK_DOT );
+ testcase( pExpr->op==TK_RAISE );
pWalker->eCode = 0;
return WRC_Abort;
case TK_VARIABLE:
@@ -108141,15 +112086,15 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
}
-static int exprIsConst(Expr *p, int initFlag, int iCur){
+static int exprIsConst(Parse *pParse, Expr *p, int initFlag){
Walker w;
w.eCode = initFlag;
+ w.pParse = pParse;
w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = wx_sqlite3SelectWalkFail;
#ifdef SQLITE_DEBUG
w.xSelectCallback2 = wx_sqlite3SelectWalkAssert2;
#endif
- w.u.iCur = iCur;
wx_sqlite3WalkExpr(&w, p);
return w.eCode;
}
@@ -108161,9 +112106,15 @@ static int exprIsConst(Expr *p, int initFlag, int iCur){
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
** a constant.
+**
+** The pParse parameter may be NULL. But if it is NULL, there is no way
+** to determine if function calls are constant or not, and hence all
+** function calls will be considered to be non-constant. If pParse is
+** not NULL, then a function call might be constant, depending on the
+** function and on its parameters.
*/
-SQLITE_PRIVATE int wx_sqlite3ExprIsConstant(Expr *p){
- return exprIsConst(p, 1, 0);
+SQLITE_PRIVATE int wx_sqlite3ExprIsConstant(Parse *pParse, Expr *p){
+ return exprIsConst(pParse, p, 1);
}
/*
@@ -108179,8 +112130,24 @@ SQLITE_PRIVATE int wx_sqlite3ExprIsConstant(Expr *p){
** can be added to the pParse->pConstExpr list and evaluated once when
** the prepared statement starts up. See wx_sqlite3ExprCodeRunJustOnce().
*/
-SQLITE_PRIVATE int wx_sqlite3ExprIsConstantNotJoin(Expr *p){
- return exprIsConst(p, 2, 0);
+static int wx_sqlite3ExprIsConstantNotJoin(Parse *pParse, Expr *p){
+ return exprIsConst(pParse, p, 2);
+}
+
+/*
+** This routine examines sub-SELECT statements as an expression is being
+** walked as part of wx_sqlite3ExprIsTableConstant(). Sub-SELECTs are considered
+** constant as long as they are uncorrelated - meaning that they do not
+** contain any terms from outer contexts.
+*/
+static int exprSelectWalkTableConstant(Walker *pWalker, Select *pSelect){
+ assert( pSelect!=0 );
+ assert( pWalker->eCode==3 || pWalker->eCode==0 );
+ if( (pSelect->selFlags & SF_Correlated)!=0 ){
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+ return WRC_Prune;
}
/*
@@ -108188,35 +112155,79 @@ SQLITE_PRIVATE int wx_sqlite3ExprIsConstantNotJoin(Expr *p){
** for any single row of the table with cursor iCur. In other words, the
** expression must not refer to any non-deterministic function nor any
** table other than iCur.
+**
+** Consider uncorrelated subqueries to be constants if the bAllowSubq
+** parameter is true.
*/
-SQLITE_PRIVATE int wx_sqlite3ExprIsTableConstant(Expr *p, int iCur){
- return exprIsConst(p, 3, iCur);
+static int wx_sqlite3ExprIsTableConstant(Expr *p, int iCur, int bAllowSubq){
+ Walker w;
+ w.eCode = 3;
+ w.pParse = 0;
+ w.xExprCallback = exprNodeIsConstant;
+ if( bAllowSubq ){
+ w.xSelectCallback = exprSelectWalkTableConstant;
+ }else{
+ w.xSelectCallback = wx_sqlite3SelectWalkFail;
+#ifdef SQLITE_DEBUG
+ w.xSelectCallback2 = wx_sqlite3SelectWalkAssert2;
+#endif
+ }
+ w.u.iCur = iCur;
+ wx_sqlite3WalkExpr(&w, p);
+ return w.eCode;
}
/*
-** Check pExpr to see if it is an invariant constraint on data source pSrc.
+** Check pExpr to see if it is an constraint on the single data source
+** pSrc = &pSrcList->a[iSrc]. In other words, check to see if pExpr
+** constrains pSrc but does not depend on any other tables or data
+** sources anywhere else in the query. Return true (non-zero) if pExpr
+** is a constraint on pSrc only.
+**
** This is an optimization. False negatives will perhaps cause slower
** queries, but false positives will yield incorrect answers. So when in
** doubt, return 0.
**
-** To be an invariant constraint, the following must be true:
+** To be an single-source constraint, the following must be true:
**
** (1) pExpr cannot refer to any table other than pSrc->iCursor.
**
-** (2) pExpr cannot use subqueries or non-deterministic functions.
+** (2a) pExpr cannot use subqueries unless the bAllowSubq parameter is
+** true and the subquery is non-correlated
+**
+** (2b) pExpr cannot use non-deterministic functions.
**
** (3) pSrc cannot be part of the left operand for a RIGHT JOIN.
** (Is there some way to relax this constraint?)
**
** (4) If pSrc is the right operand of a LEFT JOIN, then...
** (4a) pExpr must come from an ON clause..
- (4b) and specifically the ON clause associated with the LEFT JOIN.
+** (4b) and specifically the ON clause associated with the LEFT JOIN.
**
** (5) If pSrc is not the right operand of a LEFT JOIN or the left
** operand of a RIGHT JOIN, then pExpr must be from the WHERE
** clause, not an ON clause.
+**
+** (6) Either:
+**
+** (6a) pExpr does not originate in an ON or USING clause, or
+**
+** (6b) The ON or USING clause from which pExpr is derived is
+** not to the left of a RIGHT JOIN (or FULL JOIN).
+**
+** Without this restriction, accepting pExpr as a single-table
+** constraint might move the the ON/USING filter expression
+** from the left side of a RIGHT JOIN over to the right side,
+** which leads to incorrect answers. See also restriction (9)
+** on push-down.
*/
-SQLITE_PRIVATE int wx_sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
+SQLITE_PRIVATE int wx_sqlite3ExprIsSingleTableConstraint(
+ Expr *pExpr, /* The constraint */
+ const SrcList *pSrcList, /* Complete FROM clause */
+ int iSrc, /* Which element of pSrcList to use */
+ int bAllowSubq /* Allow non-correlated subqueries */
+){
+ const SrcItem *pSrc = &pSrcList->a[iSrc];
if( pSrc->fg.jointype & JT_LTORJ ){
return 0; /* rule (3) */
}
@@ -108226,7 +112237,21 @@ SQLITE_PRIVATE int wx_sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *p
}else{
if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (5) */
}
- return wx_sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
+ if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) /* (6a) */
+ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (6b) */
+ ){
+ int jj;
+ for(jj=0; jj<iSrc; jj++){
+ if( pExpr->w.iJoin==pSrcList->a[jj].iCursor ){
+ if( (pSrcList->a[jj].fg.jointype & JT_LTORJ)!=0 ){
+ return 0; /* restriction (6) */
+ }
+ break;
+ }
+ }
+ }
+ /* Rules (1), (2a), and (2b) handled by the following: */
+ return wx_sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor, bAllowSubq);
}
@@ -108311,7 +112336,7 @@ SQLITE_PRIVATE int wx_sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, Exp
*/
SQLITE_PRIVATE int wx_sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
assert( isInit==0 || isInit==1 );
- return exprIsConst(p, 4+isInit, 0);
+ return exprIsConst(0, p, 4+isInit);
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
@@ -108337,8 +112362,12 @@ SQLITE_PRIVATE int wx_sqlite3ExprContainsSubquery(Expr *p){
** to fit in a 32-bit integer, return 1 and put the value of the integer
** in *pValue. If the expression is not an integer or if it is too big
** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
+**
+** If the pParse pointer is provided, then allow the expression p to be
+** a parameter (TK_VARIABLE) that is bound to an integer.
+** But if pParse is NULL, then p must be a pure integer literal.
*/
-SQLITE_PRIVATE int wx_sqlite3ExprIsInteger(const Expr *p, int *pValue){
+SQLITE_PRIVATE int wx_sqlite3ExprIsInteger(const Expr *p, int *pValue, Parse *pParse){
int rc = 0;
if( NEVER(p==0) ) return 0; /* Used to only happen following on OOM */
@@ -108353,18 +112382,38 @@ SQLITE_PRIVATE int wx_sqlite3ExprIsInteger(const Expr *p, int *pValue){
}
switch( p->op ){
case TK_UPLUS: {
- rc = wx_sqlite3ExprIsInteger(p->pLeft, pValue);
+ rc = wx_sqlite3ExprIsInteger(p->pLeft, pValue, 0);
break;
}
case TK_UMINUS: {
int v = 0;
- if( wx_sqlite3ExprIsInteger(p->pLeft, &v) ){
+ if( wx_sqlite3ExprIsInteger(p->pLeft, &v, 0) ){
assert( ((unsigned int)v)!=0x80000000 );
*pValue = -v;
rc = 1;
}
break;
}
+ case TK_VARIABLE: {
+ wx_sqlite3_value *pVal;
+ if( pParse==0 ) break;
+ if( NEVER(pParse->pVdbe==0) ) break;
+ if( (pParse->db->flags & SQLITE_EnableQPSG)!=0 ) break;
+ wx_sqlite3VdbeSetVarmask(pParse->pVdbe, p->iColumn);
+ pVal = wx_sqlite3VdbeGetBoundValue(pParse->pReprepare, p->iColumn,
+ SQLITE_AFF_BLOB);
+ if( pVal ){
+ if( wx_sqlite3_value_type(pVal)==SQLITE_INTEGER ){
+ wx_sqlite3_int64 vv = wx_sqlite3_value_int64(pVal);
+ if( vv == (vv & 0x7fffffff) ){ /* non-negative numbers only */
+ *pValue = (int)vv;
+ rc = 1;
+ }
+ }
+ wx_sqlite3ValueFree(pVal);
+ }
+ break;
+ }
default: break;
}
return rc;
@@ -108401,10 +112450,14 @@ SQLITE_PRIVATE int wx_sqlite3ExprCanBeNull(const Expr *p){
return 0;
case TK_COLUMN:
assert( ExprUseYTab(p) );
- return ExprHasProperty(p, EP_CanBeNull) ||
- p->y.pTab==0 || /* Reference to column of index on expression */
- (p->iColumn>=0
+ return ExprHasProperty(p, EP_CanBeNull)
+ || NEVER(p->y.pTab==0) /* Reference to column of index on expr */
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ || (p->iColumn==XN_ROWID && IsView(p->y.pTab))
+#endif
+ || (p->iColumn>=0
&& p->y.pTab->aCol!=0 /* Possible due to prior error */
+ && ALWAYS(p->iColumn<p->y.pTab->nCol)
&& p->y.pTab->aCol[p->iColumn].notNull==0);
default:
return 1;
@@ -108465,10 +112518,31 @@ SQLITE_PRIVATE int wx_sqlite3IsRowid(const char *z){
}
/*
+** Return a pointer to a buffer containing a usable rowid alias for table
+** pTab. An alias is usable if there is not an explicit user-defined column
+** of the same name.
+*/
+SQLITE_PRIVATE const char *wx_sqlite3RowidAlias(Table *pTab){
+ const char *azOpt[] = {"_ROWID_", "ROWID", "OID"};
+ int ii;
+ assert( VisibleRowid(pTab) );
+ for(ii=0; ii<ArraySize(azOpt); ii++){
+ int iCol;
+ for(iCol=0; iCol<pTab->nCol; iCol++){
+ if( wx_sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break;
+ }
+ if( iCol==pTab->nCol ){
+ return azOpt[ii];
+ }
+ }
+ return 0;
+}
+
+/*
** pX is the RHS of an IN operator. If pX is a SELECT statement
** that can be simplified to a direct table access, then return
** a pointer to the SELECT statement. If pX is not a SELECT statement,
-** or if the SELECT statement needs to be manifested into a transient
+** or if the SELECT statement needs to be materialized into a transient
** table, then return NULL.
*/
#ifndef SQLITE_OMIT_SUBQUERY
@@ -108493,8 +112567,8 @@ static Select *isCandidateForInOpt(const Expr *pX){
pSrc = p->pSrc;
assert( pSrc!=0 );
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
- if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
- pTab = pSrc->a[0].pTab;
+ if( pSrc->a[0].fg.isSubquery) return 0;/* FROM is not a subquery or view */
+ pTab = pSrc->a[0].pSTab;
assert( pTab!=0 );
assert( !IsView(pTab) ); /* FROM clause is not a view */
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
@@ -108534,13 +112608,13 @@ static void wx_sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
** The argument is an IN operator with a list (not a subquery) on the
** right-hand side. Return TRUE if that list is constant.
*/
-static int wx_sqlite3InRhsIsConstant(Expr *pIn){
+static int wx_sqlite3InRhsIsConstant(Parse *pParse, Expr *pIn){
Expr *pLHS;
int res;
assert( !ExprHasProperty(pIn, EP_xIsSelect) );
pLHS = pIn->pLeft;
pIn->pLeft = 0;
- res = wx_sqlite3ExprIsConstant(pIn);
+ res = wx_sqlite3ExprIsConstant(pParse, pIn);
pIn->pLeft = pLHS;
return res;
}
@@ -108564,7 +112638,7 @@ static int wx_sqlite3InRhsIsConstant(Expr *pIn){
** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index.
** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
** IN_INDEX_EPH - The cursor was opened on a specially created and
-** populated epheremal table.
+** populated ephemeral table.
** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be
** implemented as a sequence of comparisons.
**
@@ -108577,7 +112651,7 @@ static int wx_sqlite3InRhsIsConstant(Expr *pIn){
** an ephemeral table might need to be generated from the RHS and then
** pX->iTable made to point to the ephemeral table instead of an
** existing table. In this case, the creation and initialization of the
-** ephmeral table might be put inside of a subroutine, the EP_Subrtn flag
+** ephemeral table might be put inside of a subroutine, the EP_Subrtn flag
** will be set on pX and the pX->y.sub fields will be set to show where
** the subroutine is coded.
**
@@ -108589,12 +112663,12 @@ static int wx_sqlite3InRhsIsConstant(Expr *pIn){
**
** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate
** through the set members) then the b-tree must not contain duplicates.
-** An epheremal table will be created unless the selected columns are guaranteed
+** An ephemeral table will be created unless the selected columns are guaranteed
** to be unique - either because it is an INTEGER PRIMARY KEY or due to
** a UNIQUE constraint or index.
**
** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used
-** for fast set membership tests) then an epheremal table must
+** for fast set membership tests) then an ephemeral table must
** be used unless <columns> is a single INTEGER PRIMARY KEY column or an
** index can be found with the specified <columns> as its left-most.
**
@@ -108677,7 +112751,7 @@ SQLITE_PRIVATE int wx_sqlite3FindInIndex(
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
- pTab = p->pSrc->a[0].pTab;
+ pTab = p->pSrc->a[0].pSTab;
/* Code an OP_Transaction and OP_TableLock for <table>. */
iDb = wx_sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -108754,7 +112828,6 @@ SQLITE_PRIVATE int wx_sqlite3FindInIndex(
CollSeq *pReq = wx_sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
int j;
- assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
for(j=0; j<nExpr; j++){
if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
assert( pIdx->azColl[j] );
@@ -108810,7 +112883,7 @@ SQLITE_PRIVATE int wx_sqlite3FindInIndex(
if( eType==0
&& (inFlags & IN_INDEX_NOOP_OK)
&& ExprUseXList(pX)
- && (!wx_sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2)
+ && (!wx_sqlite3InRhsIsConstant(pParse,pX) || pX->x.pList->nExpr<=2)
){
pParse->nTab--; /* Back out the allocation of the unused cursor */
iTab = -1; /* Cursor is not allocated */
@@ -108920,6 +112993,49 @@ SQLITE_PRIVATE void wx_sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
#ifndef SQLITE_OMIT_SUBQUERY
/*
+** Scan all previously generated bytecode looking for an OP_BeginSubrtn
+** that is compatible with pExpr. If found, add the y.sub values
+** to pExpr and return true. If not found, return false.
+*/
+static int findCompatibleInRhsSubrtn(
+ Parse *pParse, /* Parsing context */
+ Expr *pExpr, /* IN operator with RHS that we want to reuse */
+ SubrtnSig *pNewSig /* Signature for the IN operator */
+){
+ VdbeOp *pOp, *pEnd;
+ SubrtnSig *pSig;
+ Vdbe *v;
+
+ if( pNewSig==0 ) return 0;
+ if( (pParse->mSubrtnSig & (1<<(pNewSig->selId&7)))==0 ) return 0;
+ assert( pExpr->op==TK_IN );
+ assert( !ExprUseYSub(pExpr) );
+ assert( ExprUseXSelect(pExpr) );
+ assert( pExpr->x.pSelect!=0 );
+ assert( (pExpr->x.pSelect->selFlags & SF_All)==0 );
+ v = pParse->pVdbe;
+ assert( v!=0 );
+ pOp = wx_sqlite3VdbeGetOp(v, 1);
+ pEnd = wx_sqlite3VdbeGetLastOp(v);
+ for(; pOp<pEnd; pOp++){
+ if( pOp->p4type!=P4_SUBRTNSIG ) continue;
+ assert( pOp->opcode==OP_BeginSubrtn );
+ pSig = pOp->p4.pSubrtnSig;
+ assert( pSig!=0 );
+ if( pNewSig->selId!=pSig->selId ) continue;
+ if( strcmp(pNewSig->zAff,pSig->zAff)!=0 ) continue;
+ pExpr->y.sub.iAddr = pSig->iAddr;
+ pExpr->y.sub.regReturn = pSig->regReturn;
+ pExpr->iTable = pSig->iTable;
+ ExprSetProperty(pExpr, EP_Subrtn);
+ return 1;
+ }
+ return 0;
+}
+#endif /* SQLITE_OMIT_SUBQUERY */
+
+#ifndef SQLITE_OMIT_SUBQUERY
+/*
** Generate code that will construct an ephemeral table containing all terms
** in the RHS of an IN operator. The IN operator can be in either of two
** forms:
@@ -108928,7 +113044,7 @@ SQLITE_PRIVATE void wx_sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
** x IN (SELECT a FROM b) -- IN operator with subquery on the right
**
** The pExpr parameter is the IN operator. The cursor number for the
-** constructed ephermeral table is returned. The first time the ephemeral
+** constructed ephemeral table is returned. The first time the ephemeral
** table is computed, the cursor number is also stored in pExpr->iTable,
** however the cursor number returned might not be the same, as it might
** have been duplicated using OP_OpenDup.
@@ -108967,11 +113083,28 @@ SQLITE_PRIVATE void wx_sqlite3CodeRhsOfIN(
** and reuse it many names.
*/
if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){
- /* Reuse of the RHS is allowed */
- /* If this routine has already been coded, but the previous code
- ** might not have been invoked yet, so invoke it now as a subroutine.
+ /* Reuse of the RHS is allowed
+ **
+ ** Compute a signature for the RHS of the IN operator to facility
+ ** finding and reusing prior instances of the same IN operator.
*/
- if( ExprHasProperty(pExpr, EP_Subrtn) ){
+ SubrtnSig *pSig = 0;
+ assert( !ExprUseXSelect(pExpr) || pExpr->x.pSelect!=0 );
+ if( ExprUseXSelect(pExpr) && (pExpr->x.pSelect->selFlags & SF_All)==0 ){
+ pSig = wx_sqlite3DbMallocRawNN(pParse->db, sizeof(pSig[0]));
+ if( pSig ){
+ pSig->selId = pExpr->x.pSelect->selId;
+ pSig->zAff = exprINAffinity(pParse, pExpr);
+ }
+ }
+
+ /* Check to see if there is a prior materialization of the RHS of
+ ** this IN operator. If there is, then make use of that prior
+ ** materialization rather than recomputing it.
+ */
+ if( ExprHasProperty(pExpr, EP_Subrtn)
+ || findCompatibleInRhsSubrtn(pParse, pExpr, pSig)
+ ){
addrOnce = wx_sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
if( ExprUseXSelect(pExpr) ){
ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d",
@@ -108983,6 +113116,10 @@ SQLITE_PRIVATE void wx_sqlite3CodeRhsOfIN(
assert( iTab!=pExpr->iTable );
wx_sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);
wx_sqlite3VdbeJumpHere(v, addrOnce);
+ if( pSig ){
+ wx_sqlite3DbFree(pParse->db, pSig->zAff);
+ wx_sqlite3DbFree(pParse->db, pSig);
+ }
return;
}
@@ -108993,7 +113130,13 @@ SQLITE_PRIVATE void wx_sqlite3CodeRhsOfIN(
pExpr->y.sub.regReturn = ++pParse->nMem;
pExpr->y.sub.iAddr =
wx_sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1;
-
+ if( pSig ){
+ pSig->iAddr = pExpr->y.sub.iAddr;
+ pSig->regReturn = pExpr->y.sub.regReturn;
+ pSig->iTable = iTab;
+ pParse->mSubrtnSig = 1 << (pSig->selId&7);
+ wx_sqlite3VdbeChangeP4(v, -1, (const char*)pSig, P4_SUBRTNSIG);
+ }
addrOnce = wx_sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
@@ -109034,15 +113177,30 @@ SQLITE_PRIVATE void wx_sqlite3CodeRhsOfIN(
SelectDest dest;
int i;
int rc;
+ int addrBloom = 0;
wx_sqlite3SelectDestInit(&dest, SRT_Set, iTab);
dest.zAffSdst = exprINAffinity(pParse, pExpr);
pSelect->iLimit = 0;
+ if( addrOnce && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){
+ int regBloom = ++pParse->nMem;
+ addrBloom = wx_sqlite3VdbeAddOp2(v, OP_Blob, 10000, regBloom);
+ VdbeComment((v, "Bloom filter"));
+ dest.iSDParm2 = regBloom;
+ }
testcase( pSelect->selFlags & SF_Distinct );
testcase( pKeyInfo==0 ); /* Caused by OOM in wx_sqlite3KeyInfoAlloc() */
pCopy = wx_sqlite3SelectDup(pParse->db, pSelect, 0);
rc = pParse->db->mallocFailed ? 1 :wx_sqlite3Select(pParse, pCopy, &dest);
wx_sqlite3SelectDelete(pParse->db, pCopy);
wx_sqlite3DbFree(pParse->db, dest.zAffSdst);
+ if( addrBloom ){
+ wx_sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2;
+ if( dest.iSDParm2==0 ){
+ wx_sqlite3VdbeChangeToNoop(v, addrBloom);
+ }else{
+ wx_sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2;
+ }
+ }
if( rc ){
wx_sqlite3KeyInfoUnref(pKeyInfo);
return;
@@ -109093,7 +113251,7 @@ SQLITE_PRIVATE void wx_sqlite3CodeRhsOfIN(
** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time.
*/
- if( addrOnce && !wx_sqlite3ExprIsConstant(pE2) ){
+ if( addrOnce && !wx_sqlite3ExprIsConstant(pParse, pE2) ){
wx_sqlite3VdbeChangeToNoop(v, addrOnce-1);
wx_sqlite3VdbeChangeToNoop(v, addrOnce);
ExprClearProperty(pExpr, EP_Subrtn);
@@ -109340,9 +113498,7 @@ static void wx_sqlite3ExprCodeIN(
if( wx_sqlite3ExprCheckIN(pParse, pExpr) ) return;
zAff = exprINAffinity(pParse, pExpr);
nVector = wx_sqlite3ExprVectorSize(pExpr->pLeft);
- aiMap = (int*)wx_sqlite3DbMallocZero(
- pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1
- );
+ aiMap = (int*)wx_sqlite3DbMallocZero(pParse->db, nVector*sizeof(int));
if( pParse->db->mallocFailed ) goto wx_sqlite3ExprCodeIN_oom_error;
/* Attempt to compute the RHS. After this step, if anything other than
@@ -109485,6 +113641,15 @@ static void wx_sqlite3ExprCodeIN(
wx_sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector);
if( destIfFalse==destIfNull ){
/* Combine Step 3 and Step 5 into a single opcode */
+ if( ExprHasProperty(pExpr, EP_Subrtn) ){
+ const VdbeOp *pOp = wx_sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr);
+ assert( pOp->opcode==OP_Once || pParse->nErr );
+ if( pOp->opcode==OP_Once && pOp->p3>0 ){
+ assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) );
+ wx_sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse,
+ rLhs, nVector); VdbeCoverage(v);
+ }
+ }
wx_sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse,
rLhs, nVector); VdbeCoverage(v);
goto wx_sqlite3ExprCodeIN_finished;
@@ -109743,10 +113908,13 @@ SQLITE_PRIVATE int wx_sqlite3ExprCodeGetColumn(
u8 p5 /* P5 value for OP_Column + FLAGS */
){
assert( pParse->pVdbe!=0 );
+ assert( (p5 & (OPFLAG_NOCHNG|OPFLAG_TYPEOFARG|OPFLAG_LENGTHARG))==p5 );
+ assert( IsVirtual(pTab) || (p5 & OPFLAG_NOCHNG)==0 );
wx_sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
if( p5 ){
VdbeOp *pOp = wx_sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Column ) pOp->p5 = p5;
+ if( pOp->opcode==OP_VColumn ) pOp->p5 = (p5 & OPFLAG_NOCHNG);
}
return iReg;
}
@@ -109764,18 +113932,22 @@ SQLITE_PRIVATE void wx_sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, in
** register iReg. The caller must ensure that iReg already contains
** the correct value for the expression.
*/
-static void exprToRegister(Expr *pExpr, int iReg){
+SQLITE_PRIVATE void wx_sqlite3ExprToRegister(Expr *pExpr, int iReg){
Expr *p = wx_sqlite3ExprSkipCollateAndLikely(pExpr);
if( NEVER(p==0) ) return;
- p->op2 = p->op;
- p->op = TK_REGISTER;
- p->iTable = iReg;
- ExprClearProperty(p, EP_Skip);
+ if( p->op==TK_REGISTER ){
+ assert( p->iTable==iReg );
+ }else{
+ p->op2 = p->op;
+ p->op = TK_REGISTER;
+ p->iTable = iReg;
+ ExprClearProperty(p, EP_Skip);
+ }
}
/*
** Evaluate an expression (either a vector or a scalar expression) and store
-** the result in continguous temporary registers. Return the index of
+** the result in contiguous temporary registers. Return the index of
** the first register used to store the result.
**
** If the returned result register is a temporary scalar, then also write
@@ -109815,7 +113987,7 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
*/
static void setDoNotMergeFlagOnCopy(Vdbe *v){
if( wx_sqlite3VdbeGetLastOp(v)->opcode==OP_Copy ){
- wx_sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */
+ wx_sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergeable */
}
}
@@ -109905,13 +114077,13 @@ static int exprCodeInlineFunction(
}
case INLINEFUNC_implies_nonnull_row: {
- /* REsult of wx_sqlite3ExprImpliesNonNullRow() */
+ /* Result of wx_sqlite3ExprImpliesNonNullRow() */
Expr *pA1;
assert( nFarg==2 );
pA1 = pFarg->a[1].pExpr;
if( pA1->op==TK_COLUMN ){
wx_sqlite3VdbeAddOp2(v, OP_Integer,
- wx_sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable),
+ wx_sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable,1),
target);
}else{
wx_sqlite3VdbeAddOp2(v, OP_Null, 0, target);
@@ -109941,6 +114113,59 @@ static int exprCodeInlineFunction(
}
/*
+** Expression Node callback for wx_sqlite3ExprCanReturnSubtype().
+**
+** Only a function call is able to return a subtype. So if the node
+** is not a function call, return WRC_Prune immediately.
+**
+** A function call is able to return a subtype if it has the
+** SQLITE_RESULT_SUBTYPE property.
+**
+** Assume that every function is able to pass-through a subtype from
+** one of its argument (using wx_sqlite3_result_value()). Most functions
+** are not this way, but we don't have a mechanism to distinguish those
+** that are from those that are not, so assume they all work this way.
+** That means that if one of its arguments is another function and that
+** other function is able to return a subtype, then this function is
+** able to return a subtype.
+*/
+static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
+ int n;
+ FuncDef *pDef;
+ wx_sqlite3 *db;
+ if( pExpr->op!=TK_FUNCTION ){
+ return WRC_Prune;
+ }
+ assert( ExprUseXList(pExpr) );
+ db = pWalker->pParse->db;
+ n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0;
+ pDef = wx_sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
+ if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
+ pWalker->eCode = 1;
+ return WRC_Prune;
+ }
+ return WRC_Continue;
+}
+
+/*
+** Return TRUE if expression pExpr is able to return a subtype.
+**
+** A TRUE return does not guarantee that a subtype will be returned.
+** It only indicates that a subtype return is possible. False positives
+** are acceptable as they only disable an optimization. False negatives,
+** on the other hand, can lead to incorrect answers.
+*/
+static int wx_sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.pParse = pParse;
+ w.xExprCallback = exprNodeCanReturnSubtype;
+ wx_sqlite3WalkExpr(&w, pExpr);
+ return w.eCode;
+}
+
+
+/*
** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr.
** If it is, then resolve the expression by reading from the index and
** return the register into which the value has been read. If pExpr is
@@ -109972,6 +114197,17 @@ static SQLITE_NOINLINE int wx_sqlite3IndexedExprLookup(
continue;
}
+
+ /* Functions that might set a subtype should not be replaced by the
+ ** value taken from an expression index if they are themselves an
+ ** argument to another scalar function or aggregate.
+ ** https://sqlite.org/forum/forumpost/68d284c86b082c3e */
+ if( ExprHasProperty(pExpr, EP_SubtArg)
+ && wx_sqlite3ExprCanReturnSubtype(pParse, pExpr)
+ ){
+ continue;
+ }
+
v = pParse->pVdbe;
assert( v!=0 );
if( p->bMaybeNullRow ){
@@ -110000,6 +114236,41 @@ static SQLITE_NOINLINE int wx_sqlite3IndexedExprLookup(
/*
+** Expresion pExpr is guaranteed to be a TK_COLUMN or equivalent. This
+** function checks the Parse.pIdxPartExpr list to see if this column
+** can be replaced with a constant value. If so, it generates code to
+** put the constant value in a register (ideally, but not necessarily,
+** register iTarget) and returns the register number.
+**
+** Or, if the TK_COLUMN cannot be replaced by a constant, zero is
+** returned.
+*/
+static int exprPartidxExprLookup(Parse *pParse, Expr *pExpr, int iTarget){
+ IndexedExpr *p;
+ for(p=pParse->pIdxPartExpr; p; p=p->pIENext){
+ if( pExpr->iColumn==p->iIdxCol && pExpr->iTable==p->iDataCur ){
+ Vdbe *v = pParse->pVdbe;
+ int addr = 0;
+ int ret;
+
+ if( p->bMaybeNullRow ){
+ addr = wx_sqlite3VdbeAddOp1(v, OP_IfNullRow, p->iIdxCur);
+ }
+ ret = wx_sqlite3ExprCodeTarget(pParse, p->pExpr, iTarget);
+ wx_sqlite3VdbeAddOp4(pParse->pVdbe, OP_Affinity, ret, 1, 0,
+ (const char*)&p->aff, 1);
+ if( addr ){
+ wx_sqlite3VdbeJumpHere(v, addr);
+ wx_sqlite3VdbeChangeP3(v, addr, ret);
+ }
+ return ret;
+ }
+ }
+ return 0;
+}
+
+
+/*
** Generate code into the current Vdbe to evaluate the given
** expression. Attempt to store the results in register "target".
** Return the register where results are stored.
@@ -110035,12 +114306,25 @@ expr_code_doover:
assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
op = pExpr->op;
}
+ assert( op!=TK_ORDER );
switch( op ){
case TK_AGG_COLUMN: {
AggInfo *pAggInfo = pExpr->pAggInfo;
struct AggInfo_col *pCol;
assert( pAggInfo!=0 );
- assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ assert( pExpr->iAgg>=0 );
+ if( pExpr->iAgg>=pAggInfo->nColumn ){
+ /* Happens when the left table of a RIGHT JOIN is null and
+ ** is using an expression index */
+ wx_sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+#ifdef SQLITE_VDBE_COVERAGE
+ /* Verify that the OP_Null above is exercised by tests
+ ** tag-20230325-2 */
+ wx_sqlite3VdbeAddOp3(v, OP_NotNull, target, 1, 20230325);
+ VdbeCoverageNeverTaken(v);
+#endif
+ break;
+ }
pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
return AggInfoColumnReg(pAggInfo, pExpr->iAgg);
@@ -110075,7 +114359,7 @@ expr_code_doover:
if( ExprHasProperty(pExpr, EP_FixedCol) ){
/* This COLUMN expression is really a constant due to WHERE clause
** constraints, and that constant is coded by the pExpr->pLeft
- ** expresssion. However, make sure the constant has the correct
+ ** expression. However, make sure the constant has the correct
** datatype by applying the Affinity of the table column to the
** constant.
*/
@@ -110144,6 +114428,11 @@ expr_code_doover:
iTab = pParse->iSelfTab - 1;
}
}
+ else if( pParse->pIdxPartExpr
+ && 0!=(r1 = exprPartidxExprLookup(pParse, pExpr, target))
+ ){
+ return r1;
+ }
assert( ExprUseYTab(pExpr) );
assert( pExpr->y.pTab!=0 );
iReg = wx_sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
@@ -110201,12 +114490,6 @@ expr_code_doover:
assert( pExpr->u.zToken!=0 );
assert( pExpr->u.zToken[0]!=0 );
wx_sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
- if( pExpr->u.zToken[1]!=0 ){
- const char *z = wx_sqlite3VListNumToName(pParse->pVList, pExpr->iColumn);
- assert( pExpr->u.zToken[0]=='?' || (z && !strcmp(pExpr->u.zToken, z)) );
- pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */
- wx_sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC);
- }
return target;
}
case TK_REGISTER: {
@@ -110215,11 +114498,8 @@ expr_code_doover:
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
- inReg = wx_sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- if( inReg!=target ){
- wx_sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
+ wx_sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ assert( inReg==target );
assert( !ExprHasProperty(pExpr, EP_IntValue) );
wx_sqlite3VdbeAddOp2(v, OP_Cast, target,
wx_sqlite3AffinityType(pExpr->u.zToken, 0));
@@ -110383,7 +114663,9 @@ expr_code_doover:
}
#endif
- if( ConstFactorOk(pParse) && wx_sqlite3ExprIsConstantNotJoin(pExpr) ){
+ if( ConstFactorOk(pParse)
+ && wx_sqlite3ExprIsConstantNotJoin(pParse,pExpr)
+ ){
/* SQL functions can be expensive. So try to avoid running them
** multiple times if we know they always give the same result */
return wx_sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
@@ -110404,7 +114686,7 @@ expr_code_doover:
wx_sqlite3ErrorMsg(pParse, "unknown function: %#T()", pExpr);
break;
}
- if( pDef->funcFlags & SQLITE_FUNC_INLINE ){
+ if( (pDef->funcFlags & SQLITE_FUNC_INLINE)!=0 && ALWAYS(pFarg!=0) ){
assert( (pDef->funcFlags & SQLITE_FUNC_UNSAFE)==0 );
assert( (pDef->funcFlags & SQLITE_FUNC_DIRECT)==0 );
return exprCodeInlineFunction(pParse, pFarg,
@@ -110414,7 +114696,7 @@ expr_code_doover:
}
for(i=0; i<nFarg; i++){
- if( i<32 && wx_sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
+ if( i<32 && wx_sqlite3ExprIsConstant(pParse, pFarg->a[i].pExpr) ){
testcase( i==31 );
constMask |= MASKBIT32(i);
}
@@ -110430,10 +114712,10 @@ expr_code_doover:
r1 = wx_sqlite3GetTempRange(pParse, nFarg);
}
- /* For length() and typeof() functions with a column argument,
+ /* For length() and typeof() and octet_length() functions,
** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG
- ** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
- ** loading.
+ ** or OPFLAG_TYPEOFARG or OPFLAG_BYTELENARG respectively, to avoid
+ ** unnecessary data loading.
*/
if( (pDef->funcFlags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
u8 exprOp;
@@ -110443,14 +114725,16 @@ expr_code_doover:
if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
- testcase( pDef->funcFlags & OPFLAG_LENGTHARG );
- pFarg->a[0].pExpr->op2 =
- pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
+ assert( SQLITE_FUNC_BYTELEN==OPFLAG_BYTELENARG );
+ assert( (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG)==OPFLAG_BYTELENARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_LENGTHARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_TYPEOFARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_BYTELENARG);
+ pFarg->a[0].pExpr->op2 = pDef->funcFlags & OPFLAG_BYTELENARG;
}
}
- wx_sqlite3ExprCodeExprList(pParse, pFarg, r1, 0,
- SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
+ wx_sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_FACTOR);
}else{
r1 = 0;
}
@@ -110554,17 +114838,14 @@ expr_code_doover:
if( !ExprHasProperty(pExpr, EP_Collate) ){
/* A TK_COLLATE Expr node without the EP_Collate tag is a so-called
** "SOFT-COLLATE" that is added to constraints that are pushed down
- ** from outer queries into sub-queries by the push-down optimization.
- ** Clear subtypes as subtypes may not cross a subquery boundary.
+ ** from outer queries into sub-queries by the WHERE-clause push-down
+ ** optimization. Clear subtypes as subtypes may not cross a subquery
+ ** boundary.
*/
assert( pExpr->pLeft );
- inReg = wx_sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- if( inReg!=target ){
- wx_sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
- wx_sqlite3VdbeAddOp1(v, OP_ClrSubtype, inReg);
- return inReg;
+ wx_sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ wx_sqlite3VdbeAddOp1(v, OP_ClrSubtype, target);
+ return target;
}else{
pExpr = pExpr->pLeft;
goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. */
@@ -110674,12 +114955,9 @@ expr_code_doover:
** "target" and not someplace else.
*/
pParse->okConstFactor = 0; /* note (1) above */
- inReg = wx_sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
+ wx_sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ assert( target==inReg );
pParse->okConstFactor = okConstFactor;
- if( inReg!=target ){ /* note (2) above */
- wx_sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
wx_sqlite3VdbeJumpHere(v, addrINR);
break;
}
@@ -110731,7 +115009,7 @@ expr_code_doover:
break;
}
testcase( pX->op==TK_COLUMN );
- exprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
+ wx_sqlite3ExprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
testcase( regFree1==0 );
memset(&opCompare, 0, sizeof(opCompare));
opCompare.op = TK_EQ;
@@ -110785,15 +115063,14 @@ expr_code_doover:
}
assert( !ExprHasProperty(pExpr, EP_IntValue) );
if( pExpr->affExpr==OE_Ignore ){
- wx_sqlite3VdbeAddOp4(
- v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
+ wx_sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, OE_Ignore);
VdbeCoverage(v);
}else{
- wx_sqlite3HaltConstraint(pParse,
+ r1 = wx_sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ wx_sqlite3VdbeAddOp3(v, OP_Halt,
pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
- pExpr->affExpr, pExpr->u.zToken, 0, 0);
+ pExpr->affExpr, r1);
}
-
break;
}
#endif
@@ -110812,9 +115089,9 @@ expr_code_doover:
** once. If no functions are involved, then factor the code out and put it at
** the end of the prepared statement in the initialization section.
**
-** If regDest>=0 then the result is always stored in that register and the
+** If regDest>0 then the result is always stored in that register and the
** result is not reusable. If regDest<0 then this routine is free to
-** store the value whereever it wants. The register where the expression
+** store the value wherever it wants. The register where the expression
** is stored is returned. When regDest<0, two identical expressions might
** code to the same register, if they do not contain function calls and hence
** are factored out into the initialization section at the end of the
@@ -110827,6 +115104,7 @@ SQLITE_PRIVATE int wx_sqlite3ExprCodeRunJustOnce(
){
ExprList *p;
assert( ConstFactorOk(pParse) );
+ assert( regDest!=0 );
p = pParse->pConstExpr;
if( regDest<0 && p ){
struct ExprList_item *pItem;
@@ -110885,7 +115163,7 @@ SQLITE_PRIVATE int wx_sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg)
if( ConstFactorOk(pParse)
&& ALWAYS(pExpr!=0)
&& pExpr->op!=TK_REGISTER
- && wx_sqlite3ExprIsConstantNotJoin(pExpr)
+ && wx_sqlite3ExprIsConstantNotJoin(pParse, pExpr)
){
*pReg = 0;
r2 = wx_sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
@@ -110917,7 +115195,11 @@ SQLITE_PRIVATE void wx_sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
inReg = wx_sqlite3ExprCodeTarget(pParse, pExpr, target);
if( inReg!=target ){
u8 op;
- if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){
+ Expr *pX = wx_sqlite3ExprSkipCollateAndLikely(pExpr);
+ testcase( pX!=pExpr );
+ if( ALWAYS(pX)
+ && (ExprHasProperty(pX,EP_Subquery) || pX->op==TK_REGISTER)
+ ){
op = OP_Copy;
}else{
op = OP_SCopy;
@@ -110945,7 +115227,7 @@ SQLITE_PRIVATE void wx_sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int targe
** might choose to code the expression at initialization time.
*/
SQLITE_PRIVATE void wx_sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
- if( pParse->okConstFactor && wx_sqlite3ExprIsConstantNotJoin(pExpr) ){
+ if( pParse->okConstFactor && wx_sqlite3ExprIsConstantNotJoin(pParse,pExpr) ){
wx_sqlite3ExprCodeRunJustOnce(pParse, pExpr, target);
}else{
wx_sqlite3ExprCodeCopy(pParse, pExpr, target);
@@ -111004,7 +115286,7 @@ SQLITE_PRIVATE int wx_sqlite3ExprCodeExprList(
wx_sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
}
}else if( (flags & SQLITE_ECEL_FACTOR)!=0
- && wx_sqlite3ExprIsConstantNotJoin(pExpr)
+ && wx_sqlite3ExprIsConstantNotJoin(pParse,pExpr)
){
wx_sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i);
}else{
@@ -111077,7 +115359,7 @@ static void exprCodeBetween(
compRight.op = TK_LE;
compRight.pLeft = pDel;
compRight.pRight = pExpr->x.pList->a[1].pExpr;
- exprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
+ wx_sqlite3ExprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
if( xJump ){
xJump(pParse, &exprAnd, dest, jumpIfNull);
}else{
@@ -111636,8 +115918,8 @@ SQLITE_PRIVATE int wx_sqlite3ExprListCompare(const ExprList *pA, const ExprList
*/
SQLITE_PRIVATE int wx_sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){
return wx_sqlite3ExprCompare(0,
- wx_sqlite3ExprSkipCollateAndLikely(pA),
- wx_sqlite3ExprSkipCollateAndLikely(pB),
+ wx_sqlite3ExprSkipCollate(pA),
+ wx_sqlite3ExprSkipCollate(pB),
iTab);
}
@@ -111730,7 +116012,7 @@ static int exprImpliesNotNull(
** pE1: x!=123 pE2: x IS NOT NULL Result: true
** pE1: x!=?1 pE2: x IS NOT NULL Result: true
** pE1: x IS NULL pE2: x IS NOT NULL Result: false
-** pE1: x IS ?2 pE2: x IS NOT NULL Reuslt: false
+** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
**
** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
** Expr.iTable<0 then assume a table number given by iTab.
@@ -111767,11 +116049,29 @@ SQLITE_PRIVATE int wx_sqlite3ExprImpliesExpr(
return 0;
}
+/* This is a helper function to impliesNotNullRow(). In this routine,
+** set pWalker->eCode to one only if *both* of the input expressions
+** separately have the implies-not-null-row property.
+*/
+static void bothImplyNotNullRow(Walker *pWalker, Expr *pE1, Expr *pE2){
+ if( pWalker->eCode==0 ){
+ wx_sqlite3WalkExpr(pWalker, pE1);
+ if( pWalker->eCode ){
+ pWalker->eCode = 0;
+ wx_sqlite3WalkExpr(pWalker, pE2);
+ }
+ }
+}
+
/*
** This is the Expr node callback for wx_sqlite3ExprImpliesNonNullRow().
** If the expression node requires that the table at pWalker->iCur
** have one or more non-NULL column, then set pWalker->eCode to 1 and abort.
**
+** pWalker->mWFlags is non-zero if this inquiry is being undertaking on
+** behalf of a RIGHT JOIN (or FULL JOIN). That makes a difference when
+** evaluating terms in the ON clause of an inner join.
+**
** This routine controls an optimization. False positives (setting
** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives
** (never setting pWalker->eCode) is a harmless missed optimization.
@@ -111780,28 +116080,33 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_AGG_COLUMN );
testcase( pExpr->op==TK_AGG_FUNCTION );
if( ExprHasProperty(pExpr, EP_OuterON) ) return WRC_Prune;
+ if( ExprHasProperty(pExpr, EP_InnerON) && pWalker->mWFlags ){
+ /* If iCur is used in an inner-join ON clause to the left of a
+ ** RIGHT JOIN, that does *not* mean that the table must be non-null.
+ ** But it is difficult to check for that condition precisely.
+ ** To keep things simple, any use of iCur from any inner-join is
+ ** ignored while attempting to simplify a RIGHT JOIN. */
+ return WRC_Prune;
+ }
switch( pExpr->op ){
case TK_ISNOT:
case TK_ISNULL:
case TK_NOTNULL:
case TK_IS:
- case TK_OR:
case TK_VECTOR:
- case TK_CASE:
- case TK_IN:
case TK_FUNCTION:
case TK_TRUTH:
+ case TK_CASE:
testcase( pExpr->op==TK_ISNOT );
testcase( pExpr->op==TK_ISNULL );
testcase( pExpr->op==TK_NOTNULL );
testcase( pExpr->op==TK_IS );
- testcase( pExpr->op==TK_OR );
testcase( pExpr->op==TK_VECTOR );
- testcase( pExpr->op==TK_CASE );
- testcase( pExpr->op==TK_IN );
testcase( pExpr->op==TK_FUNCTION );
testcase( pExpr->op==TK_TRUTH );
+ testcase( pExpr->op==TK_CASE );
return WRC_Prune;
+
case TK_COLUMN:
if( pWalker->u.iCur==pExpr->iTable ){
pWalker->eCode = 1;
@@ -111809,21 +116114,38 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
}
return WRC_Prune;
+ case TK_OR:
case TK_AND:
- if( pWalker->eCode==0 ){
+ /* Both sides of an AND or OR must separately imply non-null-row.
+ ** Consider these cases:
+ ** 1. NOT (x AND y)
+ ** 2. x OR y
+ ** If only one of x or y is non-null-row, then the overall expression
+ ** can be true if the other arm is false (case 1) or true (case 2).
+ */
+ testcase( pExpr->op==TK_OR );
+ testcase( pExpr->op==TK_AND );
+ bothImplyNotNullRow(pWalker, pExpr->pLeft, pExpr->pRight);
+ return WRC_Prune;
+
+ case TK_IN:
+ /* Beware of "x NOT IN ()" and "x NOT IN (SELECT 1 WHERE false)",
+ ** both of which can be true. But apart from these cases, if
+ ** the left-hand side of the IN is NULL then the IN itself will be
+ ** NULL. */
+ if( ExprUseXList(pExpr) && ALWAYS(pExpr->x.pList->nExpr>0) ){
wx_sqlite3WalkExpr(pWalker, pExpr->pLeft);
- if( pWalker->eCode ){
- pWalker->eCode = 0;
- wx_sqlite3WalkExpr(pWalker, pExpr->pRight);
- }
}
return WRC_Prune;
case TK_BETWEEN:
- if( wx_sqlite3WalkExpr(pWalker, pExpr->pLeft)==WRC_Abort ){
- assert( pWalker->eCode );
- return WRC_Abort;
- }
+ /* In "x NOT BETWEEN y AND z" either x must be non-null-row or else
+ ** both y and z must be non-null row */
+ assert( ExprUseXList(pExpr) );
+ assert( pExpr->x.pList->nExpr==2 );
+ wx_sqlite3WalkExpr(pWalker, pExpr->pLeft);
+ bothImplyNotNullRow(pWalker, pExpr->x.pList->a[0].pExpr,
+ pExpr->x.pList->a[1].pExpr);
return WRC_Prune;
/* Virtual tables are allowed to use constraints like x=NULL. So
@@ -111885,7 +116207,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
** be non-NULL, then the LEFT JOIN can be safely converted into an
** ordinary join.
*/
-SQLITE_PRIVATE int wx_sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
+SQLITE_PRIVATE int wx_sqlite3ExprImpliesNonNullRow(Expr *p, int iTab, int isRJ){
Walker w;
p = wx_sqlite3ExprSkipCollateAndLikely(p);
if( p==0 ) return 0;
@@ -111893,7 +116215,7 @@ SQLITE_PRIVATE int wx_sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
p = p->pLeft;
}else{
while( p->op==TK_AND ){
- if( wx_sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1;
+ if( wx_sqlite3ExprImpliesNonNullRow(p->pLeft, iTab, isRJ) ) return 1;
p = p->pRight;
}
}
@@ -111901,6 +116223,7 @@ SQLITE_PRIVATE int wx_sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
w.xSelectCallback = 0;
w.xSelectCallback2 = 0;
w.eCode = 0;
+ w.mWFlags = isRJ!=0;
w.u.iCur = iTab;
wx_sqlite3WalkExpr(&w, p);
return w.eCode;
@@ -111961,7 +116284,7 @@ SQLITE_PRIVATE int wx_sqlite3ExprCoveredByIndex(
}
-/* Structure used to pass information throught the Walker in order to
+/* Structure used to pass information throughout the Walker in order to
** implement wx_sqlite3ReferencesSrcList().
*/
struct RefSrcList {
@@ -112068,6 +116391,12 @@ SQLITE_PRIVATE int wx_sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcLi
assert( pExpr->op==TK_AGG_FUNCTION );
assert( ExprUseXList(pExpr) );
wx_sqlite3WalkExprList(&w, pExpr->x.pList);
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ assert( pExpr->pLeft->x.pList!=0 );
+ wx_sqlite3WalkExprList(&w, pExpr->pLeft->x.pList);
+ }
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(pExpr, EP_WinFunc) ){
wx_sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
@@ -112102,23 +116431,24 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
int iAgg = pExpr->iAgg;
Parse *pParse = pWalker->pParse;
wx_sqlite3 *db = pParse->db;
+ assert( iAgg>=0 );
if( pExpr->op!=TK_AGG_FUNCTION ){
- assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
- if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
+ if( iAgg<pAggInfo->nColumn
+ && pAggInfo->aCol[iAgg].pCExpr==pExpr
+ ){
pExpr = wx_sqlite3ExprDup(db, pExpr, 0);
- if( pExpr ){
+ if( pExpr && !wx_sqlite3ExprDeferredDelete(pParse, pExpr) ){
pAggInfo->aCol[iAgg].pCExpr = pExpr;
- wx_sqlite3ExprDeferredDelete(pParse, pExpr);
}
}
}else{
assert( pExpr->op==TK_AGG_FUNCTION );
- assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
- if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
+ if( ALWAYS(iAgg<pAggInfo->nFunc)
+ && pAggInfo->aFunc[iAgg].pFExpr==pExpr
+ ){
pExpr = wx_sqlite3ExprDup(db, pExpr, 0);
- if( pExpr ){
+ if( pExpr && !wx_sqlite3ExprDeferredDelete(pParse, pExpr) ){
pAggInfo->aFunc[iAgg].pFExpr = pExpr;
- wx_sqlite3ExprDeferredDelete(pParse, pExpr);
}
}
}
@@ -112174,7 +116504,7 @@ static int addAggInfoFunc(wx_sqlite3 *db, AggInfo *pInfo){
** Return the index in aCol[] of the entry that describes that column.
**
** If no prior entry is found, create a new one and return -1. The
-** new column will have an idex of pAggInfo->nColumn-1.
+** new column will have an index of pAggInfo->nColumn-1.
*/
static void findOrCreateAggInfoColumn(
Parse *pParse, /* Parsing context */
@@ -112187,6 +116517,7 @@ static void findOrCreateAggInfoColumn(
assert( pAggInfo->iFirstReg==0 );
pCol = pAggInfo->aCol;
for(k=0; k<pAggInfo->nColumn; k++, pCol++){
+ if( pCol->pCExpr==pExpr ) return;
if( pCol->iTable==pExpr->iTable
&& pCol->iColumn==pExpr->iColumn
&& pExpr->op!=TK_IF_NULL_ROW
@@ -112264,7 +116595,12 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
}
if( pIEpr==0 ) break;
if( NEVER(!ExprUseYTab(pExpr)) ) break;
- if( pExpr->pAggInfo!=0 ) break; /* Already resolved by outer context */
+ for(i=0; i<pSrcList->nSrc; i++){
+ if( pSrcList->a[0].iCursor==pIEpr->iDataCur ) break;
+ }
+ if( i>=pSrcList->nSrc ) break;
+ if( NEVER(pExpr->pAggInfo!=0) ) break; /* Resolved by outer context */
+ if( pParse->nErr ){ return WRC_Abort; }
/* If we reach this point, it means that expression pExpr can be
** translated into a reference to an index column as described by
@@ -112275,6 +116611,9 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
tmp.iTable = pIEpr->iIdxCur;
tmp.iColumn = pIEpr->iIdxCol;
findOrCreateAggInfoColumn(pParse, pAggInfo, &tmp);
+ if( pParse->nErr ){ return WRC_Abort; }
+ assert( pAggInfo->aCol!=0 );
+ assert( tmp.iAgg<pAggInfo->nColumn );
pAggInfo->aCol[tmp.iAgg].pCExpr = pExpr;
pExpr->pAggInfo = pAggInfo;
pExpr->iAgg = tmp.iAgg;
@@ -112298,18 +116637,19 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
} /* endif pExpr->iTable==pItem->iCursor */
} /* end loop over pSrcList */
}
- return WRC_Prune;
+ return WRC_Continue;
}
case TK_AGG_FUNCTION: {
if( (pNC->ncFlags & NC_InAggFunc)==0
&& pWalker->walkerDepth==pExpr->op2
+ && pExpr->pAggInfo==0
){
/* Check to see if pExpr is a duplicate of another aggregate
** function that is already in the pAggInfo structure
*/
struct AggInfo_func *pItem = pAggInfo->aFunc;
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
- if( pItem->pFExpr==pExpr ) break;
+ if( NEVER(pItem->pFExpr==pExpr) ) break;
if( wx_sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
break;
}
@@ -112320,14 +116660,44 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
u8 enc = ENC(pParse->db);
i = addAggInfoFunc(pParse->db, pAggInfo);
if( i>=0 ){
+ int nArg;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pItem = &pAggInfo->aFunc[i];
pItem->pFExpr = pExpr;
assert( ExprUseUToken(pExpr) );
+ nArg = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
pItem->pFunc = wx_sqlite3FindFunction(pParse->db,
- pExpr->u.zToken,
- pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
- if( pExpr->flags & EP_Distinct ){
+ pExpr->u.zToken, nArg, enc, 0);
+ assert( pItem->bOBUnique==0 );
+ if( pExpr->pLeft
+ && (pItem->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)==0
+ ){
+ /* The NEEDCOLL test above causes any ORDER BY clause on
+ ** aggregate min() or max() to be ignored. */
+ ExprList *pOBList;
+ assert( nArg>0 );
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ pItem->iOBTab = pParse->nTab++;
+ pOBList = pExpr->pLeft->x.pList;
+ assert( pOBList->nExpr>0 );
+ assert( pItem->bOBUnique==0 );
+ if( pOBList->nExpr==1
+ && nArg==1
+ && wx_sqlite3ExprCompare(0,pOBList->a[0].pExpr,
+ pExpr->x.pList->a[0].pExpr,0)==0
+ ){
+ pItem->bOBPayload = 0;
+ pItem->bOBUnique = ExprHasProperty(pExpr, EP_Distinct);
+ }else{
+ pItem->bOBPayload = 1;
+ }
+ pItem->bUseSubtype =
+ (pItem->pFunc->funcFlags & SQLITE_SUBTYPE)!=0;
+ }else{
+ pItem->iOBTab = -1;
+ }
+ if( ExprHasProperty(pExpr, EP_Distinct) && !pItem->bOBUnique ){
pItem->iDistinct = pParse->nTab++;
}else{
pItem->iDistinct = -1;
@@ -112452,6 +116822,37 @@ SQLITE_PRIVATE void wx_sqlite3ClearTempRegCache(Parse *pParse){
}
/*
+** Make sure sufficient registers have been allocated so that
+** iReg is a valid register number.
+*/
+SQLITE_PRIVATE void wx_sqlite3TouchRegister(Parse *pParse, int iReg){
+ if( pParse->nMem<iReg ) pParse->nMem = iReg;
+}
+
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
+/*
+** Return the latest reusable register in the set of all registers.
+** The value returned is no less than iMin. If any register iMin or
+** greater is in permanent use, then return one more than that last
+** permanent register.
+*/
+SQLITE_PRIVATE int wx_sqlite3FirstAvailableRegister(Parse *pParse, int iMin){
+ const ExprList *pList = pParse->pConstExpr;
+ if( pList ){
+ int i;
+ for(i=0; i<pList->nExpr; i++){
+ if( pList->a[i].u.iConstExprReg>=iMin ){
+ iMin = pList->a[i].u.iConstExprReg + 1;
+ }
+ }
+ }
+ pParse->nTempReg = 0;
+ pParse->nRangeReg = 0;
+ return iMin;
+}
+#endif /* SQLITE_ENABLE_STAT4 || SQLITE_DEBUG */
+
+/*
** Validate that no temporary register falls within the range of
** iFirst..iLast, inclusive. This routine is only call from within assert()
** statements.
@@ -112470,6 +116871,14 @@ SQLITE_PRIVATE int wx_sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast
return 0;
}
}
+ if( pParse->pConstExpr ){
+ ExprList *pList = pParse->pConstExpr;
+ for(i=0; i<pList->nExpr; i++){
+ int iReg = pList->a[i].u.iConstExprReg;
+ if( iReg==0 ) continue;
+ if( iReg>=iFirst && iReg<=iLast ) return 0;
+ }
+ }
return 1;
}
#endif /* SQLITE_DEBUG */
@@ -112924,14 +117333,19 @@ SQLITE_PRIVATE void wx_sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef
/* Verify that constraints are still satisfied */
if( pNew->pCheck!=0
|| (pCol->notNull && (pCol->colFlags & COLFLAG_GENERATED)!=0)
+ || (pTab->tabFlags & TF_Strict)!=0
){
wx_sqlite3NestedParse(pParse,
"SELECT CASE WHEN quick_check GLOB 'CHECK*'"
" THEN raise(ABORT,'CHECK constraint failed')"
+ " WHEN quick_check GLOB 'non-* value in*'"
+ " THEN raise(ABORT,'type mismatch on DEFAULT')"
" ELSE raise(ABORT,'NOT NULL constraint failed')"
" END"
" FROM pragma_quick_check(%Q,%Q)"
- " WHERE quick_check GLOB 'CHECK*' OR quick_check GLOB 'NULL*'",
+ " WHERE quick_check GLOB 'CHECK*'"
+ " OR quick_check GLOB 'NULL*'"
+ " OR quick_check GLOB 'non-* value in*'",
zTab, zDb
);
}
@@ -113020,7 +117434,7 @@ SQLITE_PRIVATE void wx_sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
pNew->u.tab.pDfltList = wx_sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0);
pNew->pSchema = db->aDb[iDb].pSchema;
pNew->u.tab.addColOffset = pTab->u.tab.addColOffset;
- pNew->nTabRef = 1;
+ assert( pNew->nTabRef==1 );
exit_begin_add_column:
wx_sqlite3SrcListDelete(db, pSrc);
@@ -113525,7 +117939,7 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
}
/*
-** An error occured while parsing or otherwise processing a database
+** An error occurred while parsing or otherwise processing a database
** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an
** ALTER TABLE RENAME COLUMN program. The error message emitted by the
** sub-routine is currently stored in pParse->zErrMsg. This function
@@ -113758,6 +118172,19 @@ static int renameEditSql(
}
/*
+** Set all pEList->a[].fg.eEName fields in the expression-list to val.
+*/
+static void renameSetENames(ExprList *pEList, int val){
+ if( pEList ){
+ int i;
+ for(i=0; i<pEList->nExpr; i++){
+ assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME );
+ pEList->a[i].fg.eEName = val;
+ }
+ }
+}
+
+/*
** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming
** it was read from the schema of database zDb. Return SQLITE_OK if
** successful. Otherwise, return an SQLite error code and leave an error
@@ -113780,7 +118207,7 @@ static int renameResolveTrigger(Parse *pParse){
/* ALWAYS() because if the table of the trigger does not exist, the
** error would have been hit before this point */
if( ALWAYS(pParse->pTriggerTab) ){
- rc = wx_sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab);
+ rc = wx_sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab)!=0;
}
/* Resolve symbols in WHEN clause */
@@ -113804,7 +118231,17 @@ static int renameResolveTrigger(Parse *pParse){
pSrc = 0;
rc = SQLITE_NOMEM;
}else{
+ /* pStep->pExprList contains an expression-list used for an UPDATE
+ ** statement. So the a[].zEName values are the RHS of the
+ ** "<col> = <expr>" clauses of the UPDATE statement. So, before
+ ** running SelectPrep(), change all the eEName values in
+ ** pStep->pExprList to ENAME_SPAN (from their current value of
+ ** ENAME_NAME). This is to prevent any ids in ON() clauses that are
+ ** part of pSrc from being incorrectly resolved against the
+ ** a[].zEName values as if they were column aliases. */
+ renameSetENames(pStep->pExprList, ENAME_SPAN);
wx_sqlite3SelectPrep(pParse, pSel, 0);
+ renameSetENames(pStep->pExprList, ENAME_NAME);
rc = pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
assert( pStep->pExprList==0 || pStep->pExprList==pSel->pEList );
assert( pSrc==pSel->pSrc );
@@ -113816,8 +118253,9 @@ static int renameResolveTrigger(Parse *pParse){
int i;
for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){
SrcItem *p = &pStep->pFrom->a[i];
- if( p->pSelect ){
- wx_sqlite3SelectPrep(pParse, p->pSelect, 0);
+ if( p->fg.isSubquery ){
+ assert( p->u4.pSubq!=0 );
+ wx_sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0);
}
}
}
@@ -113885,8 +118323,12 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
}
if( pStep->pFrom ){
int i;
- for(i=0; i<pStep->pFrom->nSrc; i++){
- wx_sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect);
+ SrcList *pFrom = pStep->pFrom;
+ for(i=0; i<pFrom->nSrc; i++){
+ if( pFrom->a[i].fg.isSubquery ){
+ assert( pFrom->a[i].u4.pSubq!=0 );
+ wx_sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect);
+ }
}
}
}
@@ -114133,7 +118575,7 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
}
for(i=0; i<pSrc->nSrc; i++){
SrcItem *pItem = &pSrc->a[i];
- if( pItem->pTab==p->pTab ){
+ if( pItem->pSTab==p->pTab ){
renameTokenFind(pWalker->pParse, p, pItem->zName);
}
}
@@ -114712,7 +119154,12 @@ SQLITE_PRIVATE void wx_sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, cons
if( i==pTab->iPKey ){
wx_sqlite3VdbeAddOp2(v, OP_Null, 0, regOut);
}else{
+ char aff = pTab->aCol[i].affinity;
+ if( aff==SQLITE_AFF_REAL ){
+ pTab->aCol[i].affinity = SQLITE_AFF_NUMERIC;
+ }
wx_sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
+ pTab->aCol[i].affinity = aff;
}
nField++;
}
@@ -115023,9 +119470,9 @@ static void openStatTable(
typedef struct StatAccum StatAccum;
typedef struct StatSample StatSample;
struct StatSample {
- tRowcnt *anEq; /* sqlite_stat4.nEq */
tRowcnt *anDLt; /* sqlite_stat4.nDLt */
#ifdef SQLITE_ENABLE_STAT4
+ tRowcnt *anEq; /* sqlite_stat4.nEq */
tRowcnt *anLt; /* sqlite_stat4.nLt */
union {
i64 iRowid; /* Rowid in main table of the key */
@@ -115183,9 +119630,9 @@ static void statInit(
/* Allocate the space required for the StatAccum object */
n = sizeof(*p)
- + sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
- + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
+ + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
#ifdef SQLITE_ENABLE_STAT4
+ n += sizeof(tRowcnt)*nColUp; /* StatAccum.anEq */
if( mxSample ){
n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
+ sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
@@ -115206,9 +119653,9 @@ static void statInit(
p->nKeyCol = nKeyCol;
p->nSkipAhead = 0;
p->current.anDLt = (tRowcnt*)&p[1];
- p->current.anEq = &p->current.anDLt[nColUp];
#ifdef SQLITE_ENABLE_STAT4
+ p->current.anEq = &p->current.anDLt[nColUp];
p->mxSample = p->nLimit==0 ? mxSample : 0;
if( mxSample ){
u8 *pSpace; /* Allocated space not yet assigned */
@@ -115475,7 +119922,9 @@ static void statPush(
if( p->nRow==0 ){
/* This is the first call to this function. Do initialization. */
+#ifdef SQLITE_ENABLE_STAT4
for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
+#endif
}else{
/* Second and subsequent calls get processed here */
#ifdef SQLITE_ENABLE_STAT4
@@ -115484,15 +119933,17 @@ static void statPush(
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
** to the current row of the index. */
+#ifdef SQLITE_ENABLE_STAT4
for(i=0; i<iChng; i++){
p->current.anEq[i]++;
}
+#endif
for(i=iChng; i<p->nCol; i++){
p->current.anDLt[i]++;
#ifdef SQLITE_ENABLE_STAT4
if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i];
-#endif
p->current.anEq[i] = 1;
+#endif
}
}
@@ -115626,7 +120077,9 @@ static void statGet(
u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1;
wx_sqlite3_str_appendf(&sStat, " %llu", iVal);
- assert( p->current.anEq[i] );
+#ifdef SQLITE_ENABLE_STAT4
+ assert( p->current.anEq[i] || p->nRow==0 );
+#endif
}
wx_sqlite3ResultStrAccum(context, &sStat);
}
@@ -115753,11 +120206,15 @@ static void analyzeOneTable(
int regIdxname = iMem++; /* Register containing index name */
int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */
int regPrev = iMem; /* MUST BE LAST (see below) */
+#ifdef SQLITE_ENABLE_STAT4
+ int doOnce = 1; /* Flag for a one-time computation */
+#endif
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
Table *pStat1 = 0;
#endif
- pParse->nMem = MAX(pParse->nMem, iMem);
+ wx_sqlite3TouchRegister(pParse, iMem);
+ assert( wx_sqlite3NoTempsInRange(pParse, regNewRowid, iMem) );
v = wx_sqlite3GetVdbe(pParse);
if( v==0 || NEVER(pTab==0) ){
return;
@@ -115806,7 +120263,7 @@ static void analyzeOneTable(
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int nCol; /* Number of columns in pIdx. "N" */
- int addrRewind; /* Address of "OP_Rewind iIdxCur" */
+ int addrGotoEnd; /* Address of "OP_Rewind iIdxCur" */
int addrNextRow; /* Address of "next_row:" */
const char *zIdxName; /* Name of the index */
int nColTest; /* Number of columns to test for changes */
@@ -115830,9 +120287,14 @@ static void analyzeOneTable(
/*
** Pseudo-code for loop that calls stat_push():
**
- ** Rewind csr
- ** if eof(csr) goto end_of_scan;
** regChng = 0
+ ** Rewind csr
+ ** if eof(csr){
+ ** stat_init() with count = 0;
+ ** goto end_of_scan;
+ ** }
+ ** count()
+ ** stat_init()
** goto chng_addr_0;
**
** next_row:
@@ -115863,7 +120325,7 @@ static void analyzeOneTable(
** the regPrev array and a trailing rowid (the rowid slot is required
** when building a record to insert into the sample column of
** the sqlite_stat4 table. */
- pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
+ wx_sqlite3TouchRegister(pParse, regPrev+nColTest);
/* Open a read-only cursor on the index being analyzed. */
assert( iDb==wx_sqlite3SchemaToIndex(db, pIdx->pSchema) );
@@ -115871,41 +120333,36 @@ static void analyzeOneTable(
wx_sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
- /* Invoke the stat_init() function. The arguments are:
+ /* Implementation of the following:
**
+ ** regChng = 0
+ ** Rewind csr
+ ** if eof(csr){
+ ** stat_init() with count = 0;
+ ** goto end_of_scan;
+ ** }
+ ** count()
+ ** stat_init()
+ ** goto chng_addr_0;
+ */
+ assert( regTemp2==regStat+4 );
+ wx_sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
+
+ /* Arguments to stat_init():
** (1) the number of columns in the index including the rowid
** (or for a WITHOUT ROWID table, the number of PK columns),
** (2) the number of columns in the key without the rowid/pk
- ** (3) estimated number of rows in the index,
- */
+ ** (3) estimated number of rows in the index. */
wx_sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1);
assert( regRowid==regStat+2 );
wx_sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid);
-#ifdef SQLITE_ENABLE_STAT4
- if( OptimizationEnabled(db, SQLITE_Stat4) ){
- wx_sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp);
- addrRewind = wx_sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
- VdbeCoverage(v);
- }else
-#endif
- {
- addrRewind = wx_sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
- VdbeCoverage(v);
- wx_sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1);
- }
- assert( regTemp2==regStat+4 );
- wx_sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
+ wx_sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp,
+ OptimizationDisabled(db, SQLITE_Stat4));
wx_sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4,
&statInitFuncdef, 0);
+ addrGotoEnd = wx_sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
+ VdbeCoverage(v);
- /* Implementation of the following:
- **
- ** Rewind csr
- ** if eof(csr) goto end_of_scan;
- ** regChng = 0
- ** goto next_push_0;
- **
- */
wx_sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
addrNextRow = wx_sqlite3VdbeCurrentAddr(v);
@@ -116012,6 +120469,12 @@ static void analyzeOneTable(
}
/* Add the entry to the stat1 table. */
+ if( pIdx->pPartIdxWhere ){
+ /* Partial indexes might get a zero-entry in sqlite_stat1. But
+ ** an empty table is omitted from sqlite_stat1. */
+ wx_sqlite3VdbeJumpHere(v, addrGotoEnd);
+ addrGotoEnd = 0;
+ }
callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1);
assert( "BBB"[0]==SQLITE_AFF_TEXT );
wx_sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
@@ -116035,7 +120498,42 @@ static void analyzeOneTable(
int addrIsNull;
u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
- pParse->nMem = MAX(pParse->nMem, regCol+nCol);
+ /* No STAT4 data is generated if the number of rows is zero */
+ if( addrGotoEnd==0 ){
+ wx_sqlite3VdbeAddOp2(v, OP_Cast, regStat1, SQLITE_AFF_INTEGER);
+ addrGotoEnd = wx_sqlite3VdbeAddOp1(v, OP_IfNot, regStat1);
+ VdbeCoverage(v);
+ }
+
+ if( doOnce ){
+ int mxCol = nCol;
+ Index *pX;
+
+ /* Compute the maximum number of columns in any index */
+ for(pX=pTab->pIndex; pX; pX=pX->pNext){
+ int nColX; /* Number of columns in pX */
+ if( !HasRowid(pTab) && IsPrimaryKeyIndex(pX) ){
+ nColX = pX->nKeyCol;
+ }else{
+ nColX = pX->nColumn;
+ }
+ if( nColX>mxCol ) mxCol = nColX;
+ }
+
+ /* Allocate space to compute results for the largest index */
+ wx_sqlite3TouchRegister(pParse, regCol+mxCol);
+ doOnce = 0;
+#ifdef SQLITE_DEBUG
+ /* Verify that the call to wx_sqlite3ClearTempRegCache() below
+ ** really is needed.
+ ** https://sqlite.org/forum/forumpost/83cb4a95a0 (2023-03-25)
+ */
+ testcase( !wx_sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
+#endif
+ wx_sqlite3ClearTempRegCache(pParse); /* tag-20230325-1 */
+ assert( wx_sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
+ }
+ assert( wx_sqlite3NoTempsInRange(pParse, regEq, regCol+nCol) );
addrNext = wx_sqlite3VdbeCurrentAddr(v);
callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
@@ -116059,7 +120557,7 @@ static void analyzeOneTable(
#endif /* SQLITE_ENABLE_STAT4 */
/* End of analysis */
- wx_sqlite3VdbeJumpHere(v, addrRewind);
+ if( addrGotoEnd ) wx_sqlite3VdbeJumpHere(v, addrGotoEnd);
}
@@ -116116,6 +120614,11 @@ static void analyzeDatabase(Parse *pParse, int iDb){
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab);
+#ifdef SQLITE_ENABLE_STAT4
+ iMem = wx_sqlite3FirstAvailableRegister(pParse, iMem);
+#else
+ assert( iMem==wx_sqlite3FirstAvailableRegister(pParse,iMem) );
+#endif
}
loadAnalysis(pParse, iDb);
}
@@ -116278,6 +120781,16 @@ static void decodeIntArray(
while( z[0]!=0 && z[0]!=' ' ) z++;
while( z[0]==' ' ) z++;
}
+
+ /* Set the bLowQual flag if the peak number of rows obtained
+ ** from a full equality match is so large that a full table scan
+ ** seems likely to be faster than using the index.
+ */
+ if( aLog[0] > 66 /* Index has more than 100 rows */
+ && aLog[0] <= aLog[nOut-1] /* And only a single value seen */
+ ){
+ pIndex->bLowQual = 1;
+ }
}
}
@@ -116490,12 +121003,13 @@ static int loadStatTbl(
while( wx_sqlite3_step(pStmt)==SQLITE_ROW ){
int nIdxCol = 1; /* Number of columns in stat4 records */
- char *zIndex; /* Index name */
- Index *pIdx; /* Pointer to the index object */
- int nSample; /* Number of samples */
- int nByte; /* Bytes of space required */
- int i; /* Bytes of space required */
- tRowcnt *pSpace;
+ char *zIndex; /* Index name */
+ Index *pIdx; /* Pointer to the index object */
+ int nSample; /* Number of samples */
+ i64 nByte; /* Bytes of space required */
+ i64 i; /* Bytes of space required */
+ tRowcnt *pSpace; /* Available allocated memory space */
+ u8 *pPtr; /* Available memory as a u8 for easier manipulation */
zIndex = (char *)wx_sqlite3_column_text(pStmt, 0);
if( zIndex==0 ) continue;
@@ -116503,6 +121017,10 @@ static int loadStatTbl(
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
assert( pIdx==0 || pIdx->nSample==0 );
if( pIdx==0 ) continue;
+ if( pIdx->aSample!=0 ){
+ /* The same index appears in sqlite_stat4 under multiple names */
+ continue;
+ }
assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
nIdxCol = pIdx->nKeyCol;
@@ -116510,7 +121028,8 @@ static int loadStatTbl(
nIdxCol = pIdx->nColumn;
}
pIdx->nSampleCol = nIdxCol;
- nByte = sizeof(IndexSample) * nSample;
+ pIdx->mxSample = nSample;
+ nByte = ROUND8(sizeof(IndexSample) * nSample);
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
@@ -116519,7 +121038,10 @@ static int loadStatTbl(
wx_sqlite3_finalize(pStmt);
return SQLITE_NOMEM_BKPT;
}
- pSpace = (tRowcnt*)&pIdx->aSample[nSample];
+ pPtr = (u8*)pIdx->aSample;
+ pPtr += ROUND8(nSample*sizeof(pIdx->aSample[0]));
+ pSpace = (tRowcnt*)pPtr;
+ assert( EIGHT_BYTE_ALIGNMENT( pSpace ) );
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
pIdx->pTable->tabFlags |= TF_HasStat4;
for(i=0; i<nSample; i++){
@@ -116549,6 +121071,11 @@ static int loadStatTbl(
if( zIndex==0 ) continue;
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
if( pIdx==0 ) continue;
+ if( pIdx->nSample>=pIdx->mxSample ){
+ /* Too many slots used because the same index appears in
+ ** sqlite_stat4 using multiple names */
+ continue;
+ }
/* This next condition is true if data has already been loaded from
** the sqlite_stat4 table. */
nCol = pIdx->nSampleCol;
@@ -116561,14 +121088,15 @@ static int loadStatTbl(
decodeIntArray((char*)wx_sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0);
decodeIntArray((char*)wx_sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0);
- /* Take a copy of the sample. Add two 0x00 bytes the end of the buffer.
+ /* Take a copy of the sample. Add 8 extra 0x00 bytes the end of the buffer.
** This is in case the sample record is corrupted. In that case, the
** wx_sqlite3VdbeRecordCompare() may read up to two varints past the
** end of the allocated buffer before it realizes it is dealing with
- ** a corrupt record. Adding the two 0x00 bytes prevents this from causing
+ ** a corrupt record. Or it might try to read a large integer from the
+ ** buffer. In any case, eight 0x00 bytes prevents this from causing
** a buffer overread. */
pSample->n = wx_sqlite3_column_bytes(pStmt, 4);
- pSample->p = wx_sqlite3DbMallocZero(db, pSample->n + 2);
+ pSample->p = wx_sqlite3DbMallocZero(db, pSample->n + 8);
if( pSample->p==0 ){
wx_sqlite3_finalize(pStmt);
return SQLITE_NOMEM_BKPT;
@@ -116592,11 +121120,12 @@ static int loadStat4(wx_sqlite3 *db, const char *zDb){
const Table *pStat4;
assert( db->lookaside.bDisable );
- if( (pStat4 = wx_sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
+ if( OptimizationEnabled(db, SQLITE_Stat4)
+ && (pStat4 = wx_sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
&& IsOrdinaryTable(pStat4)
){
rc = loadStatTbl(db,
- "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
+ "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx COLLATE nocase",
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
zDb
);
@@ -117185,20 +121714,21 @@ static int fixSelectCb(Walker *p, Select *pSelect){
if( NEVER(pList==0) ) return WRC_Continue;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
- if( pFix->bTemp==0 ){
- if( pItem->zDatabase ){
- if( iDb!=wx_sqlite3FindDbName(db, pItem->zDatabase) ){
+ if( pFix->bTemp==0 && pItem->fg.isSubquery==0 ){
+ if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
+ if( iDb!=wx_sqlite3FindDbName(db, pItem->u4.zDatabase) ){
wx_sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
- pFix->zType, pFix->pName, pItem->zDatabase);
+ pFix->zType, pFix->pName, pItem->u4.zDatabase);
return WRC_Abort;
}
- wx_sqlite3DbFree(db, pItem->zDatabase);
- pItem->zDatabase = 0;
+ wx_sqlite3DbFree(db, pItem->u4.zDatabase);
pItem->fg.notCte = 1;
+ pItem->fg.hadSchema = 1;
}
- pItem->pSchema = pFix->pSchema;
+ pItem->u4.pSchema = pFix->pSchema;
pItem->fg.fromDDL = 1;
+ pItem->fg.fixedSchema = 1;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( pList->a[i].fg.isUsing==0
@@ -117491,7 +122021,7 @@ SQLITE_PRIVATE void wx_sqlite3AuthRead(
assert( pTabList );
for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
- pTab = pTabList->a[iSrc].pTab;
+ pTab = pTabList->a[iSrc].pSTab;
break;
}
}
@@ -117530,7 +122060,7 @@ SQLITE_PRIVATE int wx_sqlite3AuthCheck(
wx_sqlite3 *db = pParse->db;
int rc;
- /* Don't do any authorization checks if the database is initialising
+ /* Don't do any authorization checks if the database is initializing
** or if the parser is being invoked from within wx_sqlite3_declare_vtab.
*/
assert( !IN_RENAME_OBJECT || db->xAuth==0 );
@@ -117786,7 +122316,7 @@ SQLITE_PRIVATE void wx_sqlite3FinishCoding(Parse *pParse){
}
wx_sqlite3VdbeAddOp0(v, OP_Halt);
-#if SQLITE_USER_AUTHENTICATION
+#if SQLITE_USER_AUTHENTICATION && !defined(SQLITE_OMIT_SHARED_CACHE)
if( pParse->nTableLock>0 && db->init.busy==0 ){
wx_sqlite3UserAuthInit(db);
if( db->auth.authLevel<UAUTH_User ){
@@ -117831,29 +122361,26 @@ SQLITE_PRIVATE void wx_sqlite3FinishCoding(Parse *pParse){
pParse->nVtabLock = 0;
#endif
+#ifndef SQLITE_OMIT_SHARED_CACHE
/* Once all the cookies have been verified and transactions opened,
** obtain the required table-locks. This is a no-op unless the
** shared-cache feature is enabled.
*/
- codeTableLocks(pParse);
+ if( pParse->nTableLock ) codeTableLocks(pParse);
+#endif
/* Initialize any AUTOINCREMENT data structures required.
*/
- wx_sqlite3AutoincrementBegin(pParse);
+ if( pParse->pAinc ) wx_sqlite3AutoincrementBegin(pParse);
- /* Code constant expressions that where factored out of inner loops.
- **
- ** The pConstExpr list might also contain expressions that we simply
- ** want to keep around until the Parse object is deleted. Such
- ** expressions have iConstExprReg==0. Do not generate code for
- ** those expressions, of course.
+ /* Code constant expressions that were factored out of inner loops.
*/
if( pParse->pConstExpr ){
ExprList *pEL = pParse->pConstExpr;
pParse->okConstFactor = 0;
for(i=0; i<pEL->nExpr; i++){
- int iReg = pEL->a[i].u.iConstExprReg;
- wx_sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
+ assert( pEL->a[i].u.iConstExprReg>0 );
+ wx_sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
}
}
@@ -118097,12 +122624,12 @@ SQLITE_PRIVATE Table *wx_sqlite3LocateTableItem(
SrcItem *p
){
const char *zDb;
- assert( p->pSchema==0 || p->zDatabase==0 );
- if( p->pSchema ){
- int iDb = wx_sqlite3SchemaToIndex(pParse->db, p->pSchema);
+ if( p->fg.fixedSchema ){
+ int iDb = wx_sqlite3SchemaToIndex(pParse->db, p->u4.pSchema);
zDb = pParse->db->aDb[iDb].zDbSName;
}else{
- zDb = p->zDatabase;
+ assert( !p->fg.isSubquery );
+ zDb = p->u4.zDatabase;
}
return wx_sqlite3LocateTable(pParse, flags, p->zName, zDb);
}
@@ -118320,7 +122847,7 @@ SQLITE_PRIVATE void wx_sqlite3ColumnSetExpr(
*/
SQLITE_PRIVATE Expr *wx_sqlite3ColumnExpr(Table *pTab, Column *pCol){
if( pCol->iDflt==0 ) return 0;
- if( NEVER(!IsOrdinaryTable(pTab)) ) return 0;
+ if( !IsOrdinaryTable(pTab) ) return 0;
if( NEVER(pTab->u.tab.pDfltList==0) ) return 0;
if( NEVER(pTab->u.tab.pDfltList->nExpr<pCol->iDflt) ) return 0;
return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
@@ -118352,7 +122879,7 @@ SQLITE_PRIVATE void wx_sqlite3ColumnSetColl(
}
/*
-** Return the collating squence name for a column
+** Return the collating sequence name for a column
*/
SQLITE_PRIVATE const char *wx_sqlite3ColumnColl(Column *pCol){
const char *z;
@@ -118445,7 +122972,7 @@ static void SQLITE_NOINLINE deleteTable(wx_sqlite3 *db, Table *pTable){
if( IsOrdinaryTable(pTable) ){
wx_sqlite3FkDelete(db, pTable);
}
-#ifndef SQLITE_OMIT_VIRTUAL_TABLE
+#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( IsVirtual(pTable) ){
wx_sqlite3VtabClear(db, pTable);
}
@@ -118473,6 +123000,9 @@ SQLITE_PRIVATE void wx_sqlite3DeleteTable(wx_sqlite3 *db, Table *pTable){
if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return;
deleteTable(db, pTable);
}
+SQLITE_PRIVATE void wx_sqlite3DeleteTableGeneric(wx_sqlite3 *db, void *pTable){
+ wx_sqlite3DeleteTable(db, (Table*)pTable);
+}
/*
@@ -119008,19 +123538,13 @@ SQLITE_PRIVATE void wx_sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol
#endif
/*
-** Name of the special TEMP trigger used to implement RETURNING. The
-** name begins with "sqlite_" so that it is guaranteed not to collide
-** with any application-generated triggers.
-*/
-#define RETURNING_TRIGGER_NAME "sqlite_returning"
-
-/*
** Clean up the data structures associated with the RETURNING clause.
*/
-static void wx_sqlite3DeleteReturning(wx_sqlite3 *db, Returning *pRet){
+static void wx_sqlite3DeleteReturning(wx_sqlite3 *db, void *pArg){
+ Returning *pRet = (Returning*)pArg;
Hash *pHash;
pHash = &(db->aDb[1].pSchema->trigHash);
- wx_sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, 0);
+ wx_sqlite3HashInsert(pHash, pRet->zName, 0);
wx_sqlite3ExprListDelete(db, pRet->pReturnEL);
wx_sqlite3DbFree(db, pRet);
}
@@ -119059,11 +123583,12 @@ SQLITE_PRIVATE void wx_sqlite3AddReturning(Parse *pParse, ExprList *pList){
pParse->u1.pReturning = pRet;
pRet->pParse = pParse;
pRet->pReturnEL = pList;
- wx_sqlite3ParserAddCleanup(pParse,
- (void(*)(wx_sqlite3*,void*))wx_sqlite3DeleteReturning, pRet);
+ wx_sqlite3ParserAddCleanup(pParse, wx_sqlite3DeleteReturning, pRet);
testcase( pParse->earlyCleanup );
if( db->mallocFailed ) return;
- pRet->retTrig.zName = RETURNING_TRIGGER_NAME;
+ wx_sqlite3_snprintf(sizeof(pRet->zName), pRet->zName,
+ "sqlite_returning_%p", pParse);
+ pRet->retTrig.zName = pRet->zName;
pRet->retTrig.op = TK_RETURNING;
pRet->retTrig.tr_tm = TRIGGER_AFTER;
pRet->retTrig.bReturning = 1;
@@ -119074,9 +123599,9 @@ SQLITE_PRIVATE void wx_sqlite3AddReturning(Parse *pParse, ExprList *pList){
pRet->retTStep.pTrig = &pRet->retTrig;
pRet->retTStep.pExprList = pList;
pHash = &(db->aDb[1].pSchema->trigHash);
- assert( wx_sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0
+ assert( wx_sqlite3HashFind(pHash, pRet->zName)==0
|| pParse->nErr || pParse->ifNotExists );
- if( wx_sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig)
+ if( wx_sqlite3HashInsert(pHash, pRet->zName, &pRet->retTrig)
==&pRet->retTrig ){
wx_sqlite3OomFault(db);
}
@@ -119110,7 +123635,7 @@ SQLITE_PRIVATE void wx_sqlite3AddColumn(Parse *pParse, Token sName, Token sType)
}
if( !IN_RENAME_OBJECT ) wx_sqlite3DequoteToken(&sName);
- /* Because keywords GENERATE ALWAYS can be converted into indentifiers
+ /* Because keywords GENERATE ALWAYS can be converted into identifiers
** by the parser, we can sometimes end up with a typename that ends
** with "generated always". Check for this case and omit the surplus
** text. */
@@ -119257,7 +123782,8 @@ SQLITE_PRIVATE char wx_sqlite3AffinityType(const char *zIn, Column *pCol){
assert( zIn!=0 );
while( zIn[0] ){
- h = (h<<8) + wx_sqlite3UpperToLower[(*zIn)&0xff];
+ u8 x = *(u8*)zIn;
+ h = (h<<8) + wx_sqlite3UpperToLower[x];
zIn++;
if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */
aff = SQLITE_AFF_TEXT;
@@ -119331,7 +123857,7 @@ SQLITE_PRIVATE void wx_sqlite3AddDefaultValue(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* The parsed expression of the default value */
const char *zStart, /* Start of the default value text */
- const char *zEnd /* First character past end of defaut value text */
+ const char *zEnd /* First character past end of default value text */
){
Table *p;
Column *pCol;
@@ -119679,7 +124205,7 @@ static int identLength(const char *z){
** to the specified offset in the buffer and updates *pIdx to refer
** to the first byte after the last byte written before returning.
**
-** If the string zSignedIdent consists entirely of alpha-numeric
+** If the string zSignedIdent consists entirely of alphanumeric
** characters, does not begin with a digit and is not an SQL keyword,
** then it is copied to the output buffer exactly as it is. Otherwise,
** it is quoted using double-quotes.
@@ -119831,7 +124357,7 @@ static void estimateIndexWidth(Index *pIdx){
for(i=0; i<pIdx->nColumn; i++){
i16 x = pIdx->aiColumn[i];
assert( x<pIdx->pTable->nCol );
- wIndex += x<0 ? 1 : aCol[pIdx->aiColumn[i]].szEst;
+ wIndex += x<0 ? 1 : aCol[x].szEst;
}
pIdx->szIdxRow = wx_sqlite3LogEst(wIndex*4);
}
@@ -120429,20 +124955,20 @@ SQLITE_PRIVATE void wx_sqlite3EndTable(
int regRowid; /* Rowid of the next row to insert */
int addrInsLoop; /* Top of the loop for inserting rows */
Table *pSelTab; /* A table that describes the SELECT results */
+ int iCsr; /* Write cursor on the new table */
if( IN_SPECIAL_PARSE ){
pParse->rc = SQLITE_ERROR;
pParse->nErr++;
return;
}
+ iCsr = pParse->nTab++;
regYield = ++pParse->nMem;
regRec = ++pParse->nMem;
regRowid = ++pParse->nMem;
- assert(pParse->nTab==1);
wx_sqlite3MayAbort(pParse);
- wx_sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
+ wx_sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->regRoot, iDb);
wx_sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
- pParse->nTab = 2;
addrTop = wx_sqlite3VdbeCurrentAddr(v) + 1;
wx_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
if( pParse->nErr ) return;
@@ -120463,11 +124989,11 @@ SQLITE_PRIVATE void wx_sqlite3EndTable(
VdbeCoverage(v);
wx_sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec);
wx_sqlite3TableAffinity(v, p, 0);
- wx_sqlite3VdbeAddOp2(v, OP_NewRowid, 1, regRowid);
- wx_sqlite3VdbeAddOp3(v, OP_Insert, 1, regRec, regRowid);
+ wx_sqlite3VdbeAddOp2(v, OP_NewRowid, iCsr, regRowid);
+ wx_sqlite3VdbeAddOp3(v, OP_Insert, iCsr, regRec, regRowid);
wx_sqlite3VdbeGoto(v, addrInsLoop);
wx_sqlite3VdbeJumpHere(v, addrInsLoop);
- wx_sqlite3VdbeAddOp1(v, OP_Close, 1);
+ wx_sqlite3VdbeAddOp1(v, OP_Close, iCsr);
}
/* Compute the complete text of the CREATE statement */
@@ -120520,6 +125046,14 @@ SQLITE_PRIVATE void wx_sqlite3EndTable(
/* Reparse everything to update our internal data structures */
wx_sqlite3VdbeAddParseSchemaOp(v, iDb,
wx_sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);
+
+ /* Test for cycles in generated columns and illegal expressions
+ ** in CHECK constraints and in DEFAULT clauses. */
+ if( p->tabFlags & TF_HasGenerated ){
+ wx_sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0,
+ wx_sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"",
+ db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
+ }
}
/* Add the table to the in-memory representation of the database.
@@ -120596,9 +125130,12 @@ SQLITE_PRIVATE void wx_sqlite3CreateView(
** on a view, even though views do not have rowids. The following flag
** setting fixes this problem. But the fix can be disabled by compiling
** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that
- ** depend upon the old buggy behavior. */
-#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
- p->tabFlags |= TF_NoVisibleRowid;
+ ** depend upon the old buggy behavior. The ability can also be toggled
+ ** using wx_sqlite3_config(SQLITE_CONFIG_ROWID_IN_VIEW,...) */
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ p->tabFlags |= wx_sqlite3Config.mNoVisibleRowid; /* Optional. Allow by default */
+#else
+ p->tabFlags |= TF_NoVisibleRowid; /* Never allow rowid in view */
#endif
wx_sqlite3TwoPartName(pParse, pName1, pName2, &pName);
@@ -120654,8 +125191,9 @@ create_view_fail:
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** The Table structure pTable is really a VIEW. Fill in the names of
-** the columns of the view in the pTable structure. Return the number
-** of errors. If an error is seen leave an error message in pParse->zErrMsg.
+** the columns of the view in the pTable structure. Return non-zero if
+** there are errors. If an error is seen an error message is left
+** in pParse->zErrMsg.
*/
static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){
Table *pSelTab; /* A fake table from which we get the result set */
@@ -120778,7 +125316,7 @@ static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){
wx_sqlite3DeleteColumnNames(db, pTable);
}
#endif /* SQLITE_OMIT_VIEW */
- return nErr;
+ return nErr + pParse->nErr;
}
SQLITE_PRIVATE int wx_sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable!=0 );
@@ -121076,6 +125614,8 @@ SQLITE_PRIVATE void wx_sqlite3DropTable(Parse *pParse, SrcList *pName, int isVie
}
assert( pParse->nErr==0 );
assert( pName->nSrc==1 );
+ assert( pName->a[0].fg.fixedSchema==0 );
+ assert( pName->a[0].fg.isSubquery==0 );
if( wx_sqlite3ReadSchema(pParse) ) goto exit_drop_table;
if( noErr ) db->suppressErr++;
assert( isView==0 || isView==LOCATE_VIEW );
@@ -121084,7 +125624,7 @@ SQLITE_PRIVATE void wx_sqlite3DropTable(Parse *pParse, SrcList *pName, int isVie
if( pTab==0 ){
if( noErr ){
- wx_sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
+ wx_sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
wx_sqlite3ForceNotReadOnly(pParse);
}
goto exit_drop_table;
@@ -121569,7 +126109,7 @@ SQLITE_PRIVATE void wx_sqlite3CreateIndex(
#ifndef SQLITE_OMIT_TEMPDB
/* If the index name was unqualified, check if the table
** is a temp table. If so, set the database to 1. Do not do this
- ** if initialising a database schema.
+ ** if initializing a database schema.
*/
if( !db->init.busy ){
pTab = wx_sqlite3SrcListLookup(pParse, pTblName);
@@ -122175,15 +126715,17 @@ SQLITE_PRIVATE void wx_sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExi
}
assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
assert( pName->nSrc==1 );
+ assert( pName->a[0].fg.fixedSchema==0 );
+ assert( pName->a[0].fg.isSubquery==0 );
if( SQLITE_OK!=wx_sqlite3ReadSchema(pParse) ){
goto exit_drop_index;
}
- pIndex = wx_sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
+ pIndex = wx_sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].u4.zDatabase);
if( pIndex==0 ){
if( !ifExists ){
wx_sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
}else{
- wx_sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
+ wx_sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
wx_sqlite3ForceNotReadOnly(pParse);
}
pParse->checkSchema = 1;
@@ -122480,12 +127022,14 @@ SQLITE_PRIVATE SrcList *wx_sqlite3SrcListAppend(
if( pDatabase && pDatabase->z==0 ){
pDatabase = 0;
}
+ assert( pItem->fg.fixedSchema==0 );
+ assert( pItem->fg.isSubquery==0 );
if( pDatabase ){
pItem->zName = wx_sqlite3NameFromToken(db, pDatabase);
- pItem->zDatabase = wx_sqlite3NameFromToken(db, pTable);
+ pItem->u4.zDatabase = wx_sqlite3NameFromToken(db, pTable);
}else{
pItem->zName = wx_sqlite3NameFromToken(db, pTable);
- pItem->zDatabase = 0;
+ pItem->u4.zDatabase = 0;
}
return pList;
}
@@ -122501,14 +127045,41 @@ SQLITE_PRIVATE void wx_sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pItem->iCursor>=0 ) continue;
pItem->iCursor = pParse->nTab++;
- if( pItem->pSelect ){
- wx_sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
+ if( pItem->fg.isSubquery ){
+ assert( pItem->u4.pSubq!=0 );
+ assert( pItem->u4.pSubq->pSelect!=0 );
+ assert( pItem->u4.pSubq->pSelect->pSrc!=0 );
+ wx_sqlite3SrcListAssignCursors(pParse, pItem->u4.pSubq->pSelect->pSrc);
}
}
}
}
/*
+** Delete a Subquery object and its substructure.
+*/
+SQLITE_PRIVATE void wx_sqlite3SubqueryDelete(wx_sqlite3 *db, Subquery *pSubq){
+ assert( pSubq!=0 && pSubq->pSelect!=0 );
+ wx_sqlite3SelectDelete(db, pSubq->pSelect);
+ wx_sqlite3DbFree(db, pSubq);
+}
+
+/*
+** Remove a Subquery from a SrcItem. Return the associated Select object.
+** The returned Select becomes the responsibility of the caller.
+*/
+SQLITE_PRIVATE Select *wx_sqlite3SubqueryDetach(wx_sqlite3 *db, SrcItem *pItem){
+ Select *pSel;
+ assert( pItem!=0 );
+ assert( pItem->fg.isSubquery );
+ pSel = pItem->u4.pSubq->pSelect;
+ wx_sqlite3DbFree(db, pItem->u4.pSubq);
+ pItem->u4.pSubq = 0;
+ pItem->fg.isSubquery = 0;
+ return pSel;
+}
+
+/*
** Delete an entire SrcList including all its substructure.
*/
SQLITE_PRIVATE void wx_sqlite3SrcListDelete(wx_sqlite3 *db, SrcList *pList){
@@ -122517,13 +127088,24 @@ SQLITE_PRIVATE void wx_sqlite3SrcListDelete(wx_sqlite3 *db, SrcList *pList){
assert( db!=0 );
if( pList==0 ) return;
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
- if( pItem->zDatabase ) wx_sqlite3DbNNFreeNN(db, pItem->zDatabase);
+
+ /* Check invariants on SrcItem */
+ assert( !pItem->fg.isIndexedBy || !pItem->fg.isTabFunc );
+ assert( !pItem->fg.isCte || !pItem->fg.isIndexedBy );
+ assert( !pItem->fg.fixedSchema || !pItem->fg.isSubquery );
+ assert( !pItem->fg.isSubquery || (pItem->u4.pSubq!=0 &&
+ pItem->u4.pSubq->pSelect!=0) );
+
if( pItem->zName ) wx_sqlite3DbNNFreeNN(db, pItem->zName);
if( pItem->zAlias ) wx_sqlite3DbNNFreeNN(db, pItem->zAlias);
+ if( pItem->fg.isSubquery ){
+ wx_sqlite3SubqueryDelete(db, pItem->u4.pSubq);
+ }else if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
+ wx_sqlite3DbNNFreeNN(db, pItem->u4.zDatabase);
+ }
if( pItem->fg.isIndexedBy ) wx_sqlite3DbFree(db, pItem->u1.zIndexedBy);
if( pItem->fg.isTabFunc ) wx_sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
- wx_sqlite3DeleteTable(db, pItem->pTab);
- if( pItem->pSelect ) wx_sqlite3SelectDelete(db, pItem->pSelect);
+ wx_sqlite3DeleteTable(db, pItem->pSTab);
if( pItem->fg.isUsing ){
wx_sqlite3IdListDelete(db, pItem->u3.pUsing);
}else if( pItem->u3.pOn ){
@@ -122534,6 +127116,54 @@ SQLITE_PRIVATE void wx_sqlite3SrcListDelete(wx_sqlite3 *db, SrcList *pList){
}
/*
+** Attach a Subquery object to pItem->uv.pSubq. Set the
+** pSelect value but leave all the other values initialized
+** to zero.
+**
+** A copy of the Select object is made if dupSelect is true, and the
+** SrcItem takes responsibility for deleting the copy. If dupSelect is
+** false, ownership of the Select passes to the SrcItem. Either way,
+** the SrcItem will take responsibility for deleting the Select.
+**
+** When dupSelect is zero, that means the Select might get deleted right
+** away if there is an OOM error. Beware.
+**
+** Return non-zero on success. Return zero on an OOM error.
+*/
+SQLITE_PRIVATE int wx_sqlite3SrcItemAttachSubquery(
+ Parse *pParse, /* Parsing context */
+ SrcItem *pItem, /* Item to which the subquery is to be attached */
+ Select *pSelect, /* The subquery SELECT. Must be non-NULL */
+ int dupSelect /* If true, attach a copy of pSelect, not pSelect itself.*/
+){
+ Subquery *p;
+ assert( pSelect!=0 );
+ assert( pItem->fg.isSubquery==0 );
+ if( pItem->fg.fixedSchema ){
+ pItem->u4.pSchema = 0;
+ pItem->fg.fixedSchema = 0;
+ }else if( pItem->u4.zDatabase!=0 ){
+ wx_sqlite3DbFree(pParse->db, pItem->u4.zDatabase);
+ pItem->u4.zDatabase = 0;
+ }
+ if( dupSelect ){
+ pSelect = wx_sqlite3SelectDup(pParse->db, pSelect, 0);
+ if( pSelect==0 ) return 0;
+ }
+ p = pItem->u4.pSubq = wx_sqlite3DbMallocRawNN(pParse->db, sizeof(Subquery));
+ if( p==0 ){
+ wx_sqlite3SelectDelete(pParse->db, pSelect);
+ return 0;
+ }
+ pItem->fg.isSubquery = 1;
+ p->pSelect = pSelect;
+ assert( offsetof(Subquery, pSelect)==0 );
+ memset(((char*)p)+sizeof(p->pSelect), 0, sizeof(*p)-sizeof(p->pSelect));
+ return 1;
+}
+
+
+/*
** This routine is called by the parser to add a new term to the
** end of a growing FROM clause. The "p" parameter is the part of
** the FROM clause that has already been constructed. "p" is NULL
@@ -122582,10 +127212,12 @@ SQLITE_PRIVATE SrcList *wx_sqlite3SrcListAppendFromTerm(
if( pAlias->n ){
pItem->zAlias = wx_sqlite3NameFromToken(db, pAlias);
}
+ assert( pSubquery==0 || pDatabase==0 );
if( pSubquery ){
- pItem->pSelect = pSubquery;
- if( pSubquery->selFlags & SF_NestedFrom ){
- pItem->fg.isNestedFrom = 1;
+ if( wx_sqlite3SrcItemAttachSubquery(pParse, pItem, pSubquery, 0) ){
+ if( pSubquery->selFlags & SF_NestedFrom ){
+ pItem->fg.isNestedFrom = 1;
+ }
}
}
assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 );
@@ -123111,7 +127743,7 @@ SQLITE_PRIVATE void wx_sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName
if( iDb<0 ) return;
z = wx_sqlite3NameFromToken(db, pObjName);
if( z==0 ) return;
- zDb = db->aDb[iDb].zDbSName;
+ zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
pTab = wx_sqlite3FindTable(db, z, zDb);
if( pTab ){
reindexTable(pParse, pTab, 0);
@@ -123121,6 +127753,7 @@ SQLITE_PRIVATE void wx_sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName
pIndex = wx_sqlite3FindIndex(db, z, zDb);
wx_sqlite3DbFree(db, z);
if( pIndex ){
+ iDb = wx_sqlite3SchemaToIndex(db, pIndex->pTable->pSchema);
wx_sqlite3BeginWriteOperation(pParse, 0, iDb);
wx_sqlite3RefillIndex(pParse, pIndex, -1);
return;
@@ -123226,7 +127859,7 @@ SQLITE_PRIVATE void wx_sqlite3CteDelete(wx_sqlite3 *db, Cte *pCte){
/*
** This routine is invoked once per CTE by the parser while parsing a
-** WITH clause. The CTE described by teh third argument is added to
+** WITH clause. The CTE described by the third argument is added to
** the WITH clause of the second argument. If the second argument is
** NULL, then a new WITH argument is created.
*/
@@ -123286,6 +127919,9 @@ SQLITE_PRIVATE void wx_sqlite3WithDelete(wx_sqlite3 *db, With *pWith){
wx_sqlite3DbFree(db, pWith);
}
}
+SQLITE_PRIVATE void wx_sqlite3WithDeleteGeneric(wx_sqlite3 *db, void *pWith){
+ wx_sqlite3WithDelete(db, (With*)pWith);
+}
#endif /* !defined(SQLITE_OMIT_CTE) */
/************** End of build.c ***********************************************/
@@ -123477,6 +128113,7 @@ SQLITE_PRIVATE void wx_sqlite3SetTextEncoding(wx_sqlite3 *db, u8 enc){
** strings is BINARY.
*/
db->pDfltColl = wx_sqlite3FindCollSeq(db, enc, wx_sqlite3StrBINARY, 0);
+ wx_sqlite3ExpirePreparedStatements(db, 1);
}
/*
@@ -123858,8 +128495,8 @@ SQLITE_PRIVATE Schema *wx_sqlite3SchemaGet(wx_sqlite3 *db, Btree *pBt){
**
** The following fields are initialized appropriate in pSrc:
**
-** pSrc->a[0].pTab Pointer to the Table object
-** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one
+** pSrc->a[0].spTab Pointer to the Table object
+** pSrc->a[0].u2.pIBIndex Pointer to the INDEXED BY index, if there is one
**
*/
SQLITE_PRIVATE Table *wx_sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
@@ -123867,8 +128504,9 @@ SQLITE_PRIVATE Table *wx_sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
Table *pTab;
assert( pItem && pSrc->nSrc>=1 );
pTab = wx_sqlite3LocateTableItem(pParse, 0, pItem);
- wx_sqlite3DeleteTable(pParse->db, pItem->pTab);
- pItem->pTab = pTab;
+ if( pItem->pSTab ) wx_sqlite3DeleteTable(pParse->db, pItem->pSTab);
+ pItem->pSTab = pTab;
+ pItem->fg.notCte = 1;
if( pTab ){
pTab->nTabRef++;
if( pItem->fg.isIndexedBy && wx_sqlite3IndexedByLookup(pParse, pItem) ){
@@ -123908,6 +128546,7 @@ SQLITE_PRIVATE void wx_sqlite3CodeChangeCount(Vdbe *v, int regCounter, const cha
** is for a top-level SQL statement.
*/
static int vtabIsReadOnly(Parse *pParse, Table *pTab){
+ assert( IsVirtual(pTab) );
if( wx_sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){
return 1;
}
@@ -123948,13 +128587,15 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
** If pTab is writable but other errors have occurred -> return 1.
** If pTab is writable and no prior errors -> return 0;
*/
-SQLITE_PRIVATE int wx_sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
+SQLITE_PRIVATE int wx_sqlite3IsReadOnly(Parse *pParse, Table *pTab, Trigger *pTrigger){
if( tabIsReadOnly(pParse, pTab) ){
wx_sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
#ifndef SQLITE_OMIT_VIEW
- if( !viewOk && IsView(pTab) ){
+ if( IsView(pTab)
+ && (pTrigger==0 || (pTrigger->bReturning && pTrigger->pNext==0))
+ ){
wx_sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
return 1;
}
@@ -123987,7 +128628,8 @@ SQLITE_PRIVATE void wx_sqlite3MaterializeView(
if( pFrom ){
assert( pFrom->nSrc==1 );
pFrom->a[0].zName = wx_sqlite3DbStrDup(db, pView->zName);
- pFrom->a[0].zDatabase = wx_sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
+ assert( pFrom->a[0].fg.fixedSchema==0 && pFrom->a[0].fg.isSubquery==0 );
+ pFrom->a[0].u4.zDatabase = wx_sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
assert( pFrom->a[0].fg.isUsing==0 );
assert( pFrom->a[0].u3.pOn==0 );
}
@@ -124019,7 +128661,7 @@ SQLITE_PRIVATE Expr *wx_sqlite3LimitWhere(
wx_sqlite3 *db = pParse->db;
Expr *pLhs = NULL; /* LHS of IN(SELECT...) operator */
Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */
- ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */
+ ExprList *pEList = NULL; /* Expression list containing only pSelectRowid*/
SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */
Select *pSelect = NULL; /* Complete SELECT tree */
Table *pTab;
@@ -124049,7 +128691,7 @@ SQLITE_PRIVATE Expr *wx_sqlite3LimitWhere(
** );
*/
- pTab = pSrc->a[0].pTab;
+ pTab = pSrc->a[0].pSTab;
if( HasRowid(pTab) ){
pLhs = wx_sqlite3PExpr(pParse, TK_ROW, 0, 0);
pEList = wx_sqlite3ExprListAppend(
@@ -124057,14 +128699,20 @@ SQLITE_PRIVATE Expr *wx_sqlite3LimitWhere(
);
}else{
Index *pPk = wx_sqlite3PrimaryKeyIndex(pTab);
+ assert( pPk!=0 );
+ assert( pPk->nKeyCol>=1 );
if( pPk->nKeyCol==1 ){
- const char *zName = pTab->aCol[pPk->aiColumn[0]].zCnName;
+ const char *zName;
+ assert( pPk->aiColumn[0]>=0 && pPk->aiColumn[0]<pTab->nCol );
+ zName = pTab->aCol[pPk->aiColumn[0]].zCnName;
pLhs = wx_sqlite3Expr(db, TK_ID, zName);
pEList = wx_sqlite3ExprListAppend(pParse, 0, wx_sqlite3Expr(db, TK_ID, zName));
}else{
int i;
for(i=0; i<pPk->nKeyCol; i++){
- Expr *p = wx_sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName);
+ Expr *p;
+ assert( pPk->aiColumn[i]>=0 && pPk->aiColumn[i]<pTab->nCol );
+ p = wx_sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName);
pEList = wx_sqlite3ExprListAppend(pParse, pEList, p);
}
pLhs = wx_sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
@@ -124076,9 +128724,9 @@ SQLITE_PRIVATE Expr *wx_sqlite3LimitWhere(
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
- pSrc->a[0].pTab = 0;
+ pSrc->a[0].pSTab = 0;
pSelectSrc = wx_sqlite3SrcListDup(db, pSrc, 0);
- pSrc->a[0].pTab = pTab;
+ pSrc->a[0].pSTab = pTab;
if( pSrc->a[0].fg.isIndexedBy ){
assert( pSrc->a[0].fg.isCte==0 );
pSrc->a[0].u2.pIBIndex = 0;
@@ -124093,7 +128741,7 @@ SQLITE_PRIVATE Expr *wx_sqlite3LimitWhere(
pOrderBy,0,pLimit
);
- /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
+ /* now generate the new WHERE rowid IN clause for the DELETE/UPDATE */
pInClause = wx_sqlite3PExpr(pParse, TK_IN, pLhs, 0);
wx_sqlite3PExprAddSelect(pParse, pInClause, pSelect);
return pInClause;
@@ -124208,7 +128856,7 @@ SQLITE_PRIVATE void wx_sqlite3DeleteFrom(
goto delete_from_cleanup;
}
- if( wx_sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
+ if( wx_sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto delete_from_cleanup;
}
iDb = wx_sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -124322,7 +128970,7 @@ SQLITE_PRIVATE void wx_sqlite3DeleteFrom(
if( HasRowid(pTab) ){
/* For a rowid table, initialize the RowSet to an empty set */
pPk = 0;
- nPk = 1;
+ assert( nPk==1 );
iRowSet = ++pParse->nMem;
wx_sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
}else{
@@ -124350,7 +128998,8 @@ SQLITE_PRIVATE void wx_sqlite3DeleteFrom(
if( pWInfo==0 ) goto delete_from_cleanup;
eOnePass = wx_sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
- assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF );
+ assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF
+ || OptimizationDisabled(db, SQLITE_OnePass) );
if( eOnePass!=ONEPASS_SINGLE ) wx_sqlite3MultiWrite(pParse);
if( wx_sqlite3WhereUsesDeferredSeek(pWInfo) ){
wx_sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur);
@@ -124687,9 +129336,11 @@ SQLITE_PRIVATE void wx_sqlite3GenerateRowDelete(
wx_sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0);
/* Invoke AFTER DELETE trigger programs. */
- wx_sqlite3CodeRowTrigger(pParse, pTrigger,
- TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
- );
+ if( pTrigger ){
+ wx_sqlite3CodeRowTrigger(pParse, pTrigger,
+ TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
+ );
+ }
/* Jump here if the row had already been deleted before any BEFORE
** trigger programs were invoked. Or if a trigger program throws a
@@ -125003,6 +129654,42 @@ static void lengthFunc(
}
/*
+** Implementation of the octet_length() function
+*/
+static void bytelengthFunc(
+ wx_sqlite3_context *context,
+ int argc,
+ wx_sqlite3_value **argv
+){
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ switch( wx_sqlite3_value_type(argv[0]) ){
+ case SQLITE_BLOB: {
+ wx_sqlite3_result_int(context, wx_sqlite3_value_bytes(argv[0]));
+ break;
+ }
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT: {
+ i64 m = wx_sqlite3_context_db_handle(context)->enc<=SQLITE_UTF8 ? 1 : 2;
+ wx_sqlite3_result_int64(context, wx_sqlite3_value_bytes(argv[0])*m);
+ break;
+ }
+ case SQLITE_TEXT: {
+ if( wx_sqlite3_value_encoding(argv[0])<=SQLITE_UTF8 ){
+ wx_sqlite3_result_int(context, wx_sqlite3_value_bytes(argv[0]));
+ }else{
+ wx_sqlite3_result_int(context, wx_sqlite3_value_bytes16(argv[0]));
+ }
+ break;
+ }
+ default: {
+ wx_sqlite3_result_null(context);
+ break;
+ }
+ }
+}
+
+/*
** Implementation of the abs() function.
**
** IMP: R-23979-26855 The abs(X) function returns the absolute value of
@@ -125278,7 +129965,7 @@ static void roundFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **
}else if( n==0 ){
r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5)));
}else{
- zBuf = wx_sqlite3_mprintf("%.*f",n,r);
+ zBuf = wx_sqlite3_mprintf("%!.*f",n,r);
if( zBuf==0 ){
wx_sqlite3_result_error_nomem(context);
return;
@@ -125478,7 +130165,7 @@ struct compareInfo {
/*
** For LIKE and GLOB matching on EBCDIC machines, assume that every
-** character is exactly one byte in size. Also, provde the Utf8Read()
+** character is exactly one byte in size. Also, provide the Utf8Read()
** macro for fast reading of the next character in the common case where
** the next character is ASCII.
*/
@@ -125711,7 +130398,7 @@ SQLITE_API int wx_sqlite3_like_count = 0;
/*
** Implementation of the like() SQL function. This function implements
-** the build-in LIKE operator. The first argument to the function is the
+** the built-in LIKE operator. The first argument to the function is the
** pattern and the second argument is the string. So, the SQL statements:
**
** A LIKE B
@@ -125918,13 +130605,13 @@ SQLITE_PRIVATE void wx_sqlite3QuoteValue(StrAccum *pStr, wx_sqlite3_value *pValu
double r1, r2;
const char *zVal;
r1 = wx_sqlite3_value_double(pValue);
- wx_sqlite3_str_appendf(pStr, "%!.15g", r1);
+ wx_sqlite3_str_appendf(pStr, "%!0.15g", r1);
zVal = wx_sqlite3_str_value(pStr);
if( zVal ){
wx_sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
if( r1!=r2 ){
wx_sqlite3_str_reset(pStr);
- wx_sqlite3_str_appendf(pStr, "%!.20e", r1);
+ wx_sqlite3_str_appendf(pStr, "%!0.20e", r1);
}
}
break;
@@ -126044,6 +130731,7 @@ static void charFunc(
*zOut++ = 0x80 + (u8)(c & 0x3F);
} \
}
+ *zOut = 0;
wx_sqlite3_result_text64(context, (char*)z, zOut-z, wx_sqlite3_free, SQLITE_UTF8);
}
@@ -126072,7 +130760,8 @@ static void hexFunc(
*(z++) = hexdigits[c&0xf];
}
*z = 0;
- wx_sqlite3_result_text(context, zHex, n*2, wx_sqlite3_free);
+ wx_sqlite3_result_text64(context, zHex, (u64)(z-zHex),
+ wx_sqlite3_free, SQLITE_UTF8);
}
}
@@ -126097,7 +130786,7 @@ static int strContainsChar(const u8 *zStr, int nStr, u32 ch){
** decoded and returned as a blob.
**
** If there is only a single argument, then it must consist only of an
-** even number of hexadeximal digits. Otherwise, return NULL.
+** even number of hexadecimal digits. Otherwise, return NULL.
**
** Or, if there is a second argument, then any character that appears in
** the second argument is also allowed to appear between pairs of hexadecimal
@@ -126224,7 +130913,7 @@ static void replaceFunc(
}
if( zPattern[0]==0 ){
assert( wx_sqlite3_value_type(argv[1])!=SQLITE_NULL );
- wx_sqlite3_result_value(context, argv[0]);
+ wx_sqlite3_result_text(context, (const char*)zStr, nStr, SQLITE_TRANSIENT);
return;
}
nPattern = wx_sqlite3_value_bytes(argv[1]);
@@ -126366,12 +131055,87 @@ static void trimFunc(
wx_sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
}
+/* The core implementation of the CONCAT(...) and CONCAT_WS(SEP,...)
+** functions.
+**
+** Return a string value that is the concatenation of all non-null
+** entries in argv[]. Use zSep as the separator.
+*/
+static void concatFuncCore(
+ wx_sqlite3_context *context,
+ int argc,
+ wx_sqlite3_value **argv,
+ int nSep,
+ const char *zSep
+){
+ i64 j, k, n = 0;
+ int i;
+ char *z;
+ for(i=0; i<argc; i++){
+ n += wx_sqlite3_value_bytes(argv[i]);
+ }
+ n += (argc-1)*nSep;
+ z = wx_sqlite3_malloc64(n+1);
+ if( z==0 ){
+ wx_sqlite3_result_error_nomem(context);
+ return;
+ }
+ j = 0;
+ for(i=0; i<argc; i++){
+ k = wx_sqlite3_value_bytes(argv[i]);
+ if( k>0 ){
+ const char *v = (const char*)wx_sqlite3_value_text(argv[i]);
+ if( v!=0 ){
+ if( j>0 && nSep>0 ){
+ memcpy(&z[j], zSep, nSep);
+ j += nSep;
+ }
+ memcpy(&z[j], v, k);
+ j += k;
+ }
+ }
+ }
+ z[j] = 0;
+ assert( j<=n );
+ wx_sqlite3_result_text64(context, z, j, wx_sqlite3_free, SQLITE_UTF8);
+}
+
+/*
+** The CONCAT(...) function. Generate a string result that is the
+** concatentation of all non-null arguments.
+*/
+static void concatFunc(
+ wx_sqlite3_context *context,
+ int argc,
+ wx_sqlite3_value **argv
+){
+ concatFuncCore(context, argc, argv, 0, "");
+}
+
+/*
+** The CONCAT_WS(separator, ...) function.
+**
+** Generate a string that is the concatenation of 2nd through the Nth
+** argument. Use the first argument (which must be non-NULL) as the
+** separator.
+*/
+static void concatwsFunc(
+ wx_sqlite3_context *context,
+ int argc,
+ wx_sqlite3_value **argv
+){
+ int nSep = wx_sqlite3_value_bytes(argv[0]);
+ const char *zSep = (const char*)wx_sqlite3_value_text(argv[0]);
+ if( zSep==0 ) return;
+ concatFuncCore(context, argc-1, argv+1, nSep, zSep);
+}
+
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
/*
** The "unknown" function is automatically substituted in place of
** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN
-** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used.
+** when the SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION compile-time option is used.
** When the "wx_sqlite3" command-line shell is built using this functionality,
** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries
** involving application-defined functions to be examined in a generic
@@ -126487,14 +131251,69 @@ static void loadExt(wx_sqlite3_context *context, int argc, wx_sqlite3_value **ar
*/
typedef struct SumCtx SumCtx;
struct SumCtx {
- double rSum; /* Floating point sum */
- i64 iSum; /* Integer sum */
+ double rSum; /* Running sum as as a double */
+ double rErr; /* Error term for Kahan-Babushka-Neumaier summation */
+ i64 iSum; /* Running sum as a signed integer */
i64 cnt; /* Number of elements summed */
- u8 overflow; /* True if integer overflow seen */
- u8 approx; /* True if non-integer value was input to the sum */
+ u8 approx; /* True if any non-integer value was input to the sum */
+ u8 ovrfl; /* Integer overflow seen */
};
/*
+** Do one step of the Kahan-Babushka-Neumaier summation.
+**
+** https://en.wikipedia.org/wiki/Kahan_summation_algorithm
+**
+** Variables are marked "volatile" to defeat c89 x86 floating point
+** optimizations can mess up this algorithm.
+*/
+static void kahanBabuskaNeumaierStep(
+ volatile SumCtx *pSum,
+ volatile double r
+){
+ volatile double s = pSum->rSum;
+ volatile double t = s + r;
+ if( fabs(s) > fabs(r) ){
+ pSum->rErr += (s - t) + r;
+ }else{
+ pSum->rErr += (r - t) + s;
+ }
+ pSum->rSum = t;
+}
+
+/*
+** Add a (possibly large) integer to the running sum.
+*/
+static void kahanBabuskaNeumaierStepInt64(volatile SumCtx *pSum, i64 iVal){
+ if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){
+ i64 iBig, iSm;
+ iSm = iVal % 16384;
+ iBig = iVal - iSm;
+ kahanBabuskaNeumaierStep(pSum, iBig);
+ kahanBabuskaNeumaierStep(pSum, iSm);
+ }else{
+ kahanBabuskaNeumaierStep(pSum, (double)iVal);
+ }
+}
+
+/*
+** Initialize the Kahan-Babaska-Neumaier sum from a 64-bit integer
+*/
+static void kahanBabuskaNeumaierInit(
+ volatile SumCtx *p,
+ i64 iVal
+){
+ if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){
+ i64 iSm = iVal % 16384;
+ p->rSum = (double)(iVal - iSm);
+ p->rErr = (double)iSm;
+ }else{
+ p->rSum = (double)iVal;
+ p->rErr = 0.0;
+ }
+}
+
+/*
** Routines used to compute the sum, average, and total.
**
** The SUM() function follows the (broken) SQL standard which means
@@ -126513,15 +131332,29 @@ static void sumStep(wx_sqlite3_context *context, int argc, wx_sqlite3_value **ar
type = wx_sqlite3_value_numeric_type(argv[0]);
if( p && type!=SQLITE_NULL ){
p->cnt++;
- if( type==SQLITE_INTEGER ){
- i64 v = wx_sqlite3_value_int64(argv[0]);
- p->rSum += v;
- if( (p->approx|p->overflow)==0 && wx_sqlite3AddInt64(&p->iSum, v) ){
- p->approx = p->overflow = 1;
+ if( p->approx==0 ){
+ if( type!=SQLITE_INTEGER ){
+ kahanBabuskaNeumaierInit(p, p->iSum);
+ p->approx = 1;
+ kahanBabuskaNeumaierStep(p, wx_sqlite3_value_double(argv[0]));
+ }else{
+ i64 x = p->iSum;
+ if( wx_sqlite3AddInt64(&x, wx_sqlite3_value_int64(argv[0]))==0 ){
+ p->iSum = x;
+ }else{
+ p->ovrfl = 1;
+ kahanBabuskaNeumaierInit(p, p->iSum);
+ p->approx = 1;
+ kahanBabuskaNeumaierStepInt64(p, wx_sqlite3_value_int64(argv[0]));
+ }
}
}else{
- p->rSum += wx_sqlite3_value_double(argv[0]);
- p->approx = 1;
+ if( type==SQLITE_INTEGER ){
+ kahanBabuskaNeumaierStepInt64(p, wx_sqlite3_value_int64(argv[0]));
+ }else{
+ p->ovrfl = 0;
+ kahanBabuskaNeumaierStep(p, wx_sqlite3_value_double(argv[0]));
+ }
}
}
}
@@ -126538,13 +131371,18 @@ static void sumInverse(wx_sqlite3_context *context, int argc, wx_sqlite3_value**
if( ALWAYS(p) && type!=SQLITE_NULL ){
assert( p->cnt>0 );
p->cnt--;
- assert( type==SQLITE_INTEGER || p->approx );
- if( type==SQLITE_INTEGER && p->approx==0 ){
- i64 v = wx_sqlite3_value_int64(argv[0]);
- p->rSum -= v;
- p->iSum -= v;
+ if( !p->approx ){
+ p->iSum -= wx_sqlite3_value_int64(argv[0]);
+ }else if( type==SQLITE_INTEGER ){
+ i64 iVal = wx_sqlite3_value_int64(argv[0]);
+ if( iVal!=SMALLEST_INT64 ){
+ kahanBabuskaNeumaierStepInt64(p, -iVal);
+ }else{
+ kahanBabuskaNeumaierStepInt64(p, LARGEST_INT64);
+ kahanBabuskaNeumaierStepInt64(p, 1);
+ }
}else{
- p->rSum -= wx_sqlite3_value_double(argv[0]);
+ kahanBabuskaNeumaierStep(p, -wx_sqlite3_value_double(argv[0]));
}
}
}
@@ -126555,10 +131393,14 @@ static void sumFinalize(wx_sqlite3_context *context){
SumCtx *p;
p = wx_sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
- if( p->overflow ){
- wx_sqlite3_result_error(context,"integer overflow",-1);
- }else if( p->approx ){
- wx_sqlite3_result_double(context, p->rSum);
+ if( p->approx ){
+ if( p->ovrfl ){
+ wx_sqlite3_result_error(context,"integer overflow",-1);
+ }else if( !wx_sqlite3IsOverflow(p->rErr) ){
+ wx_sqlite3_result_double(context, p->rSum+p->rErr);
+ }else{
+ wx_sqlite3_result_double(context, p->rSum);
+ }
}else{
wx_sqlite3_result_int64(context, p->iSum);
}
@@ -126568,14 +131410,29 @@ static void avgFinalize(wx_sqlite3_context *context){
SumCtx *p;
p = wx_sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
- wx_sqlite3_result_double(context, p->rSum/(double)p->cnt);
+ double r;
+ if( p->approx ){
+ r = p->rSum;
+ if( !wx_sqlite3IsOverflow(p->rErr) ) r += p->rErr;
+ }else{
+ r = (double)(p->iSum);
+ }
+ wx_sqlite3_result_double(context, r/(double)p->cnt);
}
}
static void totalFinalize(wx_sqlite3_context *context){
SumCtx *p;
+ double r = 0.0;
p = wx_sqlite3_aggregate_context(context, 0);
- /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
- wx_sqlite3_result_double(context, p ? p->rSum : (double)0);
+ if( p ){
+ if( p->approx ){
+ r = p->rSum;
+ if( !wx_sqlite3IsOverflow(p->rErr) ) r += p->rErr;
+ }else{
+ r = (double)(p->iSum);
+ }
+ }
+ wx_sqlite3_result_double(context, r);
}
/*
@@ -126694,8 +131551,13 @@ static void minMaxFinalize(wx_sqlite3_context *context){
/*
** group_concat(EXPR, ?SEPARATOR?)
+** string_agg(EXPR, SEPARATOR)
+**
+** Content is accumulated in GroupConcatCtx.str with the SEPARATOR
+** coming before the EXPR value, except for the first entry which
+** omits the SEPARATOR.
**
-** The SEPARATOR goes before the EXPR string. This is tragic. The
+** It is tragic that the SEPARATOR goes before the EXPR string. The
** groupConcatInverse() implementation would have been easier if the
** SEPARATOR were appended after EXPR. And the order is undocumented,
** so we could change it, in theory. But the old behavior has been
@@ -126797,9 +131659,9 @@ static void groupConcatInverse(
if( wx_sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pGCC = (GroupConcatCtx*)wx_sqlite3_aggregate_context(context, sizeof(*pGCC));
/* pGCC is always non-NULL since groupConcatStep() will have always
- ** run frist to initialize it */
+ ** run first to initialize it */
if( ALWAYS(pGCC) ){
- int nVS;
+ int nVS; /* Number of characters to remove */
/* Must call wx_sqlite3_value_text() to convert the argument into text prior
** to invoking wx_sqlite3_value_bytes(), in case the text encoding is UTF16 */
(void)wx_sqlite3_value_text(argv[0]);
@@ -126852,6 +131714,8 @@ static void groupConcatValue(wx_sqlite3_context *context){
wx_sqlite3_result_error_toobig(context);
}else if( pAccum->accError==SQLITE_NOMEM ){
wx_sqlite3_result_error_nomem(context);
+ }else if( pGCC->nAccum>0 && pAccum->nChar==0 ){
+ wx_sqlite3_result_text(context, "", 1, SQLITE_STATIC);
}else{
const char *zText = wx_sqlite3_str_value(pAccum);
wx_sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT);
@@ -126881,8 +131745,10 @@ SQLITE_PRIVATE void wx_sqlite3RegisterPerConnectionBuiltinFunctions(wx_sqlite3 *
** sensitive.
*/
SQLITE_PRIVATE void wx_sqlite3RegisterLikeFunctions(wx_sqlite3 *db, int caseSensitive){
+ FuncDef *pDef;
struct compareInfo *pInfo;
int flags;
+ int nArg;
if( caseSensitive ){
pInfo = (struct compareInfo*)&likeInfoAlt;
flags = SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE;
@@ -126890,10 +131756,13 @@ SQLITE_PRIVATE void wx_sqlite3RegisterLikeFunctions(wx_sqlite3 *db, int caseSens
pInfo = (struct compareInfo*)&likeInfoNorm;
flags = SQLITE_FUNC_LIKE;
}
- wx_sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
- wx_sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
- wx_sqlite3FindFunction(db, "like", 2, SQLITE_UTF8, 0)->funcFlags |= flags;
- wx_sqlite3FindFunction(db, "like", 3, SQLITE_UTF8, 0)->funcFlags |= flags;
+ for(nArg=2; nArg<=3; nArg++){
+ wx_sqlite3CreateFunc(db, "like", nArg, SQLITE_UTF8, pInfo, likeFunc,
+ 0, 0, 0, 0, 0);
+ pDef = wx_sqlite3FindFunction(db, "like", nArg, SQLITE_UTF8, 0);
+ pDef->funcFlags |= flags;
+ pDef->funcFlags &= ~SQLITE_FUNC_UNSAFE;
+ }
}
/*
@@ -127165,6 +132034,120 @@ static void signFunc(
wx_sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0);
}
+#ifdef SQLITE_DEBUG
+/*
+** Implementation of fpdecode(x,y,z) function.
+**
+** x is a real number that is to be decoded. y is the precision.
+** z is the maximum real precision. Return a string that shows the
+** results of the wx_sqlite3FpDecode() function.
+**
+** Used for testing and debugging only, specifically testing and debugging
+** of the wx_sqlite3FpDecode() function. This SQL function does not appear
+** in production builds. This function is not an API and is subject to
+** modification or removal in future versions of SQLite.
+*/
+static void fpdecodeFunc(
+ wx_sqlite3_context *context,
+ int argc,
+ wx_sqlite3_value **argv
+){
+ FpDecode s;
+ double x;
+ int y, z;
+ char zBuf[100];
+ UNUSED_PARAMETER(argc);
+ assert( argc==3 );
+ x = wx_sqlite3_value_double(argv[0]);
+ y = wx_sqlite3_value_int(argv[1]);
+ z = wx_sqlite3_value_int(argv[2]);
+ if( z<=0 ) z = 1;
+ wx_sqlite3FpDecode(&s, x, y, z);
+ if( s.isSpecial==2 ){
+ wx_sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN");
+ }else{
+ wx_sqlite3_snprintf(sizeof(zBuf), zBuf, "%c%.*s/%d", s.sign, s.n, s.z, s.iDP);
+ }
+ wx_sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+}
+#endif /* SQLITE_DEBUG */
+
+#ifdef SQLITE_DEBUG
+/*
+** Implementation of parseuri(uri,flags) function.
+**
+** Required Arguments:
+** "uri" The URI to parse.
+** "flags" Bitmask of flags, as if to wx_sqlite3_open_v2().
+**
+** Additional arguments beyond the first two make calls to
+** wx_sqlite3_uri_key() for integers and wx_sqlite3_uri_parameter for
+** anything else.
+**
+** The result is a string showing the results of calling wx_sqlite3ParseUri().
+**
+** Used for testing and debugging only, specifically testing and debugging
+** of the wx_sqlite3ParseUri() function. This SQL function does not appear
+** in production builds. This function is not an API and is subject to
+** modification or removal in future versions of SQLite.
+*/
+static void parseuriFunc(
+ wx_sqlite3_context *ctx,
+ int argc,
+ wx_sqlite3_value **argv
+){
+ wx_sqlite3_str *pResult;
+ const char *zVfs;
+ const char *zUri;
+ unsigned int flgs;
+ int rc;
+ wx_sqlite3_vfs *pVfs = 0;
+ char *zFile = 0;
+ char *zErr = 0;
+
+ if( argc<2 ) return;
+ pVfs = wx_sqlite3_vfs_find(0);
+ assert( pVfs );
+ zVfs = pVfs->zName;
+ zUri = (const char*)wx_sqlite3_value_text(argv[0]);
+ if( zUri==0 ) return;
+ flgs = (unsigned int)wx_sqlite3_value_int(argv[1]);
+ rc = wx_sqlite3ParseUri(zVfs, zUri, &flgs, &pVfs, &zFile, &zErr);
+ pResult = wx_sqlite3_str_new(0);
+ if( pResult ){
+ int i;
+ wx_sqlite3_str_appendf(pResult, "rc=%d", rc);
+ wx_sqlite3_str_appendf(pResult, ", flags=0x%x", flgs);
+ wx_sqlite3_str_appendf(pResult, ", vfs=%Q", pVfs ? pVfs->zName: 0);
+ wx_sqlite3_str_appendf(pResult, ", err=%Q", zErr);
+ wx_sqlite3_str_appendf(pResult, ", file=%Q", zFile);
+ if( zFile ){
+ const char *z = zFile;
+ z += wx_sqlite3Strlen30(z)+1;
+ while( z[0] ){
+ wx_sqlite3_str_appendf(pResult, ", %Q", z);
+ z += wx_sqlite3Strlen30(z)+1;
+ }
+ for(i=2; i<argc; i++){
+ const char *zArg;
+ if( wx_sqlite3_value_type(argv[i])==SQLITE_INTEGER ){
+ int k = wx_sqlite3_value_int(argv[i]);
+ wx_sqlite3_str_appendf(pResult, ", '%d:%q'",k,wx_sqlite3_uri_key(zFile, k));
+ }else if( (zArg = (const char*)wx_sqlite3_value_text(argv[i]))!=0 ){
+ wx_sqlite3_str_appendf(pResult, ", '%q:%q'",
+ zArg, wx_sqlite3_uri_parameter(zFile,zArg));
+ }else{
+ wx_sqlite3_str_appendf(pResult, ", NULL");
+ }
+ }
+ }
+ wx_sqlite3_result_text(ctx, wx_sqlite3_str_finish(pResult), -1, wx_sqlite3_free);
+ }
+ wx_sqlite3_free_filename(zFile);
+ wx_sqlite3_free(zErr);
+}
+#endif /* SQLITE_DEBUG */
+
/*
** All of the FuncDef structures in the aBuiltinFunc[] array above
** to the global function hash table. This occurs at start-time (as
@@ -127227,14 +132210,20 @@ SQLITE_PRIVATE void wx_sqlite3RegisterBuiltinFunctions(void){
WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
- FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
+ FUNCTION2(subtype, 1, 0, 0, subtypeFunc,
+ SQLITE_FUNC_TYPEOF|SQLITE_SUBTYPE),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
+ FUNCTION2(octet_length, 1, 0, 0, bytelengthFunc,SQLITE_FUNC_BYTELEN),
FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(printf, -1, 0, 0, printfFunc ),
FUNCTION(format, -1, 0, 0, printfFunc ),
FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
FUNCTION(char, -1, 0, 0, charFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ),
+#ifdef SQLITE_DEBUG
+ FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ),
+ FUNCTION(parseuri, -1, 0, 0, parseuriFunc ),
+#endif
#ifndef SQLITE_OMIT_FLOATING_POINT
FUNCTION(round, 1, 0, 0, roundFunc ),
FUNCTION(round, 2, 0, 0, roundFunc ),
@@ -127244,6 +132233,11 @@ SQLITE_PRIVATE void wx_sqlite3RegisterBuiltinFunctions(void){
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION(unhex, 1, 0, 0, unhexFunc ),
FUNCTION(unhex, 2, 0, 0, unhexFunc ),
+ FUNCTION(concat, -1, 0, 0, concatFunc ),
+ FUNCTION(concat, 0, 0, 0, 0 ),
+ FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ),
+ FUNCTION(concat_ws, 0, 0, 0, 0 ),
+ FUNCTION(concat_ws, 1, 0, 0, 0 ),
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
@@ -127273,6 +132267,8 @@ SQLITE_PRIVATE void wx_sqlite3RegisterBuiltinFunctions(void){
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
+ WAGGREGATE(string_agg, 2, 0, 0, groupConcatStep,
+ groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
#ifdef SQLITE_CASE_SENSITIVE_LIKE
@@ -127321,7 +132317,7 @@ SQLITE_PRIVATE void wx_sqlite3RegisterBuiltinFunctions(void){
MFUNCTION(sqrt, 1, sqrt, math1Func ),
MFUNCTION(radians, 1, degToRad, math1Func ),
MFUNCTION(degrees, 1, radToDeg, math1Func ),
- FUNCTION(pi, 0, 0, 0, piFunc ),
+ MFUNCTION(pi, 0, 0, piFunc ),
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
FUNCTION(sign, 1, 0, 0, signFunc ),
INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
@@ -128215,6 +133211,7 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){
if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull)
|| (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull)
){
+ assert( (pTop->db->flags & SQLITE_FkNoAction)==0 );
return 1;
}
}
@@ -128399,9 +133396,9 @@ SQLITE_PRIVATE void wx_sqlite3FkCheck(
pSrc = wx_sqlite3SrcListAppend(pParse, 0, 0, 0);
if( pSrc ){
SrcItem *pItem = pSrc->a;
- pItem->pTab = pFKey->pFrom;
+ pItem->pSTab = pFKey->pFrom;
pItem->zName = pFKey->pFrom->zName;
- pItem->pTab->nTabRef++;
+ pItem->pSTab->nTabRef++;
pItem->iCursor = pParse->nTab++;
if( regNew!=0 ){
@@ -128409,6 +133406,8 @@ SQLITE_PRIVATE void wx_sqlite3FkCheck(
}
if( regOld!=0 ){
int eAction = pFKey->aAction[aChange!=0];
+ if( (db->flags & SQLITE_FkNoAction) ) eAction = OE_None;
+
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1);
/* If this is a deferred FK constraint, or a CASCADE or SET NULL
** action applies, then any foreign key violations caused by
@@ -128524,7 +133523,11 @@ SQLITE_PRIVATE int wx_sqlite3FkRequired(
/* Check if any parent key columns are being modified. */
for(p=wx_sqlite3FkReferences(pTab); p; p=p->pNextTo){
if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
- if( p->aAction[1]!=OE_None ) return 2;
+ if( (pParse->db->flags & SQLITE_FkNoAction)==0
+ && p->aAction[1]!=OE_None
+ ){
+ return 2;
+ }
bHaveFK = 1;
}
}
@@ -128574,6 +133577,7 @@ static Trigger *fkActionTrigger(
int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */
action = pFKey->aAction[iAction];
+ if( (db->flags & SQLITE_FkNoAction) ) action = OE_None;
if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){
return 0;
}
@@ -128674,22 +133678,24 @@ static Trigger *fkActionTrigger(
if( action==OE_Restrict ){
int iDb = wx_sqlite3SchemaToIndex(db, pTab->pSchema);
- Token tFrom;
- Token tDb;
+ SrcList *pSrc;
Expr *pRaise;
- tFrom.z = zFrom;
- tFrom.n = nFrom;
- tDb.z = db->aDb[iDb].zDbSName;
- tDb.n = wx_sqlite3Strlen30(tDb.z);
-
- pRaise = wx_sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
+ pRaise = wx_sqlite3Expr(db, TK_STRING, "FOREIGN KEY constraint failed"),
+ pRaise = wx_sqlite3PExpr(pParse, TK_RAISE, pRaise, 0);
if( pRaise ){
pRaise->affExpr = OE_Abort;
}
+ pSrc = wx_sqlite3SrcListAppend(pParse, 0, 0, 0);
+ if( pSrc ){
+ assert( pSrc->nSrc==1 );
+ pSrc->a[0].zName = wx_sqlite3DbStrDup(db, zFrom);
+ assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 );
+ pSrc->a[0].u4.zDatabase = wx_sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
+ }
pSelect = wx_sqlite3SelectNew(pParse,
wx_sqlite3ExprListAppend(pParse, 0, pRaise),
- wx_sqlite3SrcListAppend(pParse, 0, &tDb, &tFrom),
+ pSrc,
pWhere,
0, 0, 0, 0, 0
);
@@ -128805,9 +133811,8 @@ SQLITE_PRIVATE void wx_sqlite3FkDelete(wx_sqlite3 *db, Table *pTab){
if( pFKey->pPrevTo ){
pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
}else{
- void *p = (void *)pFKey->pNextTo;
- const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo);
- wx_sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p);
+ const char *z = (pFKey->pNextTo ? pFKey->pNextTo->zTo : pFKey->zTo);
+ wx_sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, pFKey->pNextTo);
}
if( pFKey->pNextTo ){
pFKey->pNextTo->pPrevTo = pFKey->pPrevTo;
@@ -128870,8 +133875,10 @@ SQLITE_PRIVATE void wx_sqlite3OpenTable(
assert( pParse->pVdbe!=0 );
v = pParse->pVdbe;
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
- wx_sqlite3TableLock(pParse, iDb, pTab->tnum,
- (opcode==OP_OpenWrite)?1:0, pTab->zName);
+ if( !pParse->db->noSharedCache ){
+ wx_sqlite3TableLock(pParse, iDb, pTab->tnum,
+ (opcode==OP_OpenWrite)?1:0, pTab->zName);
+ }
if( HasRowid(pTab) ){
wx_sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol);
VdbeComment((v, "%s", pTab->zName));
@@ -128905,46 +133912,48 @@ SQLITE_PRIVATE void wx_sqlite3OpenTable(
** is managed along with the rest of the Index structure. It will be
** released when wx_sqlite3DeleteIndex() is called.
*/
-SQLITE_PRIVATE const char *wx_sqlite3IndexAffinityStr(wx_sqlite3 *db, Index *pIdx){
+static SQLITE_NOINLINE const char *computeIndexAffStr(wx_sqlite3 *db, Index *pIdx){
+ /* The first time a column affinity string for a particular index is
+ ** required, it is allocated and populated here. It is then stored as
+ ** a member of the Index structure for subsequent use.
+ **
+ ** The column affinity string will eventually be deleted by
+ ** sqliteDeleteIndex() when the Index structure itself is cleaned
+ ** up.
+ */
+ int n;
+ Table *pTab = pIdx->pTable;
+ pIdx->zColAff = (char *)wx_sqlite3DbMallocRaw(0, pIdx->nColumn+1);
if( !pIdx->zColAff ){
- /* The first time a column affinity string for a particular index is
- ** required, it is allocated and populated here. It is then stored as
- ** a member of the Index structure for subsequent use.
- **
- ** The column affinity string will eventually be deleted by
- ** sqliteDeleteIndex() when the Index structure itself is cleaned
- ** up.
- */
- int n;
- Table *pTab = pIdx->pTable;
- pIdx->zColAff = (char *)wx_sqlite3DbMallocRaw(0, pIdx->nColumn+1);
- if( !pIdx->zColAff ){
- wx_sqlite3OomFault(db);
- return 0;
- }
- for(n=0; n<pIdx->nColumn; n++){
- i16 x = pIdx->aiColumn[n];
- char aff;
- if( x>=0 ){
- aff = pTab->aCol[x].affinity;
- }else if( x==XN_ROWID ){
- aff = SQLITE_AFF_INTEGER;
- }else{
- assert( x==XN_EXPR );
- assert( pIdx->bHasExpr );
- assert( pIdx->aColExpr!=0 );
- aff = wx_sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
- }
- if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
- if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
- pIdx->zColAff[n] = aff;
+ wx_sqlite3OomFault(db);
+ return 0;
+ }
+ for(n=0; n<pIdx->nColumn; n++){
+ i16 x = pIdx->aiColumn[n];
+ char aff;
+ if( x>=0 ){
+ aff = pTab->aCol[x].affinity;
+ }else if( x==XN_ROWID ){
+ aff = SQLITE_AFF_INTEGER;
+ }else{
+ assert( x==XN_EXPR );
+ assert( pIdx->bHasExpr );
+ assert( pIdx->aColExpr!=0 );
+ aff = wx_sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
}
- pIdx->zColAff[n] = 0;
+ if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
+ if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
+ pIdx->zColAff[n] = aff;
}
-
+ pIdx->zColAff[n] = 0;
+ return pIdx->zColAff;
+}
+SQLITE_PRIVATE const char *wx_sqlite3IndexAffinityStr(wx_sqlite3 *db, Index *pIdx){
+ if( !pIdx->zColAff ) return computeIndexAffStr(db, pIdx);
return pIdx->zColAff;
}
+
/*
** Compute an affinity string for a table. Space is obtained
** from wx_sqlite3DbMalloc(). The caller is responsible for freeing
@@ -128998,7 +134007,7 @@ SQLITE_PRIVATE char *wx_sqlite3TableAffinityStr(wx_sqlite3 *db, const Table *pTa
** For STRICT tables:
** ------------------
**
-** Generate an appropropriate OP_TypeCheck opcode that will verify the
+** Generate an appropriate OP_TypeCheck opcode that will verify the
** datatypes against the column definitions in pTab. If iReg==0, that
** means an OP_MakeRecord opcode has already been generated and should be
** the last opcode generated. The new OP_TypeCheck needs to be inserted
@@ -129408,6 +134417,210 @@ SQLITE_PRIVATE void wx_sqlite3AutoincrementEnd(Parse *pParse){
# define autoIncStep(A,B,C)
#endif /* SQLITE_OMIT_AUTOINCREMENT */
+/*
+** If argument pVal is a Select object returned by an wx_sqlite3MultiValues()
+** that was able to use the co-routine optimization, finish coding the
+** co-routine.
+*/
+SQLITE_PRIVATE void wx_sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
+ if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){
+ SrcItem *pItem = &pVal->pSrc->a[0];
+ assert( (pItem->fg.isSubquery && pItem->u4.pSubq!=0) || pParse->nErr );
+ if( pItem->fg.isSubquery ){
+ wx_sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->u4.pSubq->regReturn);
+ wx_sqlite3VdbeJumpHere(pParse->pVdbe, pItem->u4.pSubq->addrFillSub - 1);
+ }
+ }
+}
+
+/*
+** Return true if all expressions in the expression-list passed as the
+** only argument are constant.
+*/
+static int exprListIsConstant(Parse *pParse, ExprList *pRow){
+ int ii;
+ for(ii=0; ii<pRow->nExpr; ii++){
+ if( 0==wx_sqlite3ExprIsConstant(pParse, pRow->a[ii].pExpr) ) return 0;
+ }
+ return 1;
+}
+
+/*
+** Return true if all expressions in the expression-list passed as the
+** only argument are both constant and have no affinity.
+*/
+static int exprListIsNoAffinity(Parse *pParse, ExprList *pRow){
+ int ii;
+ if( exprListIsConstant(pParse,pRow)==0 ) return 0;
+ for(ii=0; ii<pRow->nExpr; ii++){
+ Expr *pExpr = pRow->a[ii].pExpr;
+ assert( pExpr->op!=TK_RAISE );
+ assert( pExpr->affExpr==0 );
+ if( 0!=wx_sqlite3ExprAffinity(pExpr) ) return 0;
+ }
+ return 1;
+
+}
+
+/*
+** This function is called by the parser for the second and subsequent
+** rows of a multi-row VALUES clause. Argument pLeft is the part of
+** the VALUES clause already parsed, argument pRow is the vector of values
+** for the new row. The Select object returned represents the complete
+** VALUES clause, including the new row.
+**
+** There are two ways in which this may be achieved - by incremental
+** coding of a co-routine (the "co-routine" method) or by returning a
+** Select object equivalent to the following (the "UNION ALL" method):
+**
+** "pLeft UNION ALL SELECT pRow"
+**
+** If the VALUES clause contains a lot of rows, this compound Select
+** object may consume a lot of memory.
+**
+** When the co-routine method is used, each row that will be returned
+** by the VALUES clause is coded into part of a co-routine as it is
+** passed to this function. The returned Select object is equivalent to:
+**
+** SELECT * FROM (
+** Select object to read co-routine
+** )
+**
+** The co-routine method is used in most cases. Exceptions are:
+**
+** a) If the current statement has a WITH clause. This is to avoid
+** statements like:
+**
+** WITH cte AS ( VALUES('x'), ('y') ... )
+** SELECT * FROM cte AS a, cte AS b;
+**
+** This will not work, as the co-routine uses a hard-coded register
+** for its OP_Yield instructions, and so it is not possible for two
+** cursors to iterate through it concurrently.
+**
+** b) The schema is currently being parsed (i.e. the VALUES clause is part
+** of a schema item like a VIEW or TRIGGER). In this case there is no VM
+** being generated when parsing is taking place, and so generating
+** a co-routine is not possible.
+**
+** c) There are non-constant expressions in the VALUES clause (e.g.
+** the VALUES clause is part of a correlated sub-query).
+**
+** d) One or more of the values in the first row of the VALUES clause
+** has an affinity (i.e. is a CAST expression). This causes problems
+** because the complex rules SQLite uses (see function
+** wx_sqlite3SubqueryColumnTypes() in select.c) to determine the effective
+** affinity of such a column for all rows require access to all values in
+** the column simultaneously.
+*/
+SQLITE_PRIVATE Select *wx_sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
+
+ if( pParse->bHasWith /* condition (a) above */
+ || pParse->db->init.busy /* condition (b) above */
+ || exprListIsConstant(pParse,pRow)==0 /* condition (c) above */
+ || (pLeft->pSrc->nSrc==0 &&
+ exprListIsNoAffinity(pParse,pLeft->pEList)==0) /* condition (d) above */
+ || IN_SPECIAL_PARSE
+ ){
+ /* The co-routine method cannot be used. Fall back to UNION ALL. */
+ Select *pSelect = 0;
+ int f = SF_Values | SF_MultiValue;
+ if( pLeft->pSrc->nSrc ){
+ wx_sqlite3MultiValuesEnd(pParse, pLeft);
+ f = SF_Values;
+ }else if( pLeft->pPrior ){
+ /* In this case set the SF_MultiValue flag only if it was set on pLeft */
+ f = (f & pLeft->selFlags);
+ }
+ pSelect = wx_sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0);
+ pLeft->selFlags &= ~SF_MultiValue;
+ if( pSelect ){
+ pSelect->op = TK_ALL;
+ pSelect->pPrior = pLeft;
+ pLeft = pSelect;
+ }
+ }else{
+ SrcItem *p = 0; /* SrcItem that reads from co-routine */
+
+ if( pLeft->pSrc->nSrc==0 ){
+ /* Co-routine has not yet been started and the special Select object
+ ** that accesses the co-routine has not yet been created. This block
+ ** does both those things. */
+ Vdbe *v = wx_sqlite3GetVdbe(pParse);
+ Select *pRet = wx_sqlite3SelectNew(pParse, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ /* Ensure the database schema has been read. This is to ensure we have
+ ** the correct text encoding. */
+ if( (pParse->db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ){
+ wx_sqlite3ReadSchema(pParse);
+ }
+
+ if( pRet ){
+ SelectDest dest;
+ Subquery *pSubq;
+ pRet->pSrc->nSrc = 1;
+ pRet->pPrior = pLeft->pPrior;
+ pRet->op = pLeft->op;
+ if( pRet->pPrior ) pRet->selFlags |= SF_Values;
+ pLeft->pPrior = 0;
+ pLeft->op = TK_SELECT;
+ assert( pLeft->pNext==0 );
+ assert( pRet->pNext==0 );
+ p = &pRet->pSrc->a[0];
+ p->fg.viaCoroutine = 1;
+ p->iCursor = -1;
+ assert( !p->fg.isIndexedBy && !p->fg.isTabFunc );
+ p->u1.nRow = 2;
+ if( wx_sqlite3SrcItemAttachSubquery(pParse, p, pLeft, 0) ){
+ pSubq = p->u4.pSubq;
+ pSubq->addrFillSub = wx_sqlite3VdbeCurrentAddr(v) + 1;
+ pSubq->regReturn = ++pParse->nMem;
+ wx_sqlite3VdbeAddOp3(v, OP_InitCoroutine,
+ pSubq->regReturn, 0, pSubq->addrFillSub);
+ wx_sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
+
+ /* Allocate registers for the output of the co-routine. Do so so
+ ** that there are two unused registers immediately before those
+ ** used by the co-routine. This allows the code in wx_sqlite3Insert()
+ ** to use these registers directly, instead of copying the output
+ ** of the co-routine to a separate array for processing. */
+ dest.iSdst = pParse->nMem + 3;
+ dest.nSdst = pLeft->pEList->nExpr;
+ pParse->nMem += 2 + dest.nSdst;
+
+ pLeft->selFlags |= SF_MultiValue;
+ wx_sqlite3Select(pParse, pLeft, &dest);
+ pSubq->regResult = dest.iSdst;
+ assert( pParse->nErr || dest.iSdst>0 );
+ }
+ pLeft = pRet;
+ }
+ }else{
+ p = &pLeft->pSrc->a[0];
+ assert( !p->fg.isTabFunc && !p->fg.isIndexedBy );
+ p->u1.nRow++;
+ }
+
+ if( pParse->nErr==0 ){
+ Subquery *pSubq;
+ assert( p!=0 );
+ assert( p->fg.isSubquery );
+ pSubq = p->u4.pSubq;
+ assert( pSubq!=0 );
+ assert( pSubq->pSelect!=0 );
+ assert( pSubq->pSelect->pEList!=0 );
+ if( pSubq->pSelect->pEList->nExpr!=pRow->nExpr ){
+ wx_sqlite3SelectWrongNumTermsError(pParse, pSubq->pSelect);
+ }else{
+ wx_sqlite3ExprCodeExprList(pParse, pRow, pSubq->regResult, 0, 0);
+ wx_sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, pSubq->regReturn);
+ }
+ }
+ wx_sqlite3ExprListDelete(pParse->db, pRow);
+ }
+
+ return pLeft;
+}
/* Forward declaration */
static int xferOptimization(
@@ -129629,7 +134842,7 @@ SQLITE_PRIVATE void wx_sqlite3Insert(
/* Cannot insert into a read-only table.
*/
- if( wx_sqlite3IsReadOnly(pParse, pTab, tmask) ){
+ if( wx_sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto insert_cleanup;
}
@@ -129744,25 +134957,45 @@ SQLITE_PRIVATE void wx_sqlite3Insert(
if( pSelect ){
/* Data is coming from a SELECT or from a multi-row VALUES clause.
** Generate a co-routine to run the SELECT. */
- int regYield; /* Register holding co-routine entry-point */
- int addrTop; /* Top of the co-routine */
int rc; /* Result code */
- regYield = ++pParse->nMem;
- addrTop = wx_sqlite3VdbeCurrentAddr(v) + 1;
- wx_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
- wx_sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
- dest.iSdst = bIdListInOrder ? regData : 0;
- dest.nSdst = pTab->nCol;
- rc = wx_sqlite3Select(pParse, pSelect, &dest);
- regFromSelect = dest.iSdst;
- assert( db->pParse==pParse );
- if( rc || pParse->nErr ) goto insert_cleanup;
- assert( db->mallocFailed==0 );
- wx_sqlite3VdbeEndCoroutine(v, regYield);
- wx_sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
- assert( pSelect->pEList );
- nColumn = pSelect->pEList->nExpr;
+ if( pSelect->pSrc->nSrc==1
+ && pSelect->pSrc->a[0].fg.viaCoroutine
+ && pSelect->pPrior==0
+ ){
+ SrcItem *pItem = &pSelect->pSrc->a[0];
+ Subquery *pSubq;
+ assert( pItem->fg.isSubquery );
+ pSubq = pItem->u4.pSubq;
+ dest.iSDParm = pSubq->regReturn;
+ regFromSelect = pSubq->regResult;
+ assert( pSubq->pSelect!=0 );
+ assert( pSubq->pSelect->pEList!=0 );
+ nColumn = pSubq->pSelect->pEList->nExpr;
+ ExplainQueryPlan((pParse, 0, "SCAN %S", pItem));
+ if( bIdListInOrder && nColumn==pTab->nCol ){
+ regData = regFromSelect;
+ regRowid = regData - 1;
+ regIns = regRowid - (IsVirtual(pTab) ? 1 : 0);
+ }
+ }else{
+ int addrTop; /* Top of the co-routine */
+ int regYield = ++pParse->nMem;
+ addrTop = wx_sqlite3VdbeCurrentAddr(v) + 1;
+ wx_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
+ wx_sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
+ dest.iSdst = bIdListInOrder ? regData : 0;
+ dest.nSdst = pTab->nCol;
+ rc = wx_sqlite3Select(pParse, pSelect, &dest);
+ regFromSelect = dest.iSdst;
+ assert( db->pParse==pParse );
+ if( rc || pParse->nErr ) goto insert_cleanup;
+ assert( db->mallocFailed==0 );
+ wx_sqlite3VdbeEndCoroutine(v, regYield);
+ wx_sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
+ assert( pSelect->pEList );
+ nColumn = pSelect->pEList->nExpr;
+ }
/* Set useTempTable to TRUE if the result of the SELECT statement
** should be written into a temporary table (template 4). Set to
@@ -129917,7 +135150,7 @@ SQLITE_PRIVATE void wx_sqlite3Insert(
pNx->iDataCur = iDataCur;
pNx->iIdxCur = iIdxCur;
if( pNx->pUpsertTarget ){
- if( wx_sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){
+ if( wx_sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx, pUpsert) ){
goto insert_cleanup;
}
}
@@ -130076,7 +135309,7 @@ SQLITE_PRIVATE void wx_sqlite3Insert(
}
/* Copy the new data already generated. */
- assert( pTab->nNVCol>0 );
+ assert( pTab->nNVCol>0 || pParse->nErr>0 );
wx_sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
@@ -130290,7 +135523,7 @@ insert_cleanup:
/* This is the Walker callback from wx_sqlite3ExprReferencesUpdatedColumn().
* Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this
** expression node references any of the
-** columns that are being modifed by an UPDATE statement.
+** columns that are being modified by an UPDATE statement.
*/
static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_COLUMN ){
@@ -130513,7 +135746,7 @@ SQLITE_PRIVATE void wx_sqlite3GenerateConstraintChecks(
int *aiChng, /* column i is unchanged if aiChng[i]<0 */
Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */
){
- Vdbe *v; /* VDBE under constrution */
+ Vdbe *v; /* VDBE under construction */
Index *pIdx; /* Pointer to one of the indices */
Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */
wx_sqlite3 *db; /* Database connection */
@@ -130996,7 +136229,7 @@ SQLITE_PRIVATE void wx_sqlite3GenerateConstraintChecks(
pIdx;
pIdx = indexIteratorNext(&sIdxIter, &ix)
){
- int regIdx; /* Range of registers hold conent for pIdx */
+ int regIdx; /* Range of registers holding content for pIdx */
int regR; /* Range of registers holding conflicting PK */
int iThisCur; /* Cursor for this UNIQUE index */
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
@@ -131491,6 +136724,8 @@ SQLITE_PRIVATE int wx_sqlite3OpenTableAndIndices(
assert( op==OP_OpenRead || op==OP_OpenWrite );
assert( op==OP_OpenWrite || p5==0 );
+ assert( piDataCur!=0 );
+ assert( piIdxCur!=0 );
if( IsVirtual(pTab) ){
/* This routine is a no-op for virtual tables. Leave the output
** variables *piDataCur and *piIdxCur set to illegal cursor numbers
@@ -131503,18 +136738,18 @@ SQLITE_PRIVATE int wx_sqlite3OpenTableAndIndices(
assert( v!=0 );
if( iBase<0 ) iBase = pParse->nTab;
iDataCur = iBase++;
- if( piDataCur ) *piDataCur = iDataCur;
+ *piDataCur = iDataCur;
if( HasRowid(pTab) && (aToOpen==0 || aToOpen[0]) ){
wx_sqlite3OpenTable(pParse, iDataCur, iDb, pTab, op);
- }else{
+ }else if( pParse->db->noSharedCache==0 ){
wx_sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
}
- if( piIdxCur ) *piIdxCur = iBase;
+ *piIdxCur = iBase;
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
int iIdxCur = iBase++;
assert( pIdx->pSchema==pTab->pSchema );
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
- if( piDataCur ) *piDataCur = iIdxCur;
+ *piDataCur = iIdxCur;
p5 = 0;
}
if( aToOpen==0 || aToOpen[i+1] ){
@@ -131656,7 +136891,7 @@ static int xferOptimization(
if( pSelect->pSrc->nSrc!=1 ){
return 0; /* FROM clause must have exactly one term */
}
- if( pSelect->pSrc->a[0].pSelect ){
+ if( pSelect->pSrc->a[0].fg.isSubquery ){
return 0; /* FROM clause cannot contain a subquery */
}
if( pSelect->pWhere ){
@@ -131807,12 +137042,15 @@ static int xferOptimization(
}
}
#ifndef SQLITE_OMIT_CHECK
- if( pDest->pCheck && wx_sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){
+ if( pDest->pCheck
+ && (db->mDbFlags & DBFLAG_Vacuum)==0
+ && wx_sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1)
+ ){
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
}
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
- /* Disallow the transfer optimization if the destination table constains
+ /* Disallow the transfer optimization if the destination table contains
** any foreign key constraints. This is more restrictive than necessary.
** But the main beneficiary of the transfer optimization is the VACUUM
** command, and the VACUUM command disables foreign key constraints. So
@@ -132522,6 +137760,11 @@ struct wx_sqlite3_api_routines {
int (*value_encoding)(wx_sqlite3_value*);
/* Version 3.41.0 and later */
int (*is_interrupted)(wx_sqlite3*);
+ /* Version 3.43.0 and later */
+ int (*stmt_explain)(wx_sqlite3_stmt*,int);
+ /* Version 3.44.0 and later */
+ void *(*get_clientdata)(wx_sqlite3*,const char*);
+ int (*set_clientdata)(wx_sqlite3*, const char*, void*, void(*)(void*));
};
/*
@@ -132850,6 +138093,11 @@ typedef int (*wx_sqlite3_loadext_entry)(
#define wx_sqlite3_value_encoding wx_sqlite3_api->value_encoding
/* Version 3.41.0 and later */
#define wx_sqlite3_is_interrupted wx_sqlite3_api->is_interrupted
+/* Version 3.43.0 and later */
+#define wx_sqlite3_stmt_explain wx_sqlite3_api->stmt_explain
+/* Version 3.44.0 and later */
+#define wx_sqlite3_get_clientdata wx_sqlite3_api->get_clientdata
+#define wx_sqlite3_set_clientdata wx_sqlite3_api->set_clientdata
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -133366,7 +138614,12 @@ static const wx_sqlite3_api_routines wx_sqlite3Apis = {
/* Version 3.40.0 and later */
wx_sqlite3_value_encoding,
/* Version 3.41.0 and later */
- wx_sqlite3_is_interrupted
+ wx_sqlite3_is_interrupted,
+ /* Version 3.43.0 and later */
+ wx_sqlite3_stmt_explain,
+ /* Version 3.44.0 and later */
+ wx_sqlite3_get_clientdata,
+ wx_sqlite3_set_clientdata
};
/* True if x is the directory separator character
@@ -133439,15 +138692,25 @@ static int wx_sqlite3LoadExtension(
/* tag-20210611-1. Some dlopen() implementations will segfault if given
** an oversize filename. Most filesystems have a pathname limit of 4K,
** so limit the extension filename length to about twice that.
- ** https://sqlite.org/forum/forumpost/08a0d6d9bf */
+ ** https://sqlite.org/forum/forumpost/08a0d6d9bf
+ **
+ ** Later (2023-03-25): Save an extra 6 bytes for the filename suffix.
+ ** See https://sqlite.org/forum/forumpost/24083b579d.
+ */
if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found;
+ /* Do not allow wx_sqlite3_load_extension() to link to a copy of the
+ ** running application, by passing in an empty filename. */
+ if( nMsg==0 ) goto extension_not_found;
+
handle = wx_sqlite3OsDlOpen(pVfs, zFile);
#if SQLITE_OS_UNIX || SQLITE_OS_WIN
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
char *zAltFile = wx_sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
- handle = wx_sqlite3OsDlOpen(pVfs, zAltFile);
+ if( nMsg+strlen(azEndings[ii])+1<=SQLITE_MAX_PATHLEN ){
+ handle = wx_sqlite3OsDlOpen(pVfs, zAltFile);
+ }
wx_sqlite3_free(zAltFile);
}
#endif
@@ -133572,6 +138835,9 @@ SQLITE_PRIVATE void wx_sqlite3CloseExtensions(wx_sqlite3 *db){
** default so as not to open security holes in older applications.
*/
SQLITE_API int wx_sqlite3_enable_load_extension(wx_sqlite3 *db, int onoff){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !wx_sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
wx_sqlite3_mutex_enter(db->mutex);
if( onoff ){
db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
@@ -133621,6 +138887,9 @@ SQLITE_API int wx_sqlite3_auto_extension(
void (*xInit)(void)
){
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( xInit==0 ) return SQLITE_MISUSE_BKPT;
+#endif
#ifndef SQLITE_OMIT_AUTOINIT
rc = wx_sqlite3_initialize();
if( rc ){
@@ -133673,6 +138942,9 @@ SQLITE_API int wx_sqlite3_cancel_auto_extension(
int i;
int n = 0;
wsdAutoextInit;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( xInit==0 ) return 0;
+#endif
wx_sqlite3_mutex_enter(mutex);
for(i=(int)wsdAutoext.nExt-1; i>=0; i--){
if( wsdAutoext.aExt[i]==xInit ){
@@ -134449,6 +139721,34 @@ static const PragmaName aPragmaName[] = {
/************** Continuing where we left off in pragma.c *********************/
/*
+** When the 0x10 bit of PRAGMA optimize is set, any ANALYZE commands
+** will be run with an analysis_limit set to the lessor of the value of
+** the following macro or to the actual analysis_limit if it is non-zero,
+** in order to prevent PRAGMA optimize from running for too long.
+**
+** The value of 2000 is chosen emperically so that the worst-case run-time
+** for PRAGMA optimize does not exceed 100 milliseconds against a variety
+** of test databases on a RaspberryPI-4 compiled using -Os and without
+** -DSQLITE_DEBUG. Of course, your mileage may vary. For the purpose of
+** this paragraph, "worst-case" means that ANALYZE ends up being
+** run on every table in the database. The worst case typically only
+** happens if PRAGMA optimize is run on a database file for which ANALYZE
+** has not been previously run and the 0x10000 flag is included so that
+** all tables are analyzed. The usual case for PRAGMA optimize is that
+** no ANALYZE commands will be run at all, or if any ANALYZE happens it
+** will be against a single table, so that expected timing for PRAGMA
+** optimize on a PI-4 is more like 1 millisecond or less with the 0x10000
+** flag or less than 100 microseconds without the 0x10000 flag.
+**
+** An analysis limit of 2000 is almost always sufficient for the query
+** planner to fully characterize an index. The additional accuracy from
+** a larger analysis is not usually helpful.
+*/
+#ifndef SQLITE_DEFAULT_OPTIMIZE_LIMIT
+# define SQLITE_DEFAULT_OPTIMIZE_LIMIT 2000
+#endif
+
+/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or
** unrecognized string argument. The FULL and EXTRA option is disallowed
@@ -135272,7 +140572,7 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
**
** The first form reports the current local setting for the
** page cache spill size. The second form turns cache spill on
- ** or off. When turnning cache spill on, the size is set to the
+ ** or off. When turning cache spill on, the size is set to the
** current cache_size. The third form sets a spill size that
** may be different form the cache size.
** If N is positive then that is the
@@ -135542,7 +140842,11 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
#endif
if( wx_sqlite3GetBoolean(zRight, 0) ){
- db->flags |= mask;
+ if( (mask & SQLITE_WriteSchema)==0
+ || (db->flags & SQLITE_Defensive)==0
+ ){
+ db->flags |= mask;
+ }
}else{
db->flags &= ~mask;
if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
@@ -135942,7 +141246,7 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
zDb = db->aDb[iDb].zDbSName;
wx_sqlite3CodeVerifySchema(pParse, iDb);
wx_sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
- if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
+ wx_sqlite3TouchRegister(pParse, pTab->nCol+regRow);
wx_sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
wx_sqlite3VdbeLoadString(v, regResult, pTab->zName);
assert( IsOrdinaryTable(pTab) );
@@ -135983,7 +141287,7 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
** regRow..regRow+n. If any of the child key values are NULL, this
** row cannot cause an FK violation. Jump directly to addrOk in
** this case. */
- if( regRow+pFK->nCol>pParse->nMem ) pParse->nMem = regRow+pFK->nCol;
+ wx_sqlite3TouchRegister(pParse, regRow + pFK->nCol);
for(j=0; j<pFK->nCol; j++){
int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
wx_sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
@@ -136050,9 +141354,9 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
** The "quick_check" is reduced version of
** integrity_check designed to detect most database corruption
** without the overhead of cross-checking indexes. Quick_check
- ** is linear time wherease integrity_check is O(NlogN).
+ ** is linear time whereas integrity_check is O(NlogN).
**
- ** The maximum nubmer of errors is 100 by default. A different default
+ ** The maximum number of errors is 100 by default. A different default
** can be specified using a numeric parameter N.
**
** Or, the parameter N can be the name of a table. In that case, only
@@ -136089,7 +141393,7 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
/* Set the maximum error count */
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
if( zRight ){
- if( wx_sqlite3GetInt32(zRight, &mxErr) ){
+ if( wx_sqlite3GetInt32(pValue->z, &mxErr) ){
if( mxErr<=0 ){
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
}
@@ -136106,12 +141410,12 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
Hash *pTbls; /* Set of all tables in the schema */
int *aRoot; /* Array of root page numbers of all btrees */
int cnt = 0; /* Number of entries in aRoot[] */
- int mxIdx = 0; /* Maximum number of indexes for any table */
if( OMIT_TEMPDB && i==1 ) continue;
if( iDb>=0 && i!=iDb ) continue;
wx_sqlite3CodeVerifySchema(pParse, i);
+ pParse->okConstFactor = 0; /* tag-20230327-1 */
/* Do an integrity check of the B-Tree
**
@@ -136127,7 +141431,6 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
if( pObjTab && pObjTab!=pTab ) continue;
if( HasRowid(pTab) ) cnt++;
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
- if( nIdx>mxIdx ) mxIdx = nIdx;
}
if( cnt==0 ) continue;
if( pObjTab ) cnt++;
@@ -136147,11 +141450,12 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
aRoot[0] = cnt;
/* Make sure sufficient number of registers have been allocated */
- pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
+ wx_sqlite3TouchRegister(pParse, 8+cnt);
+ wx_sqlite3VdbeAddOp3(v, OP_Null, 0, 8, 8+cnt);
wx_sqlite3ClearTempRegCache(pParse);
/* Do the b-tree integrity checks */
- wx_sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
+ wx_sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY);
wx_sqlite3VdbeChangeP5(v, (u8)i);
addr = wx_sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
wx_sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
@@ -136161,6 +141465,36 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
integrityCheckResultRow(v);
wx_sqlite3VdbeJumpHere(v, addr);
+ /* Check that the indexes all have the right number of rows */
+ cnt = pObjTab ? 1 : 0;
+ wx_sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ int iTab = 0;
+ Table *pTab = sqliteHashData(x);
+ Index *pIdx;
+ if( pObjTab && pObjTab!=pTab ) continue;
+ if( HasRowid(pTab) ){
+ iTab = cnt++;
+ }else{
+ iTab = cnt;
+ for(pIdx=pTab->pIndex; ALWAYS(pIdx); pIdx=pIdx->pNext){
+ if( IsPrimaryKeyIndex(pIdx) ) break;
+ iTab++;
+ }
+ }
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->pPartIdxWhere==0 ){
+ addr = wx_sqlite3VdbeAddOp3(v, OP_Eq, 8+cnt, 0, 8+iTab);
+ VdbeCoverageNeverNull(v);
+ wx_sqlite3VdbeLoadString(v, 4, pIdx->zName);
+ wx_sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
+ integrityCheckResultRow(v);
+ wx_sqlite3VdbeJumpHere(v, addr);
+ }
+ cnt++;
+ }
+ }
+
/* Make sure all the indices are constructed correctly.
*/
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
@@ -136174,8 +141508,8 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
int r2; /* Previous key for WITHOUT ROWID tables */
int mxCol; /* Maximum non-virtual column number */
- if( !IsOrdinaryTable(pTab) ) continue;
if( pObjTab && pObjTab!=pTab ) continue;
+ if( !IsOrdinaryTable(pTab) ) continue;
if( isQuick || HasRowid(pTab) ){
pPk = 0;
r2 = 0;
@@ -136297,15 +141631,30 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
labelOk = wx_sqlite3VdbeMakeLabel(pParse);
if( pCol->notNull ){
/* (1) NOT NULL columns may not contain a NULL */
+ int jmp3;
int jmp2 = wx_sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
- wx_sqlite3VdbeChangeP5(v, 0x0f);
VdbeCoverage(v);
+ if( p1<0 ){
+ wx_sqlite3VdbeChangeP5(v, 0x0f); /* INT, REAL, TEXT, or BLOB */
+ jmp3 = jmp2;
+ }else{
+ wx_sqlite3VdbeChangeP5(v, 0x0d); /* INT, TEXT, or BLOB */
+ /* OP_IsType does not detect NaN values in the database file
+ ** which should be treated as a NULL. So if the header type
+ ** is REAL, we have to load the actual data using OP_Column
+ ** to reliably determine if the value is a NULL. */
+ wx_sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3);
+ wx_sqlite3ColumnDefault(v, pTab, j, 3);
+ jmp3 = wx_sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk);
+ VdbeCoverage(v);
+ }
zErr = wx_sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pCol->zCnName);
wx_sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
if( doTypeCheck ){
wx_sqlite3VdbeGoto(v, labelError);
wx_sqlite3VdbeJumpHere(v, jmp2);
+ wx_sqlite3VdbeJumpHere(v, jmp3);
}else{
/* VDBE byte code will fall thru */
}
@@ -136413,7 +141762,7 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
int jmp7;
wx_sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur+j, 3);
jmp7 = wx_sqlite3VdbeAddOp3(v, OP_Eq, 3, 0, r1+pIdx->nColumn-1);
- VdbeCoverage(v);
+ VdbeCoverageNeverNull(v);
wx_sqlite3VdbeLoadString(v, 3,
"rowid not at end-of-record for row ");
wx_sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
@@ -136469,23 +141818,43 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
}
wx_sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
wx_sqlite3VdbeJumpHere(v, loopTop-1);
- if( !isQuick ){
- wx_sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
- for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
- if( pPk==pIdx ) continue;
- wx_sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
- addr = wx_sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
- wx_sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
- wx_sqlite3VdbeLoadString(v, 4, pIdx->zName);
- wx_sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
- integrityCheckResultRow(v);
- wx_sqlite3VdbeJumpHere(v, addr);
- }
- if( pPk ){
- wx_sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
- }
+ if( pPk ){
+ assert( !isQuick );
+ wx_sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
}
}
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ /* Second pass to invoke the xIntegrity method on all virtual
+ ** tables.
+ */
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ Table *pTab = sqliteHashData(x);
+ wx_sqlite3_vtab *pVTab;
+ int a1;
+ if( pObjTab && pObjTab!=pTab ) continue;
+ if( IsOrdinaryTable(pTab) ) continue;
+ if( !IsVirtual(pTab) ) continue;
+ if( pTab->nCol<=0 ){
+ const char *zMod = pTab->u.vtab.azArg[0];
+ if( wx_sqlite3HashFind(&db->aModule, zMod)==0 ) continue;
+ }
+ wx_sqlite3ViewGetColumnNames(pParse, pTab);
+ if( pTab->u.vtab.p==0 ) continue;
+ pVTab = pTab->u.vtab.p->pVtab;
+ if( NEVER(pVTab==0) ) continue;
+ if( NEVER(pVTab->pModule==0) ) continue;
+ if( pVTab->pModule->iVersion<4 ) continue;
+ if( pVTab->pModule->xIntegrity==0 ) continue;
+ wx_sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick);
+ pTab->nTabRef++;
+ wx_sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF);
+ a1 = wx_sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
+ integrityCheckResultRow(v);
+ wx_sqlite3VdbeJumpHere(v, a1);
+ continue;
+ }
+#endif
}
{
static const int iLn = VDBE_OFFSET_LINENO(2);
@@ -136749,44 +142118,63 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
**
** The optional argument is a bitmask of optimizations to perform:
**
- ** 0x0001 Debugging mode. Do not actually perform any optimizations
- ** but instead return one line of text for each optimization
- ** that would have been done. Off by default.
+ ** 0x00001 Debugging mode. Do not actually perform any optimizations
+ ** but instead return one line of text for each optimization
+ ** that would have been done. Off by default.
**
- ** 0x0002 Run ANALYZE on tables that might benefit. On by default.
- ** See below for additional information.
+ ** 0x00002 Run ANALYZE on tables that might benefit. On by default.
+ ** See below for additional information.
**
- ** 0x0004 (Not yet implemented) Record usage and performance
- ** information from the current session in the
- ** database file so that it will be available to "optimize"
- ** pragmas run by future database connections.
+ ** 0x00010 Run all ANALYZE operations using an analysis_limit that
+ ** is the lessor of the current analysis_limit and the
+ ** SQLITE_DEFAULT_OPTIMIZE_LIMIT compile-time option.
+ ** The default value of SQLITE_DEFAULT_OPTIMIZE_LIMIT is
+ ** currently (2024-02-19) set to 2000, which is such that
+ ** the worst case run-time for PRAGMA optimize on a 100MB
+ ** database will usually be less than 100 milliseconds on
+ ** a RaspberryPI-4 class machine. On by default.
**
- ** 0x0008 (Not yet implemented) Create indexes that might have
- ** been helpful to recent queries
+ ** 0x10000 Look at tables to see if they need to be reanalyzed
+ ** due to growth or shrinkage even if they have not been
+ ** queried during the current connection. Off by default.
**
- ** The default MASK is and always shall be 0xfffe. 0xfffe means perform all
- ** of the optimizations listed above except Debug Mode, including new
- ** optimizations that have not yet been invented. If new optimizations are
- ** ever added that should be off by default, those off-by-default
- ** optimizations will have bitmasks of 0x10000 or larger.
+ ** The default MASK is and always shall be 0x0fffe. In the current
+ ** implementation, the default mask only covers the 0x00002 optimization,
+ ** though additional optimizations that are covered by 0x0fffe might be
+ ** added in the future. Optimizations that are off by default and must
+ ** be explicitly requested have masks of 0x10000 or greater.
**
** DETERMINATION OF WHEN TO RUN ANALYZE
**
** In the current implementation, a table is analyzed if only if all of
** the following are true:
**
- ** (1) MASK bit 0x02 is set.
+ ** (1) MASK bit 0x00002 is set.
**
- ** (2) The query planner used sqlite_stat1-style statistics for one or
- ** more indexes of the table at some point during the lifetime of
- ** the current connection.
+ ** (2) The table is an ordinary table, not a virtual table or view.
**
- ** (3) One or more indexes of the table are currently unanalyzed OR
- ** the number of rows in the table has increased by 25 times or more
- ** since the last time ANALYZE was run.
+ ** (3) The table name does not begin with "sqlite_".
+ **
+ ** (4) One or more of the following is true:
+ ** (4a) The 0x10000 MASK bit is set.
+ ** (4b) One or more indexes on the table lacks an entry
+ ** in the sqlite_stat1 table.
+ ** (4c) The query planner used sqlite_stat1-style statistics for one
+ ** or more indexes of the table at some point during the lifetime
+ ** of the current connection.
+ **
+ ** (5) One or more of the following is true:
+ ** (5a) One or more indexes on the table lacks an entry
+ ** in the sqlite_stat1 table. (Same as 4a)
+ ** (5b) The number of rows in the table has increased or decreased by
+ ** 10-fold. In other words, the current size of the table is
+ ** 10 times larger than the size in sqlite_stat1 or else the
+ ** current size is less than 1/10th the size in sqlite_stat1.
**
** The rules for when tables are analyzed are likely to change in
- ** future releases.
+ ** future releases. Future versions of SQLite might accept a string
+ ** literal argument to this pragma that contains a mnemonic description
+ ** of the options rather than a bitmap.
*/
case PragTyp_OPTIMIZE: {
int iDbLast; /* Loop termination point for the schema loop */
@@ -136795,9 +142183,13 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
Schema *pSchema; /* The current schema */
Table *pTab; /* A table in the schema */
Index *pIdx; /* An index of the table */
- LogEst szThreshold; /* Size threshold above which reanalysis is needd */
+ LogEst szThreshold; /* Size threshold above which reanalysis needed */
char *zSubSql; /* SQL statement for the OP_SqlExec opcode */
u32 opMask; /* Mask of operations to perform */
+ int nLimit; /* Analysis limit to use */
+ int nCheck = 0; /* Number of tables to be optimized */
+ int nBtree = 0; /* Number of btrees to scan */
+ int nIndex; /* Number of indexes on the current table */
if( zRight ){
opMask = (u32)wx_sqlite3Atoi(zRight);
@@ -136805,6 +142197,14 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
}else{
opMask = 0xfffe;
}
+ if( (opMask & 0x10)==0 ){
+ nLimit = 0;
+ }else if( db->nAnalysisLimit>0
+ && db->nAnalysisLimit<SQLITE_DEFAULT_OPTIMIZE_LIMIT ){
+ nLimit = 0;
+ }else{
+ nLimit = SQLITE_DEFAULT_OPTIMIZE_LIMIT;
+ }
iTabCur = pParse->nTab++;
for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){
if( iDb==1 ) continue;
@@ -136813,23 +142213,61 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
pTab = (Table*)sqliteHashData(k);
- /* If table pTab has not been used in a way that would benefit from
- ** having analysis statistics during the current session, then skip it.
- ** This also has the effect of skipping virtual tables and views */
- if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue;
+ /* This only works for ordinary tables */
+ if( !IsOrdinaryTable(pTab) ) continue;
+
+ /* Do not scan system tables */
+ if( 0==wx_sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ) continue;
- /* Reanalyze if the table is 25 times larger than the last analysis */
- szThreshold = pTab->nRowLogEst + 46; assert( wx_sqlite3LogEst(25)==46 );
+ /* Find the size of the table as last recorded in sqlite_stat1.
+ ** If any index is unanalyzed, then the threshold is -1 to
+ ** indicate a new, unanalyzed index
+ */
+ szThreshold = pTab->nRowLogEst;
+ nIndex = 0;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ nIndex++;
if( !pIdx->hasStat1 ){
- szThreshold = 0; /* Always analyze if any index lacks statistics */
- break;
+ szThreshold = -1; /* Always analyze if any index lacks statistics */
}
}
- if( szThreshold ){
- wx_sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
- wx_sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur,
- wx_sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold);
+
+ /* If table pTab has not been used in a way that would benefit from
+ ** having analysis statistics during the current session, then skip it,
+ ** unless the 0x10000 MASK bit is set. */
+ if( (pTab->tabFlags & TF_MaybeReanalyze)!=0 ){
+ /* Check for size change if stat1 has been used for a query */
+ }else if( opMask & 0x10000 ){
+ /* Check for size change if 0x10000 is set */
+ }else if( pTab->pIndex!=0 && szThreshold<0 ){
+ /* Do analysis if unanalyzed indexes exists */
+ }else{
+ /* Otherwise, we can skip this table */
+ continue;
+ }
+
+ nCheck++;
+ if( nCheck==2 ){
+ /* If ANALYZE might be invoked two or more times, hold a write
+ ** transaction for efficiency */
+ wx_sqlite3BeginWriteOperation(pParse, 0, iDb);
+ }
+ nBtree += nIndex+1;
+
+ /* Reanalyze if the table is 10 times larger or smaller than
+ ** the last analysis. Unconditional reanalysis if there are
+ ** unanalyzed indexes. */
+ wx_sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
+ if( szThreshold>=0 ){
+ const LogEst iRange = 33; /* 10x size change */
+ wx_sqlite3VdbeAddOp4Int(v, OP_IfSizeBetween, iTabCur,
+ wx_sqlite3VdbeCurrentAddr(v)+2+(opMask&1),
+ szThreshold>=iRange ? szThreshold-iRange : -1,
+ szThreshold+iRange);
+ VdbeCoverage(v);
+ }else{
+ wx_sqlite3VdbeAddOp2(v, OP_Rewind, iTabCur,
+ wx_sqlite3VdbeCurrentAddr(v)+2+(opMask&1));
VdbeCoverage(v);
}
zSubSql = wx_sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"",
@@ -136839,11 +142277,27 @@ SQLITE_PRIVATE void wx_sqlite3Pragma(
wx_sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC);
wx_sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1);
}else{
- wx_sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC);
+ wx_sqlite3VdbeAddOp4(v, OP_SqlExec, nLimit ? 0x02 : 00, nLimit, 0,
+ zSubSql, P4_DYNAMIC);
}
}
}
wx_sqlite3VdbeAddOp0(v, OP_Expire);
+
+ /* In a schema with a large number of tables and indexes, scale back
+ ** the analysis_limit to avoid excess run-time in the worst case.
+ */
+ if( !db->mallocFailed && nLimit>0 && nBtree>100 ){
+ int iAddr, iEnd;
+ VdbeOp *aOp;
+ nLimit = 100*nLimit/nBtree;
+ if( nLimit<100 ) nLimit = 100;
+ aOp = wx_sqlite3VdbeGetOp(v, 0);
+ iEnd = wx_sqlite3VdbeCurrentAddr(v);
+ for(iAddr=0; iAddr<iEnd; iAddr++){
+ if( aOp[iAddr].opcode==OP_SqlExec ) aOp[iAddr].p2 = nLimit;
+ }
+ }
break;
}
@@ -137107,9 +142561,9 @@ static int pragmaVtabBestIndex(wx_sqlite3_vtab *tab, wx_sqlite3_index_info *pIdx
seen[0] = 0;
seen[1] = 0;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
- if( pConstraint->usable==0 ) continue;
- if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
if( pConstraint->iColumn < pTab->iHidden ) continue;
+ if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ if( pConstraint->usable==0 ) return SQLITE_CONSTRAINT;
j = pConstraint->iColumn - pTab->iHidden;
assert( j < 2 );
seen[j] = i+1;
@@ -137122,12 +142576,13 @@ static int pragmaVtabBestIndex(wx_sqlite3_vtab *tab, wx_sqlite3_index_info *pIdx
j = seen[0]-1;
pIdxInfo->aConstraintUsage[j].argvIndex = 1;
pIdxInfo->aConstraintUsage[j].omit = 1;
- if( seen[1]==0 ) return SQLITE_OK;
pIdxInfo->estimatedCost = (double)20;
pIdxInfo->estimatedRows = 20;
- j = seen[1]-1;
- pIdxInfo->aConstraintUsage[j].argvIndex = 2;
- pIdxInfo->aConstraintUsage[j].omit = 1;
+ if( seen[1] ){
+ j = seen[1]-1;
+ pIdxInfo->aConstraintUsage[j].argvIndex = 2;
+ pIdxInfo->aConstraintUsage[j].omit = 1;
+ }
return SQLITE_OK;
}
@@ -137147,6 +142602,7 @@ static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){
int i;
wx_sqlite3_finalize(pCsr->pPragma);
pCsr->pPragma = 0;
+ pCsr->iRowid = 0;
for(i=0; i<ArraySize(pCsr->azArg); i++){
wx_sqlite3_free(pCsr->azArg[i]);
pCsr->azArg[i] = 0;
@@ -137287,7 +142743,8 @@ static const wx_sqlite3_module pragmaVtabModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
/*
@@ -137619,7 +143076,9 @@ SQLITE_PRIVATE int wx_sqlite3InitOne(wx_sqlite3 *db, int iDb, char **pzErrMsg, u
#else
encoding = SQLITE_UTF8;
#endif
- if( db->nVdbeActive>0 && encoding!=ENC(db) ){
+ if( db->nVdbeActive>0 && encoding!=ENC(db)
+ && (db->mDbFlags & DBFLAG_Vacuum)==0
+ ){
rc = SQLITE_LOCKED;
goto initone_error_out;
}else{
@@ -137909,8 +143368,6 @@ SQLITE_PRIVATE void wx_sqlite3ParseObjectReset(Parse *pParse){
db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
assert( pParse->db->pParse==pParse );
db->pParse = pParse->pOuterParse;
- pParse->db = 0;
- pParse->disableLookaside = 0;
}
/*
@@ -137919,7 +143376,7 @@ SQLITE_PRIVATE void wx_sqlite3ParseObjectReset(Parse *pParse){
** immediately.
**
** Use this mechanism for uncommon cleanups. There is a higher setup
-** cost for this mechansim (an extra malloc), so it should not be used
+** cost for this mechanism (an extra malloc), so it should not be used
** for common cleanups that happen on most calls. But for less
** common cleanups, we save a single NULL-pointer comparison in
** wx_sqlite3ParseObjectReset(), which reduces the total CPU cycle count.
@@ -137946,7 +143403,13 @@ SQLITE_PRIVATE void *wx_sqlite3ParserAddCleanup(
void (*xCleanup)(wx_sqlite3*,void*), /* The cleanup routine */
void *pPtr /* Pointer to object to be cleaned up */
){
- ParseCleanup *pCleanup = wx_sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup));
+ ParseCleanup *pCleanup;
+ if( wx_sqlite3FaultSim(300) ){
+ pCleanup = 0;
+ wx_sqlite3OomFault(pParse->db);
+ }else{
+ pCleanup = wx_sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup));
+ }
if( pCleanup ){
pCleanup->pNext = pParse->pCleanup;
pParse->pCleanup = pCleanup;
@@ -138011,9 +143474,18 @@ static int wx_sqlite3Prepare(
sParse.pOuterParse = db->pParse;
db->pParse = &sParse;
sParse.db = db;
- sParse.pReprepare = pReprepare;
+ if( pReprepare ){
+ sParse.pReprepare = pReprepare;
+ sParse.explain = wx_sqlite3_stmt_isexplain((wx_sqlite3_stmt*)pReprepare);
+ }else{
+ assert( sParse.pReprepare==0 );
+ }
assert( ppStmt && *ppStmt==0 );
- if( db->mallocFailed ) wx_sqlite3ErrorMsg(&sParse, "out of memory");
+ if( db->mallocFailed ){
+ wx_sqlite3ErrorMsg(&sParse, "out of memory");
+ db->errCode = rc = SQLITE_NOMEM;
+ goto end_prepare;
+ }
assert( wx_sqlite3_mutex_held(db->mutex) );
/* For a long-term use prepared statement avoid the use of
@@ -138172,6 +143644,7 @@ static int wx_sqlite3LockAndPrepare(
assert( (rc&db->errMask)==rc );
db->busyHandler.nBusy = 0;
wx_sqlite3_mutex_leave(db->mutex);
+ assert( rc==SQLITE_OK || (*ppStmt)==0 );
return rc;
}
@@ -138304,12 +143777,24 @@ static int wx_sqlite3Prepare16(
if( !wx_sqlite3SafetyCheckOk(db)||zSql==0 ){
return SQLITE_MISUSE_BKPT;
}
+
+ /* Make sure nBytes is non-negative and correct. It should be the
+ ** number of bytes until the end of the input buffer or until the first
+ ** U+0000 character. If the input nBytes is odd, convert it into
+ ** an even number. If the input nBytes is negative, then the input
+ ** must be terminated by at least one U+0000 character */
if( nBytes>=0 ){
int sz;
const char *z = (const char*)zSql;
for(sz=0; sz<nBytes && (z[sz]!=0 || z[sz+1]!=0); sz += 2){}
nBytes = sz;
+ }else{
+ int sz;
+ const char *z = (const char*)zSql;
+ for(sz=0; z[sz]!=0 || z[sz+1]!=0; sz += 2){}
+ nBytes = sz;
}
+
wx_sqlite3_mutex_enter(db->mutex);
zSql8 = wx_sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
if( zSql8 ){
@@ -138323,7 +143808,7 @@ static int wx_sqlite3Prepare16(
** the same number of characters into the UTF-16 string.
*/
int chars_parsed = wx_sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));
- *pzTail = (u8 *)zSql + wx_sqlite3Utf16ByteLen(zSql, chars_parsed);
+ *pzTail = (u8 *)zSql + wx_sqlite3Utf16ByteLen(zSql, nBytes, chars_parsed);
}
wx_sqlite3DbFree(db, zSql8);
rc = wx_sqlite3ApiExit(db, rc);
@@ -138569,6 +144054,9 @@ SQLITE_PRIVATE Select *wx_sqlite3SelectNew(
SQLITE_PRIVATE void wx_sqlite3SelectDelete(wx_sqlite3 *db, Select *p){
if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
}
+SQLITE_PRIVATE void wx_sqlite3SelectDeleteGeneric(wx_sqlite3 *db, void *p){
+ if( ALWAYS(p) ) clearSelect(db, (Select*)p, 1);
+}
/*
** Return a pointer to the right-most SELECT statement in a compound.
@@ -138617,7 +144105,7 @@ static Select *findRightmost(Select *p){
** NATURAL FULL OUTER JT_NATRUAL|JT_LEFT|JT_RIGHT
**
** To preserve historical compatibly, SQLite also accepts a variety
-** of other non-standard and in many cases non-sensical join types.
+** of other non-standard and in many cases nonsensical join types.
** This routine makes as much sense at it can from the nonsense join
** type and returns a result. Examples of accepted nonsense join types
** include but are not limited to:
@@ -138714,11 +144202,13 @@ SQLITE_PRIVATE int wx_sqlite3ColumnIndex(Table *pTab, const char *zCol){
*/
SQLITE_PRIVATE void wx_sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){
assert( pItem!=0 );
- assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
if( pItem->fg.isNestedFrom ){
ExprList *pResults;
- assert( pItem->pSelect!=0 );
- pResults = pItem->pSelect->pEList;
+ assert( pItem->fg.isSubquery );
+ assert( pItem->u4.pSubq!=0 );
+ assert( pItem->u4.pSubq->pSelect!=0 );
+ pResults = pItem->u4.pSubq->pSelect->pEList;
assert( pResults!=0 );
assert( iCol>=0 && iCol<pResults->nExpr );
pResults->a[iCol].fg.bUsed = 1;
@@ -138752,9 +144242,9 @@ static int tableAndColumnIndex(
assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
for(i=iStart; i<=iEnd; i++){
- iCol = wx_sqlite3ColumnIndex(pSrc->a[i].pTab, zCol);
+ iCol = wx_sqlite3ColumnIndex(pSrc->a[i].pSTab, zCol);
if( iCol>=0
- && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0)
+ && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pSTab->aCol[iCol])==0)
){
if( piTab ){
wx_sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol);
@@ -138839,6 +144329,7 @@ static void unsetJoinExpr(Expr *p, int iTable, int nullable){
}
if( p->op==TK_FUNCTION ){
assert( ExprUseXList(p) );
+ assert( p->pLeft==0 );
if( p->x.pList ){
int i;
for(i=0; i<p->x.pList->nExpr; i++){
@@ -138882,13 +144373,13 @@ static int wx_sqlite3ProcessJoin(Parse *pParse, Select *p){
pLeft = &pSrc->a[0];
pRight = &pLeft[1];
for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
- Table *pRightTab = pRight->pTab;
+ Table *pRightTab = pRight->pSTab;
u32 joinType;
- if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
+ if( NEVER(pLeft->pSTab==0 || pRightTab==0) ) continue;
joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
- /* If this is a NATURAL join, synthesize an approprate USING clause
+ /* If this is a NATURAL join, synthesize an appropriate USING clause
** to specify which columns should be joined.
*/
if( pRight->fg.jointype & JT_NATURAL ){
@@ -139102,9 +144593,9 @@ static void pushOntoSorter(
** (2) All output columns are included in the sort record. In that
** case regData==regOrigData.
** (3) Some output columns are omitted from the sort record due to
- ** the SQLITE_ENABLE_SORTER_REFERENCE optimization, or due to the
+ ** the SQLITE_ENABLE_SORTER_REFERENCES optimization, or due to the
** SQLITE_ECEL_OMITREF optimization, or due to the
- ** SortCtx.pDeferredRowLoad optimiation. In any of these cases
+ ** SortCtx.pDeferredRowLoad optimization. In any of these cases
** regOrigData is 0 to prevent this routine from trying to copy
** values that might not yet exist.
*/
@@ -139160,7 +144651,7 @@ static void pushOntoSorter(
testcase( pKI->nAllField > pKI->nKeyField+2 );
pOp->p4.pKeyInfo = wx_sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat,
pKI->nAllField-pKI->nKeyField-1);
- pOp = 0; /* Ensure pOp not used after sqltie3VdbeAddOp3() */
+ pOp = 0; /* Ensure pOp not used after wx_sqlite3VdbeAddOp3() */
addrJmp = wx_sqlite3VdbeCurrentAddr(v);
wx_sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
pSort->labelBkOut = wx_sqlite3VdbeMakeLabel(pParse);
@@ -139254,7 +144745,7 @@ static void codeOffset(
** The returned value in this case is a copy of parameter iTab.
**
** WHERE_DISTINCT_ORDERED:
-** In this case rows are being delivered sorted order. The ephermal
+** In this case rows are being delivered sorted order. The ephemeral
** table is not required. Instead, the current set of values
** is compared against previous row. If they match, the new row
** is not distinct and control jumps to VM address addrRepeat. Otherwise,
@@ -139683,6 +145174,16 @@ static void selectInnerLoop(
testcase( eDest==SRT_Fifo );
testcase( eDest==SRT_DistFifo );
wx_sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg);
+#if !defined(SQLITE_ENABLE_NULL_TRIM) && defined(SQLITE_DEBUG)
+ /* A destination of SRT_Table and a non-zero iSDParm2 parameter means
+ ** that this is an "UPDATE ... FROM" on a virtual table or view. In this
+ ** case set the p5 parameter of the OP_MakeRecord to OPFLAG_NOCHNG_MAGIC.
+ ** This does not affect operation in any way - it just allows MakeRecord
+ ** to process OPFLAG_NOCHANGE values without an assert() failing. */
+ if( eDest==SRT_Table && pDest->iSDParm2 ){
+ wx_sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
+ }
+#endif
#ifndef SQLITE_OMIT_CTE
if( eDest==SRT_DistFifo ){
/* If the destination is DistFifo, then cursor (iParm+1) is open
@@ -139748,12 +145249,18 @@ static void selectInnerLoop(
** case the order does matter */
pushOntoSorter(
pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
+ pDest->iSDParm2 = 0; /* Signal that any Bloom filter is unpopulated */
}else{
int r1 = wx_sqlite3GetTempReg(pParse);
assert( wx_sqlite3Strlen30(pDest->zAffSdst)==nResultCol );
wx_sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol,
r1, pDest->zAffSdst, nResultCol);
wx_sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
+ if( pDest->iSDParm2 ){
+ wx_sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0,
+ regResult, nResultCol);
+ ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER"));
+ }
wx_sqlite3ReleaseTempReg(pParse, r1);
}
break;
@@ -140044,9 +145551,16 @@ static void generateSortTail(
int addrExplain; /* Address of OP_Explain instruction */
#endif
- ExplainQueryPlan2(addrExplain, (pParse, 0,
- "USE TEMP B-TREE FOR %sORDER BY", pSort->nOBSat>0?"RIGHT PART OF ":"")
- );
+ nKey = pOrderBy->nExpr - pSort->nOBSat;
+ if( pSort->nOBSat==0 || nKey==1 ){
+ ExplainQueryPlan2(addrExplain, (pParse, 0,
+ "USE TEMP B-TREE FOR %sORDER BY", pSort->nOBSat?"LAST TERM OF ":""
+ ));
+ }else{
+ ExplainQueryPlan2(addrExplain, (pParse, 0,
+ "USE TEMP B-TREE FOR LAST %d TERMS OF ORDER BY", nKey
+ ));
+ }
wx_sqlite3VdbeScanStatusRange(v, addrExplain,pSort->addrPush,pSort->addrPushEnd);
wx_sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, pSort->addrPush);
@@ -140084,7 +145598,6 @@ static void generateSortTail(
regRow = wx_sqlite3GetTempRange(pParse, nColumn);
}
}
- nKey = pOrderBy->nExpr - pSort->nOBSat;
if( pSort->sortFlags & SORTFLAG_UseSorter ){
int regSortOut = ++pParse->nMem;
iSortTab = pParse->nTab++;
@@ -140289,8 +145802,12 @@ static const char *columnTypeImpl(
SrcList *pTabList = pNC->pSrcList;
for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
if( j<pTabList->nSrc ){
- pTab = pTabList->a[j].pTab;
- pS = pTabList->a[j].pSelect;
+ pTab = pTabList->a[j].pSTab;
+ if( pTabList->a[j].fg.isSubquery ){
+ pS = pTabList->a[j].u4.pSubq->pSelect;
+ }else{
+ pS = 0;
+ }
}else{
pNC = pNC->pNext;
}
@@ -140324,11 +145841,7 @@ static const char *columnTypeImpl(
** data for the result-set column of the sub-select.
*/
if( iCol<pS->pEList->nExpr
-#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
- && iCol>=0
-#else
- && ALWAYS(iCol>=0)
-#endif
+ && (!ViewCanHaveRowid || iCol>=0)
){
/* If iCol is less than zero, then the expression requests the
** rowid of the sub-select or view. This expression is legal (see
@@ -140486,13 +145999,6 @@ SQLITE_PRIVATE void wx_sqlite3GenerateColumnNames(
int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */
int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */
-#ifndef SQLITE_OMIT_EXPLAIN
- /* If this is an EXPLAIN, skip this step */
- if( pParse->explain ){
- return;
- }
-#endif
-
if( pParse->colNamesSet ) return;
/* Column names are determined by the left-most term of a compound select */
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
@@ -140679,7 +146185,7 @@ SQLITE_PRIVATE int wx_sqlite3ColumnsFromExprList(
** kind (maybe a parenthesized subquery in the FROM clause of a larger
** query, or a VIEW, or a CTE). This routine computes type information
** for that Table object based on the Select object that implements the
-** subquery. For the purposes of this routine, "type infomation" means:
+** subquery. For the purposes of this routine, "type information" means:
**
** * The datatype name, as it might appear in a CREATE TABLE statement
** * Which collating sequence to use for the column
@@ -140703,7 +146209,7 @@ SQLITE_PRIVATE void wx_sqlite3SubqueryColumnTypes(
assert( (pSelect->selFlags & SF_Resolved)!=0 );
assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 );
assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB );
- if( db->mallocFailed ) return;
+ if( db->mallocFailed || IN_RENAME_OBJECT ) return;
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
a = pSelect->pEList->a;
memset(&sNC, 0, sizeof(sNC));
@@ -140711,17 +146217,22 @@ SQLITE_PRIVATE void wx_sqlite3SubqueryColumnTypes(
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
const char *zType;
i64 n;
+ int m = 0;
+ Select *pS2 = pSelect;
pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT);
p = a[i].pExpr;
/* pCol->szEst = ... // Column size est for SELECT tables never used */
pCol->affinity = wx_sqlite3ExprAffinity(p);
+ while( pCol->affinity<=SQLITE_AFF_NONE && pS2->pNext!=0 ){
+ m |= wx_sqlite3ExprDataType(pS2->pEList->a[i].pExpr);
+ pS2 = pS2->pNext;
+ pCol->affinity = wx_sqlite3ExprAffinity(pS2->pEList->a[i].pExpr);
+ }
if( pCol->affinity<=SQLITE_AFF_NONE ){
pCol->affinity = aff;
}
- if( pCol->affinity>=SQLITE_AFF_TEXT && pSelect->pNext ){
- int m = 0;
- Select *pS2;
- for(m=0, pS2=pSelect->pNext; pS2; pS2=pS2->pNext){
+ if( pCol->affinity>=SQLITE_AFF_TEXT && (pS2->pNext || pS2!=pSelect) ){
+ for(pS2=pS2->pNext; pS2; pS2=pS2->pNext){
m |= wx_sqlite3ExprDataType(pS2->pEList->a[i].pExpr);
}
if( pCol->affinity==SQLITE_AFF_TEXT && (m&0x01)!=0 ){
@@ -140748,18 +146259,16 @@ SQLITE_PRIVATE void wx_sqlite3SubqueryColumnTypes(
break;
}
}
- }
- }
- if( zType ){
- i64 m = wx_sqlite3Strlen30(zType);
- n = wx_sqlite3Strlen30(pCol->zCnName);
- pCol->zCnName = wx_sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
- if( pCol->zCnName ){
- memcpy(&pCol->zCnName[n+1], zType, m+1);
- pCol->colFlags |= COLFLAG_HASTYPE;
- }else{
- testcase( pCol->colFlags & COLFLAG_HASTYPE );
- pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
+ }
+ }
+ if( zType ){
+ const i64 k = wx_sqlite3Strlen30(zType);
+ n = wx_sqlite3Strlen30(pCol->zCnName);
+ pCol->zCnName = wx_sqlite3DbReallocOrFree(db, pCol->zCnName, n+k+2);
+ pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
+ if( pCol->zCnName ){
+ memcpy(&pCol->zCnName[n+1], zType, k+1);
+ pCol->colFlags |= COLFLAG_HASTYPE;
}
}
pColl = wx_sqlite3ExprCollSeq(pParse, p);
@@ -140865,7 +146374,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
p->iLimit = iLimit = ++pParse->nMem;
v = wx_sqlite3GetVdbe(pParse);
assert( v!=0 );
- if( wx_sqlite3ExprIsInteger(pLimit->pLeft, &n) ){
+ if( wx_sqlite3ExprIsInteger(pLimit->pLeft, &n, pParse) ){
wx_sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit);
VdbeComment((v, "LIMIT counter"));
if( n==0 ){
@@ -141010,7 +146519,7 @@ static void generateWithRecursiveQuery(
int iQueue; /* The Queue table */
int iDistinct = 0; /* To ensure unique results if UNION */
int eDest = SRT_Fifo; /* How to write to Queue */
- SelectDest destQueue; /* SelectDest targetting the Queue table */
+ SelectDest destQueue; /* SelectDest targeting the Queue table */
int i; /* Loop counter */
int rc; /* Result code */
ExprList *pOrderBy; /* The ORDER BY clause */
@@ -141345,7 +146854,7 @@ static int multiSelect(
p->pPrior = pPrior;
p->nSelectRow = wx_sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
if( p->pLimit
- && wx_sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit)
+ && wx_sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit, pParse)
&& nLimit>0 && p->nSelectRow > wx_sqlite3LogEst((u64)nLimit)
){
p->nSelectRow = wx_sqlite3LogEst((u64)nLimit);
@@ -141586,9 +147095,7 @@ multi_select_end:
pDest->iSdst = dest.iSdst;
pDest->nSdst = dest.nSdst;
if( pDelete ){
- wx_sqlite3ParserAddCleanup(pParse,
- (void(*)(wx_sqlite3*,void*))wx_sqlite3SelectDelete,
- pDelete);
+ wx_sqlite3ParserAddCleanup(pParse, wx_sqlite3SelectDeleteGeneric, pDelete);
}
return rc;
}
@@ -141610,7 +147117,7 @@ SQLITE_PRIVATE void wx_sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p)
/*
** Code an output subroutine for a coroutine implementation of a
-** SELECT statment.
+** SELECT statement.
**
** The data to be output is contained in pIn->iSdst. There are
** pIn->nSdst columns to be output. pDest is where the output should
@@ -141691,6 +147198,11 @@ static int generateOutputSubroutine(
r1, pDest->zAffSdst, pIn->nSdst);
wx_sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1,
pIn->iSdst, pIn->nSdst);
+ if( pDest->iSDParm2>0 ){
+ wx_sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0,
+ pIn->iSdst, pIn->nSdst);
+ ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER"));
+ }
wx_sqlite3ReleaseTempReg(pParse, r1);
break;
}
@@ -141832,7 +147344,7 @@ static int generateOutputSubroutine(
**
** We call AltB, AeqB, AgtB, EofA, and EofB "subroutines" but they are not
** actually called using Gosub and they do not Return. EofA and EofB loop
-** until all data is exhausted then jump to the "end" labe. AltB, AeqB,
+** until all data is exhausted then jump to the "end" label. AltB, AeqB,
** and AgtB jump to either L2 or to one of EofA or EofB.
*/
#ifndef SQLITE_OMIT_COMPOUND_SELECT
@@ -141869,7 +147381,7 @@ static int multiSelectOrderBy(
int savedOffset; /* Saved value of p->iOffset */
int labelCmpr; /* Label for the start of the merge algorithm */
int labelEnd; /* Label for the end of the overall SELECT stmt */
- int addr1; /* Jump instructions that get retargetted */
+ int addr1; /* Jump instructions that get retargeted */
int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
KeyInfo *pKeyMerge; /* Comparison information for merging rows */
@@ -142139,8 +147651,7 @@ static int multiSelectOrderBy(
/* Make arrangements to free the 2nd and subsequent arms of the compound
** after the parse has finished */
if( pSplit->pPrior ){
- wx_sqlite3ParserAddCleanup(pParse,
- (void(*)(wx_sqlite3*,void*))wx_sqlite3SelectDelete, pSplit->pPrior);
+ wx_sqlite3ParserAddCleanup(pParse, wx_sqlite3SelectDeleteGeneric, pSplit->pPrior);
}
pSplit->pPrior = pPrior;
pPrior->pNext = pSplit;
@@ -142238,11 +147749,14 @@ static Expr *substExpr(
#endif
{
Expr *pNew;
- int iColumn = pExpr->iColumn;
- Expr *pCopy = pSubst->pEList->a[iColumn].pExpr;
+ int iColumn;
+ Expr *pCopy;
Expr ifNullRow;
+ iColumn = pExpr->iColumn;
+ assert( iColumn>=0 );
assert( pSubst->pEList!=0 && iColumn<pSubst->pEList->nExpr );
assert( pExpr->pRight==0 );
+ pCopy = pSubst->pEList->a[iColumn].pExpr;
if( wx_sqlite3ExprIsVector(pCopy) ){
wx_sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
}else{
@@ -142267,32 +147781,32 @@ static Expr *substExpr(
if( pSubst->isOuterJoin ){
ExprSetProperty(pNew, EP_CanBeNull);
}
- if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){
- wx_sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
- pExpr->flags & (EP_OuterON|EP_InnerON));
- }
- wx_sqlite3ExprDelete(db, pExpr);
- pExpr = pNew;
- if( pExpr->op==TK_TRUEFALSE ){
- pExpr->u.iValue = wx_sqlite3ExprTruthValue(pExpr);
- pExpr->op = TK_INTEGER;
- ExprSetProperty(pExpr, EP_IntValue);
+ if( pNew->op==TK_TRUEFALSE ){
+ pNew->u.iValue = wx_sqlite3ExprTruthValue(pNew);
+ pNew->op = TK_INTEGER;
+ ExprSetProperty(pNew, EP_IntValue);
}
/* Ensure that the expression now has an implicit collation sequence,
** just as it did when it was a column of a view or sub-query. */
{
- CollSeq *pNat = wx_sqlite3ExprCollSeq(pSubst->pParse, pExpr);
+ CollSeq *pNat = wx_sqlite3ExprCollSeq(pSubst->pParse, pNew);
CollSeq *pColl = wx_sqlite3ExprCollSeq(pSubst->pParse,
pSubst->pCList->a[iColumn].pExpr
);
- if( pNat!=pColl || (pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE) ){
- pExpr = wx_sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
+ if( pNat!=pColl || (pNew->op!=TK_COLUMN && pNew->op!=TK_COLLATE) ){
+ pNew = wx_sqlite3ExprAddCollateString(pSubst->pParse, pNew,
(pColl ? pColl->zName : "BINARY")
);
}
}
- ExprClearProperty(pExpr, EP_Collate);
+ ExprClearProperty(pNew, EP_Collate);
+ if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){
+ wx_sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
+ pExpr->flags & (EP_OuterON|EP_InnerON));
+ }
+ wx_sqlite3ExprDelete(db, pExpr);
+ pExpr = pNew;
}
}
}else{
@@ -142345,7 +147859,9 @@ static void substSelect(
pSrc = p->pSrc;
assert( pSrc!=0 );
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
- substSelect(pSubst, pItem->pSelect, 1);
+ if( pItem->fg.isSubquery ){
+ substSelect(pSubst, pItem->u4.pSubq->pSelect, 1);
+ }
if( pItem->fg.isTabFunc ){
substExprList(pSubst, pItem->u1.pFuncArg);
}
@@ -142376,7 +147892,7 @@ static void recomputeColumnsUsed(
SrcItem *pSrcItem /* Which FROM clause item to recompute */
){
Walker w;
- if( NEVER(pSrcItem->pTab==0) ) return;
+ if( NEVER(pSrcItem->pSTab==0) ) return;
memset(&w, 0, sizeof(w));
w.xExprCallback = recomputeColumnsUsedExpr;
w.xSelectCallback = wx_sqlite3SelectWalkNoop;
@@ -142416,8 +147932,10 @@ static void srclistRenumberCursors(
aCsrMap[pItem->iCursor+1] = pParse->nTab++;
}
pItem->iCursor = aCsrMap[pItem->iCursor+1];
- for(p=pItem->pSelect; p; p=p->pPrior){
- srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
+ if( pItem->fg.isSubquery ){
+ for(p=pItem->u4.pSubq->pSelect; p; p=p->pPrior){
+ srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
+ }
}
}
}
@@ -142591,7 +148109,7 @@ static int compoundHasDifferentAffinities(Select *p){
** (9) If the subquery uses LIMIT then the outer query may not be aggregate.
**
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
-** accidently carried the comment forward until 2014-09-15. Original
+** accidentally carried the comment forward until 2014-09-15. Original
** constraint: "If the subquery is aggregate then the outer query
** may not use LIMIT."
**
@@ -142626,8 +148144,7 @@ static int compoundHasDifferentAffinities(Select *p){
** query or there are no RIGHT or FULL JOINs in any arm
** of the subquery. (This is a duplicate of condition (27b).)
** (17h) The corresponding result set expressions in all arms of the
-** compound must have the same affinity. (See restriction (9)
-** on the push-down optimization.)
+** compound must have the same affinity.
**
** The parent and sub-query may contain WHERE clauses. Subject to
** rules (11), (13) and (14), they may also contain ORDER BY,
@@ -142684,7 +148201,8 @@ static int compoundHasDifferentAffinities(Select *p){
** (27b) the subquery is a compound query and the RIGHT JOIN occurs
** in any arm of the compound query. (See also (17g).)
**
-** (28) The subquery is not a MATERIALIZED CTE.
+** (28) The subquery is not a MATERIALIZED CTE. (This is handled
+** in the caller before ever reaching this routine.)
**
**
** In this routine, the "p" parameter is a pointer to the outer query.
@@ -142728,7 +148246,8 @@ static int flattenSubquery(
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
pSubitem = &pSrc->a[iFrom];
iParent = pSubitem->iCursor;
- pSub = pSubitem->pSelect;
+ assert( pSubitem->fg.isSubquery );
+ pSub = pSubitem->u4.pSubq->pSelect;
assert( pSub!=0 );
#ifndef SQLITE_OMIT_WINDOWFUNC
@@ -142781,7 +148300,7 @@ static int flattenSubquery(
*/
if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
if( pSubSrc->nSrc>1 /* (3a) */
- || IsVirtual(pSubSrc->a[0].pTab) /* (3b) */
+ || IsVirtual(pSubSrc->a[0].pSTab) /* (3b) */
|| (p->selFlags & SF_Distinct)!=0 /* (3d) */
|| (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
){
@@ -142794,9 +148313,9 @@ static int flattenSubquery(
if( iFrom>0 && (pSubSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
return 0; /* Restriction (27a) */
}
- if( pSubitem->fg.isCte && pSubitem->u2.pCteUse->eM10d==M10d_Yes ){
- return 0; /* (28) */
- }
+
+ /* Condition (28) is blocked by the caller */
+ assert( !pSubitem->fg.isCte || pSubitem->u2.pCteUse->eM10d!=M10d_Yes );
/* Restriction (17): If the sub-query is a compound SELECT, then it must
** use only the UNION ALL operator. And none of the simple select queries
@@ -142866,15 +148385,19 @@ static int flattenSubquery(
testcase( i==SQLITE_DENY );
pParse->zAuthContext = zSavedAuthContext;
- /* Delete the transient structures associated with thesubquery */
- pSub1 = pSubitem->pSelect;
- wx_sqlite3DbFree(db, pSubitem->zDatabase);
+ /* Delete the transient structures associated with the subquery */
+
+ if( ALWAYS(pSubitem->fg.isSubquery) ){
+ pSub1 = wx_sqlite3SubqueryDetach(db, pSubitem);
+ }else{
+ pSub1 = 0;
+ }
+ assert( pSubitem->fg.isSubquery==0 );
+ assert( pSubitem->fg.fixedSchema==0 );
wx_sqlite3DbFree(db, pSubitem->zName);
wx_sqlite3DbFree(db, pSubitem->zAlias);
- pSubitem->zDatabase = 0;
pSubitem->zName = 0;
pSubitem->zAlias = 0;
- pSubitem->pSelect = 0;
assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 );
/* If the sub-query is a compound SELECT statement, then (by restrictions
@@ -142915,8 +148438,8 @@ static int flattenSubquery(
ExprList *pOrderBy = p->pOrderBy;
Expr *pLimit = p->pLimit;
Select *pPrior = p->pPrior;
- Table *pItemTab = pSubitem->pTab;
- pSubitem->pTab = 0;
+ Table *pItemTab = pSubitem->pSTab;
+ pSubitem->pSTab = 0;
p->pOrderBy = 0;
p->pPrior = 0;
p->pLimit = 0;
@@ -142924,7 +148447,7 @@ static int flattenSubquery(
p->pLimit = pLimit;
p->pOrderBy = pOrderBy;
p->op = TK_ALL;
- pSubitem->pTab = pItemTab;
+ pSubitem->pSTab = pItemTab;
if( pNew==0 ){
p->pPrior = pPrior;
}else{
@@ -142939,11 +148462,14 @@ static int flattenSubquery(
TREETRACE(0x4,pParse,p,("compound-subquery flattener"
" creates %u as peer\n",pNew->selId));
}
- assert( pSubitem->pSelect==0 );
+ assert( pSubitem->fg.isSubquery==0 );
}
wx_sqlite3DbFree(db, aCsrMap);
if( db->mallocFailed ){
- pSubitem->pSelect = pSub1;
+ assert( pSubitem->fg.fixedSchema==0 );
+ assert( pSubitem->fg.isSubquery==0 );
+ assert( pSubitem->u4.zDatabase==0 );
+ wx_sqlite3SrcItemAttachSubquery(pParse, pSubitem, pSub1, 0);
return 1;
}
@@ -142954,18 +148480,16 @@ static int flattenSubquery(
**
** pSubitem->pTab is always non-NULL by test restrictions and tests above.
*/
- if( ALWAYS(pSubitem->pTab!=0) ){
- Table *pTabToDel = pSubitem->pTab;
+ if( ALWAYS(pSubitem->pSTab!=0) ){
+ Table *pTabToDel = pSubitem->pSTab;
if( pTabToDel->nTabRef==1 ){
Parse *pToplevel = wx_sqlite3ParseToplevel(pParse);
- wx_sqlite3ParserAddCleanup(pToplevel,
- (void(*)(wx_sqlite3*,void*))wx_sqlite3DeleteTable,
- pTabToDel);
+ wx_sqlite3ParserAddCleanup(pToplevel, wx_sqlite3DeleteTableGeneric, pTabToDel);
testcase( pToplevel->earlyCleanup );
}else{
pTabToDel->nTabRef--;
}
- pSubitem->pTab = 0;
+ pSubitem->pSTab = 0;
}
/* The following loop runs once for each term in a compound-subquery
@@ -143021,8 +148545,11 @@ static int flattenSubquery(
*/
for(i=0; i<nSubSrc; i++){
SrcItem *pItem = &pSrc->a[i+iFrom];
- if( pItem->fg.isUsing ) wx_sqlite3IdListDelete(db, pItem->u3.pUsing);
assert( pItem->fg.isTabFunc==0 );
+ assert( pItem->fg.isSubquery
+ || pItem->fg.fixedSchema
+ || pItem->u4.zDatabase==0 );
+ if( pItem->fg.isUsing ) wx_sqlite3IdListDelete(db, pItem->u3.pUsing);
*pItem = pSubSrc->a[i];
pItem->fg.jointype |= ltorj;
iNewParent = pSubSrc->a[i].iCursor;
@@ -143048,7 +148575,7 @@ static int flattenSubquery(
** ORDER BY column expression is identical to the iOrderByCol'th
** expression returned by SELECT statement pSub. Since these values
** do not necessarily correspond to columns in SELECT statement pParent,
- ** zero them before transfering the ORDER BY clause.
+ ** zero them before transferring the ORDER BY clause.
**
** Not doing this may cause an error if a subsequent call to this
** function attempts to flatten a compound sub-query into pParent
@@ -143108,8 +148635,7 @@ static int flattenSubquery(
}
}
- /* Finially, delete what is left of the subquery and return
- ** success.
+ /* Finally, delete what is left of the subquery and return success.
*/
wx_sqlite3AggInfoPersistWalkerInit(&w, pParse);
wx_sqlite3WalkSelect(&w,pSub1);
@@ -143144,7 +148670,7 @@ struct WhereConst {
/*
** Add a new entry to the pConst object. Except, do not add duplicate
-** pColumn entires. Also, do not add if doing so would not be appropriate.
+** pColumn entries. Also, do not add if doing so would not be appropriate.
**
** The caller guarantees the pColumn is a column and pValue is a constant.
** This routine has to do some additional checks before completing the
@@ -143158,7 +148684,7 @@ static void constInsert(
){
int i;
assert( pColumn->op==TK_COLUMN );
- assert( wx_sqlite3ExprIsConstant(pValue) );
+ assert( wx_sqlite3ExprIsConstant(pConst->pParse, pValue) );
if( ExprHasProperty(pColumn, EP_FixedCol) ) return;
if( wx_sqlite3ExprAffinity(pValue)!=0 ) return;
@@ -143216,10 +148742,10 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
pLeft = pExpr->pLeft;
assert( pRight!=0 );
assert( pLeft!=0 );
- if( pRight->op==TK_COLUMN && wx_sqlite3ExprIsConstant(pLeft) ){
+ if( pRight->op==TK_COLUMN && wx_sqlite3ExprIsConstant(pConst->pParse, pLeft) ){
constInsert(pConst,pRight,pLeft,pExpr);
}
- if( pLeft->op==TK_COLUMN && wx_sqlite3ExprIsConstant(pRight) ){
+ if( pLeft->op==TK_COLUMN && wx_sqlite3ExprIsConstant(pConst->pParse, pRight) ){
constInsert(pConst,pLeft,pRight,pExpr);
}
}
@@ -143330,7 +148856,7 @@ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
** SELECT * FROM t1 WHERE a=123 AND b=123;
**
** The two SELECT statements above should return different answers. b=a
-** is alway true because the comparison uses numeric affinity, but b=123
+** is always true because the comparison uses numeric affinity, but b=123
** is false because it uses text affinity and '0123' is not the same as '123'.
** To work around this, the expression tree is not actually changed from
** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol
@@ -143414,7 +148940,7 @@ static int propagateConstants(
** At the time this function is called it is guaranteed that
**
** * the sub-query uses only one distinct window frame, and
-** * that the window frame has a PARTITION BY clase.
+** * that the window frame has a PARTITION BY clause.
*/
static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
assert( pSubq->pWin->pPartition );
@@ -143440,6 +148966,19 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
** The hope is that the terms added to the inner query will make it more
** efficient.
**
+** NAME AMBIGUITY
+**
+** This optimization is called the "WHERE-clause push-down optimization"
+** or sometimes the "predicate push-down optimization".
+**
+** Do not confuse this optimization with another unrelated optimization
+** with a similar name: The "MySQL push-down optimization" causes WHERE
+** clause terms that can be evaluated using only the index and without
+** reference to the table are run first, so that if they are false,
+** unnecessary table seeks are avoided.
+**
+** RULES
+**
** Do not attempt this optimization if:
**
** (1) (** This restriction was removed on 2017-09-29. We used to
@@ -143495,10 +149034,28 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
** or EXCEPT, then all of the result set columns for all arms of
** the compound must use the BINARY collating sequence.
**
-** (9) If the subquery is a compound, then all arms of the compound must
-** have the same affinity. (This is the same as restriction (17h)
-** for query flattening.)
+** (9) All three of the following are true:
+**
+** (9a) The WHERE clause expression originates in the ON or USING clause
+** of a join (either an INNER or an OUTER join), and
+**
+** (9b) The subquery is to the right of the ON/USING clause
**
+** (9c) There is a RIGHT JOIN (or FULL JOIN) in between the ON/USING
+** clause and the subquery.
+**
+** Without this restriction, the WHERE-clause push-down optimization
+** might move the ON/USING filter expression from the left side of a
+** RIGHT JOIN over to the right side, which leads to incorrect answers.
+** See also restriction (6) in wx_sqlite3ExprIsSingleTableConstraint().
+**
+** (10) The inner query is not the right-hand table of a RIGHT JOIN.
+**
+** (11) The subquery is not a VALUES clause
+**
+** (12) The WHERE clause is not "rowid ISNULL" or the equivalent. This
+** case only comes up if SQLite is compiled using
+** SQLITE_ALLOW_ROWID_IN_VIEW.
**
** Return 0 if no changes are made and non-zero if one or more WHERE clause
** terms are duplicated into the subquery.
@@ -143507,13 +149064,20 @@ static int pushDownWhereTerms(
Parse *pParse, /* Parse context (for malloc() and error reporting) */
Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
Expr *pWhere, /* The WHERE clause of the outer query */
- SrcItem *pSrc /* The subquery term of the outer FROM clause */
+ SrcList *pSrcList, /* The complete from clause of the outer query */
+ int iSrc /* Which FROM clause term to try to push into */
){
Expr *pNew;
+ SrcItem *pSrc; /* The subquery FROM term into which WHERE is pushed */
int nChng = 0;
+ pSrc = &pSrcList->a[iSrc];
if( pWhere==0 ) return 0;
- if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0;
- if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ) return 0;
+ if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ){
+ return 0; /* restrictions (2) and (11) */
+ }
+ if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ){
+ return 0; /* restrictions (10) */
+ }
if( pSubq->pPrior ){
Select *pSel;
@@ -143529,9 +149093,6 @@ static int pushDownWhereTerms(
if( pSel->pWin ) return 0; /* restriction (6b) */
#endif
}
- if( compoundHasDifferentAffinities(pSubq) ){
- return 0; /* restriction (9) */
- }
if( notUnionAll ){
/* If any of the compound arms are connected using UNION, INTERSECT,
** or EXCEPT, then we must ensure that none of the columns use a
@@ -143571,11 +149132,28 @@ static int pushDownWhereTerms(
return 0; /* restriction (3) */
}
while( pWhere->op==TK_AND ){
- nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrc);
+ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrcList, iSrc);
pWhere = pWhere->pLeft;
}
-#if 0 /* Legacy code. Checks now done by wx_sqlite3ExprIsTableConstraint() */
+#if 0 /* These checks now done by wx_sqlite3ExprIsSingleTableConstraint() */
+ if( ExprHasProperty(pWhere, EP_OuterON|EP_InnerON) /* (9a) */
+ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (9c) */
+ ){
+ int jj;
+ for(jj=0; jj<iSrc; jj++){
+ if( pWhere->w.iJoin==pSrcList->a[jj].iCursor ){
+ /* If we reach this point, both (9a) and (9b) are satisfied.
+ ** The following loop checks (9c):
+ */
+ for(jj++; jj<iSrc; jj++){
+ if( (pSrcList->a[jj].fg.jointype & JT_RIGHT)!=0 ){
+ return 0; /* restriction (9) */
+ }
+ }
+ }
+ }
+ }
if( isLeftJoin
&& (ExprHasProperty(pWhere,EP_OuterON)==0
|| pWhere->w.iJoin!=iCursor)
@@ -143589,7 +149167,19 @@ static int pushDownWhereTerms(
}
#endif
- if( wx_sqlite3ExprIsTableConstraint(pWhere, pSrc) ){
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ if( ViewCanHaveRowid && (pWhere->op==TK_ISNULL || pWhere->op==TK_NOTNULL) ){
+ Expr *pLeft = pWhere->pLeft;
+ if( ALWAYS(pLeft)
+ && pLeft->op==TK_COLUMN
+ && pLeft->iColumn < 0
+ ){
+ return 0; /* Restriction (12) */
+ }
+ }
+#endif
+
+ if( wx_sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc, 1) ){
nChng++;
pSubq->selFlags |= SF_PushDown;
while( pSubq ){
@@ -143624,6 +149214,78 @@ static int pushDownWhereTerms(
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
/*
+** Check to see if a subquery contains result-set columns that are
+** never used. If it does, change the value of those result-set columns
+** to NULL so that they do not cause unnecessary work to compute.
+**
+** Return the number of column that were changed to NULL.
+*/
+static int disableUnusedSubqueryResultColumns(SrcItem *pItem){
+ int nCol;
+ Select *pSub; /* The subquery to be simplified */
+ Select *pX; /* For looping over compound elements of pSub */
+ Table *pTab; /* The table that describes the subquery */
+ int j; /* Column number */
+ int nChng = 0; /* Number of columns converted to NULL */
+ Bitmask colUsed; /* Columns that may not be NULLed out */
+
+ assert( pItem!=0 );
+ if( pItem->fg.isCorrelated || pItem->fg.isCte ){
+ return 0;
+ }
+ assert( pItem->pSTab!=0 );
+ pTab = pItem->pSTab;
+ assert( pItem->fg.isSubquery );
+ pSub = pItem->u4.pSubq->pSelect;
+ assert( pSub->pEList->nExpr==pTab->nCol );
+ for(pX=pSub; pX; pX=pX->pPrior){
+ if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
+ testcase( pX->selFlags & SF_Distinct );
+ testcase( pX->selFlags & SF_Aggregate );
+ return 0;
+ }
+ if( pX->pPrior && pX->op!=TK_ALL ){
+ /* This optimization does not work for compound subqueries that
+ ** use UNION, INTERSECT, or EXCEPT. Only UNION ALL is allowed. */
+ return 0;
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( pX->pWin ){
+ /* This optimization does not work for subqueries that use window
+ ** functions. */
+ return 0;
+ }
+#endif
+ }
+ colUsed = pItem->colUsed;
+ if( pSub->pOrderBy ){
+ ExprList *pList = pSub->pOrderBy;
+ for(j=0; j<pList->nExpr; j++){
+ u16 iCol = pList->a[j].u.x.iOrderByCol;
+ if( iCol>0 ){
+ iCol--;
+ colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
+ }
+ }
+ }
+ nCol = pTab->nCol;
+ for(j=0; j<nCol; j++){
+ Bitmask m = j<BMS-1 ? MASKBIT(j) : TOPBIT;
+ if( (m & colUsed)!=0 ) continue;
+ for(pX=pSub; pX; pX=pX->pPrior) {
+ Expr *pY = pX->pEList->a[j].pExpr;
+ if( pY->op==TK_NULL ) continue;
+ pY->op = TK_NULL;
+ ExprClearProperty(pY, EP_Skip|EP_Unlikely);
+ pX->selFlags |= SF_PushDown;
+ nChng++;
+ }
+ }
+ return nChng;
+}
+
+
+/*
** The pFunc is the only aggregate function in the query. Check to see
** if the query is a candidate for the min/max optimization.
**
@@ -143703,13 +149365,13 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
if( p->pWhere
|| p->pEList->nExpr!=1
|| p->pSrc->nSrc!=1
- || p->pSrc->a[0].pSelect
+ || p->pSrc->a[0].fg.isSubquery
|| pAggInfo->nFunc!=1
|| p->pHaving
){
return 0;
}
- pTab = p->pSrc->a[0].pTab;
+ pTab = p->pSrc->a[0].pSTab;
assert( pTab!=0 );
assert( !IsView(pTab) );
if( !IsOrdinaryTable(pTab) ) return 0;
@@ -143734,7 +149396,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
** pFrom->pIndex and return SQLITE_OK.
*/
SQLITE_PRIVATE int wx_sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){
- Table *pTab = pFrom->pTab;
+ Table *pTab = pFrom->pSTab;
char *zIndexedBy = pFrom->u1.zIndexedBy;
Index *pIdx;
assert( pTab!=0 );
@@ -143811,7 +149473,11 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
if( pNew==0 ) return WRC_Abort;
memset(&dummy, 0, sizeof(dummy));
pNewSrc = wx_sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0);
- if( pNewSrc==0 ) return WRC_Abort;
+ assert( pNewSrc!=0 || pParse->nErr );
+ if( pParse->nErr ){
+ wx_sqlite3SrcListDelete(db, pNewSrc);
+ return WRC_Abort;
+ }
*pNew = *p;
p->pSrc = pNewSrc;
p->pEList = wx_sqlite3ExprListAppend(pParse, 0, wx_sqlite3Expr(db, TK_ASTERISK, 0));
@@ -143866,7 +149532,7 @@ static struct Cte *searchWith(
){
const char *zName = pItem->zName;
With *p;
- assert( pItem->zDatabase==0 );
+ assert( pItem->fg.fixedSchema || pItem->u4.zDatabase==0 );
assert( zName!=0 );
for(p=pWith; p; p=p->pOuter){
int i;
@@ -143901,8 +149567,7 @@ static struct Cte *searchWith(
SQLITE_PRIVATE With *wx_sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
if( pWith ){
if( bFree ){
- pWith = (With*)wx_sqlite3ParserAddCleanup(pParse,
- (void(*)(wx_sqlite3*,void*))wx_sqlite3WithDelete,
+ pWith = (With*)wx_sqlite3ParserAddCleanup(pParse, wx_sqlite3WithDeleteGeneric,
pWith);
if( pWith==0 ) return 0;
}
@@ -143937,7 +149602,7 @@ static int resolveFromTermToCte(
Cte *pCte; /* Matched CTE (or NULL if no match) */
With *pWith; /* The matching WITH */
- assert( pFrom->pTab==0 );
+ assert( pFrom->pSTab==0 );
if( pParse->pWith==0 ){
/* There are no WITH clauses in the stack. No match is possible */
return 0;
@@ -143947,7 +149612,8 @@ static int resolveFromTermToCte(
** go no further. */
return 0;
}
- if( pFrom->zDatabase!=0 ){
+ assert( pFrom->fg.hadSchema==0 || pFrom->fg.notCte!=0 );
+ if( pFrom->fg.fixedSchema==0 && pFrom->u4.zDatabase!=0 ){
/* The FROM term contains a schema qualifier (ex: main.t1) and so
** it cannot possibly be a CTE reference. */
return 0;
@@ -143983,7 +149649,7 @@ static int resolveFromTermToCte(
}
if( cannotBeFunction(pParse, pFrom) ) return 2;
- assert( pFrom->pTab==0 );
+ assert( pFrom->pSTab==0 );
pTab = wx_sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return 2;
pCteUse = pCte->pUse;
@@ -143997,26 +149663,29 @@ static int resolveFromTermToCte(
}
pCteUse->eM10d = pCte->eM10d;
}
- pFrom->pTab = pTab;
+ pFrom->pSTab = pTab;
pTab->nTabRef = 1;
pTab->zName = wx_sqlite3DbStrDup(db, pCte->zName);
pTab->iPKey = -1;
pTab->nRowLogEst = 200; assert( 200==wx_sqlite3LogEst(1048576) );
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
- pFrom->pSelect = wx_sqlite3SelectDup(db, pCte->pSelect, 0);
+ wx_sqlite3SrcItemAttachSubquery(pParse, pFrom, pCte->pSelect, 1);
if( db->mallocFailed ) return 2;
- pFrom->pSelect->selFlags |= SF_CopyCte;
- assert( pFrom->pSelect );
+ assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
+ pSel = pFrom->u4.pSubq->pSelect;
+ assert( pSel!=0 );
+ pSel->selFlags |= SF_CopyCte;
if( pFrom->fg.isIndexedBy ){
wx_sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy);
return 2;
}
+ assert( !pFrom->fg.isIndexedBy );
pFrom->fg.isCte = 1;
pFrom->u2.pCteUse = pCteUse;
pCteUse->nUse++;
/* Check if this is a recursive CTE. */
- pRecTerm = pSel = pFrom->pSelect;
+ pRecTerm = pSel;
bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
while( bMayRecursive && pRecTerm->op==pSel->op ){
int i;
@@ -144024,11 +149693,13 @@ static int resolveFromTermToCte(
assert( pRecTerm->pPrior!=0 );
for(i=0; i<pSrc->nSrc; i++){
SrcItem *pItem = &pSrc->a[i];
- if( pItem->zDatabase==0
- && pItem->zName!=0
+ if( pItem->zName!=0
+ && !pItem->fg.hadSchema
+ && ALWAYS( !pItem->fg.isSubquery )
+ && (pItem->fg.fixedSchema || pItem->u4.zDatabase==0)
&& 0==wx_sqlite3StrICmp(pItem->zName, pCte->zName)
){
- pItem->pTab = pTab;
+ pItem->pSTab = pTab;
pTab->nTabRef++;
pItem->fg.isRecursive = 1;
if( pRecTerm->selFlags & SF_Recursive ){
@@ -144130,11 +149801,14 @@ SQLITE_PRIVATE void wx_sqlite3SelectPopWith(Walker *pWalker, Select *p){
** SQLITE_NOMEM.
*/
SQLITE_PRIVATE int wx_sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
- Select *pSel = pFrom->pSelect;
+ Select *pSel;
Table *pTab;
+ assert( pFrom->fg.isSubquery );
+ assert( pFrom->u4.pSubq!=0 );
+ pSel = pFrom->u4.pSubq->pSelect;
assert( pSel );
- pFrom->pTab = pTab = wx_sqlite3DbMallocZero(pParse->db, sizeof(Table));
+ pFrom->pSTab = pTab = wx_sqlite3DbMallocZero(pParse->db, sizeof(Table));
if( pTab==0 ) return SQLITE_NOMEM;
pTab->nTabRef = 1;
if( pFrom->zAlias ){
@@ -144145,12 +149819,14 @@ SQLITE_PRIVATE int wx_sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
while( pSel->pPrior ){ pSel = pSel->pPrior; }
wx_sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
pTab->iPKey = -1;
+ pTab->eTabType = TABTYP_VIEW;
pTab->nRowLogEst = 200; assert( 200==wx_sqlite3LogEst(1048576) );
#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
/* The usual case - do not allow ROWID on a subquery */
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
#else
- pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */
+ /* Legacy compatibility mode */
+ pTab->tabFlags |= TF_Ephemeral | wx_sqlite3Config.mNoVisibleRowid;
#endif
return pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
}
@@ -144252,33 +149928,35 @@ static int selectExpander(Walker *pWalker, Select *p){
*/
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab;
- assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
- if( pFrom->pTab ) continue;
+ assert( pFrom->fg.isRecursive==0 || pFrom->pSTab!=0 );
+ if( pFrom->pSTab ) continue;
assert( pFrom->fg.isRecursive==0 );
if( pFrom->zName==0 ){
#ifndef SQLITE_OMIT_SUBQUERY
- Select *pSel = pFrom->pSelect;
+ Select *pSel;
+ assert( pFrom->fg.isSubquery && pFrom->u4.pSubq!=0 );
+ pSel = pFrom->u4.pSubq->pSelect;
/* A sub-query in the FROM clause of a SELECT */
assert( pSel!=0 );
- assert( pFrom->pTab==0 );
+ assert( pFrom->pSTab==0 );
if( wx_sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
if( wx_sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
#endif
#ifndef SQLITE_OMIT_CTE
}else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){
if( rc>1 ) return WRC_Abort;
- pTab = pFrom->pTab;
+ pTab = pFrom->pSTab;
assert( pTab!=0 );
#endif
}else{
/* An ordinary table or view name in the FROM clause */
- assert( pFrom->pTab==0 );
- pFrom->pTab = pTab = wx_sqlite3LocateTableItem(pParse, 0, pFrom);
+ assert( pFrom->pSTab==0 );
+ pFrom->pSTab = pTab = wx_sqlite3LocateTableItem(pParse, 0, pFrom);
if( pTab==0 ) return WRC_Abort;
if( pTab->nTabRef>=0xffff ){
wx_sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
pTab->zName);
- pFrom->pTab = 0;
+ pFrom->pSTab = 0;
return WRC_Abort;
}
pTab->nTabRef++;
@@ -144290,7 +149968,7 @@ static int selectExpander(Walker *pWalker, Select *p){
i16 nCol;
u8 eCodeOrig = pWalker->eCode;
if( wx_sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
- assert( pFrom->pSelect==0 );
+ assert( pFrom->fg.isSubquery==0 );
if( IsView(pTab) ){
if( (db->flags & SQLITE_EnableView)==0
&& pTab->pSchema!=db->aDb[1].pSchema
@@ -144298,7 +149976,7 @@ static int selectExpander(Walker *pWalker, Select *p){
wx_sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
pTab->zName);
}
- pFrom->pSelect = wx_sqlite3SelectDup(db, pTab->u.view.pSelect, 0);
+ wx_sqlite3SrcItemAttachSubquery(pParse, pFrom, pTab->u.view.pSelect, 1);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( ALWAYS(IsVirtual(pTab))
@@ -144314,7 +149992,9 @@ static int selectExpander(Walker *pWalker, Select *p){
nCol = pTab->nCol;
pTab->nCol = -1;
pWalker->eCode = 1; /* Turn on Select.selId renumbering */
- wx_sqlite3WalkSelect(pWalker, pFrom->pSelect);
+ if( pFrom->fg.isSubquery ){
+ wx_sqlite3WalkSelect(pWalker, pFrom->u4.pSubq->pSelect);
+ }
pWalker->eCode = eCodeOrig;
pTab->nCol = nCol;
}
@@ -144387,13 +150067,21 @@ static int selectExpander(Walker *pWalker, Select *p){
** expanded. */
int tableSeen = 0; /* Set to 1 when TABLE matches */
char *zTName = 0; /* text of name of TABLE */
+ int iErrOfst;
if( pE->op==TK_DOT ){
+ assert( (selFlags & SF_NestedFrom)==0 );
assert( pE->pLeft!=0 );
assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
zTName = pE->pLeft->u.zToken;
+ assert( ExprUseWOfst(pE->pLeft) );
+ iErrOfst = pE->pRight->w.iOfst;
+ }else{
+ assert( ExprUseWOfst(pE) );
+ iErrOfst = pE->w.iOfst;
}
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
- Table *pTab = pFrom->pTab; /* Table for this data source */
+ int nAdd; /* Number of cols including rowid */
+ Table *pTab = pFrom->pSTab; /* Table for this data source */
ExprList *pNestedFrom; /* Result-set of a nested FROM clause */
char *zTabName; /* AS name for this data source */
const char *zSchemaName = 0; /* Schema name for this data source */
@@ -144404,12 +150092,14 @@ static int selectExpander(Walker *pWalker, Select *p){
zTabName = pTab->zName;
}
if( db->mallocFailed ) break;
- assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) );
+ assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom) );
if( pFrom->fg.isNestedFrom ){
- assert( pFrom->pSelect!=0 );
- pNestedFrom = pFrom->pSelect->pEList;
+ assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
+ assert( pFrom->u4.pSubq->pSelect!=0 );
+ pNestedFrom = pFrom->u4.pSubq->pSelect->pEList;
assert( pNestedFrom!=0 );
assert( pNestedFrom->nExpr==pTab->nCol );
+ assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid );
}else{
if( zTName && wx_sqlite3StrICmp(zTName, zTabName)!=0 ){
continue;
@@ -144427,6 +150117,7 @@ static int selectExpander(Walker *pWalker, Select *p){
for(ii=0; ii<pUsing->nId; ii++){
const char *zUName = pUsing->a[ii].zName;
pRight = wx_sqlite3Expr(db, TK_ID, zUName);
+ wx_sqlite3ExprSetErrorOffset(pRight, iErrOfst);
pNew = wx_sqlite3ExprListAppend(pParse, pNew, pRight);
if( pNew ){
struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
@@ -144439,33 +150130,49 @@ static int selectExpander(Walker *pWalker, Select *p){
}else{
pUsing = 0;
}
- for(j=0; j<pTab->nCol; j++){
- char *zName = pTab->aCol[j].zCnName;
+
+ nAdd = pTab->nCol;
+ if( VisibleRowid(pTab) && (selFlags & SF_NestedFrom)!=0 ) nAdd++;
+ for(j=0; j<nAdd; j++){
+ const char *zName;
struct ExprList_item *pX; /* Newly added ExprList term */
- assert( zName );
- if( zTName
- && pNestedFrom
- && wx_sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 0)==0
- ){
- continue;
- }
+ if( j==pTab->nCol ){
+ zName = wx_sqlite3RowidAlias(pTab);
+ if( zName==0 ) continue;
+ }else{
+ zName = pTab->aCol[j].zCnName;
- /* If a column is marked as 'hidden', omit it from the expanded
- ** result-set list unless the SELECT has the SF_IncludeHidden
- ** bit set.
- */
- if( (p->selFlags & SF_IncludeHidden)==0
- && IsHiddenColumn(&pTab->aCol[j])
- ){
- continue;
- }
- if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
- && zTName==0
- && (selFlags & (SF_NestedFrom))==0
- ){
- continue;
+ /* If pTab is actually an SF_NestedFrom sub-select, do not
+ ** expand any ENAME_ROWID columns. */
+ if( pNestedFrom && pNestedFrom->a[j].fg.eEName==ENAME_ROWID ){
+ continue;
+ }
+
+ if( zTName
+ && pNestedFrom
+ && wx_sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 0, 0)==0
+ ){
+ continue;
+ }
+
+ /* If a column is marked as 'hidden', omit it from the expanded
+ ** result-set list unless the SELECT has the SF_IncludeHidden
+ ** bit set.
+ */
+ if( (p->selFlags & SF_IncludeHidden)==0
+ && IsHiddenColumn(&pTab->aCol[j])
+ ){
+ continue;
+ }
+ if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
+ && zTName==0
+ && (selFlags & (SF_NestedFrom))==0
+ ){
+ continue;
+ }
}
+ assert( zName );
tableSeen = 1;
if( i>0 && zTName==0 && (selFlags & SF_NestedFrom)==0 ){
@@ -144499,6 +150206,7 @@ static int selectExpander(Walker *pWalker, Select *p){
}else{
pExpr = pRight;
}
+ wx_sqlite3ExprSetErrorOffset(pExpr, iErrOfst);
pNew = wx_sqlite3ExprListAppend(pParse, pNew, pExpr);
if( pNew==0 ){
break; /* OOM */
@@ -144506,7 +150214,8 @@ static int selectExpander(Walker *pWalker, Select *p){
pX = &pNew->a[pNew->nExpr-1];
assert( pX->zEName==0 );
if( (selFlags & SF_NestedFrom)!=0 && !IN_RENAME_OBJECT ){
- if( pNestedFrom ){
+ if( pNestedFrom && (!ViewCanHaveRowid || j<pNestedFrom->nExpr) ){
+ assert( j<pNestedFrom->nExpr );
pX->zEName = wx_sqlite3DbStrDup(db, pNestedFrom->a[j].zEName);
testcase( pX->zEName==0 );
}else{
@@ -144514,11 +150223,11 @@ static int selectExpander(Walker *pWalker, Select *p){
zSchemaName, zTabName, zName);
testcase( pX->zEName==0 );
}
- pX->fg.eEName = ENAME_TAB;
+ pX->fg.eEName = (j==pTab->nCol ? ENAME_ROWID : ENAME_TAB);
if( (pFrom->fg.isUsing
&& wx_sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0)
|| (pUsing && wx_sqlite3IdListIndex(pUsing, zName)>=0)
- || (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
+ || (j<pTab->nCol && (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND))
){
pX->fg.bNoExpand = 1;
}
@@ -144620,20 +150329,18 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
SrcList *pTabList;
SrcItem *pFrom;
- assert( p->selFlags & SF_Resolved );
if( p->selFlags & SF_HasTypeInfo ) return;
p->selFlags |= SF_HasTypeInfo;
pParse = pWalker->pParse;
+ assert( (p->selFlags & SF_Resolved) );
pTabList = p->pSrc;
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
- Table *pTab = pFrom->pTab;
+ Table *pTab = pFrom->pSTab;
assert( pTab!=0 );
- if( (pTab->tabFlags & TF_Ephemeral)!=0 ){
+ if( (pTab->tabFlags & TF_Ephemeral)!=0 && pFrom->fg.isSubquery ){
/* A sub-query in the FROM clause of a SELECT */
- Select *pSel = pFrom->pSelect;
- if( pSel ){
- wx_sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
- }
+ Select *pSel = pFrom->u4.pSubq->pSelect;
+ wx_sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
}
}
}
@@ -144693,6 +150400,8 @@ SQLITE_PRIVATE void wx_sqlite3SelectPrep(
*/
static void printAggInfo(AggInfo *pAggInfo){
int ii;
+ wx_sqlite3DebugPrintf("AggInfo %d/%p:\n",
+ pAggInfo->selId, pAggInfo);
for(ii=0; ii<pAggInfo->nColumn; ii++){
struct AggInfo_col *pCol = &pAggInfo->aCol[ii];
wx_sqlite3DebugPrintf(
@@ -144739,8 +150448,14 @@ static void analyzeAggFuncArgs(
pNC->ncFlags |= NC_InAggFunc;
for(i=0; i<pAggInfo->nFunc; i++){
Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
+ assert( pExpr->op==TK_FUNCTION || pExpr->op==TK_AGG_FUNCTION );
assert( ExprUseXList(pExpr) );
wx_sqlite3ExprAnalyzeAggList(pNC, pExpr->x.pList);
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ wx_sqlite3ExprAnalyzeAggList(pNC, pExpr->pLeft->x.pList);
+ }
#ifndef SQLITE_OMIT_WINDOWFUNC
assert( !IsWindowFunc(pExpr) );
if( ExprHasProperty(pExpr, EP_WinFunc) ){
@@ -144769,12 +150484,13 @@ static void optimizeAggregateUseOfIndexedExpr(
assert( pSelect->pGroupBy!=0 );
pAggInfo->nColumn = pAggInfo->nAccumulator;
if( ALWAYS(pAggInfo->nSortingColumn>0) ){
- if( pAggInfo->nColumn==0 ){
- pAggInfo->nSortingColumn = pSelect->pGroupBy->nExpr;
- }else{
- pAggInfo->nSortingColumn =
- pAggInfo->aCol[pAggInfo->nColumn-1].iSorterColumn+1;
+ int mx = pSelect->pGroupBy->nExpr - 1;
+ int j, k;
+ for(j=0; j<pAggInfo->nColumn; j++){
+ k = pAggInfo->aCol[j].iSorterColumn;
+ if( k>mx ) mx = k;
}
+ pAggInfo->nSortingColumn = mx+1;
}
analyzeAggFuncArgs(pAggInfo, pNC);
#if TREETRACE_ENABLED
@@ -144808,11 +150524,13 @@ static int aggregateIdxEprRefToColCallback(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_AGG_FUNCTION ) return WRC_Continue;
if( pExpr->op==TK_IF_NULL_ROW ) return WRC_Continue;
pAggInfo = pExpr->pAggInfo;
- assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ if( NEVER(pExpr->iAgg>=pAggInfo->nColumn) ) return WRC_Continue;
+ assert( pExpr->iAgg>=0 );
pCol = &pAggInfo->aCol[pExpr->iAgg];
pExpr->op = TK_AGG_COLUMN;
pExpr->iTable = pCol->iTable;
pExpr->iColumn = pCol->iColumn;
+ ExprClearProperty(pExpr, EP_Skip|EP_Collate|EP_Unlikely);
return WRC_Prune;
}
@@ -144843,7 +150561,7 @@ static void aggregateConvertIndexedExprRefToColumn(AggInfo *pAggInfo){
** * The aCol[] and aFunc[] arrays may be modified
** * The AggInfoColumnReg() and AggInfoFuncReg() macros may not be used
**
-** After clling this routine:
+** After calling this routine:
**
** * The aCol[] and aFunc[] arrays are fixed
** * The AggInfoColumnReg() and AggInfoFuncReg() macros may be used
@@ -144892,6 +150610,36 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
pFunc->pFunc->zName));
}
}
+ if( pFunc->iOBTab>=0 ){
+ ExprList *pOBList;
+ KeyInfo *pKeyInfo;
+ int nExtra = 0;
+ assert( pFunc->pFExpr->pLeft!=0 );
+ assert( pFunc->pFExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pFunc->pFExpr->pLeft) );
+ assert( pFunc->pFunc!=0 );
+ pOBList = pFunc->pFExpr->pLeft->x.pList;
+ if( !pFunc->bOBUnique ){
+ nExtra++; /* One extra column for the OP_Sequence */
+ }
+ if( pFunc->bOBPayload ){
+ /* extra columns for the function arguments */
+ assert( ExprUseXList(pFunc->pFExpr) );
+ nExtra += pFunc->pFExpr->x.pList->nExpr;
+ }
+ if( pFunc->bUseSubtype ){
+ nExtra += pFunc->pFExpr->x.pList->nExpr;
+ }
+ pKeyInfo = wx_sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra);
+ if( !pFunc->bOBUnique && pParse->nErr==0 ){
+ pKeyInfo->nKeyField++;
+ }
+ wx_sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
+ pFunc->iOBTab, pOBList->nExpr+nExtra, 0,
+ (char*)pKeyInfo, P4_KEYINFO);
+ ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(ORDER BY)",
+ pFunc->pFunc->zName));
+ }
}
}
@@ -144906,14 +150654,58 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
ExprList *pList;
assert( ExprUseXList(pF->pFExpr) );
+ if( pParse->nErr ) return;
pList = pF->pFExpr->x.pList;
+ if( pF->iOBTab>=0 ){
+ /* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs
+ ** were stored in emphermal table pF->iOBTab. Here, we extract those
+ ** inputs (in ORDER BY order) and make all calls to OP_AggStep
+ ** before doing the OP_AggFinal call. */
+ int iTop; /* Start of loop for extracting columns */
+ int nArg; /* Number of columns to extract */
+ int nKey; /* Key columns to be skipped */
+ int regAgg; /* Extract into this array */
+ int j; /* Loop counter */
+
+ assert( pF->pFunc!=0 );
+ nArg = pList->nExpr;
+ regAgg = wx_sqlite3GetTempRange(pParse, nArg);
+
+ if( pF->bOBPayload==0 ){
+ nKey = 0;
+ }else{
+ assert( pF->pFExpr->pLeft!=0 );
+ assert( ExprUseXList(pF->pFExpr->pLeft) );
+ assert( pF->pFExpr->pLeft->x.pList!=0 );
+ nKey = pF->pFExpr->pLeft->x.pList->nExpr;
+ if( ALWAYS(!pF->bOBUnique) ) nKey++;
+ }
+ iTop = wx_sqlite3VdbeAddOp1(v, OP_Rewind, pF->iOBTab); VdbeCoverage(v);
+ for(j=nArg-1; j>=0; j--){
+ wx_sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j);
+ }
+ if( pF->bUseSubtype ){
+ int regSubtype = wx_sqlite3GetTempReg(pParse);
+ int iBaseCol = nKey + nArg + (pF->bOBPayload==0 && pF->bOBUnique==0);
+ for(j=nArg-1; j>=0; j--){
+ wx_sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, iBaseCol+j, regSubtype);
+ wx_sqlite3VdbeAddOp2(v, OP_SetSubtype, regSubtype, regAgg+j);
+ }
+ wx_sqlite3ReleaseTempReg(pParse, regSubtype);
+ }
+ wx_sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
+ wx_sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
+ wx_sqlite3VdbeChangeP5(v, (u8)nArg);
+ wx_sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v);
+ wx_sqlite3VdbeJumpHere(v, iTop);
+ wx_sqlite3ReleaseTempRange(pParse, regAgg, nArg);
+ }
wx_sqlite3VdbeAddOp2(v, OP_AggFinal, AggInfoFuncReg(pAggInfo,i),
pList ? pList->nExpr : 0);
wx_sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
}
}
-
/*
** Generate code that will update the accumulator memory cells for an
** aggregate based on the current cursor position.
@@ -144922,6 +150714,13 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator
** registers if register regAcc contains 0. The caller will take care
** of setting and clearing regAcc.
+**
+** For an ORDER BY aggregate, the actual accumulator memory cell update
+** is deferred until after all input rows have been received, so that they
+** can be run in the requested order. In that case, instead of invoking
+** OP_AggStep to update the accumulator, just add the arguments that would
+** have been passed into OP_AggStep into the sorting ephemeral table
+** (along with the appropriate sort key).
*/
static void updateAccumulator(
Parse *pParse,
@@ -144943,9 +150742,12 @@ static void updateAccumulator(
int nArg;
int addrNext = 0;
int regAgg;
+ int regAggSz = 0;
+ int regDistinct = 0;
ExprList *pList;
assert( ExprUseXList(pF->pFExpr) );
assert( !IsWindowFunc(pF->pFExpr) );
+ assert( pF->pFunc!=0 );
pList = pF->pFExpr->x.pList;
if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){
Expr *pFilter = pF->pFExpr->y.pWin->pFilter;
@@ -144969,9 +150771,55 @@ static void updateAccumulator(
addrNext = wx_sqlite3VdbeMakeLabel(pParse);
wx_sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL);
}
- if( pList ){
+ if( pF->iOBTab>=0 ){
+ /* Instead of invoking AggStep, we must push the arguments that would
+ ** have been passed to AggStep onto the sorting table. */
+ int jj; /* Registered used so far in building the record */
+ ExprList *pOBList; /* The ORDER BY clause */
+ assert( pList!=0 );
+ nArg = pList->nExpr;
+ assert( nArg>0 );
+ assert( pF->pFExpr->pLeft!=0 );
+ assert( pF->pFExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pF->pFExpr->pLeft) );
+ pOBList = pF->pFExpr->pLeft->x.pList;
+ assert( pOBList!=0 );
+ assert( pOBList->nExpr>0 );
+ regAggSz = pOBList->nExpr;
+ if( !pF->bOBUnique ){
+ regAggSz++; /* One register for OP_Sequence */
+ }
+ if( pF->bOBPayload ){
+ regAggSz += nArg;
+ }
+ if( pF->bUseSubtype ){
+ regAggSz += nArg;
+ }
+ regAggSz++; /* One extra register to hold result of MakeRecord */
+ regAgg = wx_sqlite3GetTempRange(pParse, regAggSz);
+ regDistinct = regAgg;
+ wx_sqlite3ExprCodeExprList(pParse, pOBList, regAgg, 0, SQLITE_ECEL_DUP);
+ jj = pOBList->nExpr;
+ if( !pF->bOBUnique ){
+ wx_sqlite3VdbeAddOp2(v, OP_Sequence, pF->iOBTab, regAgg+jj);
+ jj++;
+ }
+ if( pF->bOBPayload ){
+ regDistinct = regAgg+jj;
+ wx_sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP);
+ jj += nArg;
+ }
+ if( pF->bUseSubtype ){
+ int kk;
+ int regBase = pF->bOBPayload ? regDistinct : regAgg;
+ for(kk=0; kk<nArg; kk++, jj++){
+ wx_sqlite3VdbeAddOp2(v, OP_GetSubtype, regBase+kk, regAgg+jj);
+ }
+ }
+ }else if( pList ){
nArg = pList->nExpr;
regAgg = wx_sqlite3GetTempRange(pParse, nArg);
+ regDistinct = regAgg;
wx_sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP);
}else{
nArg = 0;
@@ -144982,29 +150830,41 @@ static void updateAccumulator(
addrNext = wx_sqlite3VdbeMakeLabel(pParse);
}
pF->iDistinct = codeDistinct(pParse, eDistinctType,
- pF->iDistinct, addrNext, pList, regAgg);
- }
- if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
- CollSeq *pColl = 0;
- struct ExprList_item *pItem;
- int j;
- assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */
- for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
- pColl = wx_sqlite3ExprCollSeq(pParse, pItem->pExpr);
- }
- if( !pColl ){
- pColl = pParse->db->pDfltColl;
+ pF->iDistinct, addrNext, pList, regDistinct);
+ }
+ if( pF->iOBTab>=0 ){
+ /* Insert a new record into the ORDER BY table */
+ wx_sqlite3VdbeAddOp3(v, OP_MakeRecord, regAgg, regAggSz-1,
+ regAgg+regAggSz-1);
+ wx_sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pF->iOBTab, regAgg+regAggSz-1,
+ regAgg, regAggSz-1);
+ wx_sqlite3ReleaseTempRange(pParse, regAgg, regAggSz);
+ }else{
+ /* Invoke the AggStep function */
+ if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
+ CollSeq *pColl = 0;
+ struct ExprList_item *pItem;
+ int j;
+ assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */
+ for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
+ pColl = wx_sqlite3ExprCollSeq(pParse, pItem->pExpr);
+ }
+ if( !pColl ){
+ pColl = pParse->db->pDfltColl;
+ }
+ if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
+ wx_sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0,
+ (char *)pColl, P4_COLLSEQ);
}
- if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
- wx_sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
+ wx_sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
+ wx_sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
+ wx_sqlite3VdbeChangeP5(v, (u8)nArg);
+ wx_sqlite3ReleaseTempRange(pParse, regAgg, nArg);
}
- wx_sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
- wx_sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
- wx_sqlite3VdbeChangeP5(v, (u8)nArg);
- wx_sqlite3ReleaseTempRange(pParse, regAgg, nArg);
if( addrNext ){
wx_sqlite3VdbeResolveLabel(v, addrNext);
}
+ if( pParse->nErr ) return;
}
if( regHit==0 && pAggInfo->nAccumulator ){
regHit = regAcc;
@@ -145014,6 +150874,7 @@ static void updateAccumulator(
}
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
wx_sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i));
+ if( pParse->nErr ) return;
}
pAggInfo->directMode = 0;
@@ -145129,25 +150990,28 @@ static SrcItem *isSelfJoinView(
int iFirst, int iEnd /* Range of FROM-clause entries to search. */
){
SrcItem *pItem;
- assert( pThis->pSelect!=0 );
- if( pThis->pSelect->selFlags & SF_PushDown ) return 0;
+ Select *pSel;
+ assert( pThis->fg.isSubquery );
+ pSel = pThis->u4.pSubq->pSelect;
+ assert( pSel!=0 );
+ if( pSel->selFlags & SF_PushDown ) return 0;
while( iFirst<iEnd ){
Select *pS1;
pItem = &pTabList->a[iFirst++];
- if( pItem->pSelect==0 ) continue;
+ if( !pItem->fg.isSubquery ) continue;
if( pItem->fg.viaCoroutine ) continue;
if( pItem->zName==0 ) continue;
- assert( pItem->pTab!=0 );
- assert( pThis->pTab!=0 );
- if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue;
+ assert( pItem->pSTab!=0 );
+ assert( pThis->pSTab!=0 );
+ if( pItem->pSTab->pSchema!=pThis->pSTab->pSchema ) continue;
if( wx_sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
- pS1 = pItem->pSelect;
- if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){
+ pS1 = pItem->u4.pSubq->pSelect;
+ if( pItem->pSTab->pSchema==0 && pSel->selId!=pS1->selId ){
/* The query flattener left two different CTE tables with identical
** names in the same FROM clause. */
continue;
}
- if( pItem->pSelect->selFlags & SF_PushDown ){
+ if( pS1->selFlags & SF_PushDown ){
/* The view was modified by some other optimization such as
** pushDownWhereTerms() */
continue;
@@ -145160,13 +151024,13 @@ static SrcItem *isSelfJoinView(
/*
** Deallocate a single AggInfo object
*/
-static void agginfoFree(wx_sqlite3 *db, AggInfo *p){
+static void agginfoFree(wx_sqlite3 *db, void *pArg){
+ AggInfo *p = (AggInfo*)pArg;
wx_sqlite3DbFree(db, p->aCol);
wx_sqlite3DbFree(db, p->aFunc);
wx_sqlite3DbFreeNN(db, p);
}
-#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
/*
** Attempt to transform a query of the form
**
@@ -145191,9 +151055,11 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
Expr *pExpr;
Expr *pCount;
wx_sqlite3 *db;
+ SrcItem *pFrom;
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
if( p->pWhere ) return 0;
+ if( p->pHaving ) return 0;
if( p->pGroupBy ) return 0;
if( p->pOrderBy ) return 0;
pExpr = p->pEList->a[0].pExpr;
@@ -145204,8 +151070,9 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */
- pSub = p->pSrc->a[0].pSelect;
- if( pSub==0 ) return 0; /* The FROM is a subquery */
+ pFrom = p->pSrc->a;
+ if( pFrom->fg.isSubquery==0 ) return 0; /* FROM is a subquery */
+ pSub = pFrom->u4.pSubq->pSelect;
if( pSub->pPrior==0 ) return 0; /* Must be a compound */
if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
do{
@@ -145213,6 +151080,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( pSub->pWhere ) return 0; /* No WHERE clause */
if( pSub->pLimit ) return 0; /* No LIMIT clause */
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
+ assert( pSub->pHaving==0 ); /* Due to the previous */
pSub = pSub->pPrior; /* Repeat over compound */
}while( pSub );
@@ -145221,8 +151089,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
db = pParse->db;
pCount = pExpr;
pExpr = 0;
- pSub = p->pSrc->a[0].pSelect;
- p->pSrc->a[0].pSelect = 0;
+ pSub = wx_sqlite3SubqueryDetach(db, pFrom);
wx_sqlite3SrcListDelete(db, p->pSrc);
p->pSrc = wx_sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
while( pSub ){
@@ -145233,7 +151100,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
pSub->selFlags |= SF_Aggregate;
pSub->selFlags &= ~SF_Compound;
pSub->nSelectRow = 0;
- wx_sqlite3ExprListDelete(db, pSub->pEList);
+ wx_sqlite3ParserAddCleanup(pParse, wx_sqlite3ExprListDeleteGeneric, pSub->pEList);
pTerm = pPrior ? wx_sqlite3ExprDup(db, pCount, 0) : pCount;
pSub->pEList = wx_sqlite3ExprListAppend(pParse, 0, pTerm);
pTerm = wx_sqlite3PExpr(pParse, TK_SELECT, 0, 0);
@@ -145256,7 +151123,6 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
#endif
return 1;
}
-#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
/*
** If any term of pSrc, or any SF_NestedFrom sub-query, is not the same
@@ -145268,12 +151134,12 @@ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){
for(i=0; i<pSrc->nSrc; i++){
SrcItem *p1 = &pSrc->a[i];
if( p1==p0 ) continue;
- if( p0->pTab==p1->pTab && 0==wx_sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
+ if( p0->pSTab==p1->pSTab && 0==wx_sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
return 1;
}
- if( p1->pSelect
- && (p1->pSelect->selFlags & SF_NestedFrom)!=0
- && sameSrcAlias(p0, p1->pSelect->pSrc)
+ if( p1->fg.isSubquery
+ && (p1->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0
+ && sameSrcAlias(p0, p1->u4.pSubq->pSelect->pSrc)
){
return 1;
}
@@ -145338,13 +151204,13 @@ static int fromClauseTermCanBeCoroutine(
if( i==0 ) break;
i--;
pItem--;
- if( pItem->pSelect!=0 ) return 0; /* (1c-i) */
+ if( pItem->fg.isSubquery ) return 0; /* (1c-i) */
}
return 1;
}
/*
-** Generate code for the SELECT statement given in the p argument.
+** Generate byte-code for the SELECT statement given in the p argument.
**
** The results are returned according to the SelectDest structure.
** See comments in sqliteInt.h for further information.
@@ -145355,6 +151221,40 @@ static int fromClauseTermCanBeCoroutine(
**
** This routine does NOT free the Select structure passed in. The
** calling function needs to do that.
+**
+** This is a long function. The following is an outline of the processing
+** steps, with tags referencing various milestones:
+**
+** * Resolve names and similar preparation tag-select-0100
+** * Scan of the FROM clause tag-select-0200
+** + OUTER JOIN strength reduction tag-select-0220
+** + Sub-query ORDER BY removal tag-select-0230
+** + Query flattening tag-select-0240
+** * Separate subroutine for compound-SELECT tag-select-0300
+** * WHERE-clause constant propagation tag-select-0330
+** * Count()-of-VIEW optimization tag-select-0350
+** * Scan of the FROM clause again tag-select-0400
+** + Authorize unreferenced tables tag-select-0410
+** + Predicate push-down optimization tag-select-0420
+** + Omit unused subquery columns optimization tag-select-0440
+** + Generate code to implement subqueries tag-select-0480
+** - Co-routines tag-select-0482
+** - Reuse previously computed CTE tag-select-0484
+** - REuse previously computed VIEW tag-select-0486
+** - Materialize a VIEW or CTE tag-select-0488
+** * DISTINCT ORDER BY -> GROUP BY optimization tag-select-0500
+** * Set up for ORDER BY tag-select-0600
+** * Create output table tag-select-0630
+** * Prepare registers for LIMIT tag-select-0650
+** * Setup for DISTINCT tag-select-0680
+** * Generate code for non-aggregate and non-GROUP BY tag-select-0700
+** * Generate code for aggregate and/or GROUP BY tag-select-0800
+** + GROUP BY queries tag-select-0810
+** + non-GROUP BY queries tag-select-0820
+** - Special case of count() w/o GROUP BY tag-select-0821
+** - General case of non-GROUP BY aggregates tag-select-0822
+** * Sort results, as needed tag-select-0900
+** * Internal self-checks tag-select-1000
*/
SQLITE_PRIVATE int wx_sqlite3Select(
Parse *pParse, /* The parser context */
@@ -145398,6 +151298,7 @@ SQLITE_PRIVATE int wx_sqlite3Select(
}
#endif
+ /* tag-select-0100 */
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
@@ -145414,9 +151315,8 @@ SQLITE_PRIVATE int wx_sqlite3Select(
wx_sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY");
}
#endif
- wx_sqlite3ParserAddCleanup(pParse,
- (void(*)(wx_sqlite3*,void*))wx_sqlite3ExprListDelete,
- p->pOrderBy);
+ wx_sqlite3ParserAddCleanup(pParse, wx_sqlite3ExprListDeleteGeneric,
+ p->pOrderBy);
testcase( pParse->earlyCleanup );
p->pOrderBy = 0;
}
@@ -145450,7 +151350,7 @@ SQLITE_PRIVATE int wx_sqlite3Select(
if( sameSrcAlias(p0, p->pSrc) ){
wx_sqlite3ErrorMsg(pParse,
"target object/alias may not appear in FROM clause: %s",
- p0->zAlias ? p0->zAlias : p0->pTab->zName
+ p0->zAlias ? p0->zAlias : p0->pSTab->zName
);
goto select_end;
}
@@ -145485,34 +151385,72 @@ SQLITE_PRIVATE int wx_sqlite3Select(
/* Try to do various optimizations (flattening subqueries, and strength
** reduction of join operators) in the FROM clause up into the main query
+ ** tag-select-0200
*/
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
SrcItem *pItem = &pTabList->a[i];
- Select *pSub = pItem->pSelect;
- Table *pTab = pItem->pTab;
+ Select *pSub = pItem->fg.isSubquery ? pItem->u4.pSubq->pSelect : 0;
+ Table *pTab = pItem->pSTab;
/* The expander should have already created transient Table objects
** even for FROM clause elements such as subqueries that do not correspond
** to a real table */
assert( pTab!=0 );
- /* Convert LEFT JOIN into JOIN if there are terms of the right table
- ** of the LEFT JOIN used in the WHERE clause.
+ /* Try to simplify joins:
+ **
+ ** LEFT JOIN -> JOIN
+ ** RIGHT JOIN -> JOIN
+ ** FULL JOIN -> RIGHT JOIN
+ **
+ ** If terms of the i-th table are used in the WHERE clause in such a
+ ** way that the i-th table cannot be the NULL row of a join, then
+ ** perform the appropriate simplification. This is called
+ ** "OUTER JOIN strength reduction" in the SQLite documentation.
+ ** tag-select-0220
*/
- if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==JT_LEFT
- && wx_sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor)
+ if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
+ && wx_sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor,
+ pItem->fg.jointype & JT_LTORJ)
&& OptimizationEnabled(db, SQLITE_SimplifyJoin)
){
- TREETRACE(0x1000,pParse,p,
- ("LEFT-JOIN simplifies to JOIN on term %d\n",i));
- pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER);
- assert( pItem->iCursor>=0 );
- unsetJoinExpr(p->pWhere, pItem->iCursor,
- pTabList->a[0].fg.jointype & JT_LTORJ);
+ if( pItem->fg.jointype & JT_LEFT ){
+ if( pItem->fg.jointype & JT_RIGHT ){
+ TREETRACE(0x1000,pParse,p,
+ ("FULL-JOIN simplifies to RIGHT-JOIN on term %d\n",i));
+ pItem->fg.jointype &= ~JT_LEFT;
+ }else{
+ TREETRACE(0x1000,pParse,p,
+ ("LEFT-JOIN simplifies to JOIN on term %d\n",i));
+ pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER);
+ unsetJoinExpr(p->pWhere, pItem->iCursor, 0);
+ }
+ }
+ if( pItem->fg.jointype & JT_LTORJ ){
+ for(j=i+1; j<pTabList->nSrc; j++){
+ SrcItem *pI2 = &pTabList->a[j];
+ if( pI2->fg.jointype & JT_RIGHT ){
+ if( pI2->fg.jointype & JT_LEFT ){
+ TREETRACE(0x1000,pParse,p,
+ ("FULL-JOIN simplifies to LEFT-JOIN on term %d\n",j));
+ pI2->fg.jointype &= ~JT_RIGHT;
+ }else{
+ TREETRACE(0x1000,pParse,p,
+ ("RIGHT-JOIN simplifies to JOIN on term %d\n",j));
+ pI2->fg.jointype &= ~(JT_RIGHT|JT_OUTER);
+ unsetJoinExpr(p->pWhere, pI2->iCursor, 1);
+ }
+ }
+ }
+ for(j=pTabList->nSrc-1; j>=0; j--){
+ pTabList->a[j].fg.jointype &= ~JT_LTORJ;
+ if( pTabList->a[j].fg.jointype & JT_RIGHT ) break;
+ }
+ }
}
- /* No futher action if this term of the FROM clause is no a subquery */
+ /* No further action if this term of the FROM clause is not a subquery */
if( pSub==0 ) continue;
/* Catch mismatch in the declared columns of a view and the number of
@@ -145523,6 +151461,14 @@ SQLITE_PRIVATE int wx_sqlite3Select(
goto select_end;
}
+ /* Do not attempt the usual optimizations (flattening and ORDER BY
+ ** elimination) on a MATERIALIZED common table expression because
+ ** a MATERIALIZED common table expression is an optimization fence.
+ */
+ if( pItem->fg.isCte && pItem->u2.pCteUse->eM10d==M10d_Yes ){
+ continue;
+ }
+
/* Do not try to flatten an aggregate subquery.
**
** Flattening an aggregate subquery is only possible if the outer query
@@ -145533,7 +151479,8 @@ SQLITE_PRIVATE int wx_sqlite3Select(
if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
assert( pSub->pGroupBy==0 );
- /* If a FROM-clause subquery has an ORDER BY clause that is not
+ /* tag-select-0230:
+ ** If a FROM-clause subquery has an ORDER BY clause that is not
** really doing anything, then delete it now so that it does not
** interfere with query flattening. See the discussion at
** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a
@@ -145552,19 +151499,23 @@ SQLITE_PRIVATE int wx_sqlite3Select(
** (a) The outer query has a different ORDER BY clause
** (b) The subquery is part of a join
** See forum post 062d576715d277c8
+ ** (6) The subquery is not a recursive CTE. ORDER BY has a different
+ ** meaning for recursive CTEs and this optimization does not
+ ** apply.
+ **
+ ** Also retain the ORDER BY if the OmitOrderBy optimization is disabled.
*/
if( pSub->pOrderBy!=0
&& (p->pOrderBy!=0 || pTabList->nSrc>1) /* Condition (5) */
&& pSub->pLimit==0 /* Condition (1) */
- && (pSub->selFlags & SF_OrderByReqd)==0 /* Condition (2) */
+ && (pSub->selFlags & (SF_OrderByReqd|SF_Recursive))==0 /* (2) and (6) */
&& (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */
&& OptimizationEnabled(db, SQLITE_OmitOrderBy)
){
TREETRACE(0x800,pParse,p,
("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1));
- wx_sqlite3ParserAddCleanup(pParse,
- (void(*)(wx_sqlite3*,void*))wx_sqlite3ExprListDelete,
- pSub->pOrderBy);
+ wx_sqlite3ParserAddCleanup(pParse, wx_sqlite3ExprListDeleteGeneric,
+ pSub->pOrderBy);
pSub->pOrderBy = 0;
}
@@ -145595,6 +151546,7 @@ SQLITE_PRIVATE int wx_sqlite3Select(
continue;
}
+ /* tag-select-0240 */
if( flattenSubquery(pParse, p, i, isAgg) ){
if( pParse->nErr ) goto select_end;
/* This subquery can be absorbed into its parent. */
@@ -145610,7 +151562,7 @@ SQLITE_PRIVATE int wx_sqlite3Select(
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/* Handle compound SELECT statements using the separate multiSelect()
- ** procedure.
+ ** procedure. tag-select-0300
*/
if( p->pPrior ){
rc = multiSelect(pParse, p, pDest);
@@ -145626,9 +151578,9 @@ SQLITE_PRIVATE int wx_sqlite3Select(
#endif
/* Do the WHERE-clause constant propagation optimization if this is
- ** a join. No need to speed time on this operation for non-join queries
+ ** a join. No need to spend time on this operation for non-join queries
** as the equivalent optimization will be handled by query planner in
- ** wx_sqlite3WhereBegin().
+ ** wx_sqlite3WhereBegin(). tag-select-0330
*/
if( p->pWhere!=0
&& p->pWhere->op==TK_AND
@@ -145645,29 +151597,34 @@ SQLITE_PRIVATE int wx_sqlite3Select(
TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n"));
}
-#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
+ /* tag-select-0350 */
if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
&& countOfViewOptimization(pParse, p)
){
if( db->mallocFailed ) goto select_end;
pTabList = p->pSrc;
}
-#endif
- /* For each term in the FROM clause, do two things:
- ** (1) Authorized unreferenced tables
- ** (2) Generate code for all sub-queries
+ /* Loop over all terms in the FROM clause and do two things for each term:
+ **
+ ** (1) Authorize unreferenced tables
+ ** (2) Generate code for all sub-queries
+ **
+ ** tag-select-0400
*/
for(i=0; i<pTabList->nSrc; i++){
SrcItem *pItem = &pTabList->a[i];
SrcItem *pPrior;
SelectDest dest;
+ Subquery *pSubq;
Select *pSub;
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
const char *zSavedAuthContext;
#endif
- /* Issue SQLITE_READ authorizations with a fake column name for any
+ /* Authorized unreferenced tables. tag-select-0410
+ **
+ ** Issue SQLITE_READ authorizations with a fake column name for any
** tables that are referenced but from which no values are extracted.
** Examples of where these kinds of null SQLITE_READ authorizations
** would occur:
@@ -145684,17 +151641,28 @@ SQLITE_PRIVATE int wx_sqlite3Select(
** string for the fake column name seems safer.
*/
if( pItem->colUsed==0 && pItem->zName!=0 ){
- wx_sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
+ const char *zDb;
+ if( pItem->fg.fixedSchema ){
+ int iDb = wx_sqlite3SchemaToIndex(pParse->db, pItem->u4.pSchema);
+ zDb = db->aDb[iDb].zDbSName;
+ }else if( pItem->fg.isSubquery ){
+ zDb = 0;
+ }else{
+ zDb = pItem->u4.zDatabase;
+ }
+ wx_sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", zDb);
}
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/* Generate code for all sub-queries in the FROM clause
*/
- pSub = pItem->pSelect;
- if( pSub==0 ) continue;
+ if( pItem->fg.isSubquery==0 ) continue;
+ pSubq = pItem->u4.pSubq;
+ assert( pSubq!=0 );
+ pSub = pSubq->pSelect;
/* The code for a subquery should only be generated once. */
- assert( pItem->addrFillSub==0 );
+ if( pSubq->addrFillSub!=0 ) continue;
/* Increment Parse.nHeight by the height of the largest expression
** tree referred to by this, the parent select. The child select
@@ -145707,11 +151675,12 @@ SQLITE_PRIVATE int wx_sqlite3Select(
/* Make copies of constant WHERE-clause terms in the outer query down
** inside the subquery. This can help the subquery to run more efficiently.
+ ** This is the "predicate push-down optimization". tag-select-0420
*/
if( OptimizationEnabled(db, SQLITE_PushDown)
&& (pItem->fg.isCte==0
|| (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
- && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem)
+ && pushDownWhereTerms(pParse, pSub, p->pWhere, pTabList, i)
){
#if TREETRACE_ENABLED
if( wx_sqlite3TreeTrace & 0x4000 ){
@@ -145720,40 +151689,58 @@ SQLITE_PRIVATE int wx_sqlite3Select(
wx_sqlite3TreeViewSelect(0, p, 0);
}
#endif
- assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 );
+ assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 );
}else{
- TREETRACE(0x4000,pParse,p,("Push-down not possible\n"));
+ TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n"));
+ }
+
+ /* Convert unused result columns of the subquery into simple NULL
+ ** expressions, to avoid unneeded searching and computation.
+ ** tag-select-0440
+ */
+ if( OptimizationEnabled(db, SQLITE_NullUnusedCols)
+ && disableUnusedSubqueryResultColumns(pItem)
+ ){
+#if TREETRACE_ENABLED
+ if( wx_sqlite3TreeTrace & 0x4000 ){
+ TREETRACE(0x4000,pParse,p,
+ ("Change unused result columns to NULL for subquery %d:\n",
+ pSub->selId));
+ wx_sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
}
zSavedAuthContext = pParse->zAuthContext;
pParse->zAuthContext = pItem->zName;
- /* Generate code to implement the subquery
+ /* Generate byte-code to implement the subquery tag-select-0480
*/
if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){
/* Implement a co-routine that will return a single row of the result
- ** set on each invocation.
+ ** set on each invocation. tag-select-0482
*/
int addrTop = wx_sqlite3VdbeCurrentAddr(v)+1;
- pItem->regReturn = ++pParse->nMem;
- wx_sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
+ pSubq->regReturn = ++pParse->nMem;
+ wx_sqlite3VdbeAddOp3(v, OP_InitCoroutine, pSubq->regReturn, 0, addrTop);
VdbeComment((v, "%!S", pItem));
- pItem->addrFillSub = addrTop;
- wx_sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
+ pSubq->addrFillSub = addrTop;
+ wx_sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem));
wx_sqlite3Select(pParse, pSub, &dest);
- pItem->pTab->nRowLogEst = pSub->nSelectRow;
+ pItem->pSTab->nRowLogEst = pSub->nSelectRow;
pItem->fg.viaCoroutine = 1;
- pItem->regResult = dest.iSdst;
- wx_sqlite3VdbeEndCoroutine(v, pItem->regReturn);
+ pSubq->regResult = dest.iSdst;
+ wx_sqlite3VdbeEndCoroutine(v, pSubq->regReturn);
+ VdbeComment((v, "end %!S", pItem));
wx_sqlite3VdbeJumpHere(v, addrTop-1);
wx_sqlite3ClearTempRegCache(pParse);
}else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){
/* This is a CTE for which materialization code has already been
** generated. Invoke the subroutine to compute the materialization,
- ** the make the pItem->iCursor be a copy of the ephemerial table that
- ** holds the result of the materialization. */
+ ** then make the pItem->iCursor be a copy of the ephemeral table that
+ ** holds the result of the materialization. tag-select-0484 */
CteUse *pCteUse = pItem->u2.pCteUse;
wx_sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
if( pItem->iCursor!=pCteUse->iCur ){
@@ -145763,25 +151750,30 @@ SQLITE_PRIVATE int wx_sqlite3Select(
pSub->nSelectRow = pCteUse->nRowEst;
}else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){
/* This view has already been materialized by a prior entry in
- ** this same FROM clause. Reuse it. */
- if( pPrior->addrFillSub ){
- wx_sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
+ ** this same FROM clause. Reuse it. tag-select-0486 */
+ Subquery *pPriorSubq;
+ assert( pPrior->fg.isSubquery );
+ pPriorSubq = pPrior->u4.pSubq;
+ assert( pPriorSubq!=0 );
+ if( pPriorSubq->addrFillSub ){
+ wx_sqlite3VdbeAddOp2(v, OP_Gosub, pPriorSubq->regReturn,
+ pPriorSubq->addrFillSub);
}
wx_sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
- pSub->nSelectRow = pPrior->pSelect->nSelectRow;
+ pSub->nSelectRow = pPriorSubq->pSelect->nSelectRow;
}else{
/* Materialize the view. If the view is not correlated, generate a
** subroutine to do the materialization so that subsequent uses of
- ** the same view can reuse the materialization. */
+ ** the same view can reuse the materialization. tag-select-0488 */
int topAddr;
int onceAddr = 0;
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
int addrExplain;
#endif
- pItem->regReturn = ++pParse->nMem;
+ pSubq->regReturn = ++pParse->nMem;
topAddr = wx_sqlite3VdbeAddOp0(v, OP_Goto);
- pItem->addrFillSub = topAddr+1;
+ pSubq->addrFillSub = topAddr+1;
pItem->fg.isMaterialized = 1;
if( pItem->fg.isCorrelated==0 ){
/* If the subquery is not correlated and if we are not inside of
@@ -145796,17 +151788,17 @@ SQLITE_PRIVATE int wx_sqlite3Select(
ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem));
wx_sqlite3Select(pParse, pSub, &dest);
- pItem->pTab->nRowLogEst = pSub->nSelectRow;
+ pItem->pSTab->nRowLogEst = pSub->nSelectRow;
if( onceAddr ) wx_sqlite3VdbeJumpHere(v, onceAddr);
- wx_sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
+ wx_sqlite3VdbeAddOp2(v, OP_Return, pSubq->regReturn, topAddr+1);
VdbeComment((v, "end %!S", pItem));
wx_sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
wx_sqlite3VdbeJumpHere(v, topAddr);
wx_sqlite3ClearTempRegCache(pParse);
if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
CteUse *pCteUse = pItem->u2.pCteUse;
- pCteUse->addrM9e = pItem->addrFillSub;
- pCteUse->regRtn = pItem->regReturn;
+ pCteUse->addrM9e = pSubq->addrFillSub;
+ pCteUse->regRtn = pSubq->regReturn;
pCteUse->iCur = pItem->iCursor;
pCteUse->nRowEst = pSub->nSelectRow;
}
@@ -145832,7 +151824,9 @@ SQLITE_PRIVATE int wx_sqlite3Select(
}
#endif
- /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
+ /* tag-select-0500
+ **
+ ** If the query is DISTINCT with an ORDER BY but is not an aggregate, and
** if the select-list is the same as the ORDER BY list, then this query
** can be rewritten as a GROUP BY. In other words, this:
**
@@ -145849,12 +151843,18 @@ SQLITE_PRIVATE int wx_sqlite3Select(
*/
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
&& wx_sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
+ && OptimizationEnabled(db, SQLITE_GroupByOrder)
#ifndef SQLITE_OMIT_WINDOWFUNC
&& p->pWin==0
#endif
){
p->selFlags &= ~SF_Distinct;
pGroupBy = p->pGroupBy = wx_sqlite3ExprListDup(db, pEList, 0);
+ if( pGroupBy ){
+ for(i=0; i<pGroupBy->nExpr; i++){
+ pGroupBy->a[i].u.x.iOrderByCol = i+1;
+ }
+ }
p->selFlags |= SF_Aggregate;
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
** the sDistinct.isTnct is still set. Hence, isTnct represents the
@@ -145876,7 +151876,7 @@ SQLITE_PRIVATE int wx_sqlite3Select(
** If that is the case, then the OP_OpenEphemeral instruction will be
** changed to an OP_Noop once we figure out that the sorting index is
** not needed. The sSort.addrSortIndex variable is used to facilitate
- ** that change.
+ ** that change. tag-select-0600
*/
if( sSort.pOrderBy ){
KeyInfo *pKeyInfo;
@@ -145893,6 +151893,7 @@ SQLITE_PRIVATE int wx_sqlite3Select(
}
/* If the output is destined for a temporary table, open that table.
+ ** tag-select-0630
*/
if( pDest->eDest==SRT_EphemTab ){
wx_sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr);
@@ -145910,7 +151911,7 @@ SQLITE_PRIVATE int wx_sqlite3Select(
}
}
- /* Set the limiter.
+ /* Set the limiter. tag-select-0650
*/
iEnd = wx_sqlite3VdbeMakeLabel(pParse);
if( (p->selFlags & SF_FixedLimit)==0 ){
@@ -145922,7 +151923,7 @@ SQLITE_PRIVATE int wx_sqlite3Select(
sSort.sortFlags |= SORTFLAG_UseSorter;
}
- /* Open an ephemeral index to use for the distinct set.
+ /* Open an ephemeral index to use for the distinct set. tag-select-0680
*/
if( p->selFlags & SF_Distinct ){
sDistinct.tabTnct = pParse->nTab++;
@@ -145937,7 +151938,7 @@ SQLITE_PRIVATE int wx_sqlite3Select(
}
if( !isAgg && pGroupBy==0 ){
- /* No aggregate functions and no GROUP BY clause */
+ /* No aggregate functions and no GROUP BY clause. tag-select-0700 */
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
| (p->selFlags & SF_FixedLimit);
#ifndef SQLITE_OMIT_WINDOWFUNC
@@ -146010,8 +152011,8 @@ SQLITE_PRIVATE int wx_sqlite3Select(
wx_sqlite3WhereEnd(pWInfo);
}
}else{
- /* This case when there exist aggregate functions or a GROUP BY clause
- ** or both */
+ /* This case is for when there exist aggregate functions or a GROUP BY
+ ** clause or both. tag-select-0800 */
NameContext sNC; /* Name context for processing aggregate information */
int iAMem; /* First Mem address for storing current GROUP BY */
int iBMem; /* First Mem address for previous GROUP BY */
@@ -146079,8 +152080,7 @@ SQLITE_PRIVATE int wx_sqlite3Select(
*/
pAggInfo = wx_sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
if( pAggInfo ){
- wx_sqlite3ParserAddCleanup(pParse,
- (void(*)(wx_sqlite3*,void*))agginfoFree, pAggInfo);
+ wx_sqlite3ParserAddCleanup(pParse, agginfoFree, pAggInfo);
testcase( pParse->earlyCleanup );
}
if( db->mallocFailed ){
@@ -146131,11 +152131,11 @@ SQLITE_PRIVATE int wx_sqlite3Select(
/* Processing for aggregates with GROUP BY is very different and
- ** much more complex than aggregates without a GROUP BY.
+ ** much more complex than aggregates without a GROUP BY. tag-select-0810
*/
if( pGroupBy ){
KeyInfo *pKeyInfo; /* Keying information for the group by clause */
- int addr1; /* A-vs-B comparision jump */
+ int addr1; /* A-vs-B comparison jump */
int addrOutputRow; /* Start of subroutine that outputs a result row */
int regOutputRow; /* Return address register for output subroutine */
int addrSetAbort; /* Set the abort flag and return */
@@ -146226,9 +152226,13 @@ SQLITE_PRIVATE int wx_sqlite3Select(
int nCol;
int nGroupBy;
- explainTempTable(pParse,
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExp; /* Address of OP_Explain instruction */
+#endif
+ ExplainQueryPlan2(addrExp, (pParse, 0, "USE TEMP B-TREE FOR %s",
(sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ?
- "DISTINCT" : "GROUP BY");
+ "DISTINCT" : "GROUP BY"
+ ));
groupBySort = 1;
nGroupBy = pGroupBy->nExpr;
@@ -146253,18 +152257,23 @@ SQLITE_PRIVATE int wx_sqlite3Select(
}
pAggInfo->directMode = 0;
regRecord = wx_sqlite3GetTempReg(pParse);
+ wx_sqlite3VdbeScanStatusCounters(v, addrExp, 0, wx_sqlite3VdbeCurrentAddr(v));
wx_sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
wx_sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
+ wx_sqlite3VdbeScanStatusRange(v, addrExp, wx_sqlite3VdbeCurrentAddr(v)-2, -1);
wx_sqlite3ReleaseTempReg(pParse, regRecord);
wx_sqlite3ReleaseTempRange(pParse, regBase, nCol);
TREETRACE(0x2,pParse,p,("WhereEnd\n"));
wx_sqlite3WhereEnd(pWInfo);
pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
sortOut = wx_sqlite3GetTempReg(pParse);
+ wx_sqlite3VdbeScanStatusCounters(v, addrExp, wx_sqlite3VdbeCurrentAddr(v), 0);
wx_sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
wx_sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
pAggInfo->useSortingIdx = 1;
+ wx_sqlite3VdbeScanStatusRange(v, addrExp, -1, sortPTab);
+ wx_sqlite3VdbeScanStatusRange(v, addrExp, -1, pAggInfo->sortingIdx);
}
/* If there are entries in pAgggInfo->aFunc[] that contain subexpressions
@@ -146309,12 +152318,25 @@ SQLITE_PRIVATE int wx_sqlite3Select(
sortOut, sortPTab);
}
for(j=0; j<pGroupBy->nExpr; j++){
+ int iOrderByCol = pGroupBy->a[j].u.x.iOrderByCol;
+
if( groupBySort ){
wx_sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
}else{
pAggInfo->directMode = 1;
wx_sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
}
+
+ if( iOrderByCol ){
+ Expr *pX = p->pEList->a[iOrderByCol-1].pExpr;
+ Expr *pBase = wx_sqlite3ExprSkipCollateAndLikely(pX);
+ if( ALWAYS(pBase!=0)
+ && pBase->op!=TK_AGG_COLUMN
+ && pBase->op!=TK_REGISTER
+ ){
+ wx_sqlite3ExprToRegister(pX, iAMem+j);
+ }
+ }
}
wx_sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr,
(char*)wx_sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
@@ -146330,9 +152352,9 @@ SQLITE_PRIVATE int wx_sqlite3Select(
** and resets the aggregate accumulator registers in preparation
** for the next GROUP BY batch.
*/
- wx_sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr);
wx_sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow);
VdbeComment((v, "output one row"));
+ wx_sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr);
wx_sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd); VdbeCoverage(v);
VdbeComment((v, "check abort flag"));
wx_sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
@@ -146406,9 +152428,12 @@ SQLITE_PRIVATE int wx_sqlite3Select(
}
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
else {
+ /* Aggregate functions without GROUP BY. tag-select-0820 */
Table *pTab;
if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
- /* If isSimpleCount() returns a pointer to a Table structure, then
+ /* tag-select-0821
+ **
+ ** If isSimpleCount() returns a pointer to a Table structure, then
** the SQL statement is of the form:
**
** SELECT count(*) FROM <tbl>
@@ -146467,6 +152492,8 @@ SQLITE_PRIVATE int wx_sqlite3Select(
wx_sqlite3VdbeAddOp1(v, OP_Close, iCsr);
explainSimpleCount(pParse, pTab, pBest);
}else{
+ /* The general case of an aggregate query without GROUP BY
+ ** tag-select-0822 */
int regAcc = 0; /* "populate accumulators" flag */
ExprList *pDistinct = 0;
u16 distFlag = 0;
@@ -146555,7 +152582,7 @@ SQLITE_PRIVATE int wx_sqlite3Select(
}
/* If there is an ORDER BY clause, then we need to sort the results
- ** and send them to the callback one by one.
+ ** and send them to the callback one by one. tag-select-0900
*/
if( sSort.pOrderBy ){
assert( p->pEList==pEList );
@@ -146578,7 +152605,14 @@ select_end:
assert( db->mallocFailed==0 || pParse->nErr!=0 );
wx_sqlite3ExprListDelete(db, pMinMaxOrderBy);
#ifdef SQLITE_DEBUG
+ /* Internal self-checks. tag-select-1000 */
if( pAggInfo && !db->mallocFailed ){
+#if TREETRACE_ENABLED
+ if( wx_sqlite3TreeTrace & 0x20 ){
+ TREETRACE(0x20,pParse,p,("Finished with AggInfo\n"));
+ printAggInfo(pAggInfo);
+ }
+#endif
for(i=0; i<pAggInfo->nColumn; i++){
Expr *pExpr = pAggInfo->aCol[i].pCExpr;
if( pExpr==0 ) continue;
@@ -146961,8 +152995,10 @@ SQLITE_PRIVATE void wx_sqlite3BeginTrigger(
** name on pTableName if we are reparsing out of the schema table
*/
if( db->init.busy && iDb!=1 ){
- wx_sqlite3DbFree(db, pTableName->a[0].zDatabase);
- pTableName->a[0].zDatabase = 0;
+ assert( pTableName->a[0].fg.fixedSchema==0 );
+ assert( pTableName->a[0].fg.isSubquery==0 );
+ wx_sqlite3DbFree(db, pTableName->a[0].u4.zDatabase);
+ pTableName->a[0].u4.zDatabase = 0;
}
/* If the trigger name was unqualified, and the table is a temp table,
@@ -146992,6 +153028,10 @@ SQLITE_PRIVATE void wx_sqlite3BeginTrigger(
wx_sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
goto trigger_orphan_error;
}
+ if( (pTab->tabFlags & TF_Shadow)!=0 && wx_sqlite3ReadOnlyShadowTables(db) ){
+ wx_sqlite3ErrorMsg(pParse, "cannot create triggers on shadow tables");
+ goto trigger_orphan_error;
+ }
/* Check that the trigger name is not reserved and that no trigger of the
** specified name exists */
@@ -147436,7 +153476,8 @@ SQLITE_PRIVATE void wx_sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noE
}
assert( pName->nSrc==1 );
- zDb = pName->a[0].zDatabase;
+ assert( pName->a[0].fg.fixedSchema==0 && pName->a[0].fg.isSubquery==0 );
+ zDb = pName->a[0].u4.zDatabase;
zName = pName->a[0].zName;
assert( zDb!=0 || wx_sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
@@ -147673,7 +153714,9 @@ SQLITE_PRIVATE SrcList *wx_sqlite3TriggerStepSrc(
Schema *pSchema = pStep->pTrig->pSchema;
pSrc->a[0].zName = zName;
if( pSchema!=db->aDb[1].pSchema ){
- pSrc->a[0].pSchema = pSchema;
+ assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 );
+ pSrc->a[0].u4.pSchema = pSchema;
+ pSrc->a[0].fg.fixedSchema = 1;
}
if( pStep->pFrom ){
SrcList *pDup = wx_sqlite3SrcListDup(db, pStep->pFrom, 0);
@@ -147756,6 +153799,72 @@ static ExprList *wx_sqlite3ExpandReturning(
return pNew;
}
+/* If the Expr node is a subquery or an EXISTS operator or an IN operator that
+** uses a subquery, and if the subquery is SF_Correlated, then mark the
+** expression as EP_VarSelect.
+*/
+static int wx_sqlite3ReturningSubqueryVarSelect(Walker *NotUsed, Expr *pExpr){
+ UNUSED_PARAMETER(NotUsed);
+ if( ExprUseXSelect(pExpr)
+ && (pExpr->x.pSelect->selFlags & SF_Correlated)!=0
+ ){
+ testcase( ExprHasProperty(pExpr, EP_VarSelect) );
+ ExprSetProperty(pExpr, EP_VarSelect);
+ }
+ return WRC_Continue;
+}
+
+
+/*
+** If the SELECT references the table pWalker->u.pTab, then do two things:
+**
+** (1) Mark the SELECT as as SF_Correlated.
+** (2) Set pWalker->eCode to non-zero so that the caller will know
+** that (1) has happened.
+*/
+static int wx_sqlite3ReturningSubqueryCorrelated(Walker *pWalker, Select *pSelect){
+ int i;
+ SrcList *pSrc;
+ assert( pSelect!=0 );
+ pSrc = pSelect->pSrc;
+ assert( pSrc!=0 );
+ for(i=0; i<pSrc->nSrc; i++){
+ if( pSrc->a[i].pSTab==pWalker->u.pTab ){
+ testcase( pSelect->selFlags & SF_Correlated );
+ pSelect->selFlags |= SF_Correlated;
+ pWalker->eCode = 1;
+ break;
+ }
+ }
+ return WRC_Continue;
+}
+
+/*
+** Scan the expression list that is the argument to RETURNING looking
+** for subqueries that depend on the table which is being modified in the
+** statement that is hosting the RETURNING clause (pTab). Mark all such
+** subqueries as SF_Correlated. If the subqueries are part of an
+** expression, mark the expression as EP_VarSelect.
+**
+** https://sqlite.org/forum/forumpost/2c83569ce8945d39
+*/
+static void wx_sqlite3ProcessReturningSubqueries(
+ ExprList *pEList,
+ Table *pTab
+){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = wx_sqlite3ExprWalkNoop;
+ w.xSelectCallback = wx_sqlite3ReturningSubqueryCorrelated;
+ w.u.pTab = pTab;
+ wx_sqlite3WalkExprList(&w, pEList);
+ if( w.eCode ){
+ w.xExprCallback = wx_sqlite3ReturningSubqueryVarSelect;
+ w.xSelectCallback = wx_sqlite3SelectWalkNoop;
+ wx_sqlite3WalkExprList(&w, pEList);
+ }
+}
+
/*
** Generate code for the RETURNING trigger. Unlike other triggers
** that invoke a subprogram in the bytecode, the code for RETURNING
@@ -147775,16 +153884,24 @@ static void codeReturningTrigger(
SrcList sFrom;
assert( v!=0 );
- assert( pParse->bReturning );
+ if( !pParse->bReturning ){
+ /* This RETURNING trigger must be for a different statement as
+ ** this statement lacks a RETURNING clause. */
+ return;
+ }
assert( db->pParse==pParse );
pReturning = pParse->u1.pReturning;
- assert( pTrigger == &(pReturning->retTrig) );
+ if( pTrigger != &(pReturning->retTrig) ){
+ /* This RETURNING trigger is for a different statement */
+ return;
+ }
memset(&sSelect, 0, sizeof(sSelect));
memset(&sFrom, 0, sizeof(sFrom));
sSelect.pEList = wx_sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
sSelect.pSrc = &sFrom;
sFrom.nSrc = 1;
- sFrom.a[0].pTab = pTab;
+ sFrom.a[0].pSTab = pTab;
+ sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */
sFrom.a[0].iCursor = -1;
wx_sqlite3SelectPrep(pParse, &sSelect, 0);
if( pParse->nErr==0 ){
@@ -147811,6 +153928,7 @@ static void codeReturningTrigger(
int i;
int nCol = pNew->nExpr;
int reg = pParse->nMem+1;
+ wx_sqlite3ProcessReturningSubqueries(pNew, pTab);
pParse->nMem += nCol+2;
pReturning->iRetReg = reg;
for(i=0; i<nCol; i++){
@@ -148262,6 +154380,9 @@ SQLITE_PRIVATE u32 wx_sqlite3TriggerColmask(
Trigger *p;
assert( isNew==1 || isNew==0 );
+ if( IsView(pTab) ){
+ return 0xffffffff;
+ }
for(p=pTrigger; p; p=p->pNext){
if( p->op==op
&& (tr_tm&p->tr_tm)
@@ -148490,7 +154611,7 @@ static void updateFromSelect(
Expr *pLimit2 = 0;
ExprList *pOrderBy2 = 0;
wx_sqlite3 *db = pParse->db;
- Table *pTab = pTabList->a[0].pTab;
+ Table *pTab = pTabList->a[0].pSTab;
SrcList *pSrc;
Expr *pWhere2;
int eDest;
@@ -148512,10 +154633,10 @@ static void updateFromSelect(
assert( pTabList->nSrc>1 );
if( pSrc ){
- pSrc->a[0].fg.notCte = 1;
+ assert( pSrc->a[0].fg.notCte );
pSrc->a[0].iCursor = -1;
- pSrc->a[0].pTab->nTabRef--;
- pSrc->a[0].pTab = 0;
+ pSrc->a[0].pSTab->nTabRef--;
+ pSrc->a[0].pSTab = 0;
}
if( pPk ){
for(i=0; i<pPk->nKeyCol; i++){
@@ -148696,7 +154817,7 @@ SQLITE_PRIVATE void wx_sqlite3Update(
if( wx_sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
- if( wx_sqlite3IsReadOnly(pParse, pTab, tmask) ){
+ if( wx_sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto update_cleanup;
}
@@ -149029,7 +155150,7 @@ SQLITE_PRIVATE void wx_sqlite3Update(
&& !hasFK
&& !chngKey
&& !bReplace
- && (sNC.ncFlags & NC_Subquery)==0
+ && (pWhere==0 || !ExprHasProperty(pWhere, EP_Subquery))
){
flags |= WHERE_ONEPASS_MULTIROW;
}
@@ -149101,6 +155222,8 @@ SQLITE_PRIVATE void wx_sqlite3Update(
if( !isView ){
int addrOnce = 0;
+ int iNotUsed1 = 0;
+ int iNotUsed2 = 0;
/* Open every index that needs updating. */
if( eOnePass!=ONEPASS_OFF ){
@@ -149112,7 +155235,7 @@ SQLITE_PRIVATE void wx_sqlite3Update(
addrOnce = wx_sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
wx_sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur,
- aToOpen, 0, 0);
+ aToOpen, &iNotUsed1, &iNotUsed2);
if( addrOnce ){
wx_sqlite3VdbeJumpHereOrPopInst(v, addrOnce);
}
@@ -149207,6 +155330,9 @@ SQLITE_PRIVATE void wx_sqlite3Update(
}
}
if( chngRowid==0 && pPk==0 ){
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ if( isView ) wx_sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
+#endif
wx_sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
}
}
@@ -149403,8 +155529,10 @@ SQLITE_PRIVATE void wx_sqlite3Update(
wx_sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
- wx_sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
- TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue);
+ if( pTrigger ){
+ wx_sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
+ TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue);
+ }
/* Repeat the above with the next record to be updated, until
** all record selected by the WHERE clause have been updated.
@@ -149499,7 +155627,7 @@ static void updateVirtualTable(
int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */
int regArg; /* First register in VUpdate arg array */
int regRec; /* Register in which to assemble record */
- int regRowid; /* Register for ephem table rowid */
+ int regRowid; /* Register for ephemeral table rowid */
int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */
int aDummy[2]; /* Unused arg for wx_sqlite3WhereOkOnePass() */
int eOnePass; /* True to use onepass strategy */
@@ -149543,7 +155671,9 @@ static void updateVirtualTable(
wx_sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0)
);
}else{
- pList = wx_sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
+ Expr *pRowExpr = exprRowColumn(pParse, i);
+ if( pRowExpr ) pRowExpr->op2 = OPFLAG_NOCHNG;
+ pList = wx_sqlite3ExprListAppend(pParse, pList, pRowExpr);
}
}
@@ -149620,7 +155750,7 @@ static void updateVirtualTable(
wx_sqlite3WhereEnd(pWInfo);
}
- /* Begin scannning through the ephemeral table. */
+ /* Begin scanning through the ephemeral table. */
addr = wx_sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v);
/* Extract arguments from the current row of the ephemeral table and
@@ -149740,7 +155870,8 @@ SQLITE_PRIVATE Upsert *wx_sqlite3UpsertNew(
SQLITE_PRIVATE int wx_sqlite3UpsertAnalyzeTarget(
Parse *pParse, /* The parsing context */
SrcList *pTabList, /* Table into which we are inserting */
- Upsert *pUpsert /* The ON CONFLICT clauses */
+ Upsert *pUpsert, /* The ON CONFLICT clauses */
+ Upsert *pAll /* Complete list of all ON CONFLICT clauses */
){
Table *pTab; /* That table into which we are inserting */
int rc; /* Result code */
@@ -149753,7 +155884,7 @@ SQLITE_PRIVATE int wx_sqlite3UpsertAnalyzeTarget(
int nClause = 0; /* Counter of ON CONFLICT clauses */
assert( pTabList->nSrc==1 );
- assert( pTabList->a[0].pTab!=0 );
+ assert( pTabList->a[0].pSTab!=0 );
assert( pUpsert!=0 );
assert( pUpsert->pUpsertTarget!=0 );
@@ -149772,7 +155903,7 @@ SQLITE_PRIVATE int wx_sqlite3UpsertAnalyzeTarget(
if( rc ) return rc;
/* Check to see if the conflict target matches the rowid. */
- pTab = pTabList->a[0].pTab;
+ pTab = pTabList->a[0].pSTab;
pTarget = pUpsert->pUpsertTarget;
iCursor = pTabList->a[0].iCursor;
if( HasRowid(pTab)
@@ -149828,7 +155959,7 @@ SQLITE_PRIVATE int wx_sqlite3UpsertAnalyzeTarget(
pExpr = &sCol[0];
}
for(jj=0; jj<nn; jj++){
- if( wx_sqlite3ExprCompare(pParse,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
+ if( wx_sqlite3ExprCompare(0,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
break; /* Column ii of the index matches column jj of target */
}
}
@@ -149843,6 +155974,14 @@ SQLITE_PRIVATE int wx_sqlite3UpsertAnalyzeTarget(
continue;
}
pUpsert->pUpsertIdx = pIdx;
+ if( wx_sqlite3UpsertOfIndex(pAll,pIdx)!=pUpsert ){
+ /* Really this should be an error. The isDup ON CONFLICT clause will
+ ** never fire. But this problem was not discovered until three years
+ ** after multi-CONFLICT upsert was added, and so we silently ignore
+ ** the problem to prevent breaking applications that might actually
+ ** have redundant ON CONFLICT clauses. */
+ pUpsert->isDup = 1;
+ }
break;
}
if( pUpsert->pUpsertIdx==0 ){
@@ -149869,9 +156008,13 @@ SQLITE_PRIVATE int wx_sqlite3UpsertNextIsIPK(Upsert *pUpsert){
Upsert *pNext;
if( NEVER(pUpsert==0) ) return 0;
pNext = pUpsert->pNextUpsert;
- if( pNext==0 ) return 1;
- if( pNext->pUpsertTarget==0 ) return 1;
- if( pNext->pUpsertIdx==0 ) return 1;
+ while( 1 /*exit-by-return*/ ){
+ if( pNext==0 ) return 1;
+ if( pNext->pUpsertTarget==0 ) return 1;
+ if( pNext->pUpsertIdx==0 ) return 1;
+ if( !pNext->isDup ) return 0;
+ pNext = pNext->pNextUpsert;
+ }
return 0;
}
@@ -150131,6 +156274,9 @@ SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3RunVacuum(
const char *zDbMain; /* Schema name of database to vacuum */
const char *zOut; /* Name of output file */
u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
+ u64 iRandom; /* Random value used for zDbVacuum[] */
+ char zDbVacuum[42]; /* Name of the ATTACH-ed database used for vacuum */
+
if( !db->autoCommit ){
wx_sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -150171,27 +156317,29 @@ SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3RunVacuum(
pMain = db->aDb[iDb].pBt;
isMemDb = wx_sqlite3PagerIsMemdb(wx_sqlite3BtreePager(pMain));
- /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
+ /* Attach the temporary database as 'vacuum_XXXXXX'. The synchronous pragma
** can be set to 'off' for this file, as it is not recovered if a crash
** occurs anyway. The integrity of the database is maintained by a
** (possibly synchronous) transaction opened on the main database before
** wx_sqlite3BtreeCopyFile() is called.
**
- ** An optimisation would be to use a non-journaled pager.
- ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
+ ** An optimization would be to use a non-journaled pager.
+ ** (Later:) I tried setting "PRAGMA vacuum_XXXXXX.journal_mode=OFF" but
** that actually made the VACUUM run slower. Very little journalling
** actually occurs when doing a vacuum since the vacuum_db is initially
** empty. Only the journal header is written. Apparently it takes more
** time to parse and run the PRAGMA to turn journalling off than it does
** to write the journal header file.
*/
+ wx_sqlite3_randomness(sizeof(iRandom),&iRandom);
+ wx_sqlite3_snprintf(sizeof(zDbVacuum), zDbVacuum, "vacuum_%016llx", iRandom);
nDb = db->nDb;
- rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut);
+ rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS %s", zOut, zDbVacuum);
db->openFlags = saved_openFlags;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
assert( (db->nDb-1)==nDb );
pDb = &db->aDb[nDb];
- assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
+ assert( strcmp(pDb->zDbSName,zDbVacuum)==0 );
pTemp = pDb->pBt;
if( pOut ){
wx_sqlite3_file *id = wx_sqlite3PagerFile(wx_sqlite3BtreePager(pTemp));
@@ -150210,6 +156358,15 @@ SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3RunVacuum(
}
nRes = wx_sqlite3BtreeGetRequestedReserve(pMain);
+ /* A VACUUM cannot change the pagesize of an encrypted database. */
+ if( db->nextPagesize ){
+ extern void wx_sqlite3mcCodecGetKey(wx_sqlite3*, int, void**, int*);
+ int nKey;
+ char *zKey;
+ wx_sqlite3mcCodecGetKey(db, iDb, (void**)&zKey, &nKey);
+ if( nKey ) db->nextPagesize = 0;
+ }
+
wx_sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
wx_sqlite3BtreeSetSpillSize(pTemp, wx_sqlite3BtreeSetSpillSize(pMain,0));
wx_sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL);
@@ -150268,11 +156425,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3RunVacuum(
** the contents to the temporary database.
*/
rc = execSqlF(db, pzErrMsg,
- "SELECT'INSERT INTO vacuum_db.'||quote(name)"
+ "SELECT'INSERT INTO %s.'||quote(name)"
"||' SELECT*FROM\"%w\".'||quote(name)"
- "FROM vacuum_db.sqlite_schema "
+ "FROM %s.sqlite_schema "
"WHERE type='table'AND coalesce(rootpage,1)>0",
- zDbMain
+ zDbVacuum, zDbMain, zDbVacuum
);
assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
db->mDbFlags &= ~DBFLAG_Vacuum;
@@ -150284,11 +156441,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3RunVacuum(
** from the schema table.
*/
rc = execSqlF(db, pzErrMsg,
- "INSERT INTO vacuum_db.sqlite_schema"
+ "INSERT INTO %s.sqlite_schema"
" SELECT*FROM \"%w\".sqlite_schema"
" WHERE type IN('view','trigger')"
" OR(type='table'AND rootpage=0)",
- zDbMain
+ zDbVacuum, zDbMain
);
if( rc ) goto end_of_vacuum;
@@ -150700,7 +156857,6 @@ SQLITE_PRIVATE void wx_sqlite3VtabUnlockList(wx_sqlite3 *db){
if( p ){
db->pDisconnect = 0;
- wx_sqlite3ExpirePreparedStatements(db, 0);
do {
VTable *pNext = p->pNext;
wx_sqlite3VtabUnlock(p);
@@ -150866,7 +157022,7 @@ SQLITE_PRIVATE void wx_sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
** the information we've collected.
**
** The VM register number pParse->regRowid holds the rowid of an
- ** entry in the sqlite_schema table tht was created for this vtab
+ ** entry in the sqlite_schema table that was created for this vtab
** by wx_sqlite3StartTable().
*/
iDb = wx_sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -150997,6 +157153,8 @@ static int vtabCallConstructor(
db->pVtabCtx = &sCtx;
pTab->nTabRef++;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
+ assert( pTab!=0 );
+ assert( pTab->nTabRef>1 || rc!=SQLITE_OK );
wx_sqlite3DeleteTable(db, pTab);
db->pVtabCtx = sCtx.pPrior;
if( rc==SQLITE_NOMEM ) wx_sqlite3OomFault(db);
@@ -151019,7 +157177,7 @@ static int vtabCallConstructor(
pVTable->nRef = 1;
if( sCtx.bDeclared==0 ){
const char *zFormat = "vtable constructor did not declare schema: %s";
- *pzErr = wx_sqlite3MPrintf(db, zFormat, pTab->zName);
+ *pzErr = wx_sqlite3MPrintf(db, zFormat, zModuleName);
wx_sqlite3VtabUnlock(pVTable);
rc = SQLITE_ERROR;
}else{
@@ -151197,19 +157355,38 @@ SQLITE_API int wx_sqlite3_declare_vtab(wx_sqlite3 *db, const char *zCreateTable)
Table *pTab;
Parse sParse;
int initBusy;
+ int i;
+ const unsigned char *z;
+ static const u8 aKeyword[] = { TK_CREATE, TK_TABLE, 0 };
#ifdef SQLITE_ENABLE_API_ARMOR
if( !wx_sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
+
+ /* Verify that the first two keywords in the CREATE TABLE statement
+ ** really are "CREATE" and "TABLE". If this is not the case, then
+ ** wx_sqlite3_declare_vtab() is being misused.
+ */
+ z = (const unsigned char*)zCreateTable;
+ for(i=0; aKeyword[i]; i++){
+ int tokenType = 0;
+ do{ z += wx_sqlite3GetToken(z, &tokenType); }while( tokenType==TK_SPACE );
+ if( tokenType!=aKeyword[i] ){
+ wx_sqlite3ErrorWithMsg(db, SQLITE_ERROR, "syntax error");
+ return SQLITE_ERROR;
+ }
+ }
+
wx_sqlite3_mutex_enter(db->mutex);
pCtx = db->pVtabCtx;
if( !pCtx || pCtx->bDeclared ){
- wx_sqlite3Error(db, SQLITE_MISUSE);
+ wx_sqlite3Error(db, SQLITE_MISUSE_BKPT);
wx_sqlite3_mutex_leave(db->mutex);
return SQLITE_MISUSE_BKPT;
}
+
pTab = pCtx->pTab;
assert( IsVirtual(pTab) );
@@ -151223,16 +157400,16 @@ SQLITE_API int wx_sqlite3_declare_vtab(wx_sqlite3 *db, const char *zCreateTable)
initBusy = db->init.busy;
db->init.busy = 0;
sParse.nQueryLoop = 1;
- if( SQLITE_OK==wx_sqlite3RunParser(&sParse, zCreateTable)
- && ALWAYS(sParse.pNewTable!=0)
- && ALWAYS(!db->mallocFailed)
- && IsOrdinaryTable(sParse.pNewTable)
- ){
+ if( SQLITE_OK==wx_sqlite3RunParser(&sParse, zCreateTable) ){
+ assert( sParse.pNewTable!=0 );
+ assert( !db->mallocFailed );
+ assert( IsOrdinaryTable(sParse.pNewTable) );
assert( sParse.zErrMsg==0 );
if( !pTab->aCol ){
Table *pNew = sParse.pNewTable;
Index *pIdx;
pTab->aCol = pNew->aCol;
+ assert( IsOrdinaryTable(pNew) );
wx_sqlite3ExprListDelete(db, pNew->u.tab.pDfltList);
pTab->nNVCol = pTab->nCol = pNew->nCol;
pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
@@ -151487,7 +157664,10 @@ SQLITE_PRIVATE int wx_sqlite3VtabSavepoint(wx_sqlite3 *db, int op, int iSavepoin
break;
}
if( xMethod && pVTab->iSavepoint>iSavepoint ){
+ u64 savedFlags = (db->flags & SQLITE_Defensive);
+ db->flags &= ~(u64)SQLITE_Defensive;
rc = xMethod(pVTab->pVtab, iSavepoint);
+ db->flags |= savedFlags;
}
wx_sqlite3VtabUnlock(pVTab);
}
@@ -151607,7 +157787,7 @@ SQLITE_PRIVATE void wx_sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
**
** An eponymous virtual table instance is one that is named after its
** module, and more importantly, does not require a CREATE VIRTUAL TABLE
-** statement in order to come into existance. Eponymous virtual table
+** statement in order to come into existence. Eponymous virtual table
** instances always exist. They cannot be DROP-ed.
**
** Any virtual table module for which xConnect and xCreate are the same
@@ -151716,6 +157896,10 @@ SQLITE_API int wx_sqlite3_vtab_config(wx_sqlite3 *db, int op, ...){
p->pVTable->eVtabRisk = SQLITE_VTABRISK_High;
break;
}
+ case SQLITE_VTAB_USES_ALL_SCHEMAS: {
+ p->pVTable->bAllSchemas = 1;
+ break;
+ }
default: {
rc = SQLITE_MISUSE_BKPT;
break;
@@ -151794,7 +157978,7 @@ typedef struct WhereRightJoin WhereRightJoin;
/*
** This object is a header on a block of allocated memory that will be
-** automatically freed when its WInfo oject is destructed.
+** automatically freed when its WInfo object is destructed.
*/
struct WhereMemBlock {
WhereMemBlock *pNext; /* Next block in the chain */
@@ -151855,7 +158039,7 @@ struct WhereLevel {
int iCur; /* The VDBE cursor used by this IN operator */
int addrInTop; /* Top of the IN loop */
int iBase; /* Base register of multi-key index record */
- int nPrefix; /* Number of prior entires in the key */
+ int nPrefix; /* Number of prior entries in the key */
u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */
} *aInLoop; /* Information about each nested IN operator */
} in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */
@@ -151900,11 +158084,13 @@ struct WhereLoop {
u16 nTop; /* Size of TOP vector */
u16 nDistinctCol; /* Index columns used to sort for DISTINCT */
Index *pIndex; /* Index used, or NULL */
+ ExprList *pOrderBy; /* ORDER BY clause if this is really a subquery */
} btree;
struct { /* Information for virtual tables */
int idxNum; /* Index number */
u32 needFree : 1; /* True if wx_sqlite3_free(idxStr) is needed */
u32 bOmitOffset : 1; /* True to let virtual table handle offset */
+ u32 bIdxNumHex : 1; /* Show idxNum as hex in EXPLAIN QUERY PLAN */
i8 isOrdered; /* True if satisfies ORDER BY */
u16 omitMask; /* Terms that may be omitted */
char *idxStr; /* Index identifier string */
@@ -151917,6 +158103,8 @@ struct WhereLoop {
/**** whereLoopXfer() copies fields above ***********************/
# define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot)
u16 nLSlot; /* Number of slots allocated for aLTerm[] */
+ LogEst rStarDelta; /* Cost delta due to star-schema heuristic. Not
+ ** initialized unless pWInfo->nOutStarDelta>0 */
WhereTerm **aLTerm; /* WhereTerms used */
WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */
@@ -152105,7 +158293,7 @@ struct WhereClause {
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
int nBase; /* Number of terms through the last non-Virtual */
- WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
+ WhereTerm *a; /* Each a[] describes a term of the WHERE clause */
#if defined(SQLITE_SMALL_STACK)
WhereTerm aStatic[1]; /* Initial static space for a[] */
#else
@@ -152239,6 +158427,7 @@ struct WhereInfo {
unsigned untestedTerms :1; /* Not all WHERE terms resolved by outer loop */
unsigned bOrderedInnerLoop:1;/* True if only the inner-most loop is ordered */
unsigned sorted :1; /* True if really sorted (not just grouped) */
+ LogEst nOutStarDelta; /* Artifical nOut reduction for star-query */
LogEst nRowOut; /* Estimated number of output rows */
int iTop; /* The very beginning of the WHERE loop */
int iEndWhere; /* End of the WHERE clause itself */
@@ -152259,7 +158448,7 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereGetMask(WhereMaskSet*,int);
#ifdef WHERETRACE_ENABLED
SQLITE_PRIVATE void wx_sqlite3WhereClausePrint(WhereClause *pWC);
SQLITE_PRIVATE void wx_sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm);
-SQLITE_PRIVATE void wx_sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC);
+SQLITE_PRIVATE void wx_sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC);
#endif
SQLITE_PRIVATE WhereTerm *wx_sqlite3WhereFindTerm(
WhereClause *pWC, /* The WHERE clause to be searched */
@@ -152390,7 +158579,8 @@ SQLITE_PRIVATE void wx_sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
#define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */
#define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */
#define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */
-#define WHERE_VIEWSCAN 0x02000000 /* A full-scan of a VIEW or subquery */
+#define WHERE_COROUTINE 0x02000000 /* Implemented by co-routine.
+ ** NB: False-negatives are possible */
#define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */
#endif /* !defined(SQLITE_WHEREINT_H) */
@@ -152489,9 +158679,9 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
/*
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
-** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was
-** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
-** is added to the output to describe the table scan strategy in pLevel.
+** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG
+** was defined at compile-time. If it is not a no-op, a single OP_Explain
+** opcode is added to the output to describe the table scan strategy in pLevel.
**
** If an OP_Explain opcode is added to the VM, its address is returned.
** Otherwise, if no OP_Explain is coded, zero is returned.
@@ -152503,8 +158693,8 @@ SQLITE_PRIVATE int wx_sqlite3WhereExplainOneScan(
u16 wctrlFlags /* Flags passed to wx_sqlite3WhereBegin() */
){
int ret = 0;
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
- if( wx_sqlite3ParseToplevel(pParse)->explain==2 )
+#if !defined(SQLITE_DEBUG)
+ if( wx_sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
#endif
{
SrcItem *pItem = &pTabList->a[pLevel->iFrom];
@@ -152535,7 +158725,7 @@ SQLITE_PRIVATE int wx_sqlite3WhereExplainOneScan(
assert( pLoop->u.btree.pIndex!=0 );
pIdx = pLoop->u.btree.pIndex;
assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
- if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){
+ if( !HasRowid(pItem->pSTab) && IsPrimaryKeyIndex(pIdx) ){
if( isSearch ){
zFmt = "PRIMARY KEY";
}
@@ -152578,7 +158768,9 @@ SQLITE_PRIVATE int wx_sqlite3WhereExplainOneScan(
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
- wx_sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s",
+ wx_sqlite3_str_appendall(&str, " VIRTUAL TABLE INDEX ");
+ wx_sqlite3_str_appendf(&str,
+ pLoop->u.vtab.bIdxNumHex ? "0x%x:%s" : "%d:%s",
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
}
#endif
@@ -152596,7 +158788,8 @@ SQLITE_PRIVATE int wx_sqlite3WhereExplainOneScan(
zMsg = wx_sqlite3StrAccumFinish(&str);
wx_sqlite3ExplainBreakpoint("",zMsg);
ret = wx_sqlite3VdbeAddOp4(v, OP_Explain, wx_sqlite3VdbeCurrentAddr(v),
- pParse->addrExplain, 0, zMsg,P4_DYNAMIC);
+ pParse->addrExplain, pLoop->rRun,
+ zMsg, P4_DYNAMIC);
}
return ret;
}
@@ -152631,7 +158824,7 @@ SQLITE_PRIVATE int wx_sqlite3WhereExplainBloomFilter(
wx_sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem);
pLoop = pLevel->pWLoop;
if( pLoop->wsFlags & WHERE_IPK ){
- const Table *pTab = pItem->pTab;
+ const Table *pTab = pItem->pSTab;
if( pTab->iPKey>=0 ){
wx_sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName);
}else{
@@ -152670,27 +158863,37 @@ SQLITE_PRIVATE void wx_sqlite3WhereAddScanStatus(
WhereLevel *pLvl, /* Level to add scanstatus() entry for */
int addrExplain /* Address of OP_Explain (or 0) */
){
- const char *zObj = 0;
- WhereLoop *pLoop = pLvl->pWLoop;
- int wsFlags = pLoop->wsFlags;
- int viaCoroutine = 0;
+ if( IS_STMT_SCANSTATUS( wx_sqlite3VdbeDb(v) ) ){
+ const char *zObj = 0;
+ WhereLoop *pLoop = pLvl->pWLoop;
+ int wsFlags = pLoop->wsFlags;
+ int viaCoroutine = 0;
- if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
- zObj = pLoop->u.btree.pIndex->zName;
- }else{
- zObj = pSrclist->a[pLvl->iFrom].zName;
- viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine;
- }
- wx_sqlite3VdbeScanStatus(
- v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
- );
-
- if( viaCoroutine==0 ){
- if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){
- wx_sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur);
+ if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
+ zObj = pLoop->u.btree.pIndex->zName;
+ }else{
+ zObj = pSrclist->a[pLvl->iFrom].zName;
+ viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine;
}
- if( wsFlags & WHERE_INDEXED ){
- wx_sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
+ wx_sqlite3VdbeScanStatus(
+ v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
+ );
+
+ if( viaCoroutine==0 ){
+ if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){
+ wx_sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur);
+ }
+ if( wsFlags & WHERE_INDEXED ){
+ wx_sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
+ }
+ }else{
+ int addr;
+ assert( pSrclist->a[pLvl->iFrom].fg.isSubquery );
+ addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub;
+ VdbeOp *pOp = wx_sqlite3VdbeGetOp(v, addr-1);
+ assert( wx_sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
+ assert( wx_sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
+ wx_sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
}
}
}
@@ -152830,6 +159033,39 @@ static void updateRangeAffinityStr(
}
}
+/*
+** The pOrderBy->a[].u.x.iOrderByCol values might be incorrect because
+** columns might have been rearranged in the result set. This routine
+** fixes them up.
+**
+** pEList is the new result set. The pEList->a[].u.x.iOrderByCol values
+** contain the *old* locations of each expression. This is a temporary
+** use of u.x.iOrderByCol, not its intended use. The caller must reset
+** u.x.iOrderByCol back to zero for all entries in pEList before the
+** caller returns.
+**
+** This routine changes pOrderBy->a[].u.x.iOrderByCol values from
+** pEList->a[N].u.x.iOrderByCol into N+1. (The "+1" is because of the 1-based
+** indexing used by iOrderByCol.) Or if no match, iOrderByCol is set to zero.
+*/
+static void adjustOrderByCol(ExprList *pOrderBy, ExprList *pEList){
+ int i, j;
+ if( pOrderBy==0 ) return;
+ for(i=0; i<pOrderBy->nExpr; i++){
+ int t = pOrderBy->a[i].u.x.iOrderByCol;
+ if( t==0 ) continue;
+ for(j=0; j<pEList->nExpr; j++){
+ if( pEList->a[j].u.x.iOrderByCol==t ){
+ pOrderBy->a[i].u.x.iOrderByCol = j+1;
+ break;
+ }
+ }
+ if( j>=pEList->nExpr ){
+ pOrderBy->a[i].u.x.iOrderByCol = 0;
+ }
+ }
+}
+
/*
** pX is an expression of the form: (vector) IN (SELECT ...)
@@ -152893,6 +159129,7 @@ static Expr *removeUnindexableInClauseTerms(
if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */
pRhs = wx_sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
pOrigRhs->a[iField].pExpr = 0;
+ if( pRhs ) pRhs->a[pRhs->nExpr-1].u.x.iOrderByCol = iField+1;
if( pOrigLhs ){
assert( pOrigLhs->a[iField].pExpr!=0 );
pLhs = wx_sqlite3ExprListAppend(pParse,pLhs,pOrigLhs->a[iField].pExpr);
@@ -152906,6 +159143,7 @@ static Expr *removeUnindexableInClauseTerms(
pNew->pLeft->x.pList = pLhs;
}
pSelect->pEList = pRhs;
+ pSelect->selId = ++pParse->nSelect; /* Req'd for SubrtnSig validity */
if( pLhs && pLhs->nExpr==1 ){
/* Take care here not to generate a TK_VECTOR containing only a
** single value. Since the parser never creates such a vector, some
@@ -152915,18 +159153,16 @@ static Expr *removeUnindexableInClauseTerms(
wx_sqlite3ExprDelete(db, pNew->pLeft);
pNew->pLeft = p;
}
- if( pSelect->pOrderBy ){
- /* If the SELECT statement has an ORDER BY clause, zero the
- ** iOrderByCol variables. These are set to non-zero when an
- ** ORDER BY term exactly matches one of the terms of the
- ** result-set. Since the result-set of the SELECT statement may
- ** have been modified or reordered, these variables are no longer
- ** set correctly. Since setting them is just an optimization,
- ** it's easiest just to zero them here. */
- ExprList *pOrderBy = pSelect->pOrderBy;
- for(i=0; i<pOrderBy->nExpr; i++){
- pOrderBy->a[i].u.x.iOrderByCol = 0;
- }
+
+ /* If either the ORDER BY clause or the GROUP BY clause contains
+ ** references to result-set columns, those references might now be
+ ** obsolete. So fix them up.
+ */
+ assert( pRhs!=0 || db->mallocFailed );
+ if( pRhs ){
+ adjustOrderByCol(pSelect->pOrderBy, pRhs);
+ adjustOrderByCol(pSelect->pGroupBy, pRhs);
+ for(i=0; i<pRhs->nExpr; i++) pRhs->a[i].u.x.iOrderByCol = 0;
}
#if 0
@@ -152941,6 +159177,147 @@ static Expr *removeUnindexableInClauseTerms(
}
+#ifndef SQLITE_OMIT_SUBQUERY
+/*
+** Generate code for a single X IN (....) term of the WHERE clause.
+**
+** This is a special-case of codeEqualityTerm() that works for IN operators
+** only. It is broken out into a subroutine because this case is
+** uncommon and by splitting it off into a subroutine, the common case
+** runs faster.
+**
+** The current value for the constraint is left in register iTarget.
+** This routine sets up a loop that will iterate over all values of X.
+*/
+static SQLITE_NOINLINE void codeINTerm(
+ Parse *pParse, /* The parsing context */
+ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
+ WhereLevel *pLevel, /* The level of the FROM clause we are working on */
+ int iEq, /* Index of the equality term within this level */
+ int bRev, /* True for reverse-order IN operations */
+ int iTarget /* Attempt to leave results in this register */
+){
+ Expr *pX = pTerm->pExpr;
+ int eType = IN_INDEX_NOOP;
+ int iTab;
+ struct InLoop *pIn;
+ WhereLoop *pLoop = pLevel->pWLoop;
+ Vdbe *v = pParse->pVdbe;
+ int i;
+ int nEq = 0;
+ int *aiMap = 0;
+
+ if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
+ && pLoop->u.btree.pIndex!=0
+ && pLoop->u.btree.pIndex->aSortOrder[iEq]
+ ){
+ testcase( iEq==0 );
+ testcase( bRev );
+ bRev = !bRev;
+ }
+ assert( pX->op==TK_IN );
+
+ for(i=0; i<iEq; i++){
+ if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){
+ disableTerm(pLevel, pTerm);
+ return;
+ }
+ }
+ for(i=iEq;i<pLoop->nLTerm; i++){
+ assert( pLoop->aLTerm[i]!=0 );
+ if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
+ }
+
+ iTab = 0;
+ if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){
+ eType = wx_sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
+ }else{
+ Expr *pExpr = pTerm->pExpr;
+ if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){
+ wx_sqlite3 *db = pParse->db;
+ pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
+ if( !db->mallocFailed ){
+ aiMap = (int*)wx_sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
+ eType = wx_sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
+ pExpr->iTable = iTab;
+ }
+ wx_sqlite3ExprDelete(db, pX);
+ }else{
+ int n = wx_sqlite3ExprVectorSize(pX->pLeft);
+ aiMap = (int*)wx_sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n));
+ eType = wx_sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
+ }
+ pX = pExpr;
+ }
+
+ if( eType==IN_INDEX_INDEX_DESC ){
+ testcase( bRev );
+ bRev = !bRev;
+ }
+ wx_sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
+ VdbeCoverageIf(v, bRev);
+ VdbeCoverageIf(v, !bRev);
+
+ assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
+ pLoop->wsFlags |= WHERE_IN_ABLE;
+ if( pLevel->u.in.nIn==0 ){
+ pLevel->addrNxt = wx_sqlite3VdbeMakeLabel(pParse);
+ }
+ if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){
+ pLoop->wsFlags |= WHERE_IN_EARLYOUT;
+ }
+
+ i = pLevel->u.in.nIn;
+ pLevel->u.in.nIn += nEq;
+ pLevel->u.in.aInLoop =
+ wx_sqlite3WhereRealloc(pTerm->pWC->pWInfo,
+ pLevel->u.in.aInLoop,
+ sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
+ pIn = pLevel->u.in.aInLoop;
+ if( pIn ){
+ int iMap = 0; /* Index in aiMap[] */
+ pIn += i;
+ for(i=iEq;i<pLoop->nLTerm; i++){
+ if( pLoop->aLTerm[i]->pExpr==pX ){
+ int iOut = iTarget + i - iEq;
+ if( eType==IN_INDEX_ROWID ){
+ pIn->addrInTop = wx_sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut);
+ }else{
+ int iCol = aiMap ? aiMap[iMap++] : 0;
+ pIn->addrInTop = wx_sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
+ }
+ wx_sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
+ if( i==iEq ){
+ pIn->iCur = iTab;
+ pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
+ if( iEq>0 ){
+ pIn->iBase = iTarget - i;
+ pIn->nPrefix = i;
+ }else{
+ pIn->nPrefix = 0;
+ }
+ }else{
+ pIn->eEndLoopOp = OP_Noop;
+ }
+ pIn++;
+ }
+ }
+ testcase( iEq>0
+ && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0
+ && (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 );
+ if( iEq>0
+ && (pLoop->wsFlags & (WHERE_IN_SEEKSCAN|WHERE_VIRTUALTABLE))==0
+ ){
+ wx_sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq);
+ }
+ }else{
+ pLevel->u.in.nIn = 0;
+ }
+ wx_sqlite3DbFree(pParse->db, aiMap);
+}
+#endif
+
+
/*
** Generate code for a single equality term of the WHERE clause. An equality
** term can be either X=expr or X IN (...). pTerm is the term to be
@@ -152965,7 +159342,6 @@ static int codeEqualityTerm(
int iTarget /* Attempt to leave results in this register */
){
Expr *pX = pTerm->pExpr;
- Vdbe *v = pParse->pVdbe;
int iReg; /* Register holding results */
assert( pLevel->pWLoop->aLTerm[iEq]==pTerm );
@@ -152974,125 +159350,12 @@ static int codeEqualityTerm(
iReg = wx_sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
}else if( pX->op==TK_ISNULL ){
iReg = iTarget;
- wx_sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
+ wx_sqlite3VdbeAddOp2(pParse->pVdbe, OP_Null, 0, iReg);
#ifndef SQLITE_OMIT_SUBQUERY
}else{
- int eType = IN_INDEX_NOOP;
- int iTab;
- struct InLoop *pIn;
- WhereLoop *pLoop = pLevel->pWLoop;
- int i;
- int nEq = 0;
- int *aiMap = 0;
-
- if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
- && pLoop->u.btree.pIndex!=0
- && pLoop->u.btree.pIndex->aSortOrder[iEq]
- ){
- testcase( iEq==0 );
- testcase( bRev );
- bRev = !bRev;
- }
assert( pX->op==TK_IN );
iReg = iTarget;
-
- for(i=0; i<iEq; i++){
- if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){
- disableTerm(pLevel, pTerm);
- return iTarget;
- }
- }
- for(i=iEq;i<pLoop->nLTerm; i++){
- assert( pLoop->aLTerm[i]!=0 );
- if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
- }
-
- iTab = 0;
- if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){
- eType = wx_sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
- }else{
- Expr *pExpr = pTerm->pExpr;
- if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){
- wx_sqlite3 *db = pParse->db;
- pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
- if( !db->mallocFailed ){
- aiMap = (int*)wx_sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
- eType = wx_sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
- pExpr->iTable = iTab;
- }
- wx_sqlite3ExprDelete(db, pX);
- }else{
- int n = wx_sqlite3ExprVectorSize(pX->pLeft);
- aiMap = (int*)wx_sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n));
- eType = wx_sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
- }
- pX = pExpr;
- }
-
- if( eType==IN_INDEX_INDEX_DESC ){
- testcase( bRev );
- bRev = !bRev;
- }
- wx_sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
- VdbeCoverageIf(v, bRev);
- VdbeCoverageIf(v, !bRev);
-
- assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
- pLoop->wsFlags |= WHERE_IN_ABLE;
- if( pLevel->u.in.nIn==0 ){
- pLevel->addrNxt = wx_sqlite3VdbeMakeLabel(pParse);
- }
- if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){
- pLoop->wsFlags |= WHERE_IN_EARLYOUT;
- }
-
- i = pLevel->u.in.nIn;
- pLevel->u.in.nIn += nEq;
- pLevel->u.in.aInLoop =
- wx_sqlite3WhereRealloc(pTerm->pWC->pWInfo,
- pLevel->u.in.aInLoop,
- sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
- pIn = pLevel->u.in.aInLoop;
- if( pIn ){
- int iMap = 0; /* Index in aiMap[] */
- pIn += i;
- for(i=iEq;i<pLoop->nLTerm; i++){
- if( pLoop->aLTerm[i]->pExpr==pX ){
- int iOut = iReg + i - iEq;
- if( eType==IN_INDEX_ROWID ){
- pIn->addrInTop = wx_sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut);
- }else{
- int iCol = aiMap ? aiMap[iMap++] : 0;
- pIn->addrInTop = wx_sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
- }
- wx_sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
- if( i==iEq ){
- pIn->iCur = iTab;
- pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
- if( iEq>0 ){
- pIn->iBase = iReg - i;
- pIn->nPrefix = i;
- }else{
- pIn->nPrefix = 0;
- }
- }else{
- pIn->eEndLoopOp = OP_Noop;
- }
- pIn++;
- }
- }
- testcase( iEq>0
- && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0
- && (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 );
- if( iEq>0
- && (pLoop->wsFlags & (WHERE_IN_SEEKSCAN|WHERE_VIRTUALTABLE))==0
- ){
- wx_sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq);
- }
- }else{
- pLevel->u.in.nIn = 0;
- }
- wx_sqlite3DbFree(pParse->db, aiMap);
+ codeINTerm(pParse, pTerm, pLevel, iEq, bRev, iTarget);
#endif
}
@@ -153188,7 +159451,7 @@ static int codeAllEqualityTerms(
/* Figure out how many memory cells we will need then allocate them.
*/
regBase = pParse->nMem + 1;
- nReg = pLoop->u.btree.nEq + nExtraReg;
+ nReg = nEq + nExtraReg;
pParse->nMem += nReg;
zAff = wx_sqlite3DbStrDup(pParse->db,wx_sqlite3IndexAffinityStr(pParse->db,pIdx));
@@ -153235,9 +159498,6 @@ static int codeAllEqualityTerms(
wx_sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j);
}
}
- }
- for(j=nSkip; j<nEq; j++){
- pTerm = pLoop->aLTerm[j];
if( pTerm->eOperator & WO_IN ){
if( pTerm->pExpr->flags & EP_xIsSelect ){
/* No affinity ever needs to be (or should be) applied to a value
@@ -153380,18 +159640,19 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
** 2) transform the expression node to a TK_REGISTER node that reads
** from the newly populated register.
**
-** Also, if the node is a TK_COLUMN that does access the table idenified
+** Also, if the node is a TK_COLUMN that does access the table identified
** by pCCurHint.iTabCur, and an index is being used (which we will
** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into
** an access of the index rather than the original table.
*/
static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
int rc = WRC_Continue;
+ int reg;
struct CCurHint *pHint = pWalker->u.pCCurHint;
if( pExpr->op==TK_COLUMN ){
if( pExpr->iTable!=pHint->iTabCur ){
- int reg = ++pWalker->pParse->nMem; /* Register for column value */
- wx_sqlite3ExprCode(pWalker->pParse, pExpr, reg);
+ reg = ++pWalker->pParse->nMem; /* Register for column value */
+ reg = wx_sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
pExpr->op = TK_REGISTER;
pExpr->iTable = reg;
}else if( pHint->pIdx!=0 ){
@@ -153399,15 +159660,15 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
pExpr->iColumn = wx_sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn);
assert( pExpr->iColumn>=0 );
}
- }else if( pExpr->op==TK_AGG_FUNCTION ){
- /* An aggregate function in the WHERE clause of a query means this must
- ** be a correlated sub-query, and expression pExpr is an aggregate from
- ** the parent context. Do not walk the function arguments in this case.
- **
- ** todo: It should be possible to replace this node with a TK_REGISTER
- ** expression, as the result of the expression must be stored in a
- ** register at this point. The same holds for TK_AGG_COLUMN nodes. */
+ }else if( pExpr->pAggInfo ){
rc = WRC_Prune;
+ reg = ++pWalker->pParse->nMem; /* Register for column value */
+ reg = wx_sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
+ pExpr->op = TK_REGISTER;
+ pExpr->iTable = reg;
+ }else if( pExpr->op==TK_TRUEFALSE ){
+ /* Do not walk disabled expressions. tag-20230504-1 */
+ return WRC_Prune;
}
return rc;
}
@@ -153509,7 +159770,7 @@ static void codeCursorHint(
}
if( pExpr!=0 ){
sWalker.xExprCallback = codeCursorHintFixExpr;
- wx_sqlite3WalkExpr(&sWalker, pExpr);
+ if( pParse->nErr==0 ) wx_sqlite3WalkExpr(&sWalker, pExpr);
wx_sqlite3VdbeAddOp4(v, OP_CursorHint,
(sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
(const char*)pExpr, P4_EXPR);
@@ -153710,6 +159971,27 @@ static SQLITE_NOINLINE void filterPullDown(
}
/*
+** Loop pLoop is a WHERE_INDEXED level that uses at least one IN(...)
+** operator. Return true if level pLoop is guaranteed to visit only one
+** row for each key generated for the index.
+*/
+static int whereLoopIsOneRow(WhereLoop *pLoop){
+ if( pLoop->u.btree.pIndex->onError
+ && pLoop->nSkip==0
+ && pLoop->u.btree.nEq==pLoop->u.btree.pIndex->nKeyCol
+ ){
+ int ii;
+ for(ii=0; ii<pLoop->u.btree.nEq; ii++){
+ if( pLoop->aLTerm[ii]->eOperator & (WO_IS|WO_ISNULL) ){
+ return 0;
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
*/
@@ -153745,7 +160027,8 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereCodeOneLoopStart(
iCur = pTabItem->iCursor;
pLevel->notReady = notReady & ~wx_sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
bRev = (pWInfo->revMask>>iLevel)&1;
- VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
+ VdbeModuleComment((v, "Begin WHERE-loop%d: %s",
+ iLevel, pTabItem->pSTab->zName));
#if WHERETRACE_ENABLED /* 0x4001 */
if( wx_sqlite3WhereTrace & 0x1 ){
wx_sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
@@ -153787,7 +160070,7 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereCodeOneLoopStart(
if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){
pLevel->iLeftJoin = ++pParse->nMem;
wx_sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin);
- VdbeComment((v, "init LEFT JOIN no-match flag"));
+ VdbeComment((v, "init LEFT JOIN match flag"));
}
/* Compute a safe address to jump to if we discover that the table for
@@ -153800,11 +160083,15 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereCodeOneLoopStart(
/* Special case of a FROM clause subquery implemented as a co-routine */
if( pTabItem->fg.viaCoroutine ){
- int regYield = pTabItem->regReturn;
- wx_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
+ int regYield;
+ Subquery *pSubq;
+ assert( pTabItem->fg.isSubquery && pTabItem->u4.pSubq!=0 );
+ pSubq = pTabItem->u4.pSubq;
+ regYield = pSubq->regReturn;
+ wx_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub);
pLevel->p2 = wx_sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
VdbeCoverage(v);
- VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
+ VdbeComment((v, "next row of %s", pTabItem->pSTab->zName));
pLevel->op = OP_Goto;
}else
@@ -153997,7 +160284,7 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereCodeOneLoopStart(
};
assert( TK_LE==TK_GT+1 ); /* Make sure the ordering.. */
assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */
- assert( TK_GE==TK_GT+3 ); /* ... is correcct. */
+ assert( TK_GE==TK_GT+3 ); /* ... is correct. */
assert( (pStart->wtFlags & TERM_VNULL)==0 );
testcase( pStart->wtFlags & TERM_VIRTUAL );
@@ -154303,7 +160590,7 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereCodeOneLoopStart(
** guess. */
addrSeekScan = wx_sqlite3VdbeAddOp1(v, OP_SeekScan,
(pIdx->aiRowLogEst[0]+9)/10);
- if( pRangeStart ){
+ if( pRangeStart || pRangeEnd ){
wx_sqlite3VdbeChangeP5(v, 1);
wx_sqlite3VdbeChangeP2(v, addrSeekScan, wx_sqlite3VdbeCurrentAddr(v)+1);
addrSeekScan = 0;
@@ -154344,16 +160631,7 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereCodeOneLoopStart(
assert( pLevel->p2==0 );
if( pRangeEnd ){
Expr *pRight = pRangeEnd->pExpr->pRight;
- if( addrSeekScan ){
- /* For a seek-scan that has a range on the lowest term of the index,
- ** we have to make the top of the loop be code that sets the end
- ** condition of the range. Otherwise, the OP_SeekScan might jump
- ** over that initialization, leaving the range-end value set to the
- ** range-start value, resulting in a wrong answer.
- ** See ticket 5981a8c041a3c2f3 (2021-11-02).
- */
- pLevel->p2 = wx_sqlite3VdbeCurrentAddr(v);
- }
+ assert( addrSeekScan==0 );
codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
@@ -154387,7 +160665,7 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereCodeOneLoopStart(
if( zEndAff ) wx_sqlite3DbNNFreeNN(db, zEndAff);
/* Top of the loop body */
- if( pLevel->p2==0 ) pLevel->p2 = wx_sqlite3VdbeCurrentAddr(v);
+ pLevel->p2 = wx_sqlite3VdbeCurrentAddr(v);
/* Check if the index cursor is past the end of the range. */
if( nConstraint ){
@@ -154465,7 +160743,9 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereCodeOneLoopStart(
}
/* Record the instruction used to terminate the loop. */
- if( pLoop->wsFlags & WHERE_ONEROW ){
+ if( (pLoop->wsFlags & WHERE_ONEROW)
+ || (pLevel->u.in.nIn && regBignull==0 && whereLoopIsOneRow(pLoop))
+ ){
pLevel->op = OP_Noop;
}else if( bRev ){
pLevel->op = OP_Prev;
@@ -154540,7 +160820,7 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereCodeOneLoopStart(
int untestedTerms = 0; /* Some terms not completely tested */
int ii; /* Loop counter */
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
- Table *pTab = pTabItem->pTab;
+ Table *pTab = pTabItem->pSTab;
pTerm = pLoop->aLTerm[0];
assert( pTerm!=0 );
@@ -154855,6 +161135,12 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereCodeOneLoopStart(
** iLoop==3: Code all remaining expressions.
**
** An effort is made to skip unnecessary iterations of the loop.
+ **
+ ** This optimization of causing simple query restrictions to occur before
+ ** more complex one is call the "push-down" optimization in MySQL. Here
+ ** in SQLite, the name is "MySQL push-down", since there is also another
+ ** totally unrelated optimization called "WHERE-clause push-down".
+ ** Sometimes the qualifier is omitted, resulting in an ambiguity, so beware.
*/
iLoop = (pIdx ? 1 : 2);
do{
@@ -154993,7 +161279,7 @@ SQLITE_PRIVATE Bitmask wx_sqlite3WhereCodeOneLoopStart(
** least once. This is accomplished by storing the PK for the row in
** both the iMatch index and the regBloom Bloom filter.
*/
- pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab;
+ pTab = pWInfo->pTabList->a[pLevel->iFrom].pSTab;
if( HasRowid(pTab) ){
r = wx_sqlite3GetTempRange(pParse, 2);
wx_sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1);
@@ -155100,12 +161386,25 @@ SQLITE_PRIVATE SQLITE_NOINLINE void wx_sqlite3WhereRightJoinLoop(
Bitmask mAll = 0;
int k;
- ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName));
+ ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pSTab->zName));
wx_sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
pRJ->regReturn);
for(k=0; k<iLevel; k++){
int iIdxCur;
+ SrcItem *pRight;
+ assert( pWInfo->a[k].pWLoop->iTab == pWInfo->a[k].iFrom );
+ pRight = &pWInfo->pTabList->a[pWInfo->a[k].iFrom];
mAll |= pWInfo->a[k].pWLoop->maskSelf;
+ if( pRight->fg.viaCoroutine ){
+ Subquery *pSubq;
+ assert( pRight->fg.isSubquery && pRight->u4.pSubq!=0 );
+ pSubq = pRight->u4.pSubq;
+ assert( pSubq->pSelect!=0 && pSubq->pSelect->pEList!=0 );
+ wx_sqlite3VdbeAddOp3(
+ v, OP_Null, 0, pSubq->regResult,
+ pSubq->regResult + pSubq->pSelect->pEList->nExpr-1
+ );
+ }
wx_sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
iIdxCur = pWInfo->a[k].iIdxCur;
if( iIdxCur ){
@@ -155141,7 +161440,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void wx_sqlite3WhereRightJoinLoop(
int nPk;
int jmp;
int addrCont = wx_sqlite3WhereContinueLabel(pSubWInfo);
- Table *pTab = pTabItem->pTab;
+ Table *pTab = pTabItem->pSTab;
if( HasRowid(pTab) ){
wx_sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r);
nPk = 1;
@@ -155186,7 +161485,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void wx_sqlite3WhereRightJoinLoop(
** the WHERE clause of SQL statements.
**
** This file was originally part of where.c but was split out to improve
-** readability and editabiliity. This file contains utility routines for
+** readability and editability. This file contains utility routines for
** analyzing Expr objects in the WHERE clause.
*/
/* #include "sqliteInt.h" */
@@ -155274,7 +161573,12 @@ static int allowedOp(int op){
assert( TK_LT>TK_EQ && TK_LT<TK_GE );
assert( TK_LE>TK_EQ && TK_LE<TK_GE );
assert( TK_GE==TK_EQ+4 );
- return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS;
+ assert( TK_IN<TK_EQ );
+ assert( TK_IS<TK_EQ );
+ assert( TK_ISNULL<TK_EQ );
+ if( op>TK_GE ) return 0;
+ if( op>=TK_EQ ) return 1;
+ return op==TK_IN || op==TK_ISNULL || op==TK_IS;
}
/*
@@ -155307,15 +161611,16 @@ static u16 exprCommute(Parse *pParse, Expr *pExpr){
static u16 operatorMask(int op){
u16 c;
assert( allowedOp(op) );
- if( op==TK_IN ){
+ if( op>=TK_EQ ){
+ assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff );
+ c = (u16)(WO_EQ<<(op-TK_EQ));
+ }else if( op==TK_IN ){
c = WO_IN;
}else if( op==TK_ISNULL ){
c = WO_ISNULL;
- }else if( op==TK_IS ){
- c = WO_IS;
}else{
- assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff );
- c = (u16)(WO_EQ<<(op-TK_EQ));
+ assert( op==TK_IS );
+ c = WO_IS;
}
assert( op!=TK_ISNULL || c==WO_ISNULL );
assert( op!=TK_IN || c==WO_IN );
@@ -155386,12 +161691,26 @@ static int isLikeOrGlob(
z = (u8*)pRight->u.zToken;
}
if( z ){
-
- /* Count the number of prefix characters prior to the first wildcard */
+ /* Count the number of prefix bytes prior to the first wildcard.
+ ** or U+fffd character. If the underlying database has a UTF16LE
+ ** encoding, then only consider ASCII characters. Note that the
+ ** encoding of z[] is UTF8 - we are dealing with only UTF8 here in
+ ** this code, but the database engine itself might be processing
+ ** content using a different encoding. */
cnt = 0;
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
cnt++;
- if( c==wc[3] && z[cnt]!=0 ) cnt++;
+ if( c==wc[3] && z[cnt]>0 && z[cnt]<0x80 ){
+ cnt++;
+ }else if( c>=0x80 ){
+ const u8 *z2 = z+cnt-1;
+ if( wx_sqlite3Utf8Read(&z2)==0xfffd || ENC(db)==SQLITE_UTF16LE ){
+ cnt--;
+ break;
+ }else{
+ cnt = (int)(z2-z);
+ }
+ }
}
/* The optimization is possible only if (1) the pattern does not begin
@@ -155402,11 +161721,11 @@ static int isLikeOrGlob(
** range search. The third is because the caller assumes that the pattern
** consists of at least one character after all escapes have been
** removed. */
- if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){
+ if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && ALWAYS(255!=(u8)z[cnt-1]) ){
Expr *pPrefix;
/* A "complete" match if the pattern ends with "*" or "%" */
- *pisComplete = c==wc[0] && z[cnt+1]==0;
+ *pisComplete = c==wc[0] && z[cnt+1]==0 && ENC(db)!=SQLITE_UTF16LE;
/* Get the pattern prefix. Remove all escapes from the prefix. */
pPrefix = wx_sqlite3Expr(db, TK_STRING, (char*)z);
@@ -155602,6 +161921,13 @@ static int isAuxiliaryVtabOperator(
}
}
}
+ }else if( pExpr->op>=TK_EQ ){
+ /* Comparison operators are a common case. Save a few comparisons for
+ ** that common case by terminating early. */
+ assert( TK_NE < TK_EQ );
+ assert( TK_ISNOT < TK_EQ );
+ assert( TK_NOTNULL < TK_EQ );
+ return 0;
}else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
int res = 0;
Expr *pLeft = pExpr->pLeft;
@@ -155975,7 +162301,7 @@ static void exprAnalyzeOrTerm(
pOrTerm->leftCursor))==0 ){
/* This term must be of the form t1.a==t2.b where t2 is in the
** chngToIN set but t1 is not. This term will be either preceded
- ** or follwed by an inverted copy (t2.b==t1.a). Skip this term
+ ** or followed by an inverted copy (t2.b==t1.a). Skip this term
** and use its inversion. */
testcase( pOrTerm->wtFlags & TERM_COPIED );
testcase( pOrTerm->wtFlags & TERM_VIRTUAL );
@@ -156118,7 +162444,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
if( ALWAYS(pSrc!=0) ){
int i;
for(i=0; i<pSrc->nSrc; i++){
- mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
+ if( pSrc->a[i].fg.isSubquery ){
+ mask |= exprSelectUsage(pMaskSet, pSrc->a[i].u4.pSubq->pSelect);
+ }
if( pSrc->a[i].fg.isUsing==0 ){
mask |= wx_sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn);
}
@@ -156156,13 +162484,13 @@ static SQLITE_NOINLINE int exprMightBeIndexed2(
int iCur;
do{
iCur = pFrom->a[j].iCursor;
- for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ for(pIdx=pFrom->a[j].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->aColExpr==0 ) continue;
for(i=0; i<pIdx->nKeyCol; i++){
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
assert( pIdx->bHasExpr );
if( wx_sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0
- && pExpr->op!=TK_STRING
+ && !wx_sqlite3ExprIsConstant(0,pIdx->aColExpr->a[i].pExpr)
){
aiCurCol[0] = iCur;
aiCurCol[1] = XN_EXPR;
@@ -156200,7 +162528,7 @@ static int exprMightBeIndexed(
for(i=0; i<pFrom->nSrc; i++){
Index *pIdx;
- for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ for(pIdx=pFrom->a[i].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->aColExpr ){
return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i);
}
@@ -156237,8 +162565,8 @@ static void exprAnalyze(
WhereTerm *pTerm; /* The term to be analyzed */
WhereMaskSet *pMaskSet; /* Set of table index masks */
Expr *pExpr; /* The expression to be analyzed */
- Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */
- Bitmask prereqAll; /* Prerequesites of pExpr */
+ Bitmask prereqLeft; /* Prerequisites of the pExpr->pLeft */
+ Bitmask prereqAll; /* Prerequisites of pExpr */
Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */
Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */
int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */
@@ -156384,7 +162712,7 @@ static void exprAnalyze(
&& 0==wx_sqlite3ExprCanBeNull(pLeft)
){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- pExpr->op = TK_TRUEFALSE;
+ pExpr->op = TK_TRUEFALSE; /* See tag-20230504-1 */
pExpr->u.zToken = "false";
ExprSetProperty(pExpr, EP_IsFalse);
pTerm->prereqAll = 0;
@@ -156743,7 +163071,7 @@ static void whereAddLimitExpr(
Expr *pNew;
int iVal = 0;
- if( wx_sqlite3ExprIsInteger(pExpr, &iVal) && iVal>=0 ){
+ if( wx_sqlite3ExprIsInteger(pExpr, &iVal, pParse) && iVal>=0 ){
Expr *pVal = wx_sqlite3Expr(db, TK_INTEGER, 0);
if( pVal==0 ) return;
ExprSetProperty(pVal, EP_IntValue);
@@ -156788,7 +163116,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE wx_sqlite3WhereAddLimit(WhereClause *pWC, Se
assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
if( p->pGroupBy==0
&& (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
- && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
+ && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pSTab)) /* 3 */
){
ExprList *pOrderBy = p->pOrderBy;
int iCsr = p->pSrc->a[0].iCursor;
@@ -156811,6 +163139,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE wx_sqlite3WhereAddLimit(WhereClause *pWC, Se
continue;
}
if( pWC->a[ii].leftCursor!=iCsr ) return;
+ if( pWC->a[ii].prereqRight!=0 ) return;
}
/* Check condition (5). Return early if it is not met. */
@@ -156825,12 +163154,14 @@ SQLITE_PRIVATE void SQLITE_NOINLINE wx_sqlite3WhereAddLimit(WhereClause *pWC, Se
/* All conditions are met. Add the terms to the where-clause object. */
assert( p->pLimit->op==TK_LIMIT );
- whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft,
- iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT);
- if( p->iOffset>0 ){
+ if( p->iOffset!=0 && (p->selFlags & SF_Compound)==0 ){
whereAddLimitExpr(pWC, p->iOffset, p->pLimit->pRight,
iCsr, SQLITE_INDEX_CONSTRAINT_OFFSET);
}
+ if( p->iOffset==0 || (p->selFlags & SF_Compound)==0 ){
+ whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft,
+ iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT);
+ }
}
}
@@ -157006,7 +163337,7 @@ SQLITE_PRIVATE void wx_sqlite3WhereTabFuncArgs(
Expr *pColRef;
Expr *pTerm;
if( pItem->fg.isTabFunc==0 ) return;
- pTab = pItem->pTab;
+ pTab = pItem->pSTab;
assert( pTab!=0 );
pArgs = pItem->u1.pFuncArg;
if( pArgs==0 ) return;
@@ -157029,9 +163360,12 @@ SQLITE_PRIVATE void wx_sqlite3WhereTabFuncArgs(
pRhs = wx_sqlite3PExpr(pParse, TK_UPLUS,
wx_sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
pTerm = wx_sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
- if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ){
+ if( pItem->fg.jointype & (JT_LEFT|JT_RIGHT) ){
+ testcase( pItem->fg.jointype & JT_LEFT ); /* testtag-20230227a */
+ testcase( pItem->fg.jointype & JT_RIGHT ); /* testtag-20230227b */
joinType = EP_OuterON;
}else{
+ testcase( pItem->fg.jointype & JT_LTORJ ); /* testtag-20230227c */
joinType = EP_InnerON;
}
wx_sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType);
@@ -157346,6 +163680,42 @@ static Expr *whereRightSubexprIsColumn(Expr *p){
}
/*
+** Term pTerm is guaranteed to be a WO_IN term. It may be a component term
+** of a vector IN expression of the form "(x, y, ...) IN (SELECT ...)".
+** This function checks to see if the term is compatible with an index
+** column with affinity idxaff (one of the SQLITE_AFF_XYZ values). If so,
+** it returns a pointer to the name of the collation sequence (e.g. "BINARY"
+** or "NOCASE") used by the comparison in pTerm. If it is not compatible
+** with affinity idxaff, NULL is returned.
+*/
+static SQLITE_NOINLINE const char *indexInAffinityOk(
+ Parse *pParse,
+ WhereTerm *pTerm,
+ u8 idxaff
+){
+ Expr *pX = pTerm->pExpr;
+ Expr inexpr;
+
+ assert( pTerm->eOperator & WO_IN );
+
+ if( wx_sqlite3ExprIsVector(pX->pLeft) ){
+ int iField = pTerm->u.x.iField - 1;
+ inexpr.flags = 0;
+ inexpr.op = TK_EQ;
+ inexpr.pLeft = pX->pLeft->x.pList->a[iField].pExpr;
+ assert( ExprUseXSelect(pX) );
+ inexpr.pRight = pX->x.pSelect->pEList->a[iField].pExpr;
+ pX = &inexpr;
+ }
+
+ if( wx_sqlite3IndexAffinityOk(pX, idxaff) ){
+ CollSeq *pRet = wx_sqlite3ExprCompareCollSeq(pParse, pX);
+ return pRet ? pRet->zName : wx_sqlite3StrBINARY;
+ }
+ return 0;
+}
+
+/*
** Advance to the next WhereTerm that matches according to the criteria
** established when the pScan object was initialized by whereScanInit().
** Return NULL if there are no more matching WhereTerms.
@@ -157395,16 +163765,24 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
if( (pTerm->eOperator & pScan->opMask)!=0 ){
/* Verify the affinity and collating sequence match */
if( pScan->zCollName && (pTerm->eOperator & WO_ISNULL)==0 ){
- CollSeq *pColl;
+ const char *zCollName;
Parse *pParse = pWC->pWInfo->pParse;
pX = pTerm->pExpr;
- if( !wx_sqlite3IndexAffinityOk(pX, pScan->idxaff) ){
- continue;
+
+ if( (pTerm->eOperator & WO_IN) ){
+ zCollName = indexInAffinityOk(pParse, pTerm, pScan->idxaff);
+ if( !zCollName ) continue;
+ }else{
+ CollSeq *pColl;
+ if( !wx_sqlite3IndexAffinityOk(pX, pScan->idxaff) ){
+ continue;
+ }
+ assert(pX->pLeft);
+ pColl = wx_sqlite3ExprCompareCollSeq(pParse, pX);
+ zCollName = pColl ? pColl->zName : wx_sqlite3StrBINARY;
}
- assert(pX->pLeft);
- pColl = wx_sqlite3ExprCompareCollSeq(pParse, pX);
- if( pColl==0 ) pColl = pParse->db->pDfltColl;
- if( wx_sqlite3StrICmp(pColl->zName, pScan->zCollName) ){
+
+ if( wx_sqlite3StrICmp(zCollName, pScan->zCollName) ){
continue;
}
}
@@ -157643,7 +164021,7 @@ static int isDistinctRedundant(
** clause is redundant. */
if( pTabList->nSrc!=1 ) return 0;
iBase = pTabList->a[0].iCursor;
- pTab = pTabList->a[0].pTab;
+ pTab = pTabList->a[0].pSTab;
/* If any of the expressions is an IPK column on table iBase, then return
** true. Note: The (p->iTable==iBase) part of this test may be false if the
@@ -157718,15 +164096,31 @@ static void translateColumnToCopy(
VdbeOp *pOp = wx_sqlite3VdbeGetOp(v, iStart);
int iEnd = wx_sqlite3VdbeCurrentAddr(v);
if( pParse->db->mallocFailed ) return;
+#ifdef SQLITE_DEBUG
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
+ printf("CHECKING for column-to-copy on cursor %d for %d..%d\n",
+ iTabCur, iStart, iEnd);
+ }
+#endif
for(; iStart<iEnd; iStart++, pOp++){
if( pOp->p1!=iTabCur ) continue;
if( pOp->opcode==OP_Column ){
+#ifdef SQLITE_DEBUG
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
+ printf("TRANSLATE OP_Column to OP_Copy at %d\n", iStart);
+ }
+#endif
pOp->opcode = OP_Copy;
pOp->p1 = pOp->p2 + iRegister;
pOp->p2 = pOp->p3;
pOp->p3 = 0;
pOp->p5 = 2; /* Cause the MEM_Subtype flag to be cleared */
}else if( pOp->opcode==OP_Rowid ){
+#ifdef SQLITE_DEBUG
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
+ printf("TRANSLATE OP_Rowid to OP_Sequence at %d\n", iStart);
+ }
+#endif
pOp->opcode = OP_Sequence;
pOp->p1 = iAutoidxCur;
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
@@ -157746,9 +164140,13 @@ static void translateColumnToCopy(
** are no-ops.
*/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED)
-static void whereTraceIndexInfoInputs(wx_sqlite3_index_info *p){
+static void whereTraceIndexInfoInputs(
+ wx_sqlite3_index_info *p, /* The IndexInfo object */
+ Table *pTab /* The TABLE that is the virtual table */
+){
int i;
if( (wx_sqlite3WhereTrace & 0x10)==0 ) return;
+ wx_sqlite3DebugPrintf("wx_sqlite3_index_info inputs for %s:\n", pTab->zName);
for(i=0; i<p->nConstraint; i++){
wx_sqlite3DebugPrintf(
" constraint[%d]: col=%d termid=%d op=%d usabled=%d collseq=%s\n",
@@ -157766,9 +164164,13 @@ static void whereTraceIndexInfoInputs(wx_sqlite3_index_info *p){
p->aOrderBy[i].desc);
}
}
-static void whereTraceIndexInfoOutputs(wx_sqlite3_index_info *p){
+static void whereTraceIndexInfoOutputs(
+ wx_sqlite3_index_info *p, /* The IndexInfo object */
+ Table *pTab /* The TABLE that is the virtual table */
+){
int i;
if( (wx_sqlite3WhereTrace & 0x10)==0 ) return;
+ wx_sqlite3DebugPrintf("wx_sqlite3_index_info outputs for %s:\n", pTab->zName);
for(i=0; i<p->nConstraint; i++){
wx_sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n",
i,
@@ -157782,8 +164184,8 @@ static void whereTraceIndexInfoOutputs(wx_sqlite3_index_info *p){
wx_sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows);
}
#else
-#define whereTraceIndexInfoInputs(A)
-#define whereTraceIndexInfoOutputs(A)
+#define whereTraceIndexInfoInputs(A,B)
+#define whereTraceIndexInfoOutputs(A,B)
#endif
/*
@@ -157821,6 +164223,40 @@ static int constraintCompatibleWithOuterJoin(
return 1;
}
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+/*
+** Return true if column iCol of table pTab seem like it might be a
+** good column to use as part of a query-time index.
+**
+** Current algorithm (subject to improvement!):
+**
+** 1. If iCol is already the left-most column of some other index,
+** then return false.
+**
+** 2. If iCol is part of an existing index that has an aiRowLogEst of
+** more than 20, then return false.
+**
+** 3. If no disqualifying conditions above are found, return true.
+*/
+static SQLITE_NOINLINE int columnIsGoodIndexCandidate(
+ const Table *pTab,
+ int iCol
+){
+ const Index *pIdx;
+ for(pIdx = pTab->pIndex; pIdx!=0; pIdx=pIdx->pNext){
+ int j;
+ for(j=0; j<pIdx->nKeyCol; j++){
+ if( pIdx->aiColumn[j]==iCol ){
+ if( j==0 ) return 0;
+ if( pIdx->hasStat1 && pIdx->aiRowLogEst[j+1]>20 ) return 0;
+ break;
+ }
+ }
+ }
+ return 1;
+}
+#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
+
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -157835,6 +164271,8 @@ static int termCanDriveIndex(
const Bitmask notReady /* Tables in outer loops of the join */
){
char aff;
+ int leftCol;
+
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
assert( (pSrc->fg.jointype & JT_RIGHT)==0 );
@@ -157845,11 +164283,12 @@ static int termCanDriveIndex(
}
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
- if( pTerm->u.x.leftColumn<0 ) return 0;
- aff = pSrc->pTab->aCol[pTerm->u.x.leftColumn].affinity;
+ leftCol = pTerm->u.x.leftColumn;
+ if( leftCol<0 ) return 0;
+ aff = pSrc->pSTab->aCol[leftCol].affinity;
if( !wx_sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
testcase( pTerm->pExpr->op==TK_IS );
- return 1;
+ return columnIsGoodIndexCandidate(pSrc->pSTab, leftCol);
}
#endif
@@ -157874,7 +164313,7 @@ static void explainAutomaticIndex(
int bPartial, /* True if pIdx is a partial index */
int *pAddrExplain /* OUT: Address of OP_Explain */
){
- if( pParse->explain!=2 ){
+ if( IS_STMT_SCANSTATUS(pParse->db) && pParse->explain!=2 ){
Table *pTab = pIdx->pTable;
const char *zSep = "";
char *zText = 0;
@@ -157913,8 +164352,7 @@ static void explainAutomaticIndex(
*/
static SQLITE_NOINLINE void constructAutomaticIndex(
Parse *pParse, /* The parsing context */
- const WhereClause *pWC, /* The WHERE clause */
- const SrcItem *pSrc, /* The FROM clause term to get the next index */
+ WhereClause *pWC, /* The WHERE clause */
const Bitmask notReady, /* Mask of cursors that are not available */
WhereLevel *pLevel /* Write new index here */
){
@@ -157935,10 +164373,12 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
char *zNotUsed; /* Extra space on the end of pIdx */
Bitmask idxCols; /* Bitmap of columns used for indexing */
Bitmask extraCols; /* Bitmap of additional columns */
- u8 sentWarning = 0; /* True if a warnning has been issued */
+ u8 sentWarning = 0; /* True if a warning has been issued */
+ u8 useBloomFilter = 0; /* True to also add a Bloom filter */
Expr *pPartial = 0; /* Partial Index Expression */
int iContinue = 0; /* Jump here to skip excluded rows */
- SrcItem *pTabItem; /* FROM clause term being indexed */
+ SrcList *pTabList; /* The complete FROM clause */
+ SrcItem *pSrc; /* The FROM clause term to get the next index */
int addrCounter = 0; /* Address where integer counter is initialized */
int regBase; /* Array of registers where record is assembled */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
@@ -157954,7 +164394,9 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
/* Count the number of columns that will be added to the index
** and used to match WHERE clause constraints */
nKeyCol = 0;
- pTable = pSrc->pTab;
+ pTabList = pWC->pWInfo->pTabList;
+ pSrc = &pTabList->a[pLevel->iFrom];
+ pTable = pSrc->pSTab;
pWCEnd = &pWC->a[pWC->nTerm];
pLoop = pLevel->pWLoop;
idxCols = 0;
@@ -157964,7 +164406,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** WHERE clause (or the ON clause of a LEFT join) that constrain which
** rows of the target table (pSrc) that can be used. */
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && wx_sqlite3ExprIsTableConstraint(pExpr, pSrc)
+ && wx_sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom, 0)
){
pPartial = wx_sqlite3ExprAnd(pParse, pPartial,
wx_sqlite3ExprDup(pParse->db, pExpr, 0));
@@ -158005,7 +164447,11 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** original table changes and the index and table cannot both be used
** if they go out of sync.
*/
- extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
+ if( IsView(pTable) ){
+ extraCols = ALLBITS & ~idxCols;
+ }else{
+ extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
+ }
mxBitCol = MIN(BMS-1,pTable->nCol);
testcase( pTable->nCol==BMS-1 );
testcase( pTable->nCol==BMS-2 );
@@ -158041,6 +164487,16 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */
pIdx->azColl[n] = pColl ? pColl->zName : wx_sqlite3StrBINARY;
n++;
+ if( ALWAYS(pX->pLeft!=0)
+ && wx_sqlite3ExprAffinity(pX->pLeft)!=SQLITE_AFF_TEXT
+ ){
+ /* TUNING: only use a Bloom filter on an automatic index
+ ** if one or more key columns has the ability to hold numeric
+ ** values, since strings all have the same hash in the Bloom
+ ** filter implementation and hence a Bloom filter on a text column
+ ** is not usually helpful. */
+ useBloomFilter = 1;
+ }
}
}
}
@@ -158073,20 +164529,26 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
wx_sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1);
wx_sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "for %s", pTable->zName));
- if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){
+ if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) && useBloomFilter ){
+ wx_sqlite3WhereExplainBloomFilter(pParse, pWC->pWInfo, pLevel);
pLevel->regFilter = ++pParse->nMem;
wx_sqlite3VdbeAddOp2(v, OP_Blob, 10000, pLevel->regFilter);
}
/* Fill the automatic index with content */
- pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
- if( pTabItem->fg.viaCoroutine ){
- int regYield = pTabItem->regReturn;
+ assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] );
+ if( pSrc->fg.viaCoroutine ){
+ int regYield;
+ Subquery *pSubq;
+ assert( pSrc->fg.isSubquery );
+ pSubq = pSrc->u4.pSubq;
+ assert( pSubq!=0 );
+ regYield = pSubq->regReturn;
addrCounter = wx_sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
- wx_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
+ wx_sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub);
addrTop = wx_sqlite3VdbeAddOp1(v, OP_Yield, regYield);
VdbeCoverage(v);
- VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
+ VdbeComment((v, "next row of %s", pSrc->pSTab->zName));
}else{
addrTop = wx_sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
}
@@ -158107,14 +164569,15 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
wx_sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
wx_sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) wx_sqlite3VdbeResolveLabel(v, iContinue);
- if( pTabItem->fg.viaCoroutine ){
+ if( pSrc->fg.viaCoroutine ){
+ assert( pSrc->fg.isSubquery && pSrc->u4.pSubq!=0 );
wx_sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
testcase( pParse->db->mallocFailed );
assert( pLevel->iIdxCur>0 );
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
- pTabItem->regResult, pLevel->iIdxCur);
+ pSrc->u4.pSubq->regResult, pLevel->iIdxCur);
wx_sqlite3VdbeGoto(v, addrTop);
- pTabItem->fg.viaCoroutine = 0;
+ pSrc->fg.viaCoroutine = 0;
}else{
wx_sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
wx_sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
@@ -158167,19 +164630,25 @@ static SQLITE_NOINLINE void wx_sqlite3ConstructBloomFilter(
WhereLoop *pLoop = pLevel->pWLoop; /* The loop being coded */
int iCur; /* Cursor for table getting the filter */
IndexedExpr *saved_pIdxEpr; /* saved copy of Parse.pIdxEpr */
+ IndexedExpr *saved_pIdxPartExpr; /* saved copy of Parse.pIdxPartExpr */
saved_pIdxEpr = pParse->pIdxEpr;
+ saved_pIdxPartExpr = pParse->pIdxPartExpr;
pParse->pIdxEpr = 0;
+ pParse->pIdxPartExpr = 0;
assert( pLoop!=0 );
assert( v!=0 );
assert( pLoop->wsFlags & WHERE_BLOOMFILTER );
+ assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 );
addrOnce = wx_sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
do{
+ const SrcList *pTabList;
const SrcItem *pItem;
const Table *pTab;
u64 sz;
+ int iSrc;
wx_sqlite3WhereExplainBloomFilter(pParse, pWInfo, pLevel);
addrCont = wx_sqlite3VdbeMakeLabel(pParse);
iCur = pLevel->iTabCur;
@@ -158193,9 +164662,11 @@ static SQLITE_NOINLINE void wx_sqlite3ConstructBloomFilter(
** testing complicated. By basing the blob size on the value in the
** sqlite_stat1 table, testing is much easier.
*/
- pItem = &pWInfo->pTabList->a[pLevel->iFrom];
+ pTabList = pWInfo->pTabList;
+ iSrc = pLevel->iFrom;
+ pItem = &pTabList->a[iSrc];
assert( pItem!=0 );
- pTab = pItem->pTab;
+ pTab = pItem->pSTab;
assert( pTab!=0 );
sz = wx_sqlite3LogEstToInt(pTab->nRowLogEst);
if( sz<10000 ){
@@ -158210,7 +164681,7 @@ static SQLITE_NOINLINE void wx_sqlite3ConstructBloomFilter(
for(pTerm=pWInfo->sWC.a; pTerm<pWCEnd; pTerm++){
Expr *pExpr = pTerm->pExpr;
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && wx_sqlite3ExprIsTableConstraint(pExpr, pItem)
+ && wx_sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc, 0)
){
wx_sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
}
@@ -158226,7 +164697,7 @@ static SQLITE_NOINLINE void wx_sqlite3ConstructBloomFilter(
int r1 = wx_sqlite3GetTempRange(pParse, n);
int jj;
for(jj=0; jj<n; jj++){
- assert( pIdx->pTable==pItem->pTab );
+ assert( pIdx->pTable==pItem->pSTab );
wx_sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
}
wx_sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
@@ -158259,11 +164730,26 @@ static SQLITE_NOINLINE void wx_sqlite3ConstructBloomFilter(
}while( iLevel < pWInfo->nLevel );
wx_sqlite3VdbeJumpHere(v, addrOnce);
pParse->pIdxEpr = saved_pIdxEpr;
+ pParse->pIdxPartExpr = saved_pIdxPartExpr;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
+** Return term iTerm of the WhereClause passed as the first argument. Terms
+** are numbered from 0 upwards, starting with the terms in pWC->a[], then
+** those in pWC->pOuter->a[] (if any), and so on.
+*/
+static WhereTerm *termFromWhereClause(WhereClause *pWC, int iTerm){
+ WhereClause *p;
+ for(p=pWC; p; p=p->pOuter){
+ if( iTerm<p->nTerm ) return &p->a[iTerm];
+ iTerm -= p->nTerm;
+ }
+ return 0;
+}
+
+/*
** Allocate and populate an wx_sqlite3_index_info structure. It is the
** responsibility of the caller to eventually release the structure
** by passing the pointer returned by this function to freeIndexInfo().
@@ -158289,9 +164775,10 @@ static wx_sqlite3_index_info *allocateIndexInfo(
const Table *pTab;
int eDistinct = 0;
ExprList *pOrderBy = pWInfo->pOrderBy;
+ WhereClause *p;
assert( pSrc!=0 );
- pTab = pSrc->pTab;
+ pTab = pSrc->pSTab;
assert( pTab!=0 );
assert( IsVirtual(pTab) );
@@ -158299,28 +164786,30 @@ static wx_sqlite3_index_info *allocateIndexInfo(
** Mark each term with the TERM_OK flag. Set nTerm to the number of
** terms found.
*/
- for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
- pTerm->wtFlags &= ~TERM_OK;
- if( pTerm->leftCursor != pSrc->iCursor ) continue;
- if( pTerm->prereqRight & mUnusable ) continue;
- assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
- testcase( pTerm->eOperator & WO_IN );
- testcase( pTerm->eOperator & WO_ISNULL );
- testcase( pTerm->eOperator & WO_IS );
- testcase( pTerm->eOperator & WO_ALL );
- if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
- if( pTerm->wtFlags & TERM_VNULL ) continue;
+ for(p=pWC, nTerm=0; p; p=p->pOuter){
+ for(i=0, pTerm=p->a; i<p->nTerm; i++, pTerm++){
+ pTerm->wtFlags &= ~TERM_OK;
+ if( pTerm->leftCursor != pSrc->iCursor ) continue;
+ if( pTerm->prereqRight & mUnusable ) continue;
+ assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
+ testcase( pTerm->eOperator & WO_IN );
+ testcase( pTerm->eOperator & WO_ISNULL );
+ testcase( pTerm->eOperator & WO_IS );
+ testcase( pTerm->eOperator & WO_ALL );
+ if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
+ if( pTerm->wtFlags & TERM_VNULL ) continue;
- assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
- assert( pTerm->u.x.leftColumn>=XN_ROWID );
- assert( pTerm->u.x.leftColumn<pTab->nCol );
- if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
- && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
- ){
- continue;
+ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
+ assert( pTerm->u.x.leftColumn>=XN_ROWID );
+ assert( pTerm->u.x.leftColumn<pTab->nCol );
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
+ ){
+ continue;
+ }
+ nTerm++;
+ pTerm->wtFlags |= TERM_OK;
}
- nTerm++;
- pTerm->wtFlags |= TERM_OK;
}
/* If the ORDER BY clause contains only columns in the current
@@ -158335,7 +164824,7 @@ static wx_sqlite3_index_info *allocateIndexInfo(
Expr *pE2;
/* Skip over constant terms in the ORDER BY clause */
- if( wx_sqlite3ExprIsConstant(pExpr) ){
+ if( wx_sqlite3ExprIsConstant(0, pExpr) ){
continue;
}
@@ -158370,7 +164859,7 @@ static wx_sqlite3_index_info *allocateIndexInfo(
}
if( i==n ){
nOrderBy = n;
- if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) ){
+ if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) && !pSrc->fg.rowidUsed ){
eDistinct = 2 + ((pWInfo->wctrlFlags & WHERE_SORTBYGROUP)!=0);
}else if( pWInfo->wctrlFlags & WHERE_GROUPBY ){
eDistinct = 1;
@@ -158395,59 +164884,75 @@ static wx_sqlite3_index_info *allocateIndexInfo(
pIdxInfo->aConstraint = pIdxCons;
pIdxInfo->aOrderBy = pIdxOrderBy;
pIdxInfo->aConstraintUsage = pUsage;
+ pIdxInfo->colUsed = (wx_sqlite3_int64)pSrc->colUsed;
+ if( HasRowid(pTab)==0 ){
+ /* Ensure that all bits associated with PK columns are set. This is to
+ ** ensure they are available for cases like RIGHT joins or OR loops. */
+ Index *pPk = wx_sqlite3PrimaryKeyIndex((Table*)pTab);
+ assert( pPk!=0 );
+ for(i=0; i<pPk->nKeyCol; i++){
+ int iCol = pPk->aiColumn[i];
+ assert( iCol>=0 );
+ if( iCol>=BMS-1 ) iCol = BMS-1;
+ pIdxInfo->colUsed |= MASKBIT(iCol);
+ }
+ }
pHidden->pWC = pWC;
pHidden->pParse = pParse;
pHidden->eDistinct = eDistinct;
pHidden->mIn = 0;
- for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
- u16 op;
- if( (pTerm->wtFlags & TERM_OK)==0 ) continue;
- pIdxCons[j].iColumn = pTerm->u.x.leftColumn;
- pIdxCons[j].iTermOffset = i;
- op = pTerm->eOperator & WO_ALL;
- if( op==WO_IN ){
- if( (pTerm->wtFlags & TERM_SLICE)==0 ){
- pHidden->mIn |= SMASKBIT32(j);
- }
- op = WO_EQ;
- }
- if( op==WO_AUX ){
- pIdxCons[j].op = pTerm->eMatchOp;
- }else if( op & (WO_ISNULL|WO_IS) ){
- if( op==WO_ISNULL ){
- pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL;
+ for(p=pWC, i=j=0; p; p=p->pOuter){
+ int nLast = i+p->nTerm;;
+ for(pTerm=p->a; i<nLast; i++, pTerm++){
+ u16 op;
+ if( (pTerm->wtFlags & TERM_OK)==0 ) continue;
+ pIdxCons[j].iColumn = pTerm->u.x.leftColumn;
+ pIdxCons[j].iTermOffset = i;
+ op = pTerm->eOperator & WO_ALL;
+ if( op==WO_IN ){
+ if( (pTerm->wtFlags & TERM_SLICE)==0 ){
+ pHidden->mIn |= SMASKBIT32(j);
+ }
+ op = WO_EQ;
+ }
+ if( op==WO_AUX ){
+ pIdxCons[j].op = pTerm->eMatchOp;
+ }else if( op & (WO_ISNULL|WO_IS) ){
+ if( op==WO_ISNULL ){
+ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL;
+ }else{
+ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS;
+ }
}else{
- pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS;
- }
- }else{
- pIdxCons[j].op = (u8)op;
- /* The direct assignment in the previous line is possible only because
- ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
- ** following asserts verify this fact. */
- assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
- assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
- assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
- assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
- assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
- assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) );
-
- if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
- && wx_sqlite3ExprIsVector(pTerm->pExpr->pRight)
- ){
- testcase( j!=i );
- if( j<16 ) mNoOmit |= (1 << j);
- if( op==WO_LT ) pIdxCons[j].op = WO_LE;
- if( op==WO_GT ) pIdxCons[j].op = WO_GE;
+ pIdxCons[j].op = (u8)op;
+ /* The direct assignment in the previous line is possible only because
+ ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
+ ** following asserts verify this fact. */
+ assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
+ assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
+ assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
+ assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
+ assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
+ assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) );
+
+ if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
+ && wx_sqlite3ExprIsVector(pTerm->pExpr->pRight)
+ ){
+ testcase( j!=i );
+ if( j<16 ) mNoOmit |= (1 << j);
+ if( op==WO_LT ) pIdxCons[j].op = WO_LE;
+ if( op==WO_GT ) pIdxCons[j].op = WO_GE;
+ }
}
- }
- j++;
+ j++;
+ }
}
assert( j==nTerm );
pIdxInfo->nConstraint = j;
for(i=j=0; i<nOrderBy; i++){
Expr *pExpr = pOrderBy->a[i].pExpr;
- if( wx_sqlite3ExprIsConstant(pExpr) ) continue;
+ if( wx_sqlite3ExprIsConstant(0, pExpr) ) continue;
assert( pExpr->op==TK_COLUMN
|| (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN
&& pExpr->iColumn==pExpr->pLeft->iColumn) );
@@ -158462,6 +164967,17 @@ static wx_sqlite3_index_info *allocateIndexInfo(
}
/*
+** Free and zero the wx_sqlite3_index_info.idxStr value if needed.
+*/
+static void freeIdxStr(wx_sqlite3_index_info *pIdxInfo){
+ if( pIdxInfo->needToFreeIdxStr ){
+ wx_sqlite3_free(pIdxInfo->idxStr);
+ pIdxInfo->idxStr = 0;
+ pIdxInfo->needToFreeIdxStr = 0;
+ }
+}
+
+/*
** Free an wx_sqlite3_index_info structure allocated by allocateIndexInfo()
** and possibly modified by xBestIndex methods.
*/
@@ -158476,6 +164992,7 @@ static void freeIndexInfo(wx_sqlite3 *db, wx_sqlite3_index_info *pIdxInfo){
wx_sqlite3ValueFree(pHidden->aRhs[i]); /* IMP: R-14553-25174 */
pHidden->aRhs[i] = 0;
}
+ freeIdxStr(pIdxInfo);
wx_sqlite3DbFree(db, pIdxInfo);
}
@@ -158496,14 +165013,16 @@ static void freeIndexInfo(wx_sqlite3 *db, wx_sqlite3_index_info *pIdxInfo){
** that this is required.
*/
static int vtabBestIndex(Parse *pParse, Table *pTab, wx_sqlite3_index_info *p){
- wx_sqlite3_vtab *pVtab = wx_sqlite3GetVTable(pParse->db, pTab)->pVtab;
int rc;
+ wx_sqlite3_vtab *pVtab;
- whereTraceIndexInfoInputs(p);
+ assert( IsVirtual(pTab) );
+ pVtab = wx_sqlite3GetVTable(pParse->db, pTab)->pVtab;
+ whereTraceIndexInfoInputs(p, pTab);
pParse->db->nSchemaLock++;
rc = pVtab->pModule->xBestIndex(pVtab, p);
pParse->db->nSchemaLock--;
- whereTraceIndexInfoOutputs(p);
+ whereTraceIndexInfoOutputs(p, pTab);
if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){
if( rc==SQLITE_NOMEM ){
@@ -158514,6 +165033,9 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, wx_sqlite3_index_info *p){
wx_sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg);
}
}
+ if( pTab->u.vtab.p->bAllSchemas ){
+ wx_sqlite3VtabUsesAllSchemas(pParse);
+ }
wx_sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = 0;
return rc;
@@ -158771,7 +165293,7 @@ SQLITE_PRIVATE char wx_sqlite3IndexColumnAffinity(wx_sqlite3 *db, Index *pIdx, i
** Value pLoop->nOut is currently set to the estimated number of rows
** visited for scanning (a=? AND b=?). This function reduces that estimate
** by some factor to account for the (c BETWEEN ? AND ?) expression based
-** on the stat4 data for the index. this scan will be peformed multiple
+** on the stat4 data for the index. this scan will be performed multiple
** times (once for each (a,b) combination that matches a=?) is dealt with
** by the caller.
**
@@ -159023,7 +165545,8 @@ static int whereRangeScanEst(
** sample, then assume they are 4x more selective. This brings
** the estimated selectivity more in line with what it would be
** if estimated without the use of STAT4 tables. */
- if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==wx_sqlite3LogEst(4) );
+ if( iLwrIdx==iUprIdx ){ nNew -= 20; }
+ assert( 20==wx_sqlite3LogEst(4) );
}else{
nNew = 10; assert( 10==wx_sqlite3LogEst(2) );
}
@@ -159044,7 +165567,7 @@ static int whereRangeScanEst(
UNUSED_PARAMETER(pBuilder);
assert( pLower || pUpper );
#endif
- assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 );
+ assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 || pParse->nErr>0 );
nNew = whereRangeAdjust(pLower, nOut);
nNew = whereRangeAdjust(pUpper, nNew);
@@ -159247,17 +165770,34 @@ SQLITE_PRIVATE void wx_sqlite3WhereClausePrint(WhereClause *pWC){
#ifdef WHERETRACE_ENABLED
/*
** Print a WhereLoop object for debugging purposes
-*/
-SQLITE_PRIVATE void wx_sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
- WhereInfo *pWInfo = pWC->pWInfo;
- int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
- SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
- Table *pTab = pItem->pTab;
- Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
- wx_sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
- p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
- wx_sqlite3DebugPrintf(" %12s",
- pItem->zAlias ? pItem->zAlias : pTab->zName);
+**
+** Format example:
+**
+** .--- Position in WHERE clause rSetup, rRun, nOut ---.
+** | |
+** | .--- selfMask nTerm ------. |
+** | | | |
+** | | .-- prereq Idx wsFlags----. | |
+** | | | Name | | |
+** | | | __|__ nEq ---. ___|__ | __|__
+** | / \ / \ / \ | / \ / \ / \
+** 1.002.001 t2.t2xy 2 f 010241 N 2 cost 0,56,31
+*/
+SQLITE_PRIVATE void wx_sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
+ if( pWC ){
+ WhereInfo *pWInfo = pWC->pWInfo;
+ int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
+ SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
+ Table *pTab = pItem->pSTab;
+ Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
+ wx_sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
+ p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
+ wx_sqlite3DebugPrintf(" %12s",
+ pItem->zAlias ? pItem->zAlias : pTab->zName);
+ }else{
+ wx_sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d",
+ p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab);
+ }
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
const char *zName;
if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
@@ -159294,6 +165834,15 @@ SQLITE_PRIVATE void wx_sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
}
}
}
+SQLITE_PRIVATE void wx_sqlite3ShowWhereLoop(const WhereLoop *p){
+ if( p ) wx_sqlite3WhereLoopPrint(p, 0);
+}
+SQLITE_PRIVATE void wx_sqlite3ShowWhereLoopList(const WhereLoop *p){
+ while( p ){
+ wx_sqlite3ShowWhereLoop(p);
+ p = p->pNextLoop;
+ }
+}
#endif
/*
@@ -159406,46 +165955,60 @@ static void whereInfoFree(wx_sqlite3 *db, WhereInfo *pWInfo){
}
/*
-** Return TRUE if all of the following are true:
+** Return TRUE if X is a proper subset of Y but is of equal or less cost.
+** In other words, return true if all constraints of X are also part of Y
+** and Y has additional constraints that might speed the search that X lacks
+** but the cost of running X is not more than the cost of running Y.
+**
+** In other words, return true if the cost relationship between X and Y
+** is inverted and needs to be adjusted.
+**
+** Case 1:
**
-** (1) X has the same or lower cost, or returns the same or fewer rows,
-** than Y.
-** (2) X uses fewer WHERE clause terms than Y
-** (3) Every WHERE clause term used by X is also used by Y
-** (4) X skips at least as many columns as Y
-** (5) If X is a covering index, than Y is too
+** (1a) X and Y use the same index.
+** (1b) X has fewer == terms than Y
+** (1c) Neither X nor Y use skip-scan
+** (1d) X does not have a a greater cost than Y
**
-** Conditions (2) and (3) mean that X is a "proper subset" of Y.
-** If X is a proper subset of Y then Y is a better choice and ought
-** to have a lower cost. This routine returns TRUE when that cost
-** relationship is inverted and needs to be adjusted. Constraint (4)
-** was added because if X uses skip-scan less than Y it still might
-** deserve a lower cost even if it is a proper subset of Y. Constraint (5)
-** was added because a covering index probably deserves to have a lower cost
-** than a non-covering index even if it is a proper subset.
+** Case 2:
+**
+** (2a) X has the same or lower cost, or returns the same or fewer rows,
+** than Y.
+** (2b) X uses fewer WHERE clause terms than Y
+** (2c) Every WHERE clause term used by X is also used by Y
+** (2d) X skips at least as many columns as Y
+** (2e) If X is a covering index, than Y is too
*/
static int whereLoopCheaperProperSubset(
const WhereLoop *pX, /* First WhereLoop to compare */
const WhereLoop *pY /* Compare against this WhereLoop */
){
int i, j;
+ if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; /* (1d) and (2a) */
+ assert( (pX->wsFlags & WHERE_VIRTUALTABLE)==0 );
+ assert( (pY->wsFlags & WHERE_VIRTUALTABLE)==0 );
+ if( pX->u.btree.nEq < pY->u.btree.nEq /* (1b) */
+ && pX->u.btree.pIndex==pY->u.btree.pIndex /* (1a) */
+ && pX->nSkip==0 && pY->nSkip==0 /* (1c) */
+ ){
+ return 1; /* Case 1 is true */
+ }
if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
- return 0; /* X is not a subset of Y */
+ return 0; /* (2b) */
}
- if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0;
- if( pY->nSkip > pX->nSkip ) return 0;
+ if( pY->nSkip > pX->nSkip ) return 0; /* (2d) */
for(i=pX->nLTerm-1; i>=0; i--){
if( pX->aLTerm[i]==0 ) continue;
for(j=pY->nLTerm-1; j>=0; j--){
if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
}
- if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */
+ if( j<0 ) return 0; /* (2c) */
}
if( (pX->wsFlags&WHERE_IDX_ONLY)!=0
&& (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
- return 0; /* Constraint (5) */
+ return 0; /* (2e) */
}
- return 1; /* All conditions meet */
+ return 1; /* Case 2 is true */
}
/*
@@ -159526,7 +166089,7 @@ static WhereLoop **whereLoopFindLesser(
** rSetup. Call this SETUP-INVARIANT */
assert( p->rSetup>=pTemplate->rSetup );
- /* Any loop using an appliation-defined index (or PRIMARY KEY or
+ /* Any loop using an application-defined index (or PRIMARY KEY or
** UNIQUE constraint) with one or more == constraints is better
** than an automatic index. Unless it is a skip-scan. */
if( (p->wsFlags & WHERE_AUTO_INDEX)!=0
@@ -159553,7 +166116,7 @@ static WhereLoop **whereLoopFindLesser(
/* If pTemplate is always better than p, then cause p to be overwritten
** with pTemplate. pTemplate is better than p if:
- ** (1) pTemplate has no more dependences than p, and
+ ** (1) pTemplate has no more dependencies than p, and
** (2) pTemplate has an equal or lower cost than p.
*/
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */
@@ -159671,7 +166234,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
}else{
/* We will be overwriting WhereLoop p[]. But before we do, first
** go through the rest of the list and delete any other entries besides
- ** p[] that are also supplated by pTemplate */
+ ** p[] that are also supplanted by pTemplate */
WhereLoop **ppTail = &p->pNextLoop;
WhereLoop *pToDel;
while( *ppTail ){
@@ -159783,7 +166346,7 @@ static void whereLoopOutputAdjust(
Expr *pRight = pTerm->pExpr->pRight;
int k = 0;
testcase( pTerm->pExpr->op==TK_IS );
- if( wx_sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){
+ if( wx_sqlite3ExprIsInteger(pRight, &k, 0) && k>=(-1) && k<=1 ){
k = 10;
}else{
k = 20;
@@ -159871,7 +166434,7 @@ static int whereRangeVectorLen(
}
/*
-** Adjust the cost C by the costMult facter T. This only occurs if
+** Adjust the cost C by the costMult factor T. This only occurs if
** compiled with -DSQLITE_ENABLE_COSTMULT
*/
#ifdef SQLITE_ENABLE_COSTMULT
@@ -159898,7 +166461,7 @@ static int whereLoopAddBtreeIndex(
Index *pProbe, /* An index on pSrc */
LogEst nInMul /* log(Number of iterations due to IN) */
){
- WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */
+ WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyze context */
Parse *pParse = pWInfo->pParse; /* Parsing context */
wx_sqlite3 *db = pParse->db; /* Database connection malloc context */
WhereLoop *pNew; /* Template WhereLoop under construction */
@@ -159935,7 +166498,12 @@ static int whereLoopAddBtreeIndex(
assert( pNew->u.btree.nBtm==0 );
opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
}
- if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
+ if( pProbe->bUnordered || pProbe->bLowQual ){
+ if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
+ if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){
+ opMask &= ~(WO_EQ|WO_IN|WO_IS);
+ }
+ }
assert( pNew->u.btree.nEq<pProbe->nColumn );
assert( pNew->u.btree.nEq<pProbe->nKeyCol
@@ -160075,7 +166643,7 @@ static int whereLoopAddBtreeIndex(
|| (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
){
if( iCol==XN_ROWID || pProbe->uniqNotNull
- || (pProbe->nKeyCol==1 && pProbe->onError && eOp==WO_EQ)
+ || (pProbe->nKeyCol==1 && pProbe->onError && (eOp & WO_EQ))
){
pNew->wsFlags |= WHERE_ONEROW;
}else{
@@ -160201,21 +166769,32 @@ static int whereLoopAddBtreeIndex(
}
}
- /* Set rCostIdx to the cost of visiting selected rows in index. Add
- ** it to pNew->rRun, which is currently set to the cost of the index
- ** seek only. Then, if this is a non-covering index, add the cost of
- ** visiting the rows in the main table. */
- assert( pSrc->pTab->szTabRow>0 );
+ /* Set rCostIdx to the estimated cost of visiting selected rows in the
+ ** index. The estimate is the sum of two values:
+ ** 1. The cost of doing one search-by-key to find the first matching
+ ** entry
+ ** 2. Stepping forward in the index pNew->nOut times to find all
+ ** additional matching entries.
+ */
+ assert( pSrc->pSTab->szTabRow>0 );
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
/* The pProbe->szIdxRow is low for an IPK table since the interior
- ** pages are small. Thuse szIdxRow gives a good estimate of seek cost.
+ ** pages are small. Thus szIdxRow gives a good estimate of seek cost.
** But the leaf pages are full-size, so pProbe->szIdxRow would badly
** under-estimate the scanning cost. */
rCostIdx = pNew->nOut + 16;
}else{
- rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
+ rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pSTab->szTabRow;
}
- pNew->rRun = wx_sqlite3LogEstAdd(rLogSize, rCostIdx);
+ rCostIdx = wx_sqlite3LogEstAdd(rLogSize, rCostIdx);
+
+ /* Estimate the cost of running the loop. If all data is coming
+ ** from the index, then this is just the cost of doing the index
+ ** lookup and scan. But if some data is coming out of the main table,
+ ** we also have to add in the cost of doing pNew->nOut searches to
+ ** locate the row in the main table that corresponds to the index entry.
+ */
+ pNew->rRun = rCostIdx;
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK|WHERE_EXPRIDX))==0 ){
pNew->rRun = wx_sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16);
}
@@ -160321,7 +166900,9 @@ static int indexMightHelpWithOrderBy(
for(ii=0; ii<pOB->nExpr; ii++){
Expr *pExpr = wx_sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr);
if( NEVER(pExpr==0) ) continue;
- if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){
+ if( (pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN)
+ && pExpr->iTable==iCursor
+ ){
if( pExpr->iColumn<0 ) return 1;
for(jj=0; jj<pIndex->nKeyCol; jj++){
if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1;
@@ -160516,6 +167097,100 @@ static SQLITE_NOINLINE u32 whereIsCoveringIndex(
}
/*
+** This is an wx_sqlite3ParserAddCleanup() callback that is invoked to
+** free the Parse->pIdxEpr list when the Parse object is destroyed.
+*/
+static void whereIndexedExprCleanup(wx_sqlite3 *db, void *pObject){
+ IndexedExpr **pp = (IndexedExpr**)pObject;
+ while( *pp!=0 ){
+ IndexedExpr *p = *pp;
+ *pp = p->pIENext;
+ wx_sqlite3ExprDelete(db, p->pExpr);
+ wx_sqlite3DbFreeNN(db, p);
+ }
+}
+
+/*
+** This function is called for a partial index - one with a WHERE clause - in
+** two scenarios. In both cases, it determines whether or not the WHERE
+** clause on the index implies that a column of the table may be safely
+** replaced by a constant expression. For example, in the following
+** SELECT:
+**
+** CREATE INDEX i1 ON t1(b, c) WHERE a=<expr>;
+** SELECT a, b, c FROM t1 WHERE a=<expr> AND b=?;
+**
+** The "a" in the select-list may be replaced by <expr>, iff:
+**
+** (a) <expr> is a constant expression, and
+** (b) The (a=<expr>) comparison uses the BINARY collation sequence, and
+** (c) Column "a" has an affinity other than NONE or BLOB.
+**
+** If argument pItem is NULL, then pMask must not be NULL. In this case this
+** function is being called as part of determining whether or not pIdx
+** is a covering index. This function clears any bits in (*pMask)
+** corresponding to columns that may be replaced by constants as described
+** above.
+**
+** Otherwise, if pItem is not NULL, then this function is being called
+** as part of coding a loop that uses index pIdx. In this case, add entries
+** to the Parse.pIdxPartExpr list for each column that can be replaced
+** by a constant.
+*/
+static void wherePartIdxExpr(
+ Parse *pParse, /* Parse context */
+ Index *pIdx, /* Partial index being processed */
+ Expr *pPart, /* WHERE clause being processed */
+ Bitmask *pMask, /* Mask to clear bits in */
+ int iIdxCur, /* Cursor number for index */
+ SrcItem *pItem /* The FROM clause entry for the table */
+){
+ assert( pItem==0 || (pItem->fg.jointype & JT_RIGHT)==0 );
+ assert( (pItem==0 || pMask==0) && (pMask!=0 || pItem!=0) );
+
+ if( pPart->op==TK_AND ){
+ wherePartIdxExpr(pParse, pIdx, pPart->pRight, pMask, iIdxCur, pItem);
+ pPart = pPart->pLeft;
+ }
+
+ if( (pPart->op==TK_EQ || pPart->op==TK_IS) ){
+ Expr *pLeft = pPart->pLeft;
+ Expr *pRight = pPart->pRight;
+ u8 aff;
+
+ if( pLeft->op!=TK_COLUMN ) return;
+ if( !wx_sqlite3ExprIsConstant(0, pRight) ) return;
+ if( !wx_sqlite3IsBinary(wx_sqlite3ExprCompareCollSeq(pParse, pPart)) ) return;
+ if( pLeft->iColumn<0 ) return;
+ aff = pIdx->pTable->aCol[pLeft->iColumn].affinity;
+ if( aff>=SQLITE_AFF_TEXT ){
+ if( pItem ){
+ wx_sqlite3 *db = pParse->db;
+ IndexedExpr *p = (IndexedExpr*)wx_sqlite3DbMallocRaw(db, sizeof(*p));
+ if( p ){
+ int bNullRow = (pItem->fg.jointype&(JT_LEFT|JT_LTORJ))!=0;
+ p->pExpr = wx_sqlite3ExprDup(db, pRight, 0);
+ p->iDataCur = pItem->iCursor;
+ p->iIdxCur = iIdxCur;
+ p->iIdxCol = pLeft->iColumn;
+ p->bMaybeNullRow = bNullRow;
+ p->pIENext = pParse->pIdxPartExpr;
+ p->aff = aff;
+ pParse->pIdxPartExpr = p;
+ if( p->pIENext==0 ){
+ void *pArg = (void*)&pParse->pIdxPartExpr;
+ wx_sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg);
+ }
+ }
+ }else if( pLeft->iColumn<(BMS-1) ){
+ *pMask &= ~((Bitmask)1 << pLeft->iColumn);
+ }
+ }
+ }
+}
+
+
+/*
** Add all WhereLoop objects for a single table of the join where the table
** is identified by pBuilder->pNew->iTab. That table is guaranteed to be
** a b-tree table, not a virtual table.
@@ -160553,7 +167228,7 @@ static SQLITE_NOINLINE u32 whereIsCoveringIndex(
*/
static int whereLoopAddBtree(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
- Bitmask mPrereq /* Extra prerequesites for using this table */
+ Bitmask mPrereq /* Extra prerequisites for using this table */
){
WhereInfo *pWInfo; /* WHERE analysis context */
Index *pProbe; /* An index we are evaluating */
@@ -160574,9 +167249,9 @@ static int whereLoopAddBtree(
pWInfo = pBuilder->pWInfo;
pTabList = pWInfo->pTabList;
pSrc = pTabList->a + pNew->iTab;
- pTab = pSrc->pTab;
+ pTab = pSrc->pSTab;
pWC = pBuilder->pWC;
- assert( !IsVirtual(pSrc->pTab) );
+ assert( !IsVirtual(pSrc->pSTab) );
if( pSrc->fg.isIndexedBy ){
assert( pSrc->fg.isCte==0 );
@@ -160601,7 +167276,7 @@ static int whereLoopAddBtree(
sPk.idxType = SQLITE_IDXTYPE_IPK;
aiRowEstPk[0] = pTab->nRowLogEst;
aiRowEstPk[1] = 0;
- pFirst = pSrc->pTab->pIndex;
+ pFirst = pSrc->pSTab->pIndex;
if( pSrc->fg.notIndexed==0 ){
/* The real indices of the table are only considered if the
** NOT INDEXED qualifier is omitted from the FROM clause */
@@ -160691,6 +167366,7 @@ static int whereLoopAddBtree(
pNew->prereq = mPrereq;
pNew->nOut = rSize;
pNew->u.btree.pIndex = pProbe;
+ pNew->u.btree.pOrderBy = 0;
b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
/* The ONEPASS_DESIRED flags never occurs together with ORDER BY */
@@ -160718,11 +167394,12 @@ static int whereLoopAddBtree(
#else
pNew->rRun = rSize + 16;
#endif
- if( IsView(pTab) || (pTab->tabFlags & TF_Ephemeral)!=0 ){
- pNew->wsFlags |= WHERE_VIEWSCAN;
- }
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew, rSize);
+ if( pSrc->fg.isSubquery ){
+ if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE;
+ pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
+ }
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
@@ -160733,6 +167410,11 @@ static int whereLoopAddBtree(
pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
}else{
m = pSrc->colUsed & pProbe->colNotIdxed;
+ if( pProbe->pPartIdxWhere ){
+ wherePartIdxExpr(
+ pWInfo->pParse, pProbe, pProbe->pPartIdxWhere, &m, 0, 0
+ );
+ }
pNew->wsFlags = WHERE_INDEXED;
if( m==TOPBIT || (pProbe->bHasExpr && !pProbe->bHasVCol && m!=0) ){
u32 isCov = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor);
@@ -160755,7 +167437,9 @@ static int whereLoopAddBtree(
" according to whereIsCoveringIndex()\n", pProbe->zName));
}
}
- }else if( m==0 ){
+ }else if( m==0
+ && (HasRowid(pTab) || pWInfo->pSelect!=0 || wx_sqlite3FaultSim(700))
+ ){
WHERETRACE(0x200,
("-> %s a covering index according to bitmasks\n",
pProbe->zName, m==0 ? "is" : "is not"));
@@ -160831,7 +167515,7 @@ static int whereLoopAddBtree(
** unique index is used (making the index functionally non-unique)
** then the sqlite_stat1 data becomes important for scoring the
** plan */
- pTab->tabFlags |= TF_StatsUsed;
+ pTab->tabFlags |= TF_MaybeReanalyze;
}
#ifdef SQLITE_ENABLE_STAT4
wx_sqlite3Stat4ProbeFree(pBuilder->pRec);
@@ -160854,6 +167538,21 @@ static int isLimitTerm(WhereTerm *pTerm){
}
/*
+** Return true if the first nCons constraints in the pUsage array are
+** marked as in-use (have argvIndex>0). False otherwise.
+*/
+static int allConstraintsUsed(
+ struct wx_sqlite3_index_constraint_usage *aUsage,
+ int nCons
+){
+ int ii;
+ for(ii=0; ii<nCons; ii++){
+ if( aUsage[ii].argvIndex<=0 ) return 0;
+ }
+ return 1;
+}
+
+/*
** Argument pIdxInfo is already populated with all constraints that may
** be used by the virtual table identified by pBuilder->pNew->iTab. This
** function marks a subset of those constraints usable, invokes the
@@ -160903,7 +167602,7 @@ static int whereLoopAddVirtualOne(
** arguments mUsable and mExclude. */
pIdxCons = *(struct wx_sqlite3_index_constraint**)&pIdxInfo->aConstraint;
for(i=0; i<nConstraint; i++, pIdxCons++){
- WhereTerm *pTerm = &pWC->a[pIdxCons->iTermOffset];
+ WhereTerm *pTerm = termFromWhereClause(pWC, pIdxCons->iTermOffset);
pIdxCons->usable = 0;
if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight
&& (pTerm->eOperator & mExclude)==0
@@ -160922,11 +167621,10 @@ static int whereLoopAddVirtualOne(
pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
pIdxInfo->estimatedRows = 25;
pIdxInfo->idxFlags = 0;
- pIdxInfo->colUsed = (wx_sqlite3_int64)pSrc->colUsed;
pHidden->mHandleIn = 0;
/* Invoke the virtual table xBestIndex() method */
- rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
+ rc = vtabBestIndex(pParse, pSrc->pSTab, pIdxInfo);
if( rc ){
if( rc==SQLITE_CONSTRAINT ){
/* If the xBestIndex method returns SQLITE_CONSTRAINT, that means
@@ -160934,6 +167632,7 @@ static int whereLoopAddVirtualOne(
** Make no entries in the loop table.
*/
WHERETRACE(0xffffffff, (" ^^^^--- non-viable plan rejected!\n"));
+ freeIdxStr(pIdxInfo);
return SQLITE_OK;
}
return rc;
@@ -160951,18 +167650,17 @@ static int whereLoopAddVirtualOne(
int j = pIdxCons->iTermOffset;
if( iTerm>=nConstraint
|| j<0
- || j>=pWC->nTerm
+ || (pTerm = termFromWhereClause(pWC, j))==0
|| pNew->aLTerm[iTerm]!=0
|| pIdxCons->usable==0
){
- wx_sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
- testcase( pIdxInfo->needToFreeIdxStr );
+ wx_sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
+ freeIdxStr(pIdxInfo);
return SQLITE_ERROR;
}
testcase( iTerm==nConstraint-1 );
testcase( j==0 );
testcase( j==pWC->nTerm-1 );
- pTerm = &pWC->a[j];
pNew->prereq |= pTerm->prereqRight;
assert( iTerm<pNew->nLSlot );
pNew->aLTerm[iTerm] = pTerm;
@@ -160993,18 +167691,21 @@ static int whereLoopAddVirtualOne(
*pbIn = 1; assert( (mExclude & WO_IN)==0 );
}
+ /* Unless pbRetryLimit is non-NULL, there should be no LIMIT/OFFSET
+ ** terms. And if there are any, they should follow all other terms. */
assert( pbRetryLimit || !isLimitTerm(pTerm) );
- if( isLimitTerm(pTerm) && *pbIn ){
+ assert( !isLimitTerm(pTerm) || i>=nConstraint-2 );
+ assert( !isLimitTerm(pTerm) || i==nConstraint-1 || isLimitTerm(pTerm+1) );
+
+ if( isLimitTerm(pTerm) && (*pbIn || !allConstraintsUsed(pUsage, i)) ){
/* If there is an IN(...) term handled as an == (separate call to
** xFilter for each value on the RHS of the IN) and a LIMIT or
- ** OFFSET term handled as well, the plan is unusable. Set output
- ** variable *pbRetryLimit to true to tell the caller to retry with
- ** LIMIT and OFFSET disabled. */
- if( pIdxInfo->needToFreeIdxStr ){
- wx_sqlite3_free(pIdxInfo->idxStr);
- pIdxInfo->idxStr = 0;
- pIdxInfo->needToFreeIdxStr = 0;
- }
+ ** OFFSET term handled as well, the plan is unusable. Similarly,
+ ** if there is a LIMIT/OFFSET and there are other unused terms,
+ ** the plan cannot be used. In these cases set variable *pbRetryLimit
+ ** to true to tell the caller to retry with LIMIT and OFFSET
+ ** disabled. */
+ freeIdxStr(pIdxInfo);
*pbRetryLimit = 1;
return SQLITE_OK;
}
@@ -161016,8 +167717,8 @@ static int whereLoopAddVirtualOne(
if( pNew->aLTerm[i]==0 ){
/* The non-zero argvIdx values must be contiguous. Raise an
** error if they are not */
- wx_sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
- testcase( pIdxInfo->needToFreeIdxStr );
+ wx_sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
+ freeIdxStr(pIdxInfo);
return SQLITE_ERROR;
}
}
@@ -161028,6 +167729,7 @@ static int whereLoopAddVirtualOne(
pNew->u.vtab.idxStr = pIdxInfo->idxStr;
pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
pIdxInfo->nOrderBy : 0);
+ pNew->u.vtab.bIdxNumHex = (pIdxInfo->idxFlags&SQLITE_INDEX_SCAN_HEX)!=0;
pNew->rSetup = 0;
pNew->rRun = wx_sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
pNew->nOut = wx_sqlite3LogEst(pIdxInfo->estimatedRows);
@@ -161060,7 +167762,7 @@ static int whereLoopAddVirtualOne(
**
** Return a pointer to the collation name:
**
-** 1. If there is an explicit COLLATE operator on the constaint, return it.
+** 1. If there is an explicit COLLATE operator on the constraint, return it.
**
** 2. Else, if the column has an alternative collation, return that.
**
@@ -161072,7 +167774,7 @@ SQLITE_API const char *wx_sqlite3_vtab_collation(wx_sqlite3_index_info *pIdxInfo
if( iCons>=0 && iCons<pIdxInfo->nConstraint ){
CollSeq *pC = 0;
int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset;
- Expr *pX = pHidden->pWC->a[iTerm].pExpr;
+ Expr *pX = termFromWhereClause(pHidden->pWC, iTerm)->pExpr;
if( pX->pLeft ){
pC = wx_sqlite3ExprCompareCollSeq(pHidden->pParse, pX);
}
@@ -161115,10 +167817,12 @@ SQLITE_API int wx_sqlite3_vtab_rhs_value(
wx_sqlite3_value *pVal = 0;
int rc = SQLITE_OK;
if( iCons<0 || iCons>=pIdxInfo->nConstraint ){
- rc = SQLITE_MISUSE; /* EV: R-30545-25046 */
+ rc = SQLITE_MISUSE_BKPT; /* EV: R-30545-25046 */
}else{
if( pH->aRhs[iCons]==0 ){
- WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset];
+ WhereTerm *pTerm = termFromWhereClause(
+ pH->pWC, pIdxInfo->aConstraint[iCons].iTermOffset
+ );
rc = wx_sqlite3ValueFromExpr(
pH->pParse->db, pTerm->pExpr->pRight, ENC(pH->pParse->db),
SQLITE_AFF_BLOB, &pH->aRhs[iCons]
@@ -161145,8 +167849,6 @@ SQLITE_API int wx_sqlite3_vtab_distinct(wx_sqlite3_index_info *pIdxInfo){
return pHidden->eDistinct;
}
-#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
- && !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** Cause the prepared statement that is associated with a call to
** xBestIndex to potentially use all schemas. If the statement being
@@ -161156,9 +167858,7 @@ SQLITE_API int wx_sqlite3_vtab_distinct(wx_sqlite3_index_info *pIdxInfo){
**
** This is used by the (built-in) sqlite_dbpage virtual table.
*/
-SQLITE_PRIVATE void wx_sqlite3VtabUsesAllSchemas(wx_sqlite3_index_info *pIdxInfo){
- HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
- Parse *pParse = pHidden->pParse;
+SQLITE_PRIVATE void wx_sqlite3VtabUsesAllSchemas(Parse *pParse){
int nDb = pParse->db->nDb;
int i;
for(i=0; i<nDb; i++){
@@ -161170,7 +167870,6 @@ SQLITE_PRIVATE void wx_sqlite3VtabUsesAllSchemas(wx_sqlite3_index_info *pIdxInfo
}
}
}
-#endif
/*
** Add all WhereLoop objects for a table of the join identified by
@@ -161221,7 +167920,7 @@ static int whereLoopAddVirtual(
pWC = pBuilder->pWC;
pNew = pBuilder->pNew;
pSrc = &pWInfo->pTabList->a[pNew->iTab];
- assert( IsVirtual(pSrc->pTab) );
+ assert( IsVirtual(pSrc->pSTab) );
p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit);
if( p==0 ) return SQLITE_NOMEM_BKPT;
pNew->rSetup = 0;
@@ -161235,7 +167934,7 @@ static int whereLoopAddVirtual(
}
/* First call xBestIndex() with all constraints usable. */
- WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName));
+ WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pSTab->zName));
WHERETRACE(0x800, (" VirtualOne: all usable\n"));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
@@ -161279,9 +167978,8 @@ static int whereLoopAddVirtual(
Bitmask mNext = ALLBITS;
assert( mNext>0 );
for(i=0; i<nConstraint; i++){
- Bitmask mThis = (
- pWC->a[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq
- );
+ int iTerm = p->aConstraint[i].iTermOffset;
+ Bitmask mThis = termFromWhereClause(pWC, iTerm)->prereqRight & ~mPrereq;
if( mThis>mPrev && mThis<mNext ) mNext = mThis;
}
mPrev = mNext;
@@ -161317,9 +168015,8 @@ static int whereLoopAddVirtual(
}
}
- if( p->needToFreeIdxStr ) wx_sqlite3_free(p->idxStr);
freeIndexInfo(pParse->db, p);
- WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc));
+ WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pSTab->zName, rc));
return rc;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -161391,7 +168088,7 @@ static int whereLoopAddOr(
}
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( IsVirtual(pItem->pTab) ){
+ if( IsVirtual(pItem->pSTab) ){
rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable);
}else
#endif
@@ -161505,7 +168202,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
mPrereq = 0;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( IsVirtual(pItem->pTab) ){
+ if( IsVirtual(pItem->pSTab) ){
SrcItem *p;
for(p=&pItem[1]; p<pEnd; p++){
if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
@@ -161537,6 +168234,97 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
return rc;
}
+/* Implementation of the order-by-subquery optimization:
+**
+** WhereLoop pLoop, which the iLoop-th term of the nested loop, is really
+** a subquery or CTE that has an ORDER BY clause. See if any of the terms
+** in the subquery ORDER BY clause will satisfy pOrderBy from the outer
+** query. Mark off all satisfied terms (by setting bits in *pOBSat) and
+** return TRUE if they do. If not, return false.
+**
+** Example:
+**
+** CREATE TABLE t1(a,b,c, PRIMARY KEY(a,b));
+** CREATE TABLE t2(x,y);
+** WITH t3(p,q) AS MATERIALIZED (SELECT x+y, x-y FROM t2 ORDER BY x+y)
+** SELECT * FROM t3 JOIN t1 ON a=q ORDER BY p, b;
+**
+** The CTE named "t3" comes out in the natural order of "p", so the first
+** first them of "ORDER BY p,b" is satisfied by a sequential scan of "t3"
+** and sorting only needs to occur on the second term "b".
+**
+** Limitations:
+**
+** (1) The optimization is not applied if the outer ORDER BY contains
+** a COLLATE clause. The optimization might be applied if the
+** outer ORDER BY uses NULLS FIRST, NULLS LAST, ASC, and/or DESC as
+** long as the subquery ORDER BY does the same. But if the
+** outer ORDER BY uses COLLATE, even a redundant COLLATE, the
+** optimization is bypassed.
+**
+** (2) The subquery ORDER BY terms must exactly match subquery result
+** columns, including any COLLATE annotations. This routine relies
+** on iOrderByCol to do matching between order by terms and result
+** columns, and iOrderByCol will not be set if the result column
+** and ORDER BY collations differ.
+**
+** (3) The subquery and outer ORDER BY can be in opposite directions as
+** long as the subquery is materialized. If the subquery is
+** implemented as a co-routine, the sort orders must be in the same
+** direction because there is no way to run a co-routine backwards.
+*/
+static SQLITE_NOINLINE int wherePathMatchSubqueryOB(
+ WhereInfo *pWInfo, /* The WHERE clause */
+ WhereLoop *pLoop, /* The nested loop term that is a subquery */
+ int iLoop, /* Which level of the nested loop. 0==outermost */
+ int iCur, /* Cursor used by the this loop */
+ ExprList *pOrderBy, /* The ORDER BY clause on the whole query */
+ Bitmask *pRevMask, /* When loops need to go in reverse order */
+ Bitmask *pOBSat /* Which terms of pOrderBy are satisfied so far */
+){
+ int iOB; /* Index into pOrderBy->a[] */
+ int jSub; /* Index into pSubOB->a[] */
+ u8 rev = 0; /* True if iOB and jSub sort in opposite directions */
+ u8 revIdx = 0; /* Sort direction for jSub */
+ Expr *pOBExpr; /* Current term of outer ORDER BY */
+ ExprList *pSubOB; /* Complete ORDER BY on the subquery */
+
+ pSubOB = pLoop->u.btree.pOrderBy;
+ assert( pSubOB!=0 );
+ for(iOB=0; (MASKBIT(iOB) & *pOBSat)!=0; iOB++){}
+ for(jSub=0; jSub<pSubOB->nExpr && iOB<pOrderBy->nExpr; jSub++, iOB++){
+ if( pSubOB->a[jSub].u.x.iOrderByCol==0 ) break;
+ pOBExpr = pOrderBy->a[iOB].pExpr;
+ if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) break;
+ if( pOBExpr->iTable!=iCur ) break;
+ if( pOBExpr->iColumn!=pSubOB->a[jSub].u.x.iOrderByCol-1 ) break;
+ if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
+ u8 sfOB = pOrderBy->a[iOB].fg.sortFlags; /* sortFlags for iOB */
+ u8 sfSub = pSubOB->a[jSub].fg.sortFlags; /* sortFlags for jSub */
+ if( (sfSub & KEYINFO_ORDER_BIGNULL) != (sfOB & KEYINFO_ORDER_BIGNULL) ){
+ break;
+ }
+ revIdx = sfSub & KEYINFO_ORDER_DESC;
+ if( jSub>0 ){
+ if( (rev^revIdx)!=(sfOB & KEYINFO_ORDER_DESC) ){
+ break;
+ }
+ }else{
+ rev = revIdx ^ (sfOB & KEYINFO_ORDER_DESC);
+ if( rev ){
+ if( (pLoop->wsFlags & WHERE_COROUTINE)!=0 ){
+ /* Cannot run a co-routine in reverse order */
+ break;
+ }
+ *pRevMask |= MASKBIT(iLoop);
+ }
+ }
+ }
+ *pOBSat |= MASKBIT(iOB);
+ }
+ return jSub>0;
+}
+
/*
** Examine a WherePath (with the addition of the extra WhereLoop of the 6th
** parameters) to see if it outputs rows in the requested ORDER BY
@@ -161682,9 +168470,18 @@ static i8 wherePathSatisfiesOrderBy(
if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){
if( pLoop->wsFlags & WHERE_IPK ){
+ if( pLoop->u.btree.pOrderBy
+ && OptimizationEnabled(db, SQLITE_OrderBySubq)
+ && wherePathMatchSubqueryOB(pWInfo,pLoop,iLoop,iCur,
+ pOrderBy,pRevMask, &obSat)
+ ){
+ nColumn = 0;
+ isOrderDistinct = 0;
+ }else{
+ nColumn = 1;
+ }
pIndex = 0;
nKeyCol = 0;
- nColumn = 1;
}else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){
return 0;
}else{
@@ -161694,7 +168491,7 @@ static i8 wherePathSatisfiesOrderBy(
assert( pIndex->aiColumn[nColumn-1]==XN_ROWID
|| !HasRowid(pIndex->pTable));
/* All relevant terms of the index must also be non-NULL in order
- ** for isOrderDistinct to be true. So the isOrderDistint value
+ ** for isOrderDistinct to be true. So the isOrderDistinct value
** computed here might be a false positive. Corrections will be
** made at tag-20210426-1 below */
isOrderDistinct = IsUniqueIndex(pIndex)
@@ -161779,7 +168576,7 @@ static i8 wherePathSatisfiesOrderBy(
}
/* Find the ORDER BY term that corresponds to the j-th column
- ** of the index and mark that ORDER BY term off
+ ** of the index and mark that ORDER BY term having been satisfied.
*/
isMatch = 0;
for(i=0; bOnce && i<nOrderBy; i++){
@@ -161861,7 +168658,7 @@ static i8 wherePathSatisfiesOrderBy(
if( MASKBIT(i) & obSat ) continue;
p = pOrderBy->a[i].pExpr;
mTerm = wx_sqlite3WhereExprUsage(&pWInfo->sMaskSet,p);
- if( mTerm==0 && !wx_sqlite3ExprIsConstant(p) ) continue;
+ if( mTerm==0 && !wx_sqlite3ExprIsConstant(0,p) ) continue;
if( (mTerm&~orderDistinctMask)==0 ){
obSat |= MASKBIT(i);
}
@@ -161987,6 +168784,83 @@ static LogEst whereSortingCost(
}
/*
+** Compute the maximum number of paths in the solver algorithm, for
+** queries that have three or more terms in the FROM clause. Queries with
+** two or fewer FROM clause terms are handled by the caller.
+**
+** Query planning is NP-hard. We must limit the number of paths at
+** each step of the solver search algorithm to avoid exponential behavior.
+**
+** The value returned is a tuning parameter. Currently the value is:
+**
+** 18 for star queries
+** 12 otherwise
+**
+** For the purposes of SQLite, a star-query is defined as a query
+** with a large central table that is joined against four or more
+** smaller tables. The central table is called the "fact" table.
+** The smaller tables that get joined are "dimension tables".
+**
+** SIDE EFFECT: (and really the whole point of this subroutine)
+**
+** If pWInfo describes a star-query, then the cost on WhereLoops for the
+** fact table is reduced. This heuristic helps keep fact tables in
+** outer loops. Without this heuristic, paths with fact tables in outer
+** loops tend to get pruned by the mxChoice limit on the number of paths,
+** resulting in poor query plans. The total amount of heuristic cost
+** adjustment is stored in pWInfo->nOutStarDelta and the cost adjustment
+** for each WhereLoop is stored in its rStarDelta field.
+*/
+static int computeMxChoice(WhereInfo *pWInfo, LogEst nRowEst){
+ int nLoop = pWInfo->nLevel; /* Number of terms in the join */
+ if( nRowEst==0 && nLoop>=5 ){
+ /* Check to see if we are dealing with a star schema and if so, reduce
+ ** the cost of fact tables relative to dimension tables, as a heuristic
+ ** to help keep the fact tables in outer loops.
+ */
+ int iLoop; /* Counter over join terms */
+ Bitmask m; /* Bitmask for current loop */
+ assert( pWInfo->nOutStarDelta==0 );
+ for(iLoop=0, m=1; iLoop<nLoop; iLoop++, m<<=1){
+ WhereLoop *pWLoop; /* For looping over WhereLoops */
+ int nDep = 0; /* Number of dimension tables */
+ LogEst rDelta; /* Heuristic cost adjustment */
+ Bitmask mSeen = 0; /* Mask of dimension tables */
+ for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
+ if( (pWLoop->prereq & m)!=0 && (pWLoop->maskSelf & mSeen)==0 ){
+ nDep++;
+ mSeen |= pWLoop->maskSelf;
+ }
+ }
+ if( nDep<=3 ) continue;
+ rDelta = 15*(nDep-3);
+#ifdef WHERETRACE_ENABLED /* 0x4 */
+ if( wx_sqlite3WhereTrace&0x4 ){
+ SrcItem *pItem = pWInfo->pTabList->a + iLoop;
+ wx_sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n",
+ pItem->zAlias ? pItem->zAlias : pItem->pSTab->zName,
+ nDep, rDelta);
+ }
+#endif
+ if( pWInfo->nOutStarDelta==0 ){
+ for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
+ pWLoop->rStarDelta = 0;
+ }
+ }
+ pWInfo->nOutStarDelta += rDelta;
+ for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
+ if( pWLoop->maskSelf==m ){
+ pWLoop->rRun -= rDelta;
+ pWLoop->nOut -= rDelta;
+ pWLoop->rStarDelta = rDelta;
+ }
+ }
+ }
+ }
+ return pWInfo->nOutStarDelta>0 ? 18 : 12;
+}
+
+/*
** Given the list of WhereLoop objects at pWInfo->pLoops, this routine
** attempts to find the lowest cost path that visits each WhereLoop
** once. This path is then loaded into the pWInfo->a[].pWLoop fields.
@@ -162021,12 +168895,25 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pParse = pWInfo->pParse;
nLoop = pWInfo->nLevel;
- /* TUNING: For simple queries, only the best path is tracked.
- ** For 2-way joins, the 5 best paths are followed.
- ** For joins of 3 or more tables, track the 10 best paths */
- mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10);
+ WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d, nQueryLoop=%d)\n",
+ nRowEst, pParse->nQueryLoop));
+ /* TUNING: mxChoice is the maximum number of possible paths to preserve
+ ** at each step. Based on the number of loops in the FROM clause:
+ **
+ ** nLoop mxChoice
+ ** ----- --------
+ ** 1 1 // the most common case
+ ** 2 5
+ ** 3+ 12 or 18 // see computeMxChoice()
+ */
+ if( nLoop<=1 ){
+ mxChoice = 1;
+ }else if( nLoop==2 ){
+ mxChoice = 5;
+ }else{
+ mxChoice = computeMxChoice(pWInfo, nRowEst);
+ }
assert( nLoop<=pWInfo->pTabList->nSrc );
- WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst));
/* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this
** case the purpose of this call is to estimate the number of rows returned
@@ -162109,7 +168996,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* At this point, pWLoop is a candidate to be the next loop.
** Compute its cost */
- rUnsorted = wx_sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
+ rUnsorted = pWLoop->rRun + pFrom->nRow;
+ if( pWLoop->rSetup ){
+ rUnsorted = wx_sqlite3LogEstAdd(pWLoop->rSetup, rUnsorted);
+ }
rUnsorted = wx_sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
@@ -162129,7 +169019,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
);
}
/* TUNING: Add a small extra penalty (3) to sorting as an
- ** extra encouragment to the query planner to select a plan
+ ** extra encouragement to the query planner to select a plan
** where the rows emerge in the correct order without any sorting
** required. */
rCost = wx_sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 3;
@@ -162143,13 +169033,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */
}
- /* TUNING: A full-scan of a VIEW or subquery in the outer loop
- ** is not so bad. */
- if( iLoop==0 && (pWLoop->wsFlags & WHERE_VIEWSCAN)!=0 ){
- rCost += -10;
- nOut += -30;
- }
-
/* Check to see if pWLoop should be added to the set of
** mxChoice best-so-far paths.
**
@@ -162161,6 +169044,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** to (pTo->isOrdered==(-1))==(isOrdered==(-1))" for the range
** of legal values for isOrdered, -1..64.
*/
+ testcase( nTo==0 );
for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){
if( pTo->maskLoop==maskNew
&& ((pTo->isOrdered^isOrdered)&0x80)==0
@@ -162277,16 +169161,28 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
#ifdef WHERETRACE_ENABLED /* >=2 */
if( wx_sqlite3WhereTrace & 0x02 ){
+ LogEst rMin, rFloor = 0;
+ int nDone = 0;
wx_sqlite3DebugPrintf("---- after round %d ----\n", iLoop);
- for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
- wx_sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
- wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?');
- if( pTo->isOrdered>0 ){
- wx_sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop);
- }else{
- wx_sqlite3DebugPrintf("\n");
+ while( nDone<nTo ){
+ rMin = 0x7fff;
+ for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
+ if( pTo->rCost>rFloor && pTo->rCost<rMin ) rMin = pTo->rCost;
+ }
+ for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
+ if( pTo->rCost==rMin ){
+ wx_sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
+ wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
+ pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?');
+ if( pTo->isOrdered>0 ){
+ wx_sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop);
+ }else{
+ wx_sqlite3DebugPrintf("\n");
+ }
+ nDone++;
+ }
}
+ rFloor = rMin;
}
}
#endif
@@ -162336,10 +169232,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
- if( pWInfo->pSelect->pOrderBy
- && pWInfo->nOBSat > pWInfo->pSelect->pOrderBy->nExpr ){
- pWInfo->nOBSat = pWInfo->pSelect->pOrderBy->nExpr;
- }
+ /* vvv--- See check-in [12ad822d9b827777] on 2023-03-16 ---vvv */
+ assert( pWInfo->pSelect->pOrderBy==0
+ || pWInfo->nOBSat <= pWInfo->pSelect->pOrderBy->nExpr );
}else{
pWInfo->revMask = pFrom->revLoop;
if( pWInfo->nOBSat<=0 ){
@@ -162382,8 +169277,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
}
}
-
- pWInfo->nRowOut = pFrom->nRow;
+ pWInfo->nRowOut = pFrom->nRow + pWInfo->nOutStarDelta;
/* Free temporary memory and return success */
wx_sqlite3StackFreeNN(pParse->db, pSpace);
@@ -162391,6 +169285,83 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
}
/*
+** This routine implements a heuristic designed to improve query planning.
+** This routine is called in between the first and second call to
+** wherePathSolver(). Hence the name "Interstage" "Heuristic".
+**
+** The first call to wherePathSolver() (hereafter just "solver()") computes
+** the best path without regard to the order of the outputs. The second call
+** to the solver() builds upon the first call to try to find an alternative
+** path that satisfies the ORDER BY clause.
+**
+** This routine looks at the results of the first solver() run, and for
+** every FROM clause term in the resulting query plan that uses an equality
+** constraint against an index, disable other WhereLoops for that same
+** FROM clause term that would try to do a full-table scan. This prevents
+** an index search from being converted into a full-table scan in order to
+** satisfy an ORDER BY clause, since even though we might get slightly better
+** performance using the full-scan without sorting if the output size
+** estimates are very precise, we might also get severe performance
+** degradation using the full-scan if the output size estimate is too large.
+** It is better to err on the side of caution.
+**
+** Except, if the first solver() call generated a full-table scan in an outer
+** loop then stop this analysis at the first full-scan, since the second
+** solver() run might try to swap that full-scan for another in order to
+** get the output into the correct order. In other words, we allow a
+** rewrite like this:
+**
+** First Solver() Second Solver()
+** |-- SCAN t1 |-- SCAN t2
+** |-- SEARCH t2 `-- SEARCH t1
+** `-- SORT USING B-TREE
+**
+** The purpose of this routine is to disallow rewrites such as:
+**
+** First Solver() Second Solver()
+** |-- SEARCH t1 |-- SCAN t2 <--- bad!
+** |-- SEARCH t2 `-- SEARCH t1
+** `-- SORT USING B-TREE
+**
+** See test cases in test/whereN.test for the real-world query that
+** originally provoked this heuristic.
+*/
+static SQLITE_NOINLINE void whereInterstageHeuristic(WhereInfo *pWInfo){
+ int i;
+#ifdef WHERETRACE_ENABLED
+ int once = 0;
+#endif
+ for(i=0; i<pWInfo->nLevel; i++){
+ WhereLoop *p = pWInfo->a[i].pWLoop;
+ if( p==0 ) break;
+ if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ) continue;
+ if( (p->wsFlags & (WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_IN))!=0 ){
+ u8 iTab = p->iTab;
+ WhereLoop *pLoop;
+ for(pLoop=pWInfo->pLoops; pLoop; pLoop=pLoop->pNextLoop){
+ if( pLoop->iTab!=iTab ) continue;
+ if( (pLoop->wsFlags & (WHERE_CONSTRAINT|WHERE_AUTO_INDEX))!=0 ){
+ /* Auto-index and index-constrained loops allowed to remain */
+ continue;
+ }
+#ifdef WHERETRACE_ENABLED
+ if( wx_sqlite3WhereTrace & 0x80 ){
+ if( once==0 ){
+ wx_sqlite3DebugPrintf("Loops disabled by interstage heuristic:\n");
+ once = 1;
+ }
+ wx_sqlite3WhereLoopPrint(pLoop, &pWInfo->sWC);
+ }
+#endif /* WHERETRACE_ENABLED */
+ pLoop->prereq = ALLBITS; /* Prevent 2nd solver() from using this one */
+ }
+ }else{
+ break;
+ }
+ }
+}
+
+/*
** Most queries use only a single table (they are not joins) and have
** simple == constraints against indexed fields. This routine attempts
** to plan those simple cases using much less ceremony than the
@@ -162417,7 +169388,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
assert( pWInfo->pTabList->nSrc>=1 );
pItem = pWInfo->pTabList->a;
- pTab = pItem->pTab;
+ pTab = pItem->pSTab;
if( IsVirtual(pTab) ) return 0;
if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){
testcase( pItem->fg.isIndexedBy );
@@ -162551,6 +169522,17 @@ static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){
** at most a single row.
** 4) The table must not be referenced by any part of the query apart
** from its own USING or ON clause.
+** 5) The table must not have an inner-join ON or USING clause if there is
+** a RIGHT JOIN anywhere in the query. Otherwise the ON/USING clause
+** might move from the right side to the left side of the RIGHT JOIN.
+** Note: Due to (2), this condition can only arise if the table is
+** the right-most table of a subquery that was flattened into the
+** main query and that subquery was the right-hand operand of an
+** inner join that held an ON or USING clause.
+** 6) The ORDER BY clause has 63 or fewer terms
+** 7) The omit-noop-join optimization is enabled.
+**
+** Items (1), (6), and (7) are checked by the caller.
**
** For example, given:
**
@@ -162576,6 +169558,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
){
int i;
Bitmask tabUsed;
+ int hasRightJoin;
/* Preconditions checked by the caller */
assert( pWInfo->nLevel>=2 );
@@ -162590,10 +169573,12 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
if( pWInfo->pOrderBy ){
tabUsed |= wx_sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pOrderBy);
}
+ hasRightJoin = (pWInfo->pTabList->a[0].fg.jointype & JT_LTORJ)!=0;
for(i=pWInfo->nLevel-1; i>=1; i--){
WhereTerm *pTerm, *pEnd;
SrcItem *pItem;
WhereLoop *pLoop;
+ Bitmask m1;
pLoop = pWInfo->a[i].pWLoop;
pItem = &pWInfo->pTabList->a[pLoop->iTab];
if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ) continue;
@@ -162612,9 +169597,18 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
break;
}
}
+ if( hasRightJoin
+ && ExprHasProperty(pTerm->pExpr, EP_InnerON)
+ && pTerm->pExpr->w.iJoin==pItem->iCursor
+ ){
+ break; /* restriction (5) */
+ }
}
if( pTerm<pEnd ) continue;
- WHERETRACE(0xffffffff, ("-> drop loop %c not used\n", pLoop->cId));
+ WHERETRACE(0xffffffff,("-> omit unused FROM-clause term %c\n",pLoop->cId));
+ m1 = MASKBIT(i)-1;
+ testcase( ((pWInfo->revMask>>1) & ~m1)!=0 );
+ pWInfo->revMask = (m1 & pWInfo->revMask) | ((pWInfo->revMask>>1) & ~m1);
notReady &= ~pLoop->maskSelf;
for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
@@ -162661,9 +169655,9 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
WhereLoop *pLoop = pWInfo->a[i].pWLoop;
const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
- Table *pTab = pItem->pTab;
+ Table *pTab = pItem->pSTab;
if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
- pTab->tabFlags |= TF_StatsUsed;
+ pTab->tabFlags |= TF_MaybeReanalyze;
if( i>=1
&& (pLoop->wsFlags & reqFlags)==reqFlags
/* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */
@@ -162681,20 +169675,7 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
}
}
nSearch += pLoop->nOut;
- }
-}
-
-/*
-** This is an wx_sqlite3ParserAddCleanup() callback that is invoked to
-** free the Parse->pIdxEpr list when the Parse object is destroyed.
-*/
-static void whereIndexedExprCleanup(wx_sqlite3 *db, void *pObject){
- Parse *pParse = (Parse*)pObject;
- while( pParse->pIdxEpr!=0 ){
- IndexedExpr *p = pParse->pIdxEpr;
- pParse->pIdxEpr = p->pIENext;
- wx_sqlite3ExprDelete(db, p->pExpr);
- wx_sqlite3DbFreeNN(db, p);
+ if( pWInfo->nOutStarDelta ) nSearch += pLoop->rStarDelta;
}
}
@@ -162723,20 +169704,14 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
for(i=0; i<pIdx->nColumn; i++){
Expr *pExpr;
int j = pIdx->aiColumn[i];
- int bMaybeNullRow;
if( j==XN_EXPR ){
pExpr = pIdx->aColExpr->a[i].pExpr;
- testcase( pTabItem->fg.jointype & JT_LEFT );
- testcase( pTabItem->fg.jointype & JT_RIGHT );
- testcase( pTabItem->fg.jointype & JT_LTORJ );
- bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0;
}else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){
pExpr = wx_sqlite3ColumnExpr(pTab, &pTab->aCol[j]);
- bMaybeNullRow = 0;
}else{
continue;
}
- if( wx_sqlite3ExprIsConstant(pExpr) ) continue;
+ if( wx_sqlite3ExprIsConstant(0,pExpr) ) continue;
p = wx_sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
if( p==0 ) break;
p->pIENext = pParse->pIdxEpr;
@@ -162750,7 +169725,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
p->iDataCur = pTabItem->iCursor;
p->iIdxCur = iIdxCur;
p->iIdxCol = i;
- p->bMaybeNullRow = bMaybeNullRow;
+ p->bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0;
if( wx_sqlite3IndexAffinityStr(pParse->db, pIdx) ){
p->aff = pIdx->zColAff[i];
}
@@ -162759,7 +169734,30 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
#endif
pParse->pIdxEpr = p;
if( p->pIENext==0 ){
- wx_sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pParse);
+ void *pArg = (void*)&pParse->pIdxEpr;
+ wx_sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg);
+ }
+ }
+}
+
+/*
+** Set the reverse-scan order mask to one for all tables in the query
+** with the exception of MATERIALIZED common table expressions that have
+** their own internal ORDER BY clauses.
+**
+** This implements the PRAGMA reverse_unordered_selects=ON setting.
+** (Also SQLITE_DBCONFIG_REVERSE_SCANORDER).
+*/
+static SQLITE_NOINLINE void whereReverseScanOrder(WhereInfo *pWInfo){
+ int ii;
+ for(ii=0; ii<pWInfo->pTabList->nSrc; ii++){
+ SrcItem *pItem = &pWInfo->pTabList->a[ii];
+ if( !pItem->fg.isCte
+ || pItem->u2.pCteUse->eM10d!=M10d_Yes
+ || NEVER(pItem->fg.isSubquery==0)
+ || pItem->u4.pSubq->pSelect->pOrderBy==0
+ ){
+ pWInfo->revMask |= MASKBIT(ii);
}
}
}
@@ -162822,7 +169820,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
**
** OUTER JOINS
**
-** An outer join of tables t1 and t2 is conceptally coded as follows:
+** An outer join of tables t1 and t2 is conceptually coded as follows:
**
** foreach row1 in t1 do
** flag = 0
@@ -162892,7 +169890,11 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
/* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */
testcase( pOrderBy && pOrderBy->nExpr==BMS-1 );
- if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
+ if( pOrderBy && pOrderBy->nExpr>=BMS ){
+ pOrderBy = 0;
+ wctrlFlags &= ~WHERE_WANT_DISTINCT;
+ wctrlFlags |= WHERE_KEEP_ALL_JOINS; /* Disable omit-noop-join opt */
+ }
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
@@ -162917,7 +169919,10 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
** field (type Bitmask) it must be aligned on an 8-byte boundary on
** some architectures. Hence the ROUND8() below.
*/
- nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
+ nByteWInfo = ROUND8P(sizeof(WhereInfo));
+ if( nTabList>1 ){
+ nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel));
+ }
pWInfo = wx_sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
if( db->mallocFailed ){
wx_sqlite3DbFree(db, pWInfo);
@@ -162971,13 +169976,17 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
- ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
+ if( ALWAYS(pWInfo->pSelect)
+ && (pWInfo->pSelect->selFlags & SF_MultiValue)==0
+ ){
+ ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
+ }
}else{
/* Assign a bit from the bitmask to every term in the FROM clause.
**
** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
**
- ** The rule of the previous sentence ensures thta if X is the bitmask for
+ ** The rule of the previous sentence ensures that if X is the bitmask for
** a table T, then X-1 is the bitmask for all other tables to the left of T.
** Knowing the bitmask for all tables to the left of a left join is
** important. Ticket #3015.
@@ -163011,22 +170020,45 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
}
if( pParse->nErr ) goto whereBeginError;
- /* Special case: WHERE terms that do not refer to any tables in the join
- ** (constant expressions). Evaluate each such term, and jump over all the
- ** generated code if the result is not true.
+ /* The False-WHERE-Term-Bypass optimization:
+ **
+ ** If there are WHERE terms that are false, then no rows will be output,
+ ** so skip over all of the code generated here.
+ **
+ ** Conditions:
+ **
+ ** (1) The WHERE term must not refer to any tables in the join.
+ ** (2) The term must not come from an ON clause on the
+ ** right-hand side of a LEFT or FULL JOIN.
+ ** (3) The term must not come from an ON clause, or there must be
+ ** no RIGHT or FULL OUTER joins in pTabList.
+ ** (4) If the expression contains non-deterministic functions
+ ** that are not within a sub-select. This is not required
+ ** for correctness but rather to preserves SQLite's legacy
+ ** behaviour in the following two cases:
**
- ** Do not do this if the expression contains non-deterministic functions
- ** that are not within a sub-select. This is not strictly required, but
- ** preserves SQLite's legacy behaviour in the following two cases:
+ ** WHERE random()>0; -- eval random() once per row
+ ** WHERE (SELECT random())>0; -- eval random() just once overall
**
- ** FROM ... WHERE random()>0; -- eval random() once per row
- ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
+ ** Note that the Where term need not be a constant in order for this
+ ** optimization to apply, though it does need to be constant relative to
+ ** the current subquery (condition 1). The term might include variables
+ ** from outer queries so that the value of the term changes from one
+ ** invocation of the current subquery to the next.
*/
for(ii=0; ii<sWLB.pWC->nBase; ii++){
- WhereTerm *pT = &sWLB.pWC->a[ii];
+ WhereTerm *pT = &sWLB.pWC->a[ii]; /* A term of the WHERE clause */
+ Expr *pX; /* The expression of pT */
if( pT->wtFlags & TERM_VIRTUAL ) continue;
- if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
- wx_sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
+ pX = pT->pExpr;
+ assert( pX!=0 );
+ assert( pT->prereqAll!=0 || !ExprHasProperty(pX, EP_OuterON) );
+ if( pT->prereqAll==0 /* Conditions (1) and (2) */
+ && (nTabList==0 || exprIsDeterministic(pX)) /* Condition (4) */
+ && !(ExprHasProperty(pX, EP_InnerON) /* Condition (3) */
+ && (pTabList->a[0].fg.jointype & JT_LTORJ)!=0 )
+ ){
+ wx_sqlite3ExprIfFalse(pParse, pX, pWInfo->iBreak, SQLITE_JUMPIFNULL);
pT->wtFlags |= TERM_CODED;
}
}
@@ -163101,12 +170133,24 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
wherePathSolver(pWInfo, 0);
if( db->mallocFailed ) goto whereBeginError;
if( pWInfo->pOrderBy ){
- wherePathSolver(pWInfo, pWInfo->nRowOut+1);
+ whereInterstageHeuristic(pWInfo);
+ wherePathSolver(pWInfo, pWInfo->nRowOut<0 ? 1 : pWInfo->nRowOut+1);
if( db->mallocFailed ) goto whereBeginError;
}
+
+ /* TUNING: Assume that a DISTINCT clause on a subquery reduces
+ ** the output size by a factor of 8 (LogEst -30).
+ */
+ if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){
+ WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n",
+ pWInfo->nRowOut, pWInfo->nRowOut-30));
+ pWInfo->nRowOut -= 30;
+ }
+
}
+ assert( pWInfo->pTabList!=0 );
if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
- pWInfo->revMask = ALLBITS;
+ whereReverseScanOrder(pWInfo);
}
if( pParse->nErr ){
goto whereBeginError;
@@ -163150,10 +170194,10 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
** in-line wx_sqlite3WhereCodeOneLoopStart() for performance reasons.
*/
notReady = ~(Bitmask)0;
- if( pWInfo->nLevel>=2
- && pResultSet!=0 /* these two combine to guarantee */
- && 0==(wctrlFlags & WHERE_AGG_DISTINCT) /* condition (1) above */
- && OptimizationEnabled(db, SQLITE_OmitNoopJoin)
+ if( pWInfo->nLevel>=2 /* Must be a join, or this opt8n is pointless */
+ && pResultSet!=0 /* Condition (1) */
+ && 0==(wctrlFlags & (WHERE_AGG_DISTINCT|WHERE_KEEP_ALL_JOINS)) /* (1),(6) */
+ && OptimizationEnabled(db, SQLITE_OmitNoopJoin) /* (7) */
){
notReady = whereOmitNoopJoin(pWInfo, notReady);
nTabList = pWInfo->nLevel;
@@ -163201,14 +170245,15 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
- assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) );
+ assert( !(wsFlags&WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pSTab) );
if( bOnerow || (
0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
- && !IsVirtual(pTabList->a[0].pTab)
+ && !IsVirtual(pTabList->a[0].pSTab)
&& (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
+ && OptimizationEnabled(db, SQLITE_OnePass)
)){
pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
- if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
+ if( HasRowid(pTabList->a[0].pSTab) && (wsFlags & WHERE_IDX_ONLY) ){
if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
bFordelete = OPFLAG_FORDELETE;
}
@@ -163226,7 +170271,7 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
SrcItem *pTabItem;
pTabItem = &pTabList->a[pLevel->iFrom];
- pTab = pTabItem->pTab;
+ pTab = pTabItem->pSTab;
iDb = wx_sqlite3SchemaToIndex(db, pTab->pSchema);
pLoop = pLevel->pWLoop;
if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){
@@ -163269,7 +170314,7 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
assert( n<=pTab->nCol );
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
- if( pLoop->u.btree.pIndex!=0 ){
+ if( pLoop->u.btree.pIndex!=0 && (pTab->tabFlags & TF_WithoutRowid)==0 ){
wx_sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete);
}else
#endif
@@ -163297,7 +170342,7 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
iIndexCur = pLevel->iTabCur;
op = 0;
}else if( pWInfo->eOnePass!=ONEPASS_OFF ){
- Index *pJ = pTabItem->pTab->pIndex;
+ Index *pJ = pTabItem->pSTab->pIndex;
iIndexCur = iAuxArg;
assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
while( ALWAYS(pJ) && pJ!=pIx ){
@@ -163314,6 +170359,11 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
if( pIx->bHasExpr && OptimizationEnabled(db, SQLITE_IndexedExpr) ){
whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem);
}
+ if( pIx->pPartIdxWhere && (pTabItem->fg.jointype & JT_RIGHT)==0 ){
+ wherePartIdxExpr(
+ pParse, pIx, pIx->pPartIdxWhere, 0, iIndexCur, pTabItem
+ );
+ }
}
pLevel->iIdxCur = iIndexCur;
assert( pIx!=0 );
@@ -163359,7 +170409,7 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
wx_sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom);
pRJ->regReturn = ++pParse->nMem;
wx_sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn);
- assert( pTab==pTabItem->pTab );
+ assert( pTab==pTabItem->pSTab );
if( HasRowid(pTab) ){
KeyInfo *pInfo;
wx_sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1);
@@ -163398,19 +170448,24 @@ SQLITE_PRIVATE WhereInfo *wx_sqlite3WhereBegin(
wsFlags = pLevel->pWLoop->wsFlags;
pSrc = &pTabList->a[pLevel->iFrom];
if( pSrc->fg.isMaterialized ){
- if( pSrc->fg.isCorrelated ){
- wx_sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
+ Subquery *pSubq;
+ int iOnce = 0;
+ assert( pSrc->fg.isSubquery );
+ pSubq = pSrc->u4.pSubq;
+ if( pSrc->fg.isCorrelated==0 ){
+ iOnce = wx_sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}else{
- int iOnce = wx_sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
- wx_sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
- wx_sqlite3VdbeJumpHere(v, iOnce);
+ iOnce = 0;
}
+ wx_sqlite3VdbeAddOp2(v, OP_Gosub, pSubq->regReturn, pSubq->addrFillSub);
+ VdbeComment((v, "materialize %!S", pSrc));
+ if( iOnce ) wx_sqlite3VdbeJumpHere(v, iOnce);
}
+ assert( pTabList == pWInfo->pTabList );
if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
- constructAutomaticIndex(pParse, &pWInfo->sWC,
- &pTabList->a[pLevel->iFrom], notReady, pLevel);
+ constructAutomaticIndex(pParse, &pWInfo->sWC, notReady, pLevel);
#endif
}else{
wx_sqlite3ConstructBloomFilter(pWInfo, ii, pLevel, notReady);
@@ -163439,6 +170494,11 @@ whereBeginError:
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
whereInfoFree(db, pWInfo);
}
+#ifdef WHERETRACE_ENABLED
+ /* Prevent harmless compiler warnings about debugging routines
+ ** being declared but never used */
+ wx_sqlite3ShowWhereLoopList(0);
+#endif /* WHERETRACE_ENABLED */
return 0;
}
@@ -163462,26 +170522,6 @@ whereBeginError:
}
#endif
-#ifdef SQLITE_DEBUG
-/*
-** Return true if cursor iCur is opened by instruction k of the
-** bytecode. Used inside of assert() only.
-*/
-static int cursorIsOpen(Vdbe *v, int iCur, int k){
- while( k>=0 ){
- VdbeOp *pOp = wx_sqlite3VdbeGetOp(v,k--);
- if( pOp->p1!=iCur ) continue;
- if( pOp->opcode==OP_Close ) return 0;
- if( pOp->opcode==OP_OpenRead ) return 1;
- if( pOp->opcode==OP_OpenWrite ) return 1;
- if( pOp->opcode==OP_OpenDup ) return 1;
- if( pOp->opcode==OP_OpenAutoindex ) return 1;
- if( pOp->opcode==OP_OpenEphemeral ) return 1;
- }
- return 0;
-}
-#endif /* SQLITE_DEBUG */
-
/*
** Generate the end of the WHERE loop. See comments on
** wx_sqlite3WhereBegin() for additional information.
@@ -163628,7 +170668,16 @@ SQLITE_PRIVATE void wx_sqlite3WhereEnd(WhereInfo *pWInfo){
addr = wx_sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 );
if( (ws & WHERE_IDX_ONLY)==0 ){
- assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor );
+ SrcItem *pSrc = &pTabList->a[pLevel->iFrom];
+ assert( pLevel->iTabCur==pSrc->iCursor );
+ if( pSrc->fg.viaCoroutine ){
+ int m, n;
+ assert( pSrc->fg.isSubquery );
+ n = pSrc->u4.pSubq->regResult;
+ assert( pSrc->pSTab!=0 );
+ m = pSrc->pSTab->nCol;
+ wx_sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1);
+ }
wx_sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
}
if( (ws & WHERE_INDEXED)
@@ -163650,7 +170699,7 @@ SQLITE_PRIVATE void wx_sqlite3WhereEnd(WhereInfo *pWInfo){
wx_sqlite3VdbeJumpHere(v, addr);
}
VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
- pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
+ pWInfo->pTabList->a[pLevel->iFrom].pSTab->zName));
}
assert( pWInfo->nLevel<=pTabList->nSrc );
@@ -163659,7 +170708,7 @@ SQLITE_PRIVATE void wx_sqlite3WhereEnd(WhereInfo *pWInfo){
VdbeOp *pOp, *pLastOp;
Index *pIdx = 0;
SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
- Table *pTab = pTabItem->pTab;
+ Table *pTab = pTabItem->pSTab;
assert( pTab!=0 );
pLoop = pLevel->pWLoop;
@@ -163678,8 +170727,10 @@ SQLITE_PRIVATE void wx_sqlite3WhereEnd(WhereInfo *pWInfo){
*/
if( pTabItem->fg.viaCoroutine ){
testcase( pParse->db->mallocFailed );
+ assert( pTabItem->fg.isSubquery );
+ assert( pTabItem->u4.pSubq->regResult>=0 );
translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
- pTabItem->regResult, 0);
+ pTabItem->u4.pSubq->regResult, 0);
continue;
}
@@ -163727,7 +170778,8 @@ SQLITE_PRIVATE void wx_sqlite3WhereEnd(WhereInfo *pWInfo){
k = pLevel->addrBody + 1;
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeAddopTrace ){
- printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
+ printf("TRANSLATE cursor %d->%d in opcode range %d..%d\n",
+ pLevel->iTabCur, pLevel->iIdxCur, k, last-1);
}
/* Proof that the "+1" on the k value above is safe */
pOp = wx_sqlite3VdbeGetOp(v, k - 1);
@@ -163771,16 +170823,10 @@ SQLITE_PRIVATE void wx_sqlite3WhereEnd(WhereInfo *pWInfo){
** reference. Verify that this is harmless - that the
** table being referenced really is open.
*/
-#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
- assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
- || cursorIsOpen(v,pOp->p1,k)
- || pOp->opcode==OP_Offset
- );
-#else
- assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
- || cursorIsOpen(v,pOp->p1,k)
- );
-#endif
+ if( pLoop->wsFlags & WHERE_IDX_ONLY ){
+ wx_sqlite3ErrorMsg(pParse, "internal query planner error");
+ pParse->rc = SQLITE_INTERNAL;
+ }
}
}else if( pOp->opcode==OP_Rowid ){
pOp->p1 = pLevel->iIdxCur;
@@ -163934,7 +170980,7 @@ SQLITE_PRIVATE void wx_sqlite3WhereEnd(WhereInfo *pWInfo){
**
** These are the same built-in window functions supported by Postgres.
** Although the behaviour of aggregate window functions (functions that
-** can be used as either aggregates or window funtions) allows them to
+** can be used as either aggregates or window functions) allows them to
** be implemented using an API, built-in window functions are much more
** esoteric. Additionally, some window functions (e.g. nth_value())
** may only be implemented by caching the entire partition in memory.
@@ -164464,7 +171510,7 @@ static Window *windowFind(Parse *pParse, Window *pList, const char *zName){
** is the Window object representing the associated OVER clause. This
** function updates the contents of pWin as follows:
**
-** * If the OVER clause refered to a named window (as in "max(x) OVER win"),
+** * If the OVER clause referred to a named window (as in "max(x) OVER win"),
** search list pList for a matching WINDOW definition, and update pWin
** accordingly. If no such WINDOW clause can be found, leave an error
** in pParse.
@@ -164602,6 +171648,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
}
/* no break */ deliberate_fall_through
+ case TK_IF_NULL_ROW:
case TK_AGG_FUNCTION:
case TK_COLUMN: {
int iCol = -1;
@@ -164725,7 +171772,7 @@ static ExprList *exprListAppendList(
int iDummy;
Expr *pSub;
pSub = wx_sqlite3ExprSkipCollateAndLikely(pDup);
- if( wx_sqlite3ExprIsInteger(pSub, &iDummy) ){
+ if( wx_sqlite3ExprIsInteger(pSub, &iDummy, 0) ){
pSub->op = TK_NULL;
pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
pSub->u.zToken = 0;
@@ -164854,7 +171901,7 @@ SQLITE_PRIVATE int wx_sqlite3WindowRewrite(Parse *pParse, Select *p){
assert( ExprUseXList(pWin->pOwner) );
assert( pWin->pWFunc!=0 );
pArgs = pWin->pOwner->x.pList;
- if( pWin->pWFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){
+ if( pWin->pWFunc->funcFlags & SQLITE_SUBTYPE ){
selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist);
pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
pWin->bExprArgs = 1;
@@ -164893,9 +171940,10 @@ SQLITE_PRIVATE int wx_sqlite3WindowRewrite(Parse *pParse, Select *p){
assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside
** of wx_sqlite3DbMallocRawNN() called from
** wx_sqlite3SrcListAppend() */
- if( p->pSrc ){
+ if( p->pSrc==0 ){
+ wx_sqlite3SelectDelete(db, pSub);
+ }else if( wx_sqlite3SrcItemAttachSubquery(pParse, &p->pSrc->a[0], pSub, 0) ){
Table *pTab2;
- p->pSrc->a[0].pSelect = pSub;
p->pSrc->a[0].fg.isCorrelated = 1;
wx_sqlite3SrcListAssignCursors(pParse, p->pSrc);
pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
@@ -164909,7 +171957,7 @@ SQLITE_PRIVATE int wx_sqlite3WindowRewrite(Parse *pParse, Select *p){
}else{
memcpy(pTab, pTab2, sizeof(Table));
pTab->tabFlags |= TF_Ephemeral;
- p->pSrc->a[0].pTab = pTab;
+ p->pSrc->a[0].pSTab = pTab;
pTab = pTab2;
memset(&w, 0, sizeof(w));
w.xExprCallback = wx_sqlite3WindowExtraAggFuncDepth;
@@ -164917,8 +171965,6 @@ SQLITE_PRIVATE int wx_sqlite3WindowRewrite(Parse *pParse, Select *p){
w.xSelectCallback2 = wx_sqlite3WalkerDepthDecrease;
wx_sqlite3WalkSelect(&w, pSub);
}
- }else{
- wx_sqlite3SelectDelete(db, pSub);
}
if( db->mallocFailed ) rc = SQLITE_NOMEM;
@@ -164980,7 +172026,7 @@ SQLITE_PRIVATE void wx_sqlite3WindowListDelete(wx_sqlite3 *db, Window *p){
** variable values in the expression tree.
*/
static Expr *wx_sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){
- if( 0==wx_sqlite3ExprIsConstant(pExpr) ){
+ if( 0==wx_sqlite3ExprIsConstant(0,pExpr) ){
if( IN_RENAME_OBJECT ) wx_sqlite3RenameExprUnmap(pParse, pExpr);
wx_sqlite3ExprDelete(pParse->db, pExpr);
pExpr = wx_sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0);
@@ -165084,7 +172130,7 @@ SQLITE_PRIVATE Window *wx_sqlite3WindowAssemble(
}
/*
-** Window *pWin has just been created from a WINDOW clause. Tokne pBase
+** Window *pWin has just been created from a WINDOW clause. Token pBase
** is the base window. Earlier windows from the same WINDOW clause are
** stored in the linked list starting at pWin->pNextWin. This function
** either updates *pWin according to the base specification, or else
@@ -165128,8 +172174,9 @@ SQLITE_PRIVATE void wx_sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin)
if( p ){
assert( p->op==TK_FUNCTION );
assert( pWin );
+ assert( ExprIsFullSize(p) );
p->y.pWin = pWin;
- ExprSetProperty(p, EP_WinFunc);
+ ExprSetProperty(p, EP_WinFunc|EP_FullSize);
pWin->pOwner = p;
if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){
wx_sqlite3ErrorMsg(pParse,
@@ -165204,10 +172251,15 @@ SQLITE_PRIVATE int wx_sqlite3WindowCompare(
** and initialize registers and cursors used by wx_sqlite3WindowCodeStep().
*/
SQLITE_PRIVATE void wx_sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){
- int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr;
- Window *pMWin = pSelect->pWin;
Window *pWin;
- Vdbe *v = wx_sqlite3GetVdbe(pParse);
+ int nEphExpr;
+ Window *pMWin;
+ Vdbe *v;
+
+ assert( pSelect->pSrc->a[0].fg.isSubquery );
+ nEphExpr = pSelect->pSrc->a[0].u4.pSubq->pSelect->pEList->nExpr;
+ pMWin = pSelect->pWin;
+ v = wx_sqlite3GetVdbe(pParse);
wx_sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr);
wx_sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
@@ -165390,7 +172442,7 @@ struct WindowCsrAndReg {
**
** (ORDER BY a, b GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING)
**
-** The windows functions implmentation caches the input rows in a temp
+** The windows functions implementation caches the input rows in a temp
** table, sorted by "a, b" (it actually populates the cache lazily, and
** aggressively removes rows once they are no longer required, but that's
** a mere detail). It keeps three cursors open on the temp table. One
@@ -166399,7 +173451,7 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
**
** For the most part, the patterns above are adapted to support UNBOUNDED by
** assuming that it is equivalent to "infinity PRECEDING/FOLLOWING" and
-** CURRENT ROW by assuming that it is equivilent to "0 PRECEDING/FOLLOWING".
+** CURRENT ROW by assuming that it is equivalent to "0 PRECEDING/FOLLOWING".
** This is optimized of course - branches that will never be taken and
** conditions that are always true are omitted from the VM code. The only
** exceptional case is:
@@ -166604,7 +173656,7 @@ SQLITE_PRIVATE void wx_sqlite3WindowCodeStep(
Vdbe *v = wx_sqlite3GetVdbe(pParse);
int csrWrite; /* Cursor used to write to eph. table */
int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */
- int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */
+ int nInput = p->pSrc->a[0].pSTab->nCol; /* Number of cols returned by sub */
int iInput; /* To iterate through sub cols */
int addrNe; /* Address of OP_Ne */
int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */
@@ -166678,7 +173730,7 @@ SQLITE_PRIVATE void wx_sqlite3WindowCodeStep(
}
/* Allocate registers for the array of values from the sub-query, the
- ** samve values in record form, and the rowid used to insert said record
+ ** same values in record form, and the rowid used to insert said record
** into the ephemeral table. */
regNew = pParse->nMem+1;
pParse->nMem += nInput;
@@ -166919,7 +173971,8 @@ SQLITE_PRIVATE void wx_sqlite3WindowCodeStep(
/************** End of window.c **********************************************/
/************** Begin file parse.c *******************************************/
/* This file is automatically generated by Lemon from input grammar
-** source file "parse.y". */
+** source file "parse.y".
+*/
/*
** 2001-09-15
**
@@ -166936,7 +173989,7 @@ SQLITE_PRIVATE void wx_sqlite3WindowCodeStep(
** The canonical source code to this file ("parse.y") is a Lemon grammar
** file that specifies the input grammar and actions to take while parsing.
** That input file is processed by Lemon to generate a C-language
-** implementation of a parser for the given grammer. You might be reading
+** implementation of a parser for the given grammar. You might be reading
** this comment as part of the translated C-code. Edits should be made
** to the original parse.y sources.
*/
@@ -167048,9 +174101,9 @@ static void updateDeleteLimitError(
break;
}
}
- if( (p->selFlags & SF_MultiValue)==0 &&
- (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 &&
- cnt>mxSelect
+ if( (p->selFlags & (SF_MultiValue|SF_Values))==0
+ && (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0
+ && cnt>mxSelect
){
wx_sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
}
@@ -167070,6 +174123,14 @@ static void updateDeleteLimitError(
return pSelect;
}
+ /* Memory allocator for parser stack resizing. This is a thin wrapper around
+ ** wx_sqlite3_realloc() that includes a call to wx_sqlite3FaultSim() to facilitate
+ ** testing.
+ */
+ static void *parserStackRealloc(void *pOld, wx_sqlite3_uint64 newSize){
+ return wx_sqlite3FaultSim(700) ? 0 : wx_sqlite3_realloc(pOld, newSize);
+ }
+
/* Construct a new Expr object from a single token */
static Expr *tokenExpr(Parse *pParse, int op, Token t){
@@ -167192,135 +174253,135 @@ static void updateDeleteLimitError(
#define TK_OR 43
#define TK_AND 44
#define TK_IS 45
-#define TK_MATCH 46
-#define TK_LIKE_KW 47
-#define TK_BETWEEN 48
-#define TK_IN 49
-#define TK_ISNULL 50
-#define TK_NOTNULL 51
-#define TK_NE 52
-#define TK_EQ 53
-#define TK_GT 54
-#define TK_LE 55
-#define TK_LT 56
-#define TK_GE 57
-#define TK_ESCAPE 58
-#define TK_ID 59
-#define TK_COLUMNKW 60
-#define TK_DO 61
-#define TK_FOR 62
-#define TK_IGNORE 63
-#define TK_INITIALLY 64
-#define TK_INSTEAD 65
-#define TK_NO 66
-#define TK_KEY 67
-#define TK_OF 68
-#define TK_OFFSET 69
-#define TK_PRAGMA 70
-#define TK_RAISE 71
-#define TK_RECURSIVE 72
-#define TK_REPLACE 73
-#define TK_RESTRICT 74
-#define TK_ROW 75
-#define TK_ROWS 76
-#define TK_TRIGGER 77
-#define TK_VACUUM 78
-#define TK_VIEW 79
-#define TK_VIRTUAL 80
-#define TK_WITH 81
-#define TK_NULLS 82
-#define TK_FIRST 83
-#define TK_LAST 84
-#define TK_CURRENT 85
-#define TK_FOLLOWING 86
-#define TK_PARTITION 87
-#define TK_PRECEDING 88
-#define TK_RANGE 89
-#define TK_UNBOUNDED 90
-#define TK_EXCLUDE 91
-#define TK_GROUPS 92
-#define TK_OTHERS 93
-#define TK_TIES 94
-#define TK_GENERATED 95
-#define TK_ALWAYS 96
-#define TK_MATERIALIZED 97
-#define TK_REINDEX 98
-#define TK_RENAME 99
-#define TK_CTIME_KW 100
-#define TK_ANY 101
-#define TK_BITAND 102
-#define TK_BITOR 103
-#define TK_LSHIFT 104
-#define TK_RSHIFT 105
-#define TK_PLUS 106
-#define TK_MINUS 107
-#define TK_STAR 108
-#define TK_SLASH 109
-#define TK_REM 110
-#define TK_CONCAT 111
-#define TK_PTR 112
-#define TK_COLLATE 113
-#define TK_BITNOT 114
-#define TK_ON 115
-#define TK_INDEXED 116
-#define TK_STRING 117
-#define TK_JOIN_KW 118
-#define TK_CONSTRAINT 119
-#define TK_DEFAULT 120
-#define TK_NULL 121
-#define TK_PRIMARY 122
-#define TK_UNIQUE 123
-#define TK_CHECK 124
-#define TK_REFERENCES 125
-#define TK_AUTOINCR 126
-#define TK_INSERT 127
-#define TK_DELETE 128
-#define TK_UPDATE 129
-#define TK_SET 130
-#define TK_DEFERRABLE 131
-#define TK_FOREIGN 132
-#define TK_DROP 133
-#define TK_UNION 134
-#define TK_ALL 135
-#define TK_EXCEPT 136
-#define TK_INTERSECT 137
-#define TK_SELECT 138
-#define TK_VALUES 139
-#define TK_DISTINCT 140
-#define TK_DOT 141
-#define TK_FROM 142
-#define TK_JOIN 143
-#define TK_USING 144
-#define TK_ORDER 145
-#define TK_GROUP 146
-#define TK_HAVING 147
-#define TK_LIMIT 148
-#define TK_WHERE 149
-#define TK_RETURNING 150
-#define TK_INTO 151
-#define TK_NOTHING 152
-#define TK_FLOAT 153
-#define TK_BLOB 154
-#define TK_INTEGER 155
-#define TK_VARIABLE 156
-#define TK_CASE 157
-#define TK_WHEN 158
-#define TK_THEN 159
-#define TK_ELSE 160
-#define TK_INDEX 161
-#define TK_ALTER 162
-#define TK_ADD 163
-#define TK_WINDOW 164
-#define TK_OVER 165
-#define TK_FILTER 166
-#define TK_COLUMN 167
-#define TK_AGG_FUNCTION 168
-#define TK_AGG_COLUMN 169
-#define TK_TRUEFALSE 170
-#define TK_ISNOT 171
+#define TK_ISNOT 46
+#define TK_MATCH 47
+#define TK_LIKE_KW 48
+#define TK_BETWEEN 49
+#define TK_IN 50
+#define TK_ISNULL 51
+#define TK_NOTNULL 52
+#define TK_NE 53
+#define TK_EQ 54
+#define TK_GT 55
+#define TK_LE 56
+#define TK_LT 57
+#define TK_GE 58
+#define TK_ESCAPE 59
+#define TK_ID 60
+#define TK_COLUMNKW 61
+#define TK_DO 62
+#define TK_FOR 63
+#define TK_IGNORE 64
+#define TK_INITIALLY 65
+#define TK_INSTEAD 66
+#define TK_NO 67
+#define TK_KEY 68
+#define TK_OF 69
+#define TK_OFFSET 70
+#define TK_PRAGMA 71
+#define TK_RAISE 72
+#define TK_RECURSIVE 73
+#define TK_REPLACE 74
+#define TK_RESTRICT 75
+#define TK_ROW 76
+#define TK_ROWS 77
+#define TK_TRIGGER 78
+#define TK_VACUUM 79
+#define TK_VIEW 80
+#define TK_VIRTUAL 81
+#define TK_WITH 82
+#define TK_NULLS 83
+#define TK_FIRST 84
+#define TK_LAST 85
+#define TK_CURRENT 86
+#define TK_FOLLOWING 87
+#define TK_PARTITION 88
+#define TK_PRECEDING 89
+#define TK_RANGE 90
+#define TK_UNBOUNDED 91
+#define TK_EXCLUDE 92
+#define TK_GROUPS 93
+#define TK_OTHERS 94
+#define TK_TIES 95
+#define TK_GENERATED 96
+#define TK_ALWAYS 97
+#define TK_MATERIALIZED 98
+#define TK_REINDEX 99
+#define TK_RENAME 100
+#define TK_CTIME_KW 101
+#define TK_ANY 102
+#define TK_BITAND 103
+#define TK_BITOR 104
+#define TK_LSHIFT 105
+#define TK_RSHIFT 106
+#define TK_PLUS 107
+#define TK_MINUS 108
+#define TK_STAR 109
+#define TK_SLASH 110
+#define TK_REM 111
+#define TK_CONCAT 112
+#define TK_PTR 113
+#define TK_COLLATE 114
+#define TK_BITNOT 115
+#define TK_ON 116
+#define TK_INDEXED 117
+#define TK_STRING 118
+#define TK_JOIN_KW 119
+#define TK_CONSTRAINT 120
+#define TK_DEFAULT 121
+#define TK_NULL 122
+#define TK_PRIMARY 123
+#define TK_UNIQUE 124
+#define TK_CHECK 125
+#define TK_REFERENCES 126
+#define TK_AUTOINCR 127
+#define TK_INSERT 128
+#define TK_DELETE 129
+#define TK_UPDATE 130
+#define TK_SET 131
+#define TK_DEFERRABLE 132
+#define TK_FOREIGN 133
+#define TK_DROP 134
+#define TK_UNION 135
+#define TK_ALL 136
+#define TK_EXCEPT 137
+#define TK_INTERSECT 138
+#define TK_SELECT 139
+#define TK_VALUES 140
+#define TK_DISTINCT 141
+#define TK_DOT 142
+#define TK_FROM 143
+#define TK_JOIN 144
+#define TK_USING 145
+#define TK_ORDER 146
+#define TK_GROUP 147
+#define TK_HAVING 148
+#define TK_LIMIT 149
+#define TK_WHERE 150
+#define TK_RETURNING 151
+#define TK_INTO 152
+#define TK_NOTHING 153
+#define TK_FLOAT 154
+#define TK_BLOB 155
+#define TK_INTEGER 156
+#define TK_VARIABLE 157
+#define TK_CASE 158
+#define TK_WHEN 159
+#define TK_THEN 160
+#define TK_ELSE 161
+#define TK_INDEX 162
+#define TK_ALTER 163
+#define TK_ADD 164
+#define TK_WINDOW 165
+#define TK_OVER 166
+#define TK_FILTER 167
+#define TK_COLUMN 168
+#define TK_AGG_FUNCTION 169
+#define TK_AGG_COLUMN 170
+#define TK_TRUEFALSE 171
#define TK_FUNCTION 172
-#define TK_UMINUS 173
-#define TK_UPLUS 174
+#define TK_UPLUS 173
+#define TK_UMINUS 174
#define TK_TRUTH 175
#define TK_REGISTER 176
#define TK_VECTOR 177
@@ -167329,8 +174390,9 @@ static void updateDeleteLimitError(
#define TK_ASTERISK 180
#define TK_SPAN 181
#define TK_ERROR 182
-#define TK_SPACE 183
-#define TK_ILLEGAL 184
+#define TK_QNUMBER 183
+#define TK_SPACE 184
+#define TK_ILLEGAL 185
#endif
/**************** End token definitions ***************************************/
@@ -167371,6 +174433,9 @@ static void updateDeleteLimitError(
** wx_sqlite3ParserARG_STORE Code to store %extra_argument into yypParser
** wx_sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser
** wx_sqlite3ParserCTX_* As wx_sqlite3ParserARG_ except for %extra_context
+** YYREALLOC Name of the realloc() function to use
+** YYFREE Name of the free() function to use
+** YYDYNSTACK True if stack space should be extended on heap
** YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing.
** YYNSTATE the combined number of states.
@@ -167384,37 +174449,39 @@ static void updateDeleteLimitError(
** YY_NO_ACTION The yy_action[] code for no-op
** YY_MIN_REDUCE Minimum value for reduce actions
** YY_MAX_REDUCE Maximum value for reduce actions
+** YY_MIN_DSTRCTR Minimum symbol value that has a destructor
+** YY_MAX_DSTRCTR Maximum symbol value that has a destructor
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned short int
-#define YYNOCODE 319
+#define YYNOCODE 322
#define YYACTIONTYPE unsigned short int
-#define YYWILDCARD 101
+#define YYWILDCARD 102
#define wx_sqlite3ParserTOKENTYPE Token
typedef union {
int yyinit;
wx_sqlite3ParserTOKENTYPE yy0;
- TriggerStep* yy33;
- Window* yy41;
- Select* yy47;
- SrcList* yy131;
- struct TrigEvent yy180;
- struct {int value; int mask;} yy231;
- IdList* yy254;
- u32 yy285;
- ExprList* yy322;
- Cte* yy385;
- int yy394;
- Upsert* yy444;
- u8 yy516;
- With* yy521;
- const char* yy522;
- Expr* yy528;
- OnOrUsing yy561;
- struct FrameBound yy595;
+ ExprList* yy14;
+ With* yy59;
+ Cte* yy67;
+ Upsert* yy122;
+ IdList* yy132;
+ int yy144;
+ const char* yy168;
+ SrcList* yy203;
+ Window* yy211;
+ OnOrUsing yy269;
+ struct TrigEvent yy286;
+ struct {int value; int mask;} yy383;
+ u32 yy391;
+ TriggerStep* yy427;
+ Expr* yy454;
+ u8 yy462;
+ struct FrameBound yy509;
+ Select* yy555;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
@@ -167424,24 +174491,29 @@ typedef union {
#define wx_sqlite3ParserARG_PARAM
#define wx_sqlite3ParserARG_FETCH
#define wx_sqlite3ParserARG_STORE
+#define YYREALLOC parserStackRealloc
+#define YYFREE wx_sqlite3_free
+#define YYDYNSTACK 1
#define wx_sqlite3ParserCTX_SDECL Parse *pParse;
#define wx_sqlite3ParserCTX_PDECL ,Parse *pParse
#define wx_sqlite3ParserCTX_PARAM ,pParse
#define wx_sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
#define wx_sqlite3ParserCTX_STORE yypParser->pParse=pParse;
#define YYFALLBACK 1
-#define YYNSTATE 576
-#define YYNRULE 405
-#define YYNRULE_WITH_ACTION 342
-#define YYNTOKEN 185
-#define YY_MAX_SHIFT 575
-#define YY_MIN_SHIFTREDUCE 835
-#define YY_MAX_SHIFTREDUCE 1239
-#define YY_ERROR_ACTION 1240
-#define YY_ACCEPT_ACTION 1241
-#define YY_NO_ACTION 1242
-#define YY_MIN_REDUCE 1243
-#define YY_MAX_REDUCE 1647
+#define YYNSTATE 583
+#define YYNRULE 409
+#define YYNRULE_WITH_ACTION 344
+#define YYNTOKEN 186
+#define YY_MAX_SHIFT 582
+#define YY_MIN_SHIFTREDUCE 845
+#define YY_MAX_SHIFTREDUCE 1253
+#define YY_ERROR_ACTION 1254
+#define YY_ACCEPT_ACTION 1255
+#define YY_NO_ACTION 1256
+#define YY_MIN_REDUCE 1257
+#define YY_MAX_REDUCE 1665
+#define YY_MIN_DSTRCTR 205
+#define YY_MAX_DSTRCTR 319
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
@@ -167457,6 +174529,22 @@ typedef union {
# define yytestcase(X)
#endif
+/* Macro to determine if stack space has the ability to grow using
+** heap memory.
+*/
+#if YYSTACKDEPTH<=0 || YYDYNSTACK
+# define YYGROWABLESTACK 1
+#else
+# define YYGROWABLESTACK 0
+#endif
+
+/* Guarantee a minimum number of initial stack slots.
+*/
+#if YYSTACKDEPTH<=0
+# undef YYSTACKDEPTH
+# define YYSTACKDEPTH 2 /* Need a minimum stack size */
+#endif
+
/* Next are the tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
@@ -167508,618 +174596,643 @@ typedef union {
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (2098)
+#define YY_ACTTAB_COUNT (2207)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 568, 208, 568, 118, 115, 229, 568, 118, 115, 229,
- /* 10 */ 568, 1314, 377, 1293, 408, 562, 562, 562, 568, 409,
- /* 20 */ 378, 1314, 1276, 41, 41, 41, 41, 208, 1526, 71,
- /* 30 */ 71, 971, 419, 41, 41, 491, 303, 279, 303, 972,
- /* 40 */ 397, 71, 71, 125, 126, 80, 1217, 1217, 1050, 1053,
- /* 50 */ 1040, 1040, 123, 123, 124, 124, 124, 124, 476, 409,
- /* 60 */ 1241, 1, 1, 575, 2, 1245, 550, 118, 115, 229,
- /* 70 */ 317, 480, 146, 480, 524, 118, 115, 229, 529, 1327,
- /* 80 */ 417, 523, 142, 125, 126, 80, 1217, 1217, 1050, 1053,
- /* 90 */ 1040, 1040, 123, 123, 124, 124, 124, 124, 118, 115,
- /* 100 */ 229, 327, 122, 122, 122, 122, 121, 121, 120, 120,
- /* 110 */ 120, 119, 116, 444, 284, 284, 284, 284, 442, 442,
- /* 120 */ 442, 1567, 376, 1569, 1192, 375, 1163, 565, 1163, 565,
- /* 130 */ 409, 1567, 537, 259, 226, 444, 101, 145, 449, 316,
- /* 140 */ 559, 240, 122, 122, 122, 122, 121, 121, 120, 120,
- /* 150 */ 120, 119, 116, 444, 125, 126, 80, 1217, 1217, 1050,
- /* 160 */ 1053, 1040, 1040, 123, 123, 124, 124, 124, 124, 142,
- /* 170 */ 294, 1192, 339, 448, 120, 120, 120, 119, 116, 444,
- /* 180 */ 127, 1192, 1193, 1194, 148, 441, 440, 568, 119, 116,
- /* 190 */ 444, 124, 124, 124, 124, 117, 122, 122, 122, 122,
- /* 200 */ 121, 121, 120, 120, 120, 119, 116, 444, 454, 113,
- /* 210 */ 13, 13, 546, 122, 122, 122, 122, 121, 121, 120,
- /* 220 */ 120, 120, 119, 116, 444, 422, 316, 559, 1192, 1193,
- /* 230 */ 1194, 149, 1224, 409, 1224, 124, 124, 124, 124, 122,
- /* 240 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116,
- /* 250 */ 444, 465, 342, 1037, 1037, 1051, 1054, 125, 126, 80,
- /* 260 */ 1217, 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124,
- /* 270 */ 124, 124, 1279, 522, 222, 1192, 568, 409, 224, 514,
- /* 280 */ 175, 82, 83, 122, 122, 122, 122, 121, 121, 120,
- /* 290 */ 120, 120, 119, 116, 444, 1007, 16, 16, 1192, 133,
- /* 300 */ 133, 125, 126, 80, 1217, 1217, 1050, 1053, 1040, 1040,
- /* 310 */ 123, 123, 124, 124, 124, 124, 122, 122, 122, 122,
- /* 320 */ 121, 121, 120, 120, 120, 119, 116, 444, 1041, 546,
- /* 330 */ 1192, 373, 1192, 1193, 1194, 252, 1434, 399, 504, 501,
- /* 340 */ 500, 111, 560, 566, 4, 926, 926, 433, 499, 340,
- /* 350 */ 460, 328, 360, 394, 1237, 1192, 1193, 1194, 563, 568,
- /* 360 */ 122, 122, 122, 122, 121, 121, 120, 120, 120, 119,
- /* 370 */ 116, 444, 284, 284, 369, 1580, 1607, 441, 440, 154,
- /* 380 */ 409, 445, 71, 71, 1286, 565, 1221, 1192, 1193, 1194,
- /* 390 */ 85, 1223, 271, 557, 543, 515, 1561, 568, 98, 1222,
- /* 400 */ 6, 1278, 472, 142, 125, 126, 80, 1217, 1217, 1050,
- /* 410 */ 1053, 1040, 1040, 123, 123, 124, 124, 124, 124, 550,
- /* 420 */ 13, 13, 1027, 507, 1224, 1192, 1224, 549, 109, 109,
- /* 430 */ 222, 568, 1238, 175, 568, 427, 110, 197, 445, 570,
- /* 440 */ 569, 430, 1552, 1017, 325, 551, 1192, 270, 287, 368,
- /* 450 */ 510, 363, 509, 257, 71, 71, 543, 71, 71, 359,
- /* 460 */ 316, 559, 1613, 122, 122, 122, 122, 121, 121, 120,
- /* 470 */ 120, 120, 119, 116, 444, 1017, 1017, 1019, 1020, 27,
- /* 480 */ 284, 284, 1192, 1193, 1194, 1158, 568, 1612, 409, 901,
- /* 490 */ 190, 550, 356, 565, 550, 937, 533, 517, 1158, 516,
- /* 500 */ 413, 1158, 552, 1192, 1193, 1194, 568, 544, 1554, 51,
- /* 510 */ 51, 214, 125, 126, 80, 1217, 1217, 1050, 1053, 1040,
- /* 520 */ 1040, 123, 123, 124, 124, 124, 124, 1192, 474, 135,
- /* 530 */ 135, 409, 284, 284, 1490, 505, 121, 121, 120, 120,
- /* 540 */ 120, 119, 116, 444, 1007, 565, 518, 217, 541, 1561,
- /* 550 */ 316, 559, 142, 6, 532, 125, 126, 80, 1217, 1217,
- /* 560 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
- /* 570 */ 1555, 122, 122, 122, 122, 121, 121, 120, 120, 120,
- /* 580 */ 119, 116, 444, 485, 1192, 1193, 1194, 482, 281, 1267,
- /* 590 */ 957, 252, 1192, 373, 504, 501, 500, 1192, 340, 571,
- /* 600 */ 1192, 571, 409, 292, 499, 957, 876, 191, 480, 316,
- /* 610 */ 559, 384, 290, 380, 122, 122, 122, 122, 121, 121,
- /* 620 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 630 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 640 */ 124, 409, 394, 1136, 1192, 869, 100, 284, 284, 1192,
- /* 650 */ 1193, 1194, 373, 1093, 1192, 1193, 1194, 1192, 1193, 1194,
- /* 660 */ 565, 455, 32, 373, 233, 125, 126, 80, 1217, 1217,
- /* 670 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
- /* 680 */ 1433, 959, 568, 228, 958, 122, 122, 122, 122, 121,
- /* 690 */ 121, 120, 120, 120, 119, 116, 444, 1158, 228, 1192,
- /* 700 */ 157, 1192, 1193, 1194, 1553, 13, 13, 301, 957, 1232,
- /* 710 */ 1158, 153, 409, 1158, 373, 1583, 1176, 5, 369, 1580,
- /* 720 */ 429, 1238, 3, 957, 122, 122, 122, 122, 121, 121,
- /* 730 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 740 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 750 */ 124, 409, 208, 567, 1192, 1028, 1192, 1193, 1194, 1192,
- /* 760 */ 388, 852, 155, 1552, 286, 402, 1098, 1098, 488, 568,
- /* 770 */ 465, 342, 1319, 1319, 1552, 125, 126, 80, 1217, 1217,
- /* 780 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
- /* 790 */ 129, 568, 13, 13, 374, 122, 122, 122, 122, 121,
- /* 800 */ 121, 120, 120, 120, 119, 116, 444, 302, 568, 453,
- /* 810 */ 528, 1192, 1193, 1194, 13, 13, 1192, 1193, 1194, 1297,
- /* 820 */ 463, 1267, 409, 1317, 1317, 1552, 1012, 453, 452, 200,
- /* 830 */ 299, 71, 71, 1265, 122, 122, 122, 122, 121, 121,
- /* 840 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 850 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 860 */ 124, 409, 227, 1073, 1158, 284, 284, 419, 312, 278,
- /* 870 */ 278, 285, 285, 1419, 406, 405, 382, 1158, 565, 568,
- /* 880 */ 1158, 1196, 565, 1600, 565, 125, 126, 80, 1217, 1217,
- /* 890 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
- /* 900 */ 453, 1482, 13, 13, 1536, 122, 122, 122, 122, 121,
- /* 910 */ 121, 120, 120, 120, 119, 116, 444, 201, 568, 354,
- /* 920 */ 1586, 575, 2, 1245, 840, 841, 842, 1562, 317, 1212,
- /* 930 */ 146, 6, 409, 255, 254, 253, 206, 1327, 9, 1196,
- /* 940 */ 262, 71, 71, 424, 122, 122, 122, 122, 121, 121,
- /* 950 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 960 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 970 */ 124, 568, 284, 284, 568, 1213, 409, 574, 313, 1245,
- /* 980 */ 349, 1296, 352, 419, 317, 565, 146, 491, 525, 1643,
- /* 990 */ 395, 371, 491, 1327, 70, 70, 1295, 71, 71, 240,
- /* 1000 */ 1325, 104, 80, 1217, 1217, 1050, 1053, 1040, 1040, 123,
- /* 1010 */ 123, 124, 124, 124, 124, 122, 122, 122, 122, 121,
- /* 1020 */ 121, 120, 120, 120, 119, 116, 444, 1114, 284, 284,
- /* 1030 */ 428, 448, 1525, 1213, 439, 284, 284, 1489, 1352, 311,
- /* 1040 */ 474, 565, 1115, 971, 491, 491, 217, 1263, 565, 1538,
- /* 1050 */ 568, 972, 207, 568, 1027, 240, 383, 1116, 519, 122,
- /* 1060 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116,
- /* 1070 */ 444, 1018, 107, 71, 71, 1017, 13, 13, 912, 568,
- /* 1080 */ 1495, 568, 284, 284, 97, 526, 491, 448, 913, 1326,
- /* 1090 */ 1322, 545, 409, 284, 284, 565, 151, 209, 1495, 1497,
- /* 1100 */ 262, 450, 55, 55, 56, 56, 565, 1017, 1017, 1019,
- /* 1110 */ 443, 332, 409, 527, 12, 295, 125, 126, 80, 1217,
- /* 1120 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 1130 */ 124, 347, 409, 864, 1534, 1213, 125, 126, 80, 1217,
- /* 1140 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 1150 */ 124, 1137, 1641, 474, 1641, 371, 125, 114, 80, 1217,
- /* 1160 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 1170 */ 124, 1495, 329, 474, 331, 122, 122, 122, 122, 121,
- /* 1180 */ 121, 120, 120, 120, 119, 116, 444, 203, 1419, 568,
- /* 1190 */ 1294, 864, 464, 1213, 436, 122, 122, 122, 122, 121,
- /* 1200 */ 121, 120, 120, 120, 119, 116, 444, 553, 1137, 1642,
- /* 1210 */ 539, 1642, 15, 15, 892, 122, 122, 122, 122, 121,
- /* 1220 */ 121, 120, 120, 120, 119, 116, 444, 568, 298, 538,
- /* 1230 */ 1135, 1419, 1559, 1560, 1331, 409, 6, 6, 1169, 1268,
- /* 1240 */ 415, 320, 284, 284, 1419, 508, 565, 525, 300, 457,
- /* 1250 */ 43, 43, 568, 893, 12, 565, 330, 478, 425, 407,
- /* 1260 */ 126, 80, 1217, 1217, 1050, 1053, 1040, 1040, 123, 123,
- /* 1270 */ 124, 124, 124, 124, 568, 57, 57, 288, 1192, 1419,
- /* 1280 */ 496, 458, 392, 392, 391, 273, 389, 1135, 1558, 849,
- /* 1290 */ 1169, 407, 6, 568, 321, 1158, 470, 44, 44, 1557,
- /* 1300 */ 1114, 426, 234, 6, 323, 256, 540, 256, 1158, 431,
- /* 1310 */ 568, 1158, 322, 17, 487, 1115, 58, 58, 122, 122,
- /* 1320 */ 122, 122, 121, 121, 120, 120, 120, 119, 116, 444,
- /* 1330 */ 1116, 216, 481, 59, 59, 1192, 1193, 1194, 111, 560,
- /* 1340 */ 324, 4, 236, 456, 526, 568, 237, 456, 568, 437,
- /* 1350 */ 168, 556, 420, 141, 479, 563, 568, 293, 568, 1095,
- /* 1360 */ 568, 293, 568, 1095, 531, 568, 872, 8, 60, 60,
- /* 1370 */ 235, 61, 61, 568, 414, 568, 414, 568, 445, 62,
- /* 1380 */ 62, 45, 45, 46, 46, 47, 47, 199, 49, 49,
- /* 1390 */ 557, 568, 359, 568, 100, 486, 50, 50, 63, 63,
- /* 1400 */ 64, 64, 561, 415, 535, 410, 568, 1027, 568, 534,
- /* 1410 */ 316, 559, 316, 559, 65, 65, 14, 14, 568, 1027,
- /* 1420 */ 568, 512, 932, 872, 1018, 109, 109, 931, 1017, 66,
- /* 1430 */ 66, 131, 131, 110, 451, 445, 570, 569, 416, 177,
- /* 1440 */ 1017, 132, 132, 67, 67, 568, 467, 568, 932, 471,
- /* 1450 */ 1364, 283, 226, 931, 315, 1363, 407, 568, 459, 407,
- /* 1460 */ 1017, 1017, 1019, 239, 407, 86, 213, 1350, 52, 52,
- /* 1470 */ 68, 68, 1017, 1017, 1019, 1020, 27, 1585, 1180, 447,
- /* 1480 */ 69, 69, 288, 97, 108, 1541, 106, 392, 392, 391,
- /* 1490 */ 273, 389, 568, 879, 849, 883, 568, 111, 560, 466,
- /* 1500 */ 4, 568, 152, 30, 38, 568, 1132, 234, 396, 323,
- /* 1510 */ 111, 560, 527, 4, 563, 53, 53, 322, 568, 163,
- /* 1520 */ 163, 568, 337, 468, 164, 164, 333, 563, 76, 76,
- /* 1530 */ 568, 289, 1514, 568, 31, 1513, 568, 445, 338, 483,
- /* 1540 */ 100, 54, 54, 344, 72, 72, 296, 236, 1080, 557,
- /* 1550 */ 445, 879, 1360, 134, 134, 168, 73, 73, 141, 161,
- /* 1560 */ 161, 1574, 557, 535, 568, 319, 568, 348, 536, 1009,
- /* 1570 */ 473, 261, 261, 891, 890, 235, 535, 568, 1027, 568,
- /* 1580 */ 475, 534, 261, 367, 109, 109, 521, 136, 136, 130,
- /* 1590 */ 130, 1027, 110, 366, 445, 570, 569, 109, 109, 1017,
- /* 1600 */ 162, 162, 156, 156, 568, 110, 1080, 445, 570, 569,
- /* 1610 */ 410, 351, 1017, 568, 353, 316, 559, 568, 343, 568,
- /* 1620 */ 100, 497, 357, 258, 100, 898, 899, 140, 140, 355,
- /* 1630 */ 1310, 1017, 1017, 1019, 1020, 27, 139, 139, 362, 451,
- /* 1640 */ 137, 137, 138, 138, 1017, 1017, 1019, 1020, 27, 1180,
- /* 1650 */ 447, 568, 372, 288, 111, 560, 1021, 4, 392, 392,
- /* 1660 */ 391, 273, 389, 568, 1141, 849, 568, 1076, 568, 258,
- /* 1670 */ 492, 563, 568, 211, 75, 75, 555, 962, 234, 261,
- /* 1680 */ 323, 111, 560, 929, 4, 113, 77, 77, 322, 74,
- /* 1690 */ 74, 42, 42, 1373, 445, 48, 48, 1418, 563, 974,
- /* 1700 */ 975, 1092, 1091, 1092, 1091, 862, 557, 150, 930, 1346,
- /* 1710 */ 113, 1358, 554, 1424, 1021, 1275, 1266, 1254, 236, 1253,
- /* 1720 */ 1255, 445, 1593, 1343, 308, 276, 168, 309, 11, 141,
- /* 1730 */ 393, 310, 232, 557, 1405, 1027, 335, 291, 1400, 219,
- /* 1740 */ 336, 109, 109, 936, 297, 1410, 235, 341, 477, 110,
- /* 1750 */ 502, 445, 570, 569, 1393, 1409, 1017, 400, 1293, 365,
- /* 1760 */ 223, 1486, 1027, 1485, 1355, 1356, 1354, 1353, 109, 109,
- /* 1770 */ 204, 1596, 1232, 558, 265, 218, 110, 205, 445, 570,
- /* 1780 */ 569, 410, 387, 1017, 1533, 179, 316, 559, 1017, 1017,
- /* 1790 */ 1019, 1020, 27, 230, 1531, 1229, 79, 560, 85, 4,
- /* 1800 */ 418, 215, 548, 81, 84, 188, 1406, 173, 181, 461,
- /* 1810 */ 451, 35, 462, 563, 183, 1017, 1017, 1019, 1020, 27,
- /* 1820 */ 184, 1491, 185, 186, 495, 242, 98, 398, 1412, 36,
- /* 1830 */ 1411, 484, 91, 469, 401, 1414, 445, 192, 1480, 246,
- /* 1840 */ 1502, 490, 346, 277, 248, 196, 493, 511, 557, 350,
- /* 1850 */ 1256, 249, 250, 403, 1313, 1312, 111, 560, 432, 4,
- /* 1860 */ 1311, 1304, 93, 1611, 883, 1610, 224, 404, 434, 520,
- /* 1870 */ 263, 435, 1579, 563, 1283, 1282, 364, 1027, 306, 1281,
- /* 1880 */ 264, 1609, 1565, 109, 109, 370, 1303, 307, 1564, 438,
- /* 1890 */ 128, 110, 1378, 445, 570, 569, 445, 546, 1017, 10,
- /* 1900 */ 1466, 105, 381, 1377, 34, 572, 99, 1336, 557, 314,
- /* 1910 */ 1186, 530, 272, 274, 379, 210, 1335, 547, 385, 386,
- /* 1920 */ 275, 573, 1251, 1246, 411, 412, 1518, 165, 178, 1519,
- /* 1930 */ 1017, 1017, 1019, 1020, 27, 1517, 1516, 1027, 78, 147,
- /* 1940 */ 166, 220, 221, 109, 109, 836, 304, 167, 446, 212,
- /* 1950 */ 318, 110, 231, 445, 570, 569, 144, 1090, 1017, 1088,
- /* 1960 */ 326, 180, 169, 1212, 182, 334, 238, 915, 241, 1104,
- /* 1970 */ 187, 170, 171, 421, 87, 88, 423, 189, 89, 90,
- /* 1980 */ 172, 1107, 243, 1103, 244, 158, 18, 245, 345, 247,
- /* 1990 */ 1017, 1017, 1019, 1020, 27, 261, 1096, 193, 1226, 489,
- /* 2000 */ 194, 37, 366, 851, 494, 251, 195, 506, 92, 19,
- /* 2010 */ 498, 358, 20, 503, 881, 361, 94, 894, 305, 159,
- /* 2020 */ 513, 39, 95, 1174, 160, 1056, 966, 1143, 96, 174,
- /* 2030 */ 1142, 225, 280, 282, 198, 960, 113, 1164, 1160, 260,
- /* 2040 */ 21, 22, 23, 1162, 1168, 1167, 1148, 24, 33, 25,
- /* 2050 */ 202, 542, 26, 100, 1071, 102, 1057, 103, 7, 1055,
- /* 2060 */ 1059, 1113, 1060, 1112, 266, 267, 28, 40, 390, 1022,
- /* 2070 */ 863, 112, 29, 564, 1182, 1181, 268, 176, 143, 925,
- /* 2080 */ 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242,
- /* 2090 */ 1242, 1242, 1242, 1242, 269, 1602, 1242, 1601,
+ /* 0 */ 130, 127, 234, 282, 282, 1328, 576, 1307, 460, 289,
+ /* 10 */ 289, 576, 1622, 381, 576, 1328, 573, 576, 562, 413,
+ /* 20 */ 1300, 1542, 573, 481, 562, 524, 460, 459, 558, 82,
+ /* 30 */ 82, 983, 294, 375, 51, 51, 498, 61, 61, 984,
+ /* 40 */ 82, 82, 1577, 137, 138, 91, 7, 1228, 1228, 1063,
+ /* 50 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 413,
+ /* 60 */ 288, 288, 182, 288, 288, 481, 536, 288, 288, 130,
+ /* 70 */ 127, 234, 432, 573, 525, 562, 573, 557, 562, 1290,
+ /* 80 */ 573, 421, 562, 137, 138, 91, 559, 1228, 1228, 1063,
+ /* 90 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 296,
+ /* 100 */ 460, 398, 1249, 134, 134, 134, 134, 133, 133, 132,
+ /* 110 */ 132, 132, 131, 128, 451, 44, 1050, 1050, 1064, 1067,
+ /* 120 */ 1255, 1, 1, 582, 2, 1259, 581, 1174, 1259, 1174,
+ /* 130 */ 321, 413, 155, 321, 1584, 155, 379, 112, 498, 1341,
+ /* 140 */ 456, 299, 1341, 134, 134, 134, 134, 133, 133, 132,
+ /* 150 */ 132, 132, 131, 128, 451, 137, 138, 91, 1105, 1228,
+ /* 160 */ 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136,
+ /* 170 */ 136, 1204, 320, 567, 288, 288, 283, 288, 288, 523,
+ /* 180 */ 523, 1250, 139, 1541, 7, 214, 503, 573, 1169, 562,
+ /* 190 */ 573, 1054, 562, 136, 136, 136, 136, 129, 401, 547,
+ /* 200 */ 487, 1169, 245, 1568, 1169, 245, 133, 133, 132, 132,
+ /* 210 */ 132, 131, 128, 451, 261, 134, 134, 134, 134, 133,
+ /* 220 */ 133, 132, 132, 132, 131, 128, 451, 451, 1204, 1205,
+ /* 230 */ 1204, 130, 127, 234, 455, 413, 182, 455, 130, 127,
+ /* 240 */ 234, 134, 134, 134, 134, 133, 133, 132, 132, 132,
+ /* 250 */ 131, 128, 451, 136, 136, 136, 136, 538, 576, 137,
+ /* 260 */ 138, 91, 261, 1228, 1228, 1063, 1066, 1053, 1053, 135,
+ /* 270 */ 135, 136, 136, 136, 136, 44, 472, 346, 1204, 472,
+ /* 280 */ 346, 51, 51, 418, 93, 157, 134, 134, 134, 134,
+ /* 290 */ 133, 133, 132, 132, 132, 131, 128, 451, 166, 363,
+ /* 300 */ 298, 134, 134, 134, 134, 133, 133, 132, 132, 132,
+ /* 310 */ 131, 128, 451, 1293, 461, 1570, 423, 377, 275, 134,
+ /* 320 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128,
+ /* 330 */ 451, 418, 320, 567, 1292, 1204, 1205, 1204, 257, 413,
+ /* 340 */ 483, 511, 508, 507, 94, 132, 132, 132, 131, 128,
+ /* 350 */ 451, 506, 1204, 548, 548, 388, 576, 384, 7, 413,
+ /* 360 */ 550, 229, 522, 137, 138, 91, 530, 1228, 1228, 1063,
+ /* 370 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 51,
+ /* 380 */ 51, 1582, 380, 137, 138, 91, 331, 1228, 1228, 1063,
+ /* 390 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 320,
+ /* 400 */ 567, 288, 288, 320, 567, 1602, 582, 2, 1259, 1204,
+ /* 410 */ 1205, 1204, 1628, 321, 573, 155, 562, 576, 1511, 264,
+ /* 420 */ 231, 520, 1341, 134, 134, 134, 134, 133, 133, 132,
+ /* 430 */ 132, 132, 131, 128, 451, 519, 1511, 1513, 1333, 1333,
+ /* 440 */ 82, 82, 498, 134, 134, 134, 134, 133, 133, 132,
+ /* 450 */ 132, 132, 131, 128, 451, 1435, 257, 288, 288, 511,
+ /* 460 */ 508, 507, 944, 1568, 413, 1019, 1204, 943, 360, 506,
+ /* 470 */ 573, 1598, 562, 44, 575, 551, 551, 557, 1107, 1582,
+ /* 480 */ 544, 576, 1107, 40, 417, 245, 531, 1505, 137, 138,
+ /* 490 */ 91, 219, 1228, 1228, 1063, 1066, 1053, 1053, 135, 135,
+ /* 500 */ 136, 136, 136, 136, 81, 81, 1281, 1204, 413, 553,
+ /* 510 */ 1511, 48, 512, 448, 447, 493, 578, 455, 578, 344,
+ /* 520 */ 45, 1204, 1233, 1204, 1205, 1204, 428, 1235, 158, 882,
+ /* 530 */ 320, 567, 137, 138, 91, 1234, 1228, 1228, 1063, 1066,
+ /* 540 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 134, 134,
+ /* 550 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 451,
+ /* 560 */ 1236, 576, 1236, 329, 1204, 1205, 1204, 387, 492, 403,
+ /* 570 */ 1040, 382, 489, 123, 568, 1569, 4, 377, 1204, 1205,
+ /* 580 */ 1204, 570, 570, 570, 82, 82, 882, 1029, 1331, 1331,
+ /* 590 */ 571, 1028, 134, 134, 134, 134, 133, 133, 132, 132,
+ /* 600 */ 132, 131, 128, 451, 288, 288, 1281, 1204, 576, 423,
+ /* 610 */ 576, 1568, 413, 423, 452, 378, 886, 573, 1279, 562,
+ /* 620 */ 46, 557, 532, 1028, 1028, 1030, 565, 130, 127, 234,
+ /* 630 */ 556, 82, 82, 82, 82, 479, 137, 138, 91, 462,
+ /* 640 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136,
+ /* 650 */ 136, 136, 1188, 487, 1506, 1040, 413, 6, 1204, 50,
+ /* 660 */ 879, 121, 121, 948, 1204, 1205, 1204, 358, 557, 122,
+ /* 670 */ 316, 452, 577, 452, 535, 1204, 1028, 439, 303, 212,
+ /* 680 */ 137, 138, 91, 213, 1228, 1228, 1063, 1066, 1053, 1053,
+ /* 690 */ 135, 135, 136, 136, 136, 136, 134, 134, 134, 134,
+ /* 700 */ 133, 133, 132, 132, 132, 131, 128, 451, 1028, 1028,
+ /* 710 */ 1030, 1031, 35, 288, 288, 1204, 1205, 1204, 1040, 1339,
+ /* 720 */ 533, 123, 568, 1569, 4, 377, 573, 1019, 562, 353,
+ /* 730 */ 1277, 356, 1204, 1205, 1204, 1029, 488, 1188, 571, 1028,
+ /* 740 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131,
+ /* 750 */ 128, 451, 576, 343, 288, 288, 449, 449, 449, 971,
+ /* 760 */ 413, 1627, 452, 911, 1187, 288, 288, 573, 464, 562,
+ /* 770 */ 238, 1028, 1028, 1030, 565, 82, 82, 498, 573, 411,
+ /* 780 */ 562, 344, 467, 332, 137, 138, 91, 197, 1228, 1228,
+ /* 790 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136,
+ /* 800 */ 1188, 528, 1169, 1040, 413, 1110, 1110, 495, 1041, 121,
+ /* 810 */ 121, 1204, 317, 540, 862, 1169, 1244, 122, 1169, 452,
+ /* 820 */ 577, 452, 1340, 198, 1028, 1204, 481, 526, 137, 138,
+ /* 830 */ 91, 560, 1228, 1228, 1063, 1066, 1053, 1053, 135, 135,
+ /* 840 */ 136, 136, 136, 136, 134, 134, 134, 134, 133, 133,
+ /* 850 */ 132, 132, 132, 131, 128, 451, 1028, 1028, 1030, 1031,
+ /* 860 */ 35, 1204, 288, 288, 1204, 477, 288, 288, 1204, 1205,
+ /* 870 */ 1204, 539, 481, 437, 470, 573, 1451, 562, 364, 573,
+ /* 880 */ 1153, 562, 1204, 1205, 1204, 1188, 5, 576, 134, 134,
+ /* 890 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 451,
+ /* 900 */ 221, 214, 302, 96, 1149, 1657, 232, 1657, 413, 392,
+ /* 910 */ 19, 19, 1024, 949, 406, 373, 1595, 1085, 1204, 1205,
+ /* 920 */ 1204, 1204, 1205, 1204, 1204, 426, 1149, 1658, 413, 1658,
+ /* 930 */ 1659, 399, 137, 138, 91, 3, 1228, 1228, 1063, 1066,
+ /* 940 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 304, 1311,
+ /* 950 */ 514, 1204, 137, 138, 91, 1498, 1228, 1228, 1063, 1066,
+ /* 960 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 434, 131,
+ /* 970 */ 128, 451, 375, 1204, 274, 291, 372, 517, 367, 516,
+ /* 980 */ 262, 1204, 1205, 1204, 1147, 227, 363, 448, 447, 1435,
+ /* 990 */ 1568, 1310, 134, 134, 134, 134, 133, 133, 132, 132,
+ /* 1000 */ 132, 131, 128, 451, 1568, 576, 1147, 487, 1204, 1205,
+ /* 1010 */ 1204, 442, 134, 134, 134, 134, 133, 133, 132, 132,
+ /* 1020 */ 132, 131, 128, 451, 386, 576, 485, 576, 19, 19,
+ /* 1030 */ 1204, 1205, 1204, 1345, 1236, 970, 1236, 574, 47, 936,
+ /* 1040 */ 936, 473, 413, 431, 1552, 573, 1125, 562, 19, 19,
+ /* 1050 */ 19, 19, 49, 336, 850, 851, 852, 111, 1368, 315,
+ /* 1060 */ 429, 576, 413, 433, 341, 306, 137, 138, 91, 115,
+ /* 1070 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136,
+ /* 1080 */ 136, 136, 576, 1309, 82, 82, 137, 138, 91, 529,
+ /* 1090 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136,
+ /* 1100 */ 136, 136, 1569, 222, 377, 19, 19, 305, 1126, 1169,
+ /* 1110 */ 398, 1148, 22, 22, 498, 333, 1569, 335, 377, 576,
+ /* 1120 */ 438, 445, 1169, 1127, 486, 1169, 134, 134, 134, 134,
+ /* 1130 */ 133, 133, 132, 132, 132, 131, 128, 451, 1128, 576,
+ /* 1140 */ 902, 576, 145, 145, 6, 576, 134, 134, 134, 134,
+ /* 1150 */ 133, 133, 132, 132, 132, 131, 128, 451, 214, 1336,
+ /* 1160 */ 922, 576, 19, 19, 19, 19, 1282, 419, 19, 19,
+ /* 1170 */ 923, 412, 515, 141, 576, 1169, 413, 206, 465, 207,
+ /* 1180 */ 903, 215, 1575, 552, 147, 147, 7, 227, 1169, 411,
+ /* 1190 */ 1250, 1169, 120, 307, 117, 307, 413, 66, 66, 334,
+ /* 1200 */ 137, 138, 91, 119, 1228, 1228, 1063, 1066, 1053, 1053,
+ /* 1210 */ 135, 135, 136, 136, 136, 136, 413, 285, 209, 969,
+ /* 1220 */ 137, 138, 91, 471, 1228, 1228, 1063, 1066, 1053, 1053,
+ /* 1230 */ 135, 135, 136, 136, 136, 136, 435, 10, 1450, 267,
+ /* 1240 */ 137, 126, 91, 1435, 1228, 1228, 1063, 1066, 1053, 1053,
+ /* 1250 */ 135, 135, 136, 136, 136, 136, 1435, 1435, 410, 409,
+ /* 1260 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131,
+ /* 1270 */ 128, 451, 576, 969, 576, 1224, 498, 373, 1595, 1554,
+ /* 1280 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131,
+ /* 1290 */ 128, 451, 532, 457, 576, 82, 82, 82, 82, 111,
+ /* 1300 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131,
+ /* 1310 */ 128, 451, 109, 233, 430, 1576, 546, 67, 67, 7,
+ /* 1320 */ 413, 351, 550, 1550, 260, 259, 258, 494, 443, 569,
+ /* 1330 */ 419, 983, 446, 1224, 450, 545, 1207, 576, 969, 984,
+ /* 1340 */ 413, 475, 1449, 1574, 1180, 138, 91, 7, 1228, 1228,
+ /* 1350 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136,
+ /* 1360 */ 21, 21, 267, 576, 300, 1126, 91, 233, 1228, 1228,
+ /* 1370 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136,
+ /* 1380 */ 1127, 373, 1595, 161, 1573, 16, 53, 53, 7, 108,
+ /* 1390 */ 533, 38, 969, 125, 1207, 1128, 1180, 576, 1224, 123,
+ /* 1400 */ 568, 893, 4, 324, 134, 134, 134, 134, 133, 133,
+ /* 1410 */ 132, 132, 132, 131, 128, 451, 571, 564, 534, 576,
+ /* 1420 */ 68, 68, 576, 39, 134, 134, 134, 134, 133, 133,
+ /* 1430 */ 132, 132, 132, 131, 128, 451, 576, 160, 1571, 1223,
+ /* 1440 */ 452, 576, 54, 54, 576, 69, 69, 576, 1366, 576,
+ /* 1450 */ 420, 184, 565, 463, 297, 576, 1224, 463, 297, 70,
+ /* 1460 */ 70, 576, 44, 474, 71, 71, 576, 72, 72, 576,
+ /* 1470 */ 73, 73, 55, 55, 411, 874, 242, 576, 56, 56,
+ /* 1480 */ 576, 1040, 576, 478, 57, 57, 576, 121, 121, 59,
+ /* 1490 */ 59, 23, 60, 60, 411, 122, 319, 452, 577, 452,
+ /* 1500 */ 74, 74, 1028, 75, 75, 76, 76, 411, 290, 20,
+ /* 1510 */ 20, 108, 287, 231, 553, 123, 568, 325, 4, 320,
+ /* 1520 */ 567, 97, 218, 944, 1144, 328, 400, 576, 943, 576,
+ /* 1530 */ 1380, 424, 571, 874, 1028, 1028, 1030, 1031, 35, 293,
+ /* 1540 */ 534, 576, 1104, 576, 1104, 9, 576, 342, 576, 111,
+ /* 1550 */ 77, 77, 143, 143, 576, 205, 452, 222, 1379, 889,
+ /* 1560 */ 576, 901, 900, 1188, 144, 144, 78, 78, 565, 62,
+ /* 1570 */ 62, 79, 79, 323, 1021, 576, 266, 63, 63, 908,
+ /* 1580 */ 909, 1589, 542, 80, 80, 576, 371, 541, 123, 568,
+ /* 1590 */ 480, 4, 266, 482, 244, 266, 370, 1040, 64, 64,
+ /* 1600 */ 576, 466, 576, 121, 121, 571, 1557, 576, 170, 170,
+ /* 1610 */ 576, 122, 576, 452, 577, 452, 576, 889, 1028, 576,
+ /* 1620 */ 165, 576, 111, 171, 171, 87, 87, 337, 1616, 452,
+ /* 1630 */ 65, 65, 1530, 83, 83, 146, 146, 986, 987, 84,
+ /* 1640 */ 84, 565, 168, 168, 148, 148, 1092, 347, 1032, 111,
+ /* 1650 */ 1028, 1028, 1030, 1031, 35, 542, 1103, 576, 1103, 576,
+ /* 1660 */ 543, 123, 568, 504, 4, 263, 576, 361, 1529, 111,
+ /* 1670 */ 1040, 1088, 576, 263, 576, 490, 121, 121, 571, 1188,
+ /* 1680 */ 142, 142, 169, 169, 122, 576, 452, 577, 452, 162,
+ /* 1690 */ 162, 1028, 576, 563, 576, 152, 152, 151, 151, 348,
+ /* 1700 */ 1376, 974, 452, 266, 1092, 942, 1032, 125, 149, 149,
+ /* 1710 */ 939, 576, 125, 576, 565, 150, 150, 86, 86, 872,
+ /* 1720 */ 352, 159, 576, 1028, 1028, 1030, 1031, 35, 542, 941,
+ /* 1730 */ 576, 125, 355, 541, 88, 88, 85, 85, 357, 359,
+ /* 1740 */ 1324, 1308, 366, 1040, 376, 52, 52, 499, 1389, 121,
+ /* 1750 */ 121, 1434, 1188, 58, 58, 1362, 1374, 122, 1439, 452,
+ /* 1760 */ 577, 452, 1289, 167, 1028, 1280, 280, 1268, 1267, 1269,
+ /* 1770 */ 1609, 1359, 312, 313, 12, 314, 397, 1421, 224, 1416,
+ /* 1780 */ 295, 237, 1409, 339, 340, 1426, 301, 345, 484, 228,
+ /* 1790 */ 1371, 1307, 1372, 1370, 1425, 404, 1028, 1028, 1030, 1031,
+ /* 1800 */ 35, 1601, 1192, 454, 509, 369, 292, 1502, 210, 1501,
+ /* 1810 */ 1369, 396, 396, 395, 277, 393, 211, 566, 859, 1612,
+ /* 1820 */ 1244, 123, 568, 391, 4, 1188, 223, 270, 1549, 1547,
+ /* 1830 */ 1241, 239, 186, 327, 422, 96, 195, 220, 571, 235,
+ /* 1840 */ 180, 326, 188, 468, 190, 1507, 191, 192, 92, 193,
+ /* 1850 */ 469, 95, 1422, 13, 502, 247, 1430, 109, 199, 402,
+ /* 1860 */ 476, 405, 452, 1496, 1428, 1427, 14, 491, 251, 102,
+ /* 1870 */ 497, 1518, 241, 281, 565, 253, 203, 354, 500, 254,
+ /* 1880 */ 175, 1270, 407, 43, 350, 518, 1327, 436, 255, 1326,
+ /* 1890 */ 1325, 1318, 104, 893, 1626, 229, 408, 440, 1625, 441,
+ /* 1900 */ 240, 310, 1296, 1040, 311, 1317, 527, 1594, 1297, 121,
+ /* 1910 */ 121, 368, 1295, 1624, 268, 269, 1580, 122, 1579, 452,
+ /* 1920 */ 577, 452, 374, 444, 1028, 1394, 1393, 140, 553, 90,
+ /* 1930 */ 568, 11, 4, 1483, 383, 414, 385, 110, 116, 216,
+ /* 1940 */ 320, 567, 1350, 555, 42, 318, 571, 537, 1349, 389,
+ /* 1950 */ 390, 579, 1198, 276, 279, 278, 1028, 1028, 1030, 1031,
+ /* 1960 */ 35, 580, 415, 1265, 458, 1260, 416, 185, 1534, 172,
+ /* 1970 */ 452, 1535, 173, 156, 308, 846, 1533, 1532, 453, 217,
+ /* 1980 */ 225, 89, 565, 174, 322, 1188, 226, 236, 1102, 154,
+ /* 1990 */ 1100, 330, 176, 187, 1223, 189, 925, 338, 243, 1116,
+ /* 2000 */ 246, 194, 177, 178, 425, 427, 98, 99, 196, 100,
+ /* 2010 */ 101, 1040, 179, 1119, 248, 1115, 249, 121, 121, 24,
+ /* 2020 */ 163, 250, 349, 1108, 266, 122, 1238, 452, 577, 452,
+ /* 2030 */ 1192, 454, 1028, 200, 292, 496, 252, 201, 861, 396,
+ /* 2040 */ 396, 395, 277, 393, 15, 501, 859, 370, 292, 256,
+ /* 2050 */ 202, 554, 505, 396, 396, 395, 277, 393, 103, 239,
+ /* 2060 */ 859, 327, 25, 26, 1028, 1028, 1030, 1031, 35, 326,
+ /* 2070 */ 362, 510, 891, 239, 365, 327, 513, 904, 105, 309,
+ /* 2080 */ 164, 181, 27, 326, 106, 521, 107, 1185, 1069, 1155,
+ /* 2090 */ 17, 1154, 284, 1188, 286, 978, 265, 204, 125, 1171,
+ /* 2100 */ 241, 230, 972, 1175, 28, 1160, 29, 1179, 175, 1173,
+ /* 2110 */ 30, 43, 31, 1178, 241, 32, 41, 549, 8, 33,
+ /* 2120 */ 208, 111, 175, 1083, 1070, 43, 113, 1068, 240, 114,
+ /* 2130 */ 1072, 34, 1073, 561, 1124, 118, 271, 36, 18, 1194,
+ /* 2140 */ 1033, 873, 240, 935, 124, 37, 272, 273, 1617, 572,
+ /* 2150 */ 183, 153, 394, 1193, 1256, 1256, 1256, 1256, 1256, 1256,
+ /* 2160 */ 1256, 1256, 1256, 414, 1256, 1256, 1256, 1256, 320, 567,
+ /* 2170 */ 1256, 1256, 1256, 1256, 1256, 1256, 1256, 414, 1256, 1256,
+ /* 2180 */ 1256, 1256, 320, 567, 1256, 1256, 1256, 1256, 1256, 1256,
+ /* 2190 */ 1256, 1256, 458, 1256, 1256, 1256, 1256, 1256, 1256, 1256,
+ /* 2200 */ 1256, 1256, 1256, 1256, 1256, 1256, 458,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 193, 193, 193, 274, 275, 276, 193, 274, 275, 276,
- /* 10 */ 193, 223, 219, 225, 206, 210, 211, 212, 193, 19,
- /* 20 */ 219, 233, 216, 216, 217, 216, 217, 193, 295, 216,
- /* 30 */ 217, 31, 193, 216, 217, 193, 228, 213, 230, 39,
- /* 40 */ 206, 216, 217, 43, 44, 45, 46, 47, 48, 49,
- /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 193, 19,
- /* 60 */ 185, 186, 187, 188, 189, 190, 253, 274, 275, 276,
- /* 70 */ 195, 193, 197, 193, 261, 274, 275, 276, 253, 204,
- /* 80 */ 238, 204, 81, 43, 44, 45, 46, 47, 48, 49,
- /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 274, 275,
- /* 100 */ 276, 262, 102, 103, 104, 105, 106, 107, 108, 109,
- /* 110 */ 110, 111, 112, 113, 239, 240, 239, 240, 210, 211,
- /* 120 */ 212, 314, 315, 314, 59, 316, 86, 252, 88, 252,
- /* 130 */ 19, 314, 315, 256, 257, 113, 25, 72, 296, 138,
- /* 140 */ 139, 266, 102, 103, 104, 105, 106, 107, 108, 109,
- /* 150 */ 110, 111, 112, 113, 43, 44, 45, 46, 47, 48,
- /* 160 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 81,
- /* 170 */ 292, 59, 292, 298, 108, 109, 110, 111, 112, 113,
- /* 180 */ 69, 116, 117, 118, 72, 106, 107, 193, 111, 112,
- /* 190 */ 113, 54, 55, 56, 57, 58, 102, 103, 104, 105,
- /* 200 */ 106, 107, 108, 109, 110, 111, 112, 113, 120, 25,
- /* 210 */ 216, 217, 145, 102, 103, 104, 105, 106, 107, 108,
- /* 220 */ 109, 110, 111, 112, 113, 231, 138, 139, 116, 117,
- /* 230 */ 118, 164, 153, 19, 155, 54, 55, 56, 57, 102,
- /* 240 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
- /* 250 */ 113, 128, 129, 46, 47, 48, 49, 43, 44, 45,
- /* 260 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
- /* 270 */ 56, 57, 216, 193, 25, 59, 193, 19, 165, 166,
- /* 280 */ 193, 67, 24, 102, 103, 104, 105, 106, 107, 108,
- /* 290 */ 109, 110, 111, 112, 113, 73, 216, 217, 59, 216,
- /* 300 */ 217, 43, 44, 45, 46, 47, 48, 49, 50, 51,
- /* 310 */ 52, 53, 54, 55, 56, 57, 102, 103, 104, 105,
- /* 320 */ 106, 107, 108, 109, 110, 111, 112, 113, 121, 145,
- /* 330 */ 59, 193, 116, 117, 118, 119, 273, 204, 122, 123,
- /* 340 */ 124, 19, 20, 134, 22, 136, 137, 19, 132, 127,
- /* 350 */ 128, 129, 24, 22, 23, 116, 117, 118, 36, 193,
- /* 360 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
- /* 370 */ 112, 113, 239, 240, 311, 312, 215, 106, 107, 241,
- /* 380 */ 19, 59, 216, 217, 223, 252, 115, 116, 117, 118,
- /* 390 */ 151, 120, 26, 71, 193, 308, 309, 193, 149, 128,
- /* 400 */ 313, 216, 269, 81, 43, 44, 45, 46, 47, 48,
- /* 410 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 253,
- /* 420 */ 216, 217, 100, 95, 153, 59, 155, 261, 106, 107,
- /* 430 */ 25, 193, 101, 193, 193, 231, 114, 25, 116, 117,
- /* 440 */ 118, 113, 304, 121, 193, 204, 59, 119, 120, 121,
- /* 450 */ 122, 123, 124, 125, 216, 217, 193, 216, 217, 131,
- /* 460 */ 138, 139, 230, 102, 103, 104, 105, 106, 107, 108,
- /* 470 */ 109, 110, 111, 112, 113, 153, 154, 155, 156, 157,
- /* 480 */ 239, 240, 116, 117, 118, 76, 193, 23, 19, 25,
- /* 490 */ 22, 253, 23, 252, 253, 108, 87, 204, 89, 261,
- /* 500 */ 198, 92, 261, 116, 117, 118, 193, 306, 307, 216,
- /* 510 */ 217, 150, 43, 44, 45, 46, 47, 48, 49, 50,
- /* 520 */ 51, 52, 53, 54, 55, 56, 57, 59, 193, 216,
- /* 530 */ 217, 19, 239, 240, 283, 23, 106, 107, 108, 109,
- /* 540 */ 110, 111, 112, 113, 73, 252, 253, 142, 308, 309,
- /* 550 */ 138, 139, 81, 313, 145, 43, 44, 45, 46, 47,
- /* 560 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 570 */ 307, 102, 103, 104, 105, 106, 107, 108, 109, 110,
- /* 580 */ 111, 112, 113, 281, 116, 117, 118, 285, 23, 193,
- /* 590 */ 25, 119, 59, 193, 122, 123, 124, 59, 127, 203,
- /* 600 */ 59, 205, 19, 268, 132, 25, 23, 22, 193, 138,
- /* 610 */ 139, 249, 204, 251, 102, 103, 104, 105, 106, 107,
- /* 620 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
- /* 630 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 640 */ 57, 19, 22, 23, 59, 23, 25, 239, 240, 116,
- /* 650 */ 117, 118, 193, 11, 116, 117, 118, 116, 117, 118,
- /* 660 */ 252, 269, 22, 193, 15, 43, 44, 45, 46, 47,
- /* 670 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 680 */ 273, 143, 193, 118, 143, 102, 103, 104, 105, 106,
- /* 690 */ 107, 108, 109, 110, 111, 112, 113, 76, 118, 59,
- /* 700 */ 241, 116, 117, 118, 304, 216, 217, 292, 143, 60,
- /* 710 */ 89, 241, 19, 92, 193, 193, 23, 22, 311, 312,
- /* 720 */ 231, 101, 22, 143, 102, 103, 104, 105, 106, 107,
- /* 730 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
- /* 740 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 750 */ 57, 19, 193, 193, 59, 23, 116, 117, 118, 59,
- /* 760 */ 201, 21, 241, 304, 22, 206, 127, 128, 129, 193,
- /* 770 */ 128, 129, 235, 236, 304, 43, 44, 45, 46, 47,
- /* 780 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 790 */ 22, 193, 216, 217, 193, 102, 103, 104, 105, 106,
- /* 800 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 193,
- /* 810 */ 193, 116, 117, 118, 216, 217, 116, 117, 118, 226,
- /* 820 */ 80, 193, 19, 235, 236, 304, 23, 211, 212, 231,
- /* 830 */ 204, 216, 217, 205, 102, 103, 104, 105, 106, 107,
- /* 840 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
- /* 850 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 860 */ 57, 19, 193, 123, 76, 239, 240, 193, 253, 239,
- /* 870 */ 240, 239, 240, 193, 106, 107, 193, 89, 252, 193,
- /* 880 */ 92, 59, 252, 141, 252, 43, 44, 45, 46, 47,
- /* 890 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 900 */ 284, 161, 216, 217, 193, 102, 103, 104, 105, 106,
- /* 910 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 16,
- /* 920 */ 187, 188, 189, 190, 7, 8, 9, 309, 195, 25,
- /* 930 */ 197, 313, 19, 127, 128, 129, 262, 204, 22, 117,
- /* 940 */ 24, 216, 217, 263, 102, 103, 104, 105, 106, 107,
- /* 950 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
- /* 960 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 970 */ 57, 193, 239, 240, 193, 59, 19, 188, 253, 190,
- /* 980 */ 77, 226, 79, 193, 195, 252, 197, 193, 19, 301,
- /* 990 */ 302, 193, 193, 204, 216, 217, 226, 216, 217, 266,
- /* 1000 */ 204, 159, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 1010 */ 53, 54, 55, 56, 57, 102, 103, 104, 105, 106,
- /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 12, 239, 240,
- /* 1030 */ 232, 298, 238, 117, 253, 239, 240, 238, 259, 260,
- /* 1040 */ 193, 252, 27, 31, 193, 193, 142, 204, 252, 193,
- /* 1050 */ 193, 39, 262, 193, 100, 266, 278, 42, 204, 102,
- /* 1060 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
- /* 1070 */ 113, 117, 159, 216, 217, 121, 216, 217, 63, 193,
- /* 1080 */ 193, 193, 239, 240, 115, 116, 193, 298, 73, 238,
- /* 1090 */ 238, 231, 19, 239, 240, 252, 22, 24, 211, 212,
- /* 1100 */ 24, 193, 216, 217, 216, 217, 252, 153, 154, 155,
- /* 1110 */ 253, 16, 19, 144, 213, 268, 43, 44, 45, 46,
- /* 1120 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1130 */ 57, 238, 19, 59, 193, 59, 43, 44, 45, 46,
- /* 1140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1150 */ 57, 22, 23, 193, 25, 193, 43, 44, 45, 46,
- /* 1160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1170 */ 57, 284, 77, 193, 79, 102, 103, 104, 105, 106,
- /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 286, 193, 193,
- /* 1190 */ 193, 117, 291, 117, 232, 102, 103, 104, 105, 106,
- /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 204, 22, 23,
- /* 1210 */ 66, 25, 216, 217, 35, 102, 103, 104, 105, 106,
- /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 193, 268, 85,
- /* 1230 */ 101, 193, 309, 309, 240, 19, 313, 313, 94, 208,
- /* 1240 */ 209, 193, 239, 240, 193, 66, 252, 19, 268, 244,
- /* 1250 */ 216, 217, 193, 74, 213, 252, 161, 19, 263, 254,
- /* 1260 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 1270 */ 54, 55, 56, 57, 193, 216, 217, 5, 59, 193,
- /* 1280 */ 19, 244, 10, 11, 12, 13, 14, 101, 309, 17,
- /* 1290 */ 146, 254, 313, 193, 193, 76, 115, 216, 217, 309,
- /* 1300 */ 12, 263, 30, 313, 32, 46, 87, 46, 89, 130,
- /* 1310 */ 193, 92, 40, 22, 263, 27, 216, 217, 102, 103,
- /* 1320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
- /* 1330 */ 42, 150, 291, 216, 217, 116, 117, 118, 19, 20,
- /* 1340 */ 193, 22, 70, 260, 116, 193, 24, 264, 193, 263,
- /* 1350 */ 78, 63, 61, 81, 116, 36, 193, 260, 193, 29,
- /* 1360 */ 193, 264, 193, 33, 145, 193, 59, 48, 216, 217,
- /* 1370 */ 98, 216, 217, 193, 115, 193, 115, 193, 59, 216,
- /* 1380 */ 217, 216, 217, 216, 217, 216, 217, 255, 216, 217,
- /* 1390 */ 71, 193, 131, 193, 25, 65, 216, 217, 216, 217,
- /* 1400 */ 216, 217, 208, 209, 85, 133, 193, 100, 193, 90,
- /* 1410 */ 138, 139, 138, 139, 216, 217, 216, 217, 193, 100,
- /* 1420 */ 193, 108, 135, 116, 117, 106, 107, 140, 121, 216,
- /* 1430 */ 217, 216, 217, 114, 162, 116, 117, 118, 299, 300,
- /* 1440 */ 121, 216, 217, 216, 217, 193, 244, 193, 135, 244,
- /* 1450 */ 193, 256, 257, 140, 244, 193, 254, 193, 193, 254,
- /* 1460 */ 153, 154, 155, 141, 254, 149, 150, 258, 216, 217,
- /* 1470 */ 216, 217, 153, 154, 155, 156, 157, 0, 1, 2,
- /* 1480 */ 216, 217, 5, 115, 158, 193, 160, 10, 11, 12,
- /* 1490 */ 13, 14, 193, 59, 17, 126, 193, 19, 20, 129,
- /* 1500 */ 22, 193, 22, 22, 24, 193, 23, 30, 25, 32,
- /* 1510 */ 19, 20, 144, 22, 36, 216, 217, 40, 193, 216,
- /* 1520 */ 217, 193, 152, 129, 216, 217, 193, 36, 216, 217,
- /* 1530 */ 193, 99, 193, 193, 53, 193, 193, 59, 23, 193,
- /* 1540 */ 25, 216, 217, 193, 216, 217, 152, 70, 59, 71,
- /* 1550 */ 59, 117, 193, 216, 217, 78, 216, 217, 81, 216,
- /* 1560 */ 217, 318, 71, 85, 193, 133, 193, 193, 90, 23,
- /* 1570 */ 23, 25, 25, 120, 121, 98, 85, 193, 100, 193,
- /* 1580 */ 23, 90, 25, 121, 106, 107, 19, 216, 217, 216,
- /* 1590 */ 217, 100, 114, 131, 116, 117, 118, 106, 107, 121,
- /* 1600 */ 216, 217, 216, 217, 193, 114, 117, 116, 117, 118,
- /* 1610 */ 133, 193, 121, 193, 193, 138, 139, 193, 23, 193,
- /* 1620 */ 25, 23, 23, 25, 25, 7, 8, 216, 217, 193,
- /* 1630 */ 193, 153, 154, 155, 156, 157, 216, 217, 193, 162,
- /* 1640 */ 216, 217, 216, 217, 153, 154, 155, 156, 157, 1,
- /* 1650 */ 2, 193, 193, 5, 19, 20, 59, 22, 10, 11,
- /* 1660 */ 12, 13, 14, 193, 97, 17, 193, 23, 193, 25,
- /* 1670 */ 288, 36, 193, 242, 216, 217, 236, 23, 30, 25,
- /* 1680 */ 32, 19, 20, 23, 22, 25, 216, 217, 40, 216,
- /* 1690 */ 217, 216, 217, 193, 59, 216, 217, 193, 36, 83,
- /* 1700 */ 84, 153, 153, 155, 155, 23, 71, 25, 23, 193,
- /* 1710 */ 25, 193, 193, 193, 117, 193, 193, 193, 70, 193,
- /* 1720 */ 193, 59, 193, 255, 255, 287, 78, 255, 243, 81,
- /* 1730 */ 191, 255, 297, 71, 271, 100, 293, 245, 267, 214,
- /* 1740 */ 246, 106, 107, 108, 246, 271, 98, 245, 293, 114,
- /* 1750 */ 220, 116, 117, 118, 267, 271, 121, 271, 225, 219,
- /* 1760 */ 229, 219, 100, 219, 259, 259, 259, 259, 106, 107,
- /* 1770 */ 249, 196, 60, 280, 141, 243, 114, 249, 116, 117,
- /* 1780 */ 118, 133, 245, 121, 200, 297, 138, 139, 153, 154,
- /* 1790 */ 155, 156, 157, 297, 200, 38, 19, 20, 151, 22,
- /* 1800 */ 200, 150, 140, 294, 294, 22, 272, 43, 234, 18,
- /* 1810 */ 162, 270, 200, 36, 237, 153, 154, 155, 156, 157,
- /* 1820 */ 237, 283, 237, 237, 18, 199, 149, 246, 272, 270,
- /* 1830 */ 272, 200, 158, 246, 246, 234, 59, 234, 246, 199,
- /* 1840 */ 290, 62, 289, 200, 199, 22, 221, 115, 71, 200,
- /* 1850 */ 200, 199, 199, 221, 218, 218, 19, 20, 64, 22,
- /* 1860 */ 218, 227, 22, 224, 126, 224, 165, 221, 24, 305,
- /* 1870 */ 200, 113, 312, 36, 218, 220, 218, 100, 282, 218,
- /* 1880 */ 91, 218, 317, 106, 107, 221, 227, 282, 317, 82,
- /* 1890 */ 148, 114, 265, 116, 117, 118, 59, 145, 121, 22,
- /* 1900 */ 277, 158, 200, 265, 25, 202, 147, 250, 71, 279,
- /* 1910 */ 13, 146, 194, 194, 249, 248, 250, 140, 247, 246,
- /* 1920 */ 6, 192, 192, 192, 303, 303, 213, 207, 300, 213,
- /* 1930 */ 153, 154, 155, 156, 157, 213, 213, 100, 213, 222,
- /* 1940 */ 207, 214, 214, 106, 107, 4, 222, 207, 3, 22,
- /* 1950 */ 163, 114, 15, 116, 117, 118, 16, 23, 121, 23,
- /* 1960 */ 139, 151, 130, 25, 142, 16, 24, 20, 144, 1,
- /* 1970 */ 142, 130, 130, 61, 53, 53, 37, 151, 53, 53,
- /* 1980 */ 130, 116, 34, 1, 141, 5, 22, 115, 161, 141,
- /* 1990 */ 153, 154, 155, 156, 157, 25, 68, 68, 75, 41,
- /* 2000 */ 115, 24, 131, 20, 19, 125, 22, 96, 22, 22,
- /* 2010 */ 67, 23, 22, 67, 59, 24, 22, 28, 67, 23,
- /* 2020 */ 22, 22, 149, 23, 23, 23, 116, 23, 25, 37,
- /* 2030 */ 97, 141, 23, 23, 22, 143, 25, 75, 88, 34,
- /* 2040 */ 34, 34, 34, 86, 75, 93, 23, 34, 22, 34,
- /* 2050 */ 25, 24, 34, 25, 23, 142, 23, 142, 44, 23,
- /* 2060 */ 23, 23, 11, 23, 25, 22, 22, 22, 15, 23,
- /* 2070 */ 23, 22, 22, 25, 1, 1, 141, 25, 23, 135,
- /* 2080 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2090 */ 319, 319, 319, 319, 141, 141, 319, 141, 319, 319,
- /* 2100 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2110 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2120 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2130 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2140 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2150 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2160 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2170 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2180 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2190 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2200 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2210 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2220 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2230 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2240 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2250 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2260 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2270 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2280 */ 319, 319, 319,
+ /* 0 */ 276, 277, 278, 240, 241, 224, 194, 226, 194, 240,
+ /* 10 */ 241, 194, 216, 220, 194, 234, 253, 194, 255, 19,
+ /* 20 */ 224, 297, 253, 194, 255, 205, 212, 213, 205, 217,
+ /* 30 */ 218, 31, 205, 194, 217, 218, 194, 217, 218, 39,
+ /* 40 */ 217, 218, 312, 43, 44, 45, 316, 47, 48, 49,
+ /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 19,
+ /* 60 */ 240, 241, 194, 240, 241, 194, 254, 240, 241, 276,
+ /* 70 */ 277, 278, 233, 253, 254, 255, 253, 254, 255, 217,
+ /* 80 */ 253, 239, 255, 43, 44, 45, 263, 47, 48, 49,
+ /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 270,
+ /* 100 */ 286, 22, 23, 103, 104, 105, 106, 107, 108, 109,
+ /* 110 */ 110, 111, 112, 113, 114, 82, 47, 48, 49, 50,
+ /* 120 */ 186, 187, 188, 189, 190, 191, 189, 87, 191, 89,
+ /* 130 */ 196, 19, 198, 196, 317, 198, 319, 25, 194, 205,
+ /* 140 */ 298, 270, 205, 103, 104, 105, 106, 107, 108, 109,
+ /* 150 */ 110, 111, 112, 113, 114, 43, 44, 45, 11, 47,
+ /* 160 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ /* 170 */ 58, 60, 139, 140, 240, 241, 214, 240, 241, 311,
+ /* 180 */ 312, 102, 70, 239, 316, 194, 19, 253, 77, 255,
+ /* 190 */ 253, 122, 255, 55, 56, 57, 58, 59, 207, 88,
+ /* 200 */ 194, 90, 268, 194, 93, 268, 107, 108, 109, 110,
+ /* 210 */ 111, 112, 113, 114, 47, 103, 104, 105, 106, 107,
+ /* 220 */ 108, 109, 110, 111, 112, 113, 114, 114, 117, 118,
+ /* 230 */ 119, 276, 277, 278, 300, 19, 194, 300, 276, 277,
+ /* 240 */ 278, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ /* 250 */ 112, 113, 114, 55, 56, 57, 58, 146, 194, 43,
+ /* 260 */ 44, 45, 47, 47, 48, 49, 50, 51, 52, 53,
+ /* 270 */ 54, 55, 56, 57, 58, 82, 129, 130, 60, 129,
+ /* 280 */ 130, 217, 218, 116, 68, 25, 103, 104, 105, 106,
+ /* 290 */ 107, 108, 109, 110, 111, 112, 113, 114, 23, 132,
+ /* 300 */ 294, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ /* 310 */ 112, 113, 114, 217, 121, 306, 194, 308, 26, 103,
+ /* 320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
+ /* 330 */ 114, 116, 139, 140, 217, 117, 118, 119, 120, 19,
+ /* 340 */ 194, 123, 124, 125, 24, 109, 110, 111, 112, 113,
+ /* 350 */ 114, 133, 60, 311, 312, 250, 194, 252, 316, 19,
+ /* 360 */ 194, 166, 167, 43, 44, 45, 205, 47, 48, 49,
+ /* 370 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 217,
+ /* 380 */ 218, 317, 318, 43, 44, 45, 264, 47, 48, 49,
+ /* 390 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 139,
+ /* 400 */ 140, 240, 241, 139, 140, 188, 189, 190, 191, 117,
+ /* 410 */ 118, 119, 231, 196, 253, 198, 255, 194, 194, 258,
+ /* 420 */ 259, 146, 205, 103, 104, 105, 106, 107, 108, 109,
+ /* 430 */ 110, 111, 112, 113, 114, 109, 212, 213, 236, 237,
+ /* 440 */ 217, 218, 194, 103, 104, 105, 106, 107, 108, 109,
+ /* 450 */ 110, 111, 112, 113, 114, 194, 120, 240, 241, 123,
+ /* 460 */ 124, 125, 136, 194, 19, 74, 60, 141, 23, 133,
+ /* 470 */ 253, 194, 255, 82, 194, 309, 310, 254, 29, 317,
+ /* 480 */ 318, 194, 33, 22, 199, 268, 263, 239, 43, 44,
+ /* 490 */ 45, 151, 47, 48, 49, 50, 51, 52, 53, 54,
+ /* 500 */ 55, 56, 57, 58, 217, 218, 194, 60, 19, 146,
+ /* 510 */ 286, 242, 23, 107, 108, 66, 204, 300, 206, 128,
+ /* 520 */ 73, 60, 116, 117, 118, 119, 265, 121, 165, 60,
+ /* 530 */ 139, 140, 43, 44, 45, 129, 47, 48, 49, 50,
+ /* 540 */ 51, 52, 53, 54, 55, 56, 57, 58, 103, 104,
+ /* 550 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ /* 560 */ 154, 194, 156, 194, 117, 118, 119, 280, 283, 205,
+ /* 570 */ 101, 220, 287, 19, 20, 306, 22, 308, 117, 118,
+ /* 580 */ 119, 211, 212, 213, 217, 218, 117, 118, 236, 237,
+ /* 590 */ 36, 122, 103, 104, 105, 106, 107, 108, 109, 110,
+ /* 600 */ 111, 112, 113, 114, 240, 241, 194, 60, 194, 194,
+ /* 610 */ 194, 194, 19, 194, 60, 194, 23, 253, 206, 255,
+ /* 620 */ 73, 254, 19, 154, 155, 156, 72, 276, 277, 278,
+ /* 630 */ 263, 217, 218, 217, 218, 271, 43, 44, 45, 271,
+ /* 640 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* 650 */ 57, 58, 183, 194, 285, 101, 19, 214, 60, 242,
+ /* 660 */ 23, 107, 108, 109, 117, 118, 119, 16, 254, 115,
+ /* 670 */ 254, 117, 118, 119, 194, 60, 122, 263, 205, 264,
+ /* 680 */ 43, 44, 45, 264, 47, 48, 49, 50, 51, 52,
+ /* 690 */ 53, 54, 55, 56, 57, 58, 103, 104, 105, 106,
+ /* 700 */ 107, 108, 109, 110, 111, 112, 113, 114, 154, 155,
+ /* 710 */ 156, 157, 158, 240, 241, 117, 118, 119, 101, 205,
+ /* 720 */ 117, 19, 20, 306, 22, 308, 253, 74, 255, 78,
+ /* 730 */ 205, 80, 117, 118, 119, 118, 293, 183, 36, 122,
+ /* 740 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+ /* 750 */ 113, 114, 194, 294, 240, 241, 211, 212, 213, 144,
+ /* 760 */ 19, 23, 60, 25, 23, 240, 241, 253, 245, 255,
+ /* 770 */ 15, 154, 155, 156, 72, 217, 218, 194, 253, 256,
+ /* 780 */ 255, 128, 129, 130, 43, 44, 45, 22, 47, 48,
+ /* 790 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ /* 800 */ 183, 19, 77, 101, 19, 128, 129, 130, 23, 107,
+ /* 810 */ 108, 60, 254, 88, 21, 90, 61, 115, 93, 117,
+ /* 820 */ 118, 119, 239, 22, 122, 60, 194, 205, 43, 44,
+ /* 830 */ 45, 205, 47, 48, 49, 50, 51, 52, 53, 54,
+ /* 840 */ 55, 56, 57, 58, 103, 104, 105, 106, 107, 108,
+ /* 850 */ 109, 110, 111, 112, 113, 114, 154, 155, 156, 157,
+ /* 860 */ 158, 60, 240, 241, 60, 116, 240, 241, 117, 118,
+ /* 870 */ 119, 146, 194, 19, 81, 253, 275, 255, 24, 253,
+ /* 880 */ 98, 255, 117, 118, 119, 183, 22, 194, 103, 104,
+ /* 890 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ /* 900 */ 151, 194, 270, 152, 22, 23, 194, 25, 19, 202,
+ /* 910 */ 217, 218, 23, 109, 207, 314, 315, 124, 117, 118,
+ /* 920 */ 119, 117, 118, 119, 60, 232, 22, 23, 19, 25,
+ /* 930 */ 303, 304, 43, 44, 45, 22, 47, 48, 49, 50,
+ /* 940 */ 51, 52, 53, 54, 55, 56, 57, 58, 270, 227,
+ /* 950 */ 96, 60, 43, 44, 45, 162, 47, 48, 49, 50,
+ /* 960 */ 51, 52, 53, 54, 55, 56, 57, 58, 114, 112,
+ /* 970 */ 113, 114, 194, 60, 120, 121, 122, 123, 124, 125,
+ /* 980 */ 126, 117, 118, 119, 102, 25, 132, 107, 108, 194,
+ /* 990 */ 194, 227, 103, 104, 105, 106, 107, 108, 109, 110,
+ /* 1000 */ 111, 112, 113, 114, 194, 194, 102, 194, 117, 118,
+ /* 1010 */ 119, 233, 103, 104, 105, 106, 107, 108, 109, 110,
+ /* 1020 */ 111, 112, 113, 114, 194, 194, 19, 194, 217, 218,
+ /* 1030 */ 117, 118, 119, 241, 154, 144, 156, 135, 242, 137,
+ /* 1040 */ 138, 130, 19, 232, 194, 253, 23, 255, 217, 218,
+ /* 1050 */ 217, 218, 242, 16, 7, 8, 9, 25, 261, 262,
+ /* 1060 */ 265, 194, 19, 232, 153, 232, 43, 44, 45, 160,
+ /* 1070 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* 1080 */ 57, 58, 194, 227, 217, 218, 43, 44, 45, 194,
+ /* 1090 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* 1100 */ 57, 58, 306, 143, 308, 217, 218, 294, 12, 77,
+ /* 1110 */ 22, 23, 217, 218, 194, 78, 306, 80, 308, 194,
+ /* 1120 */ 232, 254, 90, 27, 117, 93, 103, 104, 105, 106,
+ /* 1130 */ 107, 108, 109, 110, 111, 112, 113, 114, 42, 194,
+ /* 1140 */ 35, 194, 217, 218, 214, 194, 103, 104, 105, 106,
+ /* 1150 */ 107, 108, 109, 110, 111, 112, 113, 114, 194, 239,
+ /* 1160 */ 64, 194, 217, 218, 217, 218, 209, 210, 217, 218,
+ /* 1170 */ 74, 207, 67, 22, 194, 77, 19, 232, 245, 232,
+ /* 1180 */ 75, 24, 312, 232, 217, 218, 316, 25, 90, 256,
+ /* 1190 */ 102, 93, 159, 229, 161, 231, 19, 217, 218, 162,
+ /* 1200 */ 43, 44, 45, 160, 47, 48, 49, 50, 51, 52,
+ /* 1210 */ 53, 54, 55, 56, 57, 58, 19, 23, 288, 25,
+ /* 1220 */ 43, 44, 45, 293, 47, 48, 49, 50, 51, 52,
+ /* 1230 */ 53, 54, 55, 56, 57, 58, 131, 22, 275, 24,
+ /* 1240 */ 43, 44, 45, 194, 47, 48, 49, 50, 51, 52,
+ /* 1250 */ 53, 54, 55, 56, 57, 58, 194, 194, 107, 108,
+ /* 1260 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+ /* 1270 */ 113, 114, 194, 25, 194, 60, 194, 314, 315, 194,
+ /* 1280 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+ /* 1290 */ 113, 114, 19, 194, 194, 217, 218, 217, 218, 25,
+ /* 1300 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+ /* 1310 */ 113, 114, 150, 119, 265, 312, 67, 217, 218, 316,
+ /* 1320 */ 19, 239, 194, 194, 128, 129, 130, 265, 265, 209,
+ /* 1330 */ 210, 31, 254, 118, 254, 86, 60, 194, 144, 39,
+ /* 1340 */ 19, 130, 275, 312, 95, 44, 45, 316, 47, 48,
+ /* 1350 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ /* 1360 */ 217, 218, 24, 194, 153, 12, 45, 119, 47, 48,
+ /* 1370 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ /* 1380 */ 27, 314, 315, 22, 312, 24, 217, 218, 316, 116,
+ /* 1390 */ 117, 22, 144, 25, 118, 42, 147, 194, 60, 19,
+ /* 1400 */ 20, 127, 22, 194, 103, 104, 105, 106, 107, 108,
+ /* 1410 */ 109, 110, 111, 112, 113, 114, 36, 64, 145, 194,
+ /* 1420 */ 217, 218, 194, 54, 103, 104, 105, 106, 107, 108,
+ /* 1430 */ 109, 110, 111, 112, 113, 114, 194, 22, 310, 25,
+ /* 1440 */ 60, 194, 217, 218, 194, 217, 218, 194, 260, 194,
+ /* 1450 */ 301, 302, 72, 262, 262, 194, 118, 266, 266, 217,
+ /* 1460 */ 218, 194, 82, 245, 217, 218, 194, 217, 218, 194,
+ /* 1470 */ 217, 218, 217, 218, 256, 60, 24, 194, 217, 218,
+ /* 1480 */ 194, 101, 194, 245, 217, 218, 194, 107, 108, 217,
+ /* 1490 */ 218, 22, 217, 218, 256, 115, 245, 117, 118, 119,
+ /* 1500 */ 217, 218, 122, 217, 218, 217, 218, 256, 22, 217,
+ /* 1510 */ 218, 116, 258, 259, 146, 19, 20, 194, 22, 139,
+ /* 1520 */ 140, 150, 151, 136, 23, 194, 25, 194, 141, 194,
+ /* 1530 */ 194, 62, 36, 118, 154, 155, 156, 157, 158, 100,
+ /* 1540 */ 145, 194, 154, 194, 156, 49, 194, 23, 194, 25,
+ /* 1550 */ 217, 218, 217, 218, 194, 257, 60, 143, 194, 60,
+ /* 1560 */ 194, 121, 122, 183, 217, 218, 217, 218, 72, 217,
+ /* 1570 */ 218, 217, 218, 134, 23, 194, 25, 217, 218, 7,
+ /* 1580 */ 8, 321, 86, 217, 218, 194, 122, 91, 19, 20,
+ /* 1590 */ 23, 22, 25, 23, 142, 25, 132, 101, 217, 218,
+ /* 1600 */ 194, 194, 194, 107, 108, 36, 194, 194, 217, 218,
+ /* 1610 */ 194, 115, 194, 117, 118, 119, 194, 118, 122, 194,
+ /* 1620 */ 23, 194, 25, 217, 218, 217, 218, 194, 142, 60,
+ /* 1630 */ 217, 218, 194, 217, 218, 217, 218, 84, 85, 217,
+ /* 1640 */ 218, 72, 217, 218, 217, 218, 60, 23, 60, 25,
+ /* 1650 */ 154, 155, 156, 157, 158, 86, 154, 194, 156, 194,
+ /* 1660 */ 91, 19, 20, 23, 22, 25, 194, 23, 194, 25,
+ /* 1670 */ 101, 23, 194, 25, 194, 194, 107, 108, 36, 183,
+ /* 1680 */ 217, 218, 217, 218, 115, 194, 117, 118, 119, 217,
+ /* 1690 */ 218, 122, 194, 237, 194, 217, 218, 217, 218, 194,
+ /* 1700 */ 194, 23, 60, 25, 118, 23, 118, 25, 217, 218,
+ /* 1710 */ 23, 194, 25, 194, 72, 217, 218, 217, 218, 23,
+ /* 1720 */ 194, 25, 194, 154, 155, 156, 157, 158, 86, 23,
+ /* 1730 */ 194, 25, 194, 91, 217, 218, 217, 218, 194, 194,
+ /* 1740 */ 194, 194, 194, 101, 194, 217, 218, 290, 194, 107,
+ /* 1750 */ 108, 194, 183, 217, 218, 194, 194, 115, 194, 117,
+ /* 1760 */ 118, 119, 194, 243, 122, 194, 289, 194, 194, 194,
+ /* 1770 */ 194, 257, 257, 257, 244, 257, 192, 273, 215, 269,
+ /* 1780 */ 246, 299, 269, 295, 247, 273, 247, 246, 295, 230,
+ /* 1790 */ 261, 226, 261, 261, 273, 273, 154, 155, 156, 157,
+ /* 1800 */ 158, 0, 1, 2, 221, 220, 5, 220, 250, 220,
+ /* 1810 */ 261, 10, 11, 12, 13, 14, 250, 282, 17, 197,
+ /* 1820 */ 61, 19, 20, 246, 22, 183, 244, 142, 201, 201,
+ /* 1830 */ 38, 30, 299, 32, 201, 152, 22, 151, 36, 299,
+ /* 1840 */ 43, 40, 235, 18, 238, 285, 238, 238, 296, 238,
+ /* 1850 */ 201, 296, 274, 272, 18, 200, 235, 150, 235, 247,
+ /* 1860 */ 247, 247, 60, 247, 274, 274, 272, 201, 200, 159,
+ /* 1870 */ 63, 292, 71, 201, 72, 200, 22, 201, 222, 200,
+ /* 1880 */ 79, 201, 222, 82, 291, 116, 219, 65, 200, 219,
+ /* 1890 */ 219, 228, 22, 127, 225, 166, 222, 24, 225, 114,
+ /* 1900 */ 99, 284, 221, 101, 284, 228, 307, 315, 219, 107,
+ /* 1910 */ 108, 219, 219, 219, 201, 92, 320, 115, 320, 117,
+ /* 1920 */ 118, 119, 222, 83, 122, 267, 267, 149, 146, 19,
+ /* 1930 */ 20, 22, 22, 279, 250, 134, 201, 148, 159, 249,
+ /* 1940 */ 139, 140, 251, 141, 25, 281, 36, 147, 251, 248,
+ /* 1950 */ 247, 203, 13, 195, 6, 195, 154, 155, 156, 157,
+ /* 1960 */ 158, 193, 305, 193, 163, 193, 305, 302, 214, 208,
+ /* 1970 */ 60, 214, 208, 223, 223, 4, 214, 214, 3, 22,
+ /* 1980 */ 215, 214, 72, 208, 164, 183, 215, 15, 23, 16,
+ /* 1990 */ 23, 140, 131, 152, 25, 143, 20, 16, 24, 1,
+ /* 2000 */ 145, 143, 131, 131, 62, 37, 54, 54, 152, 54,
+ /* 2010 */ 54, 101, 131, 117, 34, 1, 142, 107, 108, 22,
+ /* 2020 */ 5, 116, 162, 69, 25, 115, 76, 117, 118, 119,
+ /* 2030 */ 1, 2, 122, 69, 5, 41, 142, 116, 20, 10,
+ /* 2040 */ 11, 12, 13, 14, 24, 19, 17, 132, 5, 126,
+ /* 2050 */ 22, 141, 68, 10, 11, 12, 13, 14, 22, 30,
+ /* 2060 */ 17, 32, 22, 22, 154, 155, 156, 157, 158, 40,
+ /* 2070 */ 23, 68, 60, 30, 24, 32, 97, 28, 22, 68,
+ /* 2080 */ 23, 37, 34, 40, 150, 22, 25, 23, 23, 23,
+ /* 2090 */ 22, 98, 23, 183, 23, 117, 34, 22, 25, 89,
+ /* 2100 */ 71, 142, 144, 76, 34, 23, 34, 76, 79, 87,
+ /* 2110 */ 34, 82, 34, 94, 71, 34, 22, 24, 44, 34,
+ /* 2120 */ 25, 25, 79, 23, 23, 82, 143, 23, 99, 143,
+ /* 2130 */ 23, 22, 11, 25, 23, 25, 22, 22, 22, 1,
+ /* 2140 */ 23, 23, 99, 136, 22, 22, 142, 142, 142, 25,
+ /* 2150 */ 25, 23, 15, 1, 322, 322, 322, 322, 322, 322,
+ /* 2160 */ 322, 322, 322, 134, 322, 322, 322, 322, 139, 140,
+ /* 2170 */ 322, 322, 322, 322, 322, 322, 322, 134, 322, 322,
+ /* 2180 */ 322, 322, 139, 140, 322, 322, 322, 322, 322, 322,
+ /* 2190 */ 322, 322, 163, 322, 322, 322, 322, 322, 322, 322,
+ /* 2200 */ 322, 322, 322, 322, 322, 322, 163, 322, 322, 322,
+ /* 2210 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2220 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2230 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2240 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2250 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2260 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2270 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2280 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2290 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2300 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2310 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2320 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2330 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2340 */ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ /* 2350 */ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ /* 2360 */ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ /* 2370 */ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ /* 2380 */ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ /* 2390 */ 186, 186, 186,
};
-#define YY_SHIFT_COUNT (575)
+#define YY_SHIFT_COUNT (582)
#define YY_SHIFT_MIN (0)
-#define YY_SHIFT_MAX (2074)
+#define YY_SHIFT_MAX (2152)
static const unsigned short int yy_shift_ofst[] = {
- /* 0 */ 1648, 1477, 1272, 322, 322, 1, 1319, 1478, 1491, 1837,
- /* 10 */ 1837, 1837, 471, 0, 0, 214, 1093, 1837, 1837, 1837,
- /* 20 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 30 */ 271, 271, 1219, 1219, 216, 88, 1, 1, 1, 1,
- /* 40 */ 1, 40, 111, 258, 361, 469, 512, 583, 622, 693,
- /* 50 */ 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, 1093,
- /* 60 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093,
- /* 70 */ 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1635, 1662,
- /* 80 */ 1777, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 90 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 100 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 110 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 120 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 130 */ 137, 181, 181, 181, 181, 181, 181, 181, 94, 430,
- /* 140 */ 66, 65, 112, 366, 533, 533, 740, 1261, 533, 533,
- /* 150 */ 79, 79, 533, 412, 412, 412, 77, 412, 123, 113,
- /* 160 */ 113, 22, 22, 2098, 2098, 328, 328, 328, 239, 468,
- /* 170 */ 468, 468, 468, 1015, 1015, 409, 366, 1129, 1186, 533,
- /* 180 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533,
- /* 190 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 969,
- /* 200 */ 621, 621, 533, 642, 788, 788, 1228, 1228, 822, 822,
- /* 210 */ 67, 1274, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 1307,
- /* 220 */ 954, 954, 585, 472, 640, 387, 695, 538, 541, 700,
- /* 230 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533,
- /* 240 */ 222, 533, 533, 533, 533, 533, 533, 533, 533, 533,
- /* 250 */ 533, 533, 533, 1179, 1179, 1179, 533, 533, 533, 565,
- /* 260 */ 533, 533, 533, 916, 1144, 533, 533, 1288, 533, 533,
- /* 270 */ 533, 533, 533, 533, 533, 533, 639, 1330, 209, 1076,
- /* 280 */ 1076, 1076, 1076, 580, 209, 209, 1313, 768, 917, 649,
- /* 290 */ 1181, 1316, 405, 1316, 1238, 249, 1181, 1181, 249, 1181,
- /* 300 */ 405, 1238, 1369, 464, 1259, 1012, 1012, 1012, 1368, 1368,
- /* 310 */ 1368, 1368, 184, 184, 1326, 904, 1287, 1480, 1712, 1712,
- /* 320 */ 1633, 1633, 1757, 1757, 1633, 1647, 1651, 1783, 1764, 1791,
- /* 330 */ 1791, 1791, 1791, 1633, 1806, 1677, 1651, 1651, 1677, 1783,
- /* 340 */ 1764, 1677, 1764, 1677, 1633, 1806, 1674, 1779, 1633, 1806,
- /* 350 */ 1823, 1633, 1806, 1633, 1806, 1823, 1732, 1732, 1732, 1794,
- /* 360 */ 1840, 1840, 1823, 1732, 1738, 1732, 1794, 1732, 1732, 1701,
- /* 370 */ 1844, 1758, 1758, 1823, 1633, 1789, 1789, 1807, 1807, 1742,
- /* 380 */ 1752, 1877, 1633, 1743, 1742, 1759, 1765, 1677, 1879, 1897,
- /* 390 */ 1897, 1914, 1914, 1914, 2098, 2098, 2098, 2098, 2098, 2098,
- /* 400 */ 2098, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 207,
- /* 410 */ 1095, 331, 620, 903, 806, 1074, 1483, 1432, 1481, 1322,
- /* 420 */ 1370, 1394, 1515, 1291, 1546, 1547, 1557, 1595, 1598, 1599,
- /* 430 */ 1434, 1453, 1618, 1462, 1567, 1489, 1644, 1654, 1616, 1660,
- /* 440 */ 1548, 1549, 1682, 1685, 1597, 742, 1941, 1945, 1927, 1787,
- /* 450 */ 1937, 1940, 1934, 1936, 1821, 1810, 1832, 1938, 1938, 1942,
- /* 460 */ 1822, 1947, 1824, 1949, 1968, 1828, 1841, 1938, 1842, 1912,
- /* 470 */ 1939, 1938, 1826, 1921, 1922, 1925, 1926, 1850, 1865, 1948,
- /* 480 */ 1843, 1982, 1980, 1964, 1872, 1827, 1928, 1970, 1929, 1923,
- /* 490 */ 1958, 1848, 1885, 1977, 1983, 1985, 1871, 1880, 1984, 1943,
- /* 500 */ 1986, 1987, 1988, 1990, 1946, 1955, 1991, 1911, 1989, 1994,
- /* 510 */ 1951, 1992, 1996, 1873, 1998, 2000, 2001, 2002, 2003, 2004,
- /* 520 */ 1999, 1933, 1890, 2009, 2010, 1910, 2005, 2012, 1892, 2011,
- /* 530 */ 2006, 2007, 2008, 2013, 1950, 1962, 1957, 2014, 1969, 1952,
- /* 540 */ 2015, 2023, 2026, 2027, 2025, 2028, 2018, 1913, 1915, 2031,
- /* 550 */ 2011, 2033, 2036, 2037, 2038, 2039, 2040, 2043, 2051, 2044,
- /* 560 */ 2045, 2046, 2047, 2049, 2050, 2048, 1944, 1935, 1953, 1954,
- /* 570 */ 1956, 2052, 2055, 2053, 2073, 2074,
+ /* 0 */ 2029, 1801, 2043, 1380, 1380, 33, 391, 1496, 1569, 1642,
+ /* 10 */ 702, 702, 702, 193, 33, 33, 33, 33, 33, 0,
+ /* 20 */ 0, 216, 1177, 702, 702, 702, 702, 702, 702, 702,
+ /* 30 */ 702, 702, 702, 702, 702, 702, 702, 702, 406, 406,
+ /* 40 */ 111, 111, 218, 447, 547, 598, 598, 260, 260, 260,
+ /* 50 */ 260, 40, 112, 320, 340, 445, 489, 593, 637, 741,
+ /* 60 */ 785, 889, 909, 1023, 1043, 1157, 1177, 1177, 1177, 1177,
+ /* 70 */ 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177,
+ /* 80 */ 1177, 1177, 1177, 1177, 1197, 1177, 1301, 1321, 1321, 554,
+ /* 90 */ 1802, 1910, 702, 702, 702, 702, 702, 702, 702, 702,
+ /* 100 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702,
+ /* 110 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702,
+ /* 120 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702,
+ /* 130 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702,
+ /* 140 */ 702, 702, 138, 198, 198, 198, 198, 198, 198, 198,
+ /* 150 */ 183, 99, 236, 292, 598, 793, 167, 598, 598, 880,
+ /* 160 */ 880, 598, 857, 150, 195, 195, 195, 264, 113, 113,
+ /* 170 */ 2207, 2207, 854, 854, 854, 751, 765, 765, 765, 765,
+ /* 180 */ 1096, 1096, 725, 292, 882, 904, 598, 598, 598, 598,
+ /* 190 */ 598, 598, 598, 598, 598, 598, 598, 598, 598, 598,
+ /* 200 */ 598, 598, 598, 598, 598, 1273, 1032, 1032, 598, 147,
+ /* 210 */ 1098, 1098, 603, 603, 1276, 1276, 363, 2207, 2207, 2207,
+ /* 220 */ 2207, 2207, 2207, 2207, 469, 617, 617, 801, 336, 461,
+ /* 230 */ 804, 864, 615, 891, 913, 598, 598, 598, 598, 598,
+ /* 240 */ 598, 598, 598, 598, 598, 653, 598, 598, 598, 598,
+ /* 250 */ 598, 598, 598, 598, 598, 598, 598, 598, 1105, 1105,
+ /* 260 */ 1105, 598, 598, 598, 1194, 598, 598, 598, 1215, 1249,
+ /* 270 */ 598, 1353, 598, 598, 598, 598, 598, 598, 598, 598,
+ /* 280 */ 677, 449, 902, 1338, 1338, 1338, 1338, 1248, 902, 902,
+ /* 290 */ 326, 1151, 1047, 755, 749, 1371, 960, 1371, 1007, 1162,
+ /* 300 */ 749, 749, 1162, 749, 960, 1007, 1274, 738, 215, 1300,
+ /* 310 */ 1300, 1300, 1395, 1395, 1395, 1395, 1368, 1368, 1033, 1414,
+ /* 320 */ 1387, 1361, 1759, 1759, 1685, 1685, 1792, 1792, 1685, 1683,
+ /* 330 */ 1686, 1814, 1797, 1825, 1825, 1825, 1825, 1685, 1836, 1707,
+ /* 340 */ 1686, 1686, 1707, 1814, 1797, 1707, 1797, 1707, 1685, 1836,
+ /* 350 */ 1710, 1807, 1685, 1836, 1854, 1685, 1836, 1685, 1836, 1854,
+ /* 360 */ 1769, 1769, 1769, 1822, 1870, 1870, 1854, 1769, 1766, 1769,
+ /* 370 */ 1822, 1769, 1769, 1729, 1873, 1785, 1785, 1854, 1685, 1823,
+ /* 380 */ 1823, 1840, 1840, 1778, 1782, 1909, 1685, 1779, 1778, 1789,
+ /* 390 */ 1800, 1707, 1919, 1939, 1939, 1948, 1948, 1948, 2207, 2207,
+ /* 400 */ 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207,
+ /* 410 */ 2207, 2207, 2207, 69, 1037, 79, 1088, 651, 1196, 1415,
+ /* 420 */ 1501, 1439, 1369, 1452, 911, 1211, 1524, 1469, 1551, 1567,
+ /* 430 */ 1570, 1624, 1640, 1644, 1499, 1440, 1572, 1464, 1597, 275,
+ /* 440 */ 782, 1586, 1648, 1678, 1553, 1682, 1687, 1388, 1502, 1696,
+ /* 450 */ 1706, 1588, 1486, 1971, 1975, 1957, 1820, 1972, 1973, 1965,
+ /* 460 */ 1967, 1851, 1841, 1861, 1969, 1969, 1974, 1852, 1976, 1855,
+ /* 470 */ 1981, 1998, 1858, 1871, 1969, 1872, 1942, 1968, 1969, 1856,
+ /* 480 */ 1952, 1953, 1955, 1956, 1881, 1896, 1980, 1874, 2014, 2015,
+ /* 490 */ 1997, 1905, 1860, 1954, 1999, 1964, 1950, 1994, 1894, 1921,
+ /* 500 */ 2020, 2018, 2026, 1915, 1923, 2028, 1984, 2036, 2040, 2047,
+ /* 510 */ 2041, 2003, 2012, 2050, 1979, 2049, 2056, 2011, 2044, 2057,
+ /* 520 */ 2048, 1934, 2063, 2064, 2065, 2061, 2066, 2068, 1993, 1959,
+ /* 530 */ 2069, 2071, 1978, 2062, 2075, 1958, 2073, 2070, 2072, 2076,
+ /* 540 */ 2078, 2010, 2027, 2022, 2074, 2031, 2019, 2081, 2082, 2094,
+ /* 550 */ 2093, 2095, 2096, 2085, 1983, 1986, 2100, 2073, 2101, 2104,
+ /* 560 */ 2107, 2109, 2108, 2110, 2111, 2114, 2121, 2115, 2116, 2117,
+ /* 570 */ 2118, 2122, 2123, 2124, 2007, 2004, 2005, 2006, 2125, 2128,
+ /* 580 */ 2137, 2138, 2152,
};
-#define YY_REDUCE_COUNT (408)
-#define YY_REDUCE_MIN (-271)
-#define YY_REDUCE_MAX (1740)
+#define YY_REDUCE_COUNT (412)
+#define YY_REDUCE_MIN (-276)
+#define YY_REDUCE_MAX (1775)
static const short yy_reduce_ofst[] = {
- /* 0 */ -125, 733, 789, 241, 293, -123, -193, -191, -183, -187,
- /* 10 */ 166, 238, 133, -207, -199, -267, -176, -6, 204, 489,
- /* 20 */ 576, -175, 598, 686, 615, 725, 860, 778, 781, 857,
- /* 30 */ 616, 887, 87, 240, -192, 408, 626, 796, 843, 854,
- /* 40 */ 1003, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 50 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 60 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 70 */ -271, -271, -271, -271, -271, -271, -271, -271, 80, 83,
- /* 80 */ 313, 886, 888, 996, 1034, 1059, 1081, 1100, 1117, 1152,
- /* 90 */ 1155, 1163, 1165, 1167, 1169, 1172, 1180, 1182, 1184, 1198,
- /* 100 */ 1200, 1213, 1215, 1225, 1227, 1252, 1254, 1264, 1299, 1303,
- /* 110 */ 1308, 1312, 1325, 1328, 1337, 1340, 1343, 1371, 1373, 1384,
- /* 120 */ 1386, 1411, 1420, 1424, 1426, 1458, 1470, 1473, 1475, 1479,
- /* 130 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 140 */ -271, 138, 459, 396, -158, 470, 302, -212, 521, 201,
- /* 150 */ -195, -92, 559, 630, 632, 630, -271, 632, 901, 63,
- /* 160 */ 407, -271, -271, -271, -271, 161, 161, 161, 251, 335,
- /* 170 */ 847, 960, 980, 537, 588, 618, 628, 688, 688, -166,
- /* 180 */ -161, 674, 790, 794, 799, 851, 852, -122, 680, -120,
- /* 190 */ 995, 1038, 415, 1051, 893, 798, 962, 400, 1086, 779,
- /* 200 */ 923, 924, 263, 1041, 979, 990, 1083, 1097, 1031, 1194,
- /* 210 */ 362, 994, 1139, 1005, 1037, 1202, 1205, 1195, 1210, -194,
- /* 220 */ 56, 185, -135, 232, 522, 560, 601, 617, 669, 683,
- /* 230 */ 711, 856, 908, 941, 1048, 1101, 1147, 1257, 1262, 1265,
- /* 240 */ 392, 1292, 1333, 1339, 1342, 1346, 1350, 1359, 1374, 1418,
- /* 250 */ 1421, 1436, 1437, 593, 755, 770, 997, 1445, 1459, 1209,
- /* 260 */ 1500, 1504, 1516, 1132, 1243, 1518, 1519, 1440, 1520, 560,
- /* 270 */ 1522, 1523, 1524, 1526, 1527, 1529, 1382, 1438, 1431, 1468,
- /* 280 */ 1469, 1472, 1476, 1209, 1431, 1431, 1485, 1525, 1539, 1435,
- /* 290 */ 1463, 1471, 1492, 1487, 1443, 1494, 1474, 1484, 1498, 1486,
- /* 300 */ 1502, 1455, 1530, 1531, 1533, 1540, 1542, 1544, 1505, 1506,
- /* 310 */ 1507, 1508, 1521, 1528, 1493, 1537, 1532, 1575, 1488, 1496,
- /* 320 */ 1584, 1594, 1509, 1510, 1600, 1538, 1534, 1541, 1574, 1577,
- /* 330 */ 1583, 1585, 1586, 1612, 1626, 1581, 1556, 1558, 1587, 1559,
- /* 340 */ 1601, 1588, 1603, 1592, 1631, 1640, 1550, 1553, 1643, 1645,
- /* 350 */ 1625, 1649, 1652, 1650, 1653, 1632, 1636, 1637, 1642, 1634,
- /* 360 */ 1639, 1641, 1646, 1656, 1655, 1658, 1659, 1661, 1663, 1560,
- /* 370 */ 1564, 1596, 1605, 1664, 1670, 1565, 1571, 1627, 1638, 1657,
- /* 380 */ 1665, 1623, 1702, 1630, 1666, 1667, 1671, 1673, 1703, 1718,
- /* 390 */ 1719, 1729, 1730, 1731, 1621, 1622, 1628, 1720, 1713, 1716,
- /* 400 */ 1722, 1723, 1733, 1717, 1724, 1727, 1728, 1725, 1740,
+ /* 0 */ -66, 217, -63, -177, -180, 161, 364, 64, -183, 162,
+ /* 10 */ 223, 367, 414, -173, 473, 514, 525, 622, 626, -207,
+ /* 20 */ 351, -276, -38, 693, 811, 831, 833, 888, -188, 945,
+ /* 30 */ 947, 416, 558, 951, 867, 287, 1078, 1080, -186, 224,
+ /* 40 */ -132, 42, 964, 269, 417, 796, 810, -237, -231, -237,
+ /* 50 */ -231, -45, -45, -45, -45, -45, -45, -45, -45, -45,
+ /* 60 */ -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
+ /* 70 */ -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
+ /* 80 */ -45, -45, -45, -45, -45, -45, -45, -45, -45, 895,
+ /* 90 */ 925, 967, 980, 1100, 1143, 1169, 1203, 1225, 1228, 1242,
+ /* 100 */ 1247, 1250, 1253, 1255, 1261, 1267, 1272, 1275, 1283, 1286,
+ /* 110 */ 1288, 1292, 1333, 1335, 1347, 1349, 1352, 1354, 1360, 1366,
+ /* 120 */ 1381, 1391, 1406, 1408, 1413, 1416, 1418, 1422, 1425, 1427,
+ /* 130 */ 1463, 1465, 1472, 1478, 1480, 1491, 1498, 1500, 1517, 1519,
+ /* 140 */ 1528, 1536, -45, -45, -45, -45, -45, -45, -45, -45,
+ /* 150 */ -45, -45, -45, 312, -158, 285, -219, 9, 166, 370,
+ /* 160 */ 545, 707, -45, 930, 601, 963, 1067, 792, -45, -45,
+ /* 170 */ -45, -45, -204, -204, -204, 369, -171, -129, 632, 678,
+ /* 180 */ 202, 352, -270, 412, 627, 627, -9, 122, 415, 419,
+ /* 190 */ -56, 248, 583, 920, 6, 261, 459, 795, 1049, 813,
+ /* 200 */ 1062, 1082, -161, 778, 1063, 797, 870, 1003, 1128, 443,
+ /* 210 */ 1031, 1072, 1191, 1192, 957, 1120, 105, 1149, 523, 933,
+ /* 220 */ 1218, 1238, 1254, 1251, -138, 96, 117, 146, 181, 277,
+ /* 230 */ 280, 421, 480, 712, 830, 850, 1085, 1099, 1129, 1209,
+ /* 240 */ 1323, 1331, 1336, 1364, 1407, 368, 1412, 1433, 1438, 1474,
+ /* 250 */ 1481, 1505, 1506, 1526, 1538, 1544, 1545, 1546, 722, 764,
+ /* 260 */ 856, 1547, 1548, 1550, 1188, 1554, 1557, 1561, 1298, 1260,
+ /* 270 */ 1562, 1456, 1564, 280, 1568, 1571, 1573, 1574, 1575, 1576,
+ /* 280 */ 1457, 1477, 1520, 1514, 1515, 1516, 1518, 1188, 1520, 1520,
+ /* 290 */ 1530, 1563, 1584, 1482, 1504, 1510, 1534, 1513, 1488, 1537,
+ /* 300 */ 1512, 1521, 1539, 1522, 1541, 1493, 1583, 1559, 1565, 1585,
+ /* 310 */ 1587, 1589, 1529, 1531, 1532, 1549, 1558, 1566, 1535, 1577,
+ /* 320 */ 1582, 1622, 1533, 1540, 1627, 1628, 1552, 1555, 1633, 1560,
+ /* 330 */ 1578, 1581, 1607, 1606, 1608, 1609, 1611, 1649, 1655, 1612,
+ /* 340 */ 1590, 1591, 1613, 1594, 1621, 1614, 1623, 1616, 1666, 1668,
+ /* 350 */ 1579, 1593, 1672, 1675, 1656, 1676, 1679, 1680, 1688, 1660,
+ /* 360 */ 1667, 1670, 1671, 1663, 1669, 1673, 1674, 1689, 1681, 1692,
+ /* 370 */ 1677, 1693, 1694, 1592, 1599, 1617, 1620, 1700, 1713, 1596,
+ /* 380 */ 1598, 1658, 1659, 1691, 1684, 1654, 1735, 1664, 1697, 1690,
+ /* 390 */ 1701, 1703, 1748, 1758, 1760, 1768, 1770, 1772, 1657, 1661,
+ /* 400 */ 1665, 1761, 1754, 1757, 1762, 1763, 1764, 1750, 1751, 1765,
+ /* 410 */ 1771, 1767, 1775,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 1647, 1647, 1647, 1475, 1240, 1351, 1240, 1240, 1240, 1475,
- /* 10 */ 1475, 1475, 1240, 1381, 1381, 1528, 1273, 1240, 1240, 1240,
- /* 20 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1474, 1240, 1240,
- /* 30 */ 1240, 1240, 1563, 1563, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 40 */ 1240, 1240, 1390, 1240, 1397, 1240, 1240, 1240, 1240, 1240,
- /* 50 */ 1476, 1477, 1240, 1240, 1240, 1527, 1529, 1492, 1404, 1403,
- /* 60 */ 1402, 1401, 1510, 1369, 1395, 1388, 1392, 1470, 1471, 1469,
- /* 70 */ 1473, 1477, 1476, 1240, 1391, 1438, 1454, 1437, 1240, 1240,
- /* 80 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 90 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 100 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 110 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 120 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 130 */ 1446, 1453, 1452, 1451, 1460, 1450, 1447, 1440, 1439, 1441,
- /* 140 */ 1442, 1240, 1240, 1264, 1240, 1240, 1261, 1315, 1240, 1240,
- /* 150 */ 1240, 1240, 1240, 1547, 1546, 1240, 1443, 1240, 1273, 1432,
- /* 160 */ 1431, 1457, 1444, 1456, 1455, 1535, 1599, 1598, 1493, 1240,
- /* 170 */ 1240, 1240, 1240, 1240, 1240, 1563, 1240, 1240, 1240, 1240,
- /* 180 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 190 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1371,
- /* 200 */ 1563, 1563, 1240, 1273, 1563, 1563, 1372, 1372, 1269, 1269,
- /* 210 */ 1375, 1240, 1542, 1342, 1342, 1342, 1342, 1351, 1342, 1240,
- /* 220 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 230 */ 1240, 1240, 1240, 1240, 1532, 1530, 1240, 1240, 1240, 1240,
- /* 240 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 250 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 260 */ 1240, 1240, 1240, 1347, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 270 */ 1240, 1240, 1240, 1240, 1240, 1592, 1240, 1505, 1329, 1347,
- /* 280 */ 1347, 1347, 1347, 1349, 1330, 1328, 1341, 1274, 1247, 1639,
- /* 290 */ 1407, 1396, 1348, 1396, 1636, 1394, 1407, 1407, 1394, 1407,
- /* 300 */ 1348, 1636, 1290, 1615, 1285, 1381, 1381, 1381, 1371, 1371,
- /* 310 */ 1371, 1371, 1375, 1375, 1472, 1348, 1341, 1240, 1639, 1639,
- /* 320 */ 1357, 1357, 1638, 1638, 1357, 1493, 1623, 1416, 1318, 1324,
- /* 330 */ 1324, 1324, 1324, 1357, 1258, 1394, 1623, 1623, 1394, 1416,
- /* 340 */ 1318, 1394, 1318, 1394, 1357, 1258, 1509, 1633, 1357, 1258,
- /* 350 */ 1483, 1357, 1258, 1357, 1258, 1483, 1316, 1316, 1316, 1305,
- /* 360 */ 1240, 1240, 1483, 1316, 1290, 1316, 1305, 1316, 1316, 1581,
- /* 370 */ 1240, 1487, 1487, 1483, 1357, 1573, 1573, 1384, 1384, 1389,
- /* 380 */ 1375, 1478, 1357, 1240, 1389, 1387, 1385, 1394, 1308, 1595,
- /* 390 */ 1595, 1591, 1591, 1591, 1644, 1644, 1542, 1608, 1273, 1273,
- /* 400 */ 1273, 1273, 1608, 1292, 1292, 1274, 1274, 1273, 1608, 1240,
- /* 410 */ 1240, 1240, 1240, 1240, 1240, 1603, 1240, 1537, 1494, 1361,
- /* 420 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 430 */ 1240, 1240, 1240, 1240, 1548, 1240, 1240, 1240, 1240, 1240,
- /* 440 */ 1240, 1240, 1240, 1240, 1240, 1421, 1240, 1243, 1539, 1240,
- /* 450 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1398, 1399, 1362,
- /* 460 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1413, 1240, 1240,
- /* 470 */ 1240, 1408, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 480 */ 1635, 1240, 1240, 1240, 1240, 1240, 1240, 1508, 1507, 1240,
- /* 490 */ 1240, 1359, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 500 */ 1240, 1240, 1240, 1240, 1240, 1288, 1240, 1240, 1240, 1240,
- /* 510 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 520 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1386,
- /* 530 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 540 */ 1240, 1240, 1240, 1240, 1578, 1376, 1240, 1240, 1240, 1240,
- /* 550 */ 1626, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 560 */ 1240, 1240, 1240, 1240, 1240, 1619, 1332, 1423, 1240, 1422,
- /* 570 */ 1426, 1262, 1240, 1252, 1240, 1240,
+ /* 0 */ 1663, 1663, 1663, 1491, 1254, 1367, 1254, 1254, 1254, 1254,
+ /* 10 */ 1491, 1491, 1491, 1254, 1254, 1254, 1254, 1254, 1254, 1397,
+ /* 20 */ 1397, 1544, 1287, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 30 */ 1254, 1254, 1254, 1254, 1254, 1490, 1254, 1254, 1254, 1254,
+ /* 40 */ 1578, 1578, 1254, 1254, 1254, 1254, 1254, 1563, 1562, 1254,
+ /* 50 */ 1254, 1254, 1406, 1254, 1413, 1254, 1254, 1254, 1254, 1254,
+ /* 60 */ 1492, 1493, 1254, 1254, 1254, 1254, 1543, 1545, 1508, 1420,
+ /* 70 */ 1419, 1418, 1417, 1526, 1385, 1411, 1404, 1408, 1487, 1488,
+ /* 80 */ 1486, 1641, 1493, 1492, 1254, 1407, 1455, 1471, 1454, 1254,
+ /* 90 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 100 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 110 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 120 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 130 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 140 */ 1254, 1254, 1463, 1470, 1469, 1468, 1477, 1467, 1464, 1457,
+ /* 150 */ 1456, 1458, 1459, 1278, 1254, 1275, 1329, 1254, 1254, 1254,
+ /* 160 */ 1254, 1254, 1460, 1287, 1448, 1447, 1446, 1254, 1474, 1461,
+ /* 170 */ 1473, 1472, 1551, 1615, 1614, 1509, 1254, 1254, 1254, 1254,
+ /* 180 */ 1254, 1254, 1578, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 190 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 200 */ 1254, 1254, 1254, 1254, 1254, 1387, 1578, 1578, 1254, 1287,
+ /* 210 */ 1578, 1578, 1388, 1388, 1283, 1283, 1391, 1558, 1358, 1358,
+ /* 220 */ 1358, 1358, 1367, 1358, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 230 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1548,
+ /* 240 */ 1546, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 250 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 260 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1363, 1254,
+ /* 270 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1608,
+ /* 280 */ 1254, 1521, 1343, 1363, 1363, 1363, 1363, 1365, 1344, 1342,
+ /* 290 */ 1357, 1288, 1261, 1655, 1423, 1412, 1364, 1412, 1652, 1410,
+ /* 300 */ 1423, 1423, 1410, 1423, 1364, 1652, 1304, 1630, 1299, 1397,
+ /* 310 */ 1397, 1397, 1387, 1387, 1387, 1387, 1391, 1391, 1489, 1364,
+ /* 320 */ 1357, 1254, 1655, 1655, 1373, 1373, 1654, 1654, 1373, 1509,
+ /* 330 */ 1638, 1432, 1332, 1338, 1338, 1338, 1338, 1373, 1272, 1410,
+ /* 340 */ 1638, 1638, 1410, 1432, 1332, 1410, 1332, 1410, 1373, 1272,
+ /* 350 */ 1525, 1649, 1373, 1272, 1499, 1373, 1272, 1373, 1272, 1499,
+ /* 360 */ 1330, 1330, 1330, 1319, 1254, 1254, 1499, 1330, 1304, 1330,
+ /* 370 */ 1319, 1330, 1330, 1596, 1254, 1503, 1503, 1499, 1373, 1588,
+ /* 380 */ 1588, 1400, 1400, 1405, 1391, 1494, 1373, 1254, 1405, 1403,
+ /* 390 */ 1401, 1410, 1322, 1611, 1611, 1607, 1607, 1607, 1660, 1660,
+ /* 400 */ 1558, 1623, 1287, 1287, 1287, 1287, 1623, 1306, 1306, 1288,
+ /* 410 */ 1288, 1287, 1623, 1254, 1254, 1254, 1254, 1254, 1254, 1618,
+ /* 420 */ 1254, 1553, 1510, 1377, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 430 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 440 */ 1564, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 450 */ 1254, 1254, 1437, 1254, 1257, 1555, 1254, 1254, 1254, 1254,
+ /* 460 */ 1254, 1254, 1254, 1254, 1414, 1415, 1378, 1254, 1254, 1254,
+ /* 470 */ 1254, 1254, 1254, 1254, 1429, 1254, 1254, 1254, 1424, 1254,
+ /* 480 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1651, 1254, 1254,
+ /* 490 */ 1254, 1254, 1254, 1254, 1524, 1523, 1254, 1254, 1375, 1254,
+ /* 500 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 510 */ 1254, 1254, 1302, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 520 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 530 */ 1254, 1254, 1254, 1254, 1254, 1254, 1402, 1254, 1254, 1254,
+ /* 540 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 550 */ 1254, 1593, 1392, 1254, 1254, 1254, 1254, 1642, 1254, 1254,
+ /* 560 */ 1254, 1254, 1352, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 570 */ 1254, 1254, 1254, 1634, 1346, 1438, 1254, 1441, 1276, 1254,
+ /* 580 */ 1266, 1254, 1254,
};
/********** End of lemon-generated parsing tables *****************************/
@@ -168141,52 +175254,53 @@ static const YYACTIONTYPE yy_default[] = {
static const YYCODETYPE yyFallback[] = {
0, /* $ => nothing */
0, /* SEMI => nothing */
- 59, /* EXPLAIN => ID */
- 59, /* QUERY => ID */
- 59, /* PLAN => ID */
- 59, /* BEGIN => ID */
+ 60, /* EXPLAIN => ID */
+ 60, /* QUERY => ID */
+ 60, /* PLAN => ID */
+ 60, /* BEGIN => ID */
0, /* TRANSACTION => nothing */
- 59, /* DEFERRED => ID */
- 59, /* IMMEDIATE => ID */
- 59, /* EXCLUSIVE => ID */
+ 60, /* DEFERRED => ID */
+ 60, /* IMMEDIATE => ID */
+ 60, /* EXCLUSIVE => ID */
0, /* COMMIT => nothing */
- 59, /* END => ID */
- 59, /* ROLLBACK => ID */
- 59, /* SAVEPOINT => ID */
- 59, /* RELEASE => ID */
+ 60, /* END => ID */
+ 60, /* ROLLBACK => ID */
+ 60, /* SAVEPOINT => ID */
+ 60, /* RELEASE => ID */
0, /* TO => nothing */
0, /* TABLE => nothing */
0, /* CREATE => nothing */
- 59, /* IF => ID */
+ 60, /* IF => ID */
0, /* NOT => nothing */
0, /* EXISTS => nothing */
- 59, /* TEMP => ID */
+ 60, /* TEMP => ID */
0, /* LP => nothing */
0, /* RP => nothing */
0, /* AS => nothing */
0, /* COMMA => nothing */
- 59, /* WITHOUT => ID */
- 59, /* ABORT => ID */
- 59, /* ACTION => ID */
- 59, /* AFTER => ID */
- 59, /* ANALYZE => ID */
- 59, /* ASC => ID */
- 59, /* ATTACH => ID */
- 59, /* BEFORE => ID */
- 59, /* BY => ID */
- 59, /* CASCADE => ID */
- 59, /* CAST => ID */
- 59, /* CONFLICT => ID */
- 59, /* DATABASE => ID */
- 59, /* DESC => ID */
- 59, /* DETACH => ID */
- 59, /* EACH => ID */
- 59, /* FAIL => ID */
+ 60, /* WITHOUT => ID */
+ 60, /* ABORT => ID */
+ 60, /* ACTION => ID */
+ 60, /* AFTER => ID */
+ 60, /* ANALYZE => ID */
+ 60, /* ASC => ID */
+ 60, /* ATTACH => ID */
+ 60, /* BEFORE => ID */
+ 60, /* BY => ID */
+ 60, /* CASCADE => ID */
+ 60, /* CAST => ID */
+ 60, /* CONFLICT => ID */
+ 60, /* DATABASE => ID */
+ 60, /* DESC => ID */
+ 60, /* DETACH => ID */
+ 60, /* EACH => ID */
+ 60, /* FAIL => ID */
0, /* OR => nothing */
0, /* AND => nothing */
0, /* IS => nothing */
- 59, /* MATCH => ID */
- 59, /* LIKE_KW => ID */
+ 0, /* ISNOT => nothing */
+ 60, /* MATCH => ID */
+ 60, /* LIKE_KW => ID */
0, /* BETWEEN => nothing */
0, /* IN => nothing */
0, /* ISNULL => nothing */
@@ -168199,47 +175313,47 @@ static const YYCODETYPE yyFallback[] = {
0, /* GE => nothing */
0, /* ESCAPE => nothing */
0, /* ID => nothing */
- 59, /* COLUMNKW => ID */
- 59, /* DO => ID */
- 59, /* FOR => ID */
- 59, /* IGNORE => ID */
- 59, /* INITIALLY => ID */
- 59, /* INSTEAD => ID */
- 59, /* NO => ID */
- 59, /* KEY => ID */
- 59, /* OF => ID */
- 59, /* OFFSET => ID */
- 59, /* PRAGMA => ID */
- 59, /* RAISE => ID */
- 59, /* RECURSIVE => ID */
- 59, /* REPLACE => ID */
- 59, /* RESTRICT => ID */
- 59, /* ROW => ID */
- 59, /* ROWS => ID */
- 59, /* TRIGGER => ID */
- 59, /* VACUUM => ID */
- 59, /* VIEW => ID */
- 59, /* VIRTUAL => ID */
- 59, /* WITH => ID */
- 59, /* NULLS => ID */
- 59, /* FIRST => ID */
- 59, /* LAST => ID */
- 59, /* CURRENT => ID */
- 59, /* FOLLOWING => ID */
- 59, /* PARTITION => ID */
- 59, /* PRECEDING => ID */
- 59, /* RANGE => ID */
- 59, /* UNBOUNDED => ID */
- 59, /* EXCLUDE => ID */
- 59, /* GROUPS => ID */
- 59, /* OTHERS => ID */
- 59, /* TIES => ID */
- 59, /* GENERATED => ID */
- 59, /* ALWAYS => ID */
- 59, /* MATERIALIZED => ID */
- 59, /* REINDEX => ID */
- 59, /* RENAME => ID */
- 59, /* CTIME_KW => ID */
+ 60, /* COLUMNKW => ID */
+ 60, /* DO => ID */
+ 60, /* FOR => ID */
+ 60, /* IGNORE => ID */
+ 60, /* INITIALLY => ID */
+ 60, /* INSTEAD => ID */
+ 60, /* NO => ID */
+ 60, /* KEY => ID */
+ 60, /* OF => ID */
+ 60, /* OFFSET => ID */
+ 60, /* PRAGMA => ID */
+ 60, /* RAISE => ID */
+ 60, /* RECURSIVE => ID */
+ 60, /* REPLACE => ID */
+ 60, /* RESTRICT => ID */
+ 60, /* ROW => ID */
+ 60, /* ROWS => ID */
+ 60, /* TRIGGER => ID */
+ 60, /* VACUUM => ID */
+ 60, /* VIEW => ID */
+ 60, /* VIRTUAL => ID */
+ 60, /* WITH => ID */
+ 60, /* NULLS => ID */
+ 60, /* FIRST => ID */
+ 60, /* LAST => ID */
+ 60, /* CURRENT => ID */
+ 60, /* FOLLOWING => ID */
+ 60, /* PARTITION => ID */
+ 60, /* PRECEDING => ID */
+ 60, /* RANGE => ID */
+ 60, /* UNBOUNDED => ID */
+ 60, /* EXCLUDE => ID */
+ 60, /* GROUPS => ID */
+ 60, /* OTHERS => ID */
+ 60, /* TIES => ID */
+ 60, /* GENERATED => ID */
+ 60, /* ALWAYS => ID */
+ 60, /* MATERIALIZED => ID */
+ 60, /* REINDEX => ID */
+ 60, /* RENAME => ID */
+ 60, /* CTIME_KW => ID */
0, /* ANY => nothing */
0, /* BITAND => nothing */
0, /* BITOR => nothing */
@@ -168310,10 +175424,9 @@ static const YYCODETYPE yyFallback[] = {
0, /* AGG_FUNCTION => nothing */
0, /* AGG_COLUMN => nothing */
0, /* TRUEFALSE => nothing */
- 0, /* ISNOT => nothing */
0, /* FUNCTION => nothing */
- 0, /* UMINUS => nothing */
0, /* UPLUS => nothing */
+ 0, /* UMINUS => nothing */
0, /* TRUTH => nothing */
0, /* REGISTER => nothing */
0, /* VECTOR => nothing */
@@ -168322,6 +175435,7 @@ static const YYCODETYPE yyFallback[] = {
0, /* ASTERISK => nothing */
0, /* SPAN => nothing */
0, /* ERROR => nothing */
+ 0, /* QNUMBER => nothing */
0, /* SPACE => nothing */
0, /* ILLEGAL => nothing */
};
@@ -168364,14 +175478,9 @@ struct yyParser {
#endif
wx_sqlite3ParserARG_SDECL /* A place to hold %extra_argument */
wx_sqlite3ParserCTX_SDECL /* A place to hold %extra_context */
-#if YYSTACKDEPTH<=0
- int yystksz; /* Current side of the stack */
- yyStackEntry *yystack; /* The parser's stack */
- yyStackEntry yystk0; /* First stack entry */
-#else
- yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
- yyStackEntry *yystackEnd; /* Last entry in the stack */
-#endif
+ yyStackEntry *yystackEnd; /* Last entry in the stack */
+ yyStackEntry *yystack; /* The parser stack */
+ yyStackEntry yystk0[YYSTACKDEPTH]; /* Initial stack space */
};
typedef struct yyParser yyParser;
@@ -168458,135 +175567,135 @@ static const char *const yyTokenName[] = {
/* 43 */ "OR",
/* 44 */ "AND",
/* 45 */ "IS",
- /* 46 */ "MATCH",
- /* 47 */ "LIKE_KW",
- /* 48 */ "BETWEEN",
- /* 49 */ "IN",
- /* 50 */ "ISNULL",
- /* 51 */ "NOTNULL",
- /* 52 */ "NE",
- /* 53 */ "EQ",
- /* 54 */ "GT",
- /* 55 */ "LE",
- /* 56 */ "LT",
- /* 57 */ "GE",
- /* 58 */ "ESCAPE",
- /* 59 */ "ID",
- /* 60 */ "COLUMNKW",
- /* 61 */ "DO",
- /* 62 */ "FOR",
- /* 63 */ "IGNORE",
- /* 64 */ "INITIALLY",
- /* 65 */ "INSTEAD",
- /* 66 */ "NO",
- /* 67 */ "KEY",
- /* 68 */ "OF",
- /* 69 */ "OFFSET",
- /* 70 */ "PRAGMA",
- /* 71 */ "RAISE",
- /* 72 */ "RECURSIVE",
- /* 73 */ "REPLACE",
- /* 74 */ "RESTRICT",
- /* 75 */ "ROW",
- /* 76 */ "ROWS",
- /* 77 */ "TRIGGER",
- /* 78 */ "VACUUM",
- /* 79 */ "VIEW",
- /* 80 */ "VIRTUAL",
- /* 81 */ "WITH",
- /* 82 */ "NULLS",
- /* 83 */ "FIRST",
- /* 84 */ "LAST",
- /* 85 */ "CURRENT",
- /* 86 */ "FOLLOWING",
- /* 87 */ "PARTITION",
- /* 88 */ "PRECEDING",
- /* 89 */ "RANGE",
- /* 90 */ "UNBOUNDED",
- /* 91 */ "EXCLUDE",
- /* 92 */ "GROUPS",
- /* 93 */ "OTHERS",
- /* 94 */ "TIES",
- /* 95 */ "GENERATED",
- /* 96 */ "ALWAYS",
- /* 97 */ "MATERIALIZED",
- /* 98 */ "REINDEX",
- /* 99 */ "RENAME",
- /* 100 */ "CTIME_KW",
- /* 101 */ "ANY",
- /* 102 */ "BITAND",
- /* 103 */ "BITOR",
- /* 104 */ "LSHIFT",
- /* 105 */ "RSHIFT",
- /* 106 */ "PLUS",
- /* 107 */ "MINUS",
- /* 108 */ "STAR",
- /* 109 */ "SLASH",
- /* 110 */ "REM",
- /* 111 */ "CONCAT",
- /* 112 */ "PTR",
- /* 113 */ "COLLATE",
- /* 114 */ "BITNOT",
- /* 115 */ "ON",
- /* 116 */ "INDEXED",
- /* 117 */ "STRING",
- /* 118 */ "JOIN_KW",
- /* 119 */ "CONSTRAINT",
- /* 120 */ "DEFAULT",
- /* 121 */ "NULL",
- /* 122 */ "PRIMARY",
- /* 123 */ "UNIQUE",
- /* 124 */ "CHECK",
- /* 125 */ "REFERENCES",
- /* 126 */ "AUTOINCR",
- /* 127 */ "INSERT",
- /* 128 */ "DELETE",
- /* 129 */ "UPDATE",
- /* 130 */ "SET",
- /* 131 */ "DEFERRABLE",
- /* 132 */ "FOREIGN",
- /* 133 */ "DROP",
- /* 134 */ "UNION",
- /* 135 */ "ALL",
- /* 136 */ "EXCEPT",
- /* 137 */ "INTERSECT",
- /* 138 */ "SELECT",
- /* 139 */ "VALUES",
- /* 140 */ "DISTINCT",
- /* 141 */ "DOT",
- /* 142 */ "FROM",
- /* 143 */ "JOIN",
- /* 144 */ "USING",
- /* 145 */ "ORDER",
- /* 146 */ "GROUP",
- /* 147 */ "HAVING",
- /* 148 */ "LIMIT",
- /* 149 */ "WHERE",
- /* 150 */ "RETURNING",
- /* 151 */ "INTO",
- /* 152 */ "NOTHING",
- /* 153 */ "FLOAT",
- /* 154 */ "BLOB",
- /* 155 */ "INTEGER",
- /* 156 */ "VARIABLE",
- /* 157 */ "CASE",
- /* 158 */ "WHEN",
- /* 159 */ "THEN",
- /* 160 */ "ELSE",
- /* 161 */ "INDEX",
- /* 162 */ "ALTER",
- /* 163 */ "ADD",
- /* 164 */ "WINDOW",
- /* 165 */ "OVER",
- /* 166 */ "FILTER",
- /* 167 */ "COLUMN",
- /* 168 */ "AGG_FUNCTION",
- /* 169 */ "AGG_COLUMN",
- /* 170 */ "TRUEFALSE",
- /* 171 */ "ISNOT",
+ /* 46 */ "ISNOT",
+ /* 47 */ "MATCH",
+ /* 48 */ "LIKE_KW",
+ /* 49 */ "BETWEEN",
+ /* 50 */ "IN",
+ /* 51 */ "ISNULL",
+ /* 52 */ "NOTNULL",
+ /* 53 */ "NE",
+ /* 54 */ "EQ",
+ /* 55 */ "GT",
+ /* 56 */ "LE",
+ /* 57 */ "LT",
+ /* 58 */ "GE",
+ /* 59 */ "ESCAPE",
+ /* 60 */ "ID",
+ /* 61 */ "COLUMNKW",
+ /* 62 */ "DO",
+ /* 63 */ "FOR",
+ /* 64 */ "IGNORE",
+ /* 65 */ "INITIALLY",
+ /* 66 */ "INSTEAD",
+ /* 67 */ "NO",
+ /* 68 */ "KEY",
+ /* 69 */ "OF",
+ /* 70 */ "OFFSET",
+ /* 71 */ "PRAGMA",
+ /* 72 */ "RAISE",
+ /* 73 */ "RECURSIVE",
+ /* 74 */ "REPLACE",
+ /* 75 */ "RESTRICT",
+ /* 76 */ "ROW",
+ /* 77 */ "ROWS",
+ /* 78 */ "TRIGGER",
+ /* 79 */ "VACUUM",
+ /* 80 */ "VIEW",
+ /* 81 */ "VIRTUAL",
+ /* 82 */ "WITH",
+ /* 83 */ "NULLS",
+ /* 84 */ "FIRST",
+ /* 85 */ "LAST",
+ /* 86 */ "CURRENT",
+ /* 87 */ "FOLLOWING",
+ /* 88 */ "PARTITION",
+ /* 89 */ "PRECEDING",
+ /* 90 */ "RANGE",
+ /* 91 */ "UNBOUNDED",
+ /* 92 */ "EXCLUDE",
+ /* 93 */ "GROUPS",
+ /* 94 */ "OTHERS",
+ /* 95 */ "TIES",
+ /* 96 */ "GENERATED",
+ /* 97 */ "ALWAYS",
+ /* 98 */ "MATERIALIZED",
+ /* 99 */ "REINDEX",
+ /* 100 */ "RENAME",
+ /* 101 */ "CTIME_KW",
+ /* 102 */ "ANY",
+ /* 103 */ "BITAND",
+ /* 104 */ "BITOR",
+ /* 105 */ "LSHIFT",
+ /* 106 */ "RSHIFT",
+ /* 107 */ "PLUS",
+ /* 108 */ "MINUS",
+ /* 109 */ "STAR",
+ /* 110 */ "SLASH",
+ /* 111 */ "REM",
+ /* 112 */ "CONCAT",
+ /* 113 */ "PTR",
+ /* 114 */ "COLLATE",
+ /* 115 */ "BITNOT",
+ /* 116 */ "ON",
+ /* 117 */ "INDEXED",
+ /* 118 */ "STRING",
+ /* 119 */ "JOIN_KW",
+ /* 120 */ "CONSTRAINT",
+ /* 121 */ "DEFAULT",
+ /* 122 */ "NULL",
+ /* 123 */ "PRIMARY",
+ /* 124 */ "UNIQUE",
+ /* 125 */ "CHECK",
+ /* 126 */ "REFERENCES",
+ /* 127 */ "AUTOINCR",
+ /* 128 */ "INSERT",
+ /* 129 */ "DELETE",
+ /* 130 */ "UPDATE",
+ /* 131 */ "SET",
+ /* 132 */ "DEFERRABLE",
+ /* 133 */ "FOREIGN",
+ /* 134 */ "DROP",
+ /* 135 */ "UNION",
+ /* 136 */ "ALL",
+ /* 137 */ "EXCEPT",
+ /* 138 */ "INTERSECT",
+ /* 139 */ "SELECT",
+ /* 140 */ "VALUES",
+ /* 141 */ "DISTINCT",
+ /* 142 */ "DOT",
+ /* 143 */ "FROM",
+ /* 144 */ "JOIN",
+ /* 145 */ "USING",
+ /* 146 */ "ORDER",
+ /* 147 */ "GROUP",
+ /* 148 */ "HAVING",
+ /* 149 */ "LIMIT",
+ /* 150 */ "WHERE",
+ /* 151 */ "RETURNING",
+ /* 152 */ "INTO",
+ /* 153 */ "NOTHING",
+ /* 154 */ "FLOAT",
+ /* 155 */ "BLOB",
+ /* 156 */ "INTEGER",
+ /* 157 */ "VARIABLE",
+ /* 158 */ "CASE",
+ /* 159 */ "WHEN",
+ /* 160 */ "THEN",
+ /* 161 */ "ELSE",
+ /* 162 */ "INDEX",
+ /* 163 */ "ALTER",
+ /* 164 */ "ADD",
+ /* 165 */ "WINDOW",
+ /* 166 */ "OVER",
+ /* 167 */ "FILTER",
+ /* 168 */ "COLUMN",
+ /* 169 */ "AGG_FUNCTION",
+ /* 170 */ "AGG_COLUMN",
+ /* 171 */ "TRUEFALSE",
/* 172 */ "FUNCTION",
- /* 173 */ "UMINUS",
- /* 174 */ "UPLUS",
+ /* 173 */ "UPLUS",
+ /* 174 */ "UMINUS",
/* 175 */ "TRUTH",
/* 176 */ "REGISTER",
/* 177 */ "VECTOR",
@@ -168595,142 +175704,145 @@ static const char *const yyTokenName[] = {
/* 180 */ "ASTERISK",
/* 181 */ "SPAN",
/* 182 */ "ERROR",
- /* 183 */ "SPACE",
- /* 184 */ "ILLEGAL",
- /* 185 */ "input",
- /* 186 */ "cmdlist",
- /* 187 */ "ecmd",
- /* 188 */ "cmdx",
- /* 189 */ "explain",
- /* 190 */ "cmd",
- /* 191 */ "transtype",
- /* 192 */ "trans_opt",
- /* 193 */ "nm",
- /* 194 */ "savepoint_opt",
- /* 195 */ "create_table",
- /* 196 */ "create_table_args",
- /* 197 */ "createkw",
- /* 198 */ "temp",
- /* 199 */ "ifnotexists",
- /* 200 */ "dbnm",
- /* 201 */ "columnlist",
- /* 202 */ "conslist_opt",
- /* 203 */ "table_option_set",
- /* 204 */ "select",
- /* 205 */ "table_option",
- /* 206 */ "columnname",
- /* 207 */ "carglist",
- /* 208 */ "typetoken",
- /* 209 */ "typename",
- /* 210 */ "signed",
- /* 211 */ "plus_num",
- /* 212 */ "minus_num",
- /* 213 */ "scanpt",
- /* 214 */ "scantok",
- /* 215 */ "ccons",
- /* 216 */ "term",
- /* 217 */ "expr",
- /* 218 */ "onconf",
- /* 219 */ "sortorder",
- /* 220 */ "autoinc",
- /* 221 */ "eidlist_opt",
- /* 222 */ "refargs",
- /* 223 */ "defer_subclause",
- /* 224 */ "generated",
- /* 225 */ "refarg",
- /* 226 */ "refact",
- /* 227 */ "init_deferred_pred_opt",
- /* 228 */ "conslist",
- /* 229 */ "tconscomma",
- /* 230 */ "tcons",
- /* 231 */ "sortlist",
- /* 232 */ "eidlist",
- /* 233 */ "defer_subclause_opt",
- /* 234 */ "orconf",
- /* 235 */ "resolvetype",
- /* 236 */ "raisetype",
- /* 237 */ "ifexists",
- /* 238 */ "fullname",
- /* 239 */ "selectnowith",
- /* 240 */ "oneselect",
- /* 241 */ "wqlist",
- /* 242 */ "multiselect_op",
- /* 243 */ "distinct",
- /* 244 */ "selcollist",
- /* 245 */ "from",
- /* 246 */ "where_opt",
- /* 247 */ "groupby_opt",
- /* 248 */ "having_opt",
- /* 249 */ "orderby_opt",
- /* 250 */ "limit_opt",
- /* 251 */ "window_clause",
- /* 252 */ "values",
- /* 253 */ "nexprlist",
- /* 254 */ "sclp",
- /* 255 */ "as",
- /* 256 */ "seltablist",
- /* 257 */ "stl_prefix",
- /* 258 */ "joinop",
- /* 259 */ "on_using",
- /* 260 */ "indexed_by",
- /* 261 */ "exprlist",
- /* 262 */ "xfullname",
- /* 263 */ "idlist",
- /* 264 */ "indexed_opt",
- /* 265 */ "nulls",
- /* 266 */ "with",
- /* 267 */ "where_opt_ret",
- /* 268 */ "setlist",
- /* 269 */ "insert_cmd",
- /* 270 */ "idlist_opt",
- /* 271 */ "upsert",
- /* 272 */ "returning",
- /* 273 */ "filter_over",
- /* 274 */ "likeop",
- /* 275 */ "between_op",
- /* 276 */ "in_op",
- /* 277 */ "paren_exprlist",
- /* 278 */ "case_operand",
- /* 279 */ "case_exprlist",
- /* 280 */ "case_else",
- /* 281 */ "uniqueflag",
- /* 282 */ "collate",
- /* 283 */ "vinto",
- /* 284 */ "nmnum",
- /* 285 */ "trigger_decl",
- /* 286 */ "trigger_cmd_list",
- /* 287 */ "trigger_time",
- /* 288 */ "trigger_event",
- /* 289 */ "foreach_clause",
- /* 290 */ "when_clause",
- /* 291 */ "trigger_cmd",
- /* 292 */ "trnm",
- /* 293 */ "tridxby",
- /* 294 */ "database_kw_opt",
- /* 295 */ "key_opt",
- /* 296 */ "add_column_fullname",
- /* 297 */ "kwcolumn_opt",
- /* 298 */ "create_vtab",
- /* 299 */ "vtabarglist",
- /* 300 */ "vtabarg",
- /* 301 */ "vtabargtoken",
- /* 302 */ "lp",
- /* 303 */ "anylist",
- /* 304 */ "wqitem",
- /* 305 */ "wqas",
- /* 306 */ "windowdefn_list",
- /* 307 */ "windowdefn",
- /* 308 */ "window",
- /* 309 */ "frame_opt",
- /* 310 */ "part_opt",
- /* 311 */ "filter_clause",
- /* 312 */ "over_clause",
- /* 313 */ "range_or_rows",
- /* 314 */ "frame_bound",
- /* 315 */ "frame_bound_s",
- /* 316 */ "frame_bound_e",
- /* 317 */ "frame_exclude_opt",
- /* 318 */ "frame_exclude",
+ /* 183 */ "QNUMBER",
+ /* 184 */ "SPACE",
+ /* 185 */ "ILLEGAL",
+ /* 186 */ "input",
+ /* 187 */ "cmdlist",
+ /* 188 */ "ecmd",
+ /* 189 */ "cmdx",
+ /* 190 */ "explain",
+ /* 191 */ "cmd",
+ /* 192 */ "transtype",
+ /* 193 */ "trans_opt",
+ /* 194 */ "nm",
+ /* 195 */ "savepoint_opt",
+ /* 196 */ "create_table",
+ /* 197 */ "create_table_args",
+ /* 198 */ "createkw",
+ /* 199 */ "temp",
+ /* 200 */ "ifnotexists",
+ /* 201 */ "dbnm",
+ /* 202 */ "columnlist",
+ /* 203 */ "conslist_opt",
+ /* 204 */ "table_option_set",
+ /* 205 */ "select",
+ /* 206 */ "table_option",
+ /* 207 */ "columnname",
+ /* 208 */ "carglist",
+ /* 209 */ "typetoken",
+ /* 210 */ "typename",
+ /* 211 */ "signed",
+ /* 212 */ "plus_num",
+ /* 213 */ "minus_num",
+ /* 214 */ "scanpt",
+ /* 215 */ "scantok",
+ /* 216 */ "ccons",
+ /* 217 */ "term",
+ /* 218 */ "expr",
+ /* 219 */ "onconf",
+ /* 220 */ "sortorder",
+ /* 221 */ "autoinc",
+ /* 222 */ "eidlist_opt",
+ /* 223 */ "refargs",
+ /* 224 */ "defer_subclause",
+ /* 225 */ "generated",
+ /* 226 */ "refarg",
+ /* 227 */ "refact",
+ /* 228 */ "init_deferred_pred_opt",
+ /* 229 */ "conslist",
+ /* 230 */ "tconscomma",
+ /* 231 */ "tcons",
+ /* 232 */ "sortlist",
+ /* 233 */ "eidlist",
+ /* 234 */ "defer_subclause_opt",
+ /* 235 */ "orconf",
+ /* 236 */ "resolvetype",
+ /* 237 */ "raisetype",
+ /* 238 */ "ifexists",
+ /* 239 */ "fullname",
+ /* 240 */ "selectnowith",
+ /* 241 */ "oneselect",
+ /* 242 */ "wqlist",
+ /* 243 */ "multiselect_op",
+ /* 244 */ "distinct",
+ /* 245 */ "selcollist",
+ /* 246 */ "from",
+ /* 247 */ "where_opt",
+ /* 248 */ "groupby_opt",
+ /* 249 */ "having_opt",
+ /* 250 */ "orderby_opt",
+ /* 251 */ "limit_opt",
+ /* 252 */ "window_clause",
+ /* 253 */ "values",
+ /* 254 */ "nexprlist",
+ /* 255 */ "mvalues",
+ /* 256 */ "sclp",
+ /* 257 */ "as",
+ /* 258 */ "seltablist",
+ /* 259 */ "stl_prefix",
+ /* 260 */ "joinop",
+ /* 261 */ "on_using",
+ /* 262 */ "indexed_by",
+ /* 263 */ "exprlist",
+ /* 264 */ "xfullname",
+ /* 265 */ "idlist",
+ /* 266 */ "indexed_opt",
+ /* 267 */ "nulls",
+ /* 268 */ "with",
+ /* 269 */ "where_opt_ret",
+ /* 270 */ "setlist",
+ /* 271 */ "insert_cmd",
+ /* 272 */ "idlist_opt",
+ /* 273 */ "upsert",
+ /* 274 */ "returning",
+ /* 275 */ "filter_over",
+ /* 276 */ "likeop",
+ /* 277 */ "between_op",
+ /* 278 */ "in_op",
+ /* 279 */ "paren_exprlist",
+ /* 280 */ "case_operand",
+ /* 281 */ "case_exprlist",
+ /* 282 */ "case_else",
+ /* 283 */ "uniqueflag",
+ /* 284 */ "collate",
+ /* 285 */ "vinto",
+ /* 286 */ "nmnum",
+ /* 287 */ "trigger_decl",
+ /* 288 */ "trigger_cmd_list",
+ /* 289 */ "trigger_time",
+ /* 290 */ "trigger_event",
+ /* 291 */ "foreach_clause",
+ /* 292 */ "when_clause",
+ /* 293 */ "trigger_cmd",
+ /* 294 */ "trnm",
+ /* 295 */ "tridxby",
+ /* 296 */ "database_kw_opt",
+ /* 297 */ "key_opt",
+ /* 298 */ "add_column_fullname",
+ /* 299 */ "kwcolumn_opt",
+ /* 300 */ "create_vtab",
+ /* 301 */ "vtabarglist",
+ /* 302 */ "vtabarg",
+ /* 303 */ "vtabargtoken",
+ /* 304 */ "lp",
+ /* 305 */ "anylist",
+ /* 306 */ "wqitem",
+ /* 307 */ "wqas",
+ /* 308 */ "withnm",
+ /* 309 */ "windowdefn_list",
+ /* 310 */ "windowdefn",
+ /* 311 */ "window",
+ /* 312 */ "frame_opt",
+ /* 313 */ "part_opt",
+ /* 314 */ "filter_clause",
+ /* 315 */ "over_clause",
+ /* 316 */ "range_or_rows",
+ /* 317 */ "frame_bound",
+ /* 318 */ "frame_bound_s",
+ /* 319 */ "frame_bound_e",
+ /* 320 */ "frame_exclude_opt",
+ /* 321 */ "frame_exclude",
};
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
@@ -168833,351 +175945,363 @@ static const char *const yyRuleName[] = {
/* 92 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
/* 93 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt",
/* 94 */ "values ::= VALUES LP nexprlist RP",
- /* 95 */ "values ::= values COMMA LP nexprlist RP",
- /* 96 */ "distinct ::= DISTINCT",
- /* 97 */ "distinct ::= ALL",
- /* 98 */ "distinct ::=",
- /* 99 */ "sclp ::=",
- /* 100 */ "selcollist ::= sclp scanpt expr scanpt as",
- /* 101 */ "selcollist ::= sclp scanpt STAR",
- /* 102 */ "selcollist ::= sclp scanpt nm DOT STAR",
- /* 103 */ "as ::= AS nm",
- /* 104 */ "as ::=",
- /* 105 */ "from ::=",
- /* 106 */ "from ::= FROM seltablist",
- /* 107 */ "stl_prefix ::= seltablist joinop",
- /* 108 */ "stl_prefix ::=",
- /* 109 */ "seltablist ::= stl_prefix nm dbnm as on_using",
- /* 110 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using",
- /* 111 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using",
- /* 112 */ "seltablist ::= stl_prefix LP select RP as on_using",
- /* 113 */ "seltablist ::= stl_prefix LP seltablist RP as on_using",
- /* 114 */ "dbnm ::=",
- /* 115 */ "dbnm ::= DOT nm",
- /* 116 */ "fullname ::= nm",
- /* 117 */ "fullname ::= nm DOT nm",
- /* 118 */ "xfullname ::= nm",
- /* 119 */ "xfullname ::= nm DOT nm",
- /* 120 */ "xfullname ::= nm DOT nm AS nm",
- /* 121 */ "xfullname ::= nm AS nm",
- /* 122 */ "joinop ::= COMMA|JOIN",
- /* 123 */ "joinop ::= JOIN_KW JOIN",
- /* 124 */ "joinop ::= JOIN_KW nm JOIN",
- /* 125 */ "joinop ::= JOIN_KW nm nm JOIN",
- /* 126 */ "on_using ::= ON expr",
- /* 127 */ "on_using ::= USING LP idlist RP",
- /* 128 */ "on_using ::=",
- /* 129 */ "indexed_opt ::=",
- /* 130 */ "indexed_by ::= INDEXED BY nm",
- /* 131 */ "indexed_by ::= NOT INDEXED",
- /* 132 */ "orderby_opt ::=",
- /* 133 */ "orderby_opt ::= ORDER BY sortlist",
- /* 134 */ "sortlist ::= sortlist COMMA expr sortorder nulls",
- /* 135 */ "sortlist ::= expr sortorder nulls",
- /* 136 */ "sortorder ::= ASC",
- /* 137 */ "sortorder ::= DESC",
- /* 138 */ "sortorder ::=",
- /* 139 */ "nulls ::= NULLS FIRST",
- /* 140 */ "nulls ::= NULLS LAST",
- /* 141 */ "nulls ::=",
- /* 142 */ "groupby_opt ::=",
- /* 143 */ "groupby_opt ::= GROUP BY nexprlist",
- /* 144 */ "having_opt ::=",
- /* 145 */ "having_opt ::= HAVING expr",
- /* 146 */ "limit_opt ::=",
- /* 147 */ "limit_opt ::= LIMIT expr",
- /* 148 */ "limit_opt ::= LIMIT expr OFFSET expr",
- /* 149 */ "limit_opt ::= LIMIT expr COMMA expr",
- /* 150 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret",
- /* 151 */ "where_opt ::=",
- /* 152 */ "where_opt ::= WHERE expr",
- /* 153 */ "where_opt_ret ::=",
- /* 154 */ "where_opt_ret ::= WHERE expr",
- /* 155 */ "where_opt_ret ::= RETURNING selcollist",
- /* 156 */ "where_opt_ret ::= WHERE expr RETURNING selcollist",
- /* 157 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret",
- /* 158 */ "setlist ::= setlist COMMA nm EQ expr",
- /* 159 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
- /* 160 */ "setlist ::= nm EQ expr",
- /* 161 */ "setlist ::= LP idlist RP EQ expr",
- /* 162 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
- /* 163 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning",
- /* 164 */ "upsert ::=",
- /* 165 */ "upsert ::= RETURNING selcollist",
- /* 166 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert",
- /* 167 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert",
- /* 168 */ "upsert ::= ON CONFLICT DO NOTHING returning",
- /* 169 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning",
- /* 170 */ "returning ::= RETURNING selcollist",
- /* 171 */ "insert_cmd ::= INSERT orconf",
- /* 172 */ "insert_cmd ::= REPLACE",
- /* 173 */ "idlist_opt ::=",
- /* 174 */ "idlist_opt ::= LP idlist RP",
- /* 175 */ "idlist ::= idlist COMMA nm",
- /* 176 */ "idlist ::= nm",
- /* 177 */ "expr ::= LP expr RP",
- /* 178 */ "expr ::= ID|INDEXED",
- /* 179 */ "expr ::= JOIN_KW",
- /* 180 */ "expr ::= nm DOT nm",
- /* 181 */ "expr ::= nm DOT nm DOT nm",
- /* 182 */ "term ::= NULL|FLOAT|BLOB",
- /* 183 */ "term ::= STRING",
- /* 184 */ "term ::= INTEGER",
- /* 185 */ "expr ::= VARIABLE",
- /* 186 */ "expr ::= expr COLLATE ID|STRING",
- /* 187 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 188 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
- /* 189 */ "expr ::= ID|INDEXED LP STAR RP",
- /* 190 */ "expr ::= ID|INDEXED LP distinct exprlist RP filter_over",
- /* 191 */ "expr ::= ID|INDEXED LP STAR RP filter_over",
- /* 192 */ "term ::= CTIME_KW",
- /* 193 */ "expr ::= LP nexprlist COMMA expr RP",
- /* 194 */ "expr ::= expr AND expr",
- /* 195 */ "expr ::= expr OR expr",
- /* 196 */ "expr ::= expr LT|GT|GE|LE expr",
- /* 197 */ "expr ::= expr EQ|NE expr",
- /* 198 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
- /* 199 */ "expr ::= expr PLUS|MINUS expr",
- /* 200 */ "expr ::= expr STAR|SLASH|REM expr",
- /* 201 */ "expr ::= expr CONCAT expr",
- /* 202 */ "likeop ::= NOT LIKE_KW|MATCH",
- /* 203 */ "expr ::= expr likeop expr",
- /* 204 */ "expr ::= expr likeop expr ESCAPE expr",
- /* 205 */ "expr ::= expr ISNULL|NOTNULL",
- /* 206 */ "expr ::= expr NOT NULL",
- /* 207 */ "expr ::= expr IS expr",
- /* 208 */ "expr ::= expr IS NOT expr",
- /* 209 */ "expr ::= expr IS NOT DISTINCT FROM expr",
- /* 210 */ "expr ::= expr IS DISTINCT FROM expr",
- /* 211 */ "expr ::= NOT expr",
- /* 212 */ "expr ::= BITNOT expr",
- /* 213 */ "expr ::= PLUS|MINUS expr",
- /* 214 */ "expr ::= expr PTR expr",
- /* 215 */ "between_op ::= BETWEEN",
- /* 216 */ "between_op ::= NOT BETWEEN",
- /* 217 */ "expr ::= expr between_op expr AND expr",
- /* 218 */ "in_op ::= IN",
- /* 219 */ "in_op ::= NOT IN",
- /* 220 */ "expr ::= expr in_op LP exprlist RP",
- /* 221 */ "expr ::= LP select RP",
- /* 222 */ "expr ::= expr in_op LP select RP",
- /* 223 */ "expr ::= expr in_op nm dbnm paren_exprlist",
- /* 224 */ "expr ::= EXISTS LP select RP",
- /* 225 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 226 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 227 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 228 */ "case_else ::= ELSE expr",
- /* 229 */ "case_else ::=",
- /* 230 */ "case_operand ::= expr",
- /* 231 */ "case_operand ::=",
- /* 232 */ "exprlist ::=",
- /* 233 */ "nexprlist ::= nexprlist COMMA expr",
- /* 234 */ "nexprlist ::= expr",
- /* 235 */ "paren_exprlist ::=",
- /* 236 */ "paren_exprlist ::= LP exprlist RP",
- /* 237 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
- /* 238 */ "uniqueflag ::= UNIQUE",
- /* 239 */ "uniqueflag ::=",
- /* 240 */ "eidlist_opt ::=",
- /* 241 */ "eidlist_opt ::= LP eidlist RP",
- /* 242 */ "eidlist ::= eidlist COMMA nm collate sortorder",
- /* 243 */ "eidlist ::= nm collate sortorder",
- /* 244 */ "collate ::=",
- /* 245 */ "collate ::= COLLATE ID|STRING",
- /* 246 */ "cmd ::= DROP INDEX ifexists fullname",
- /* 247 */ "cmd ::= VACUUM vinto",
- /* 248 */ "cmd ::= VACUUM nm vinto",
- /* 249 */ "vinto ::= INTO expr",
- /* 250 */ "vinto ::=",
- /* 251 */ "cmd ::= PRAGMA nm dbnm",
- /* 252 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
- /* 253 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
- /* 254 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 255 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
- /* 256 */ "plus_num ::= PLUS INTEGER|FLOAT",
- /* 257 */ "minus_num ::= MINUS INTEGER|FLOAT",
- /* 258 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
- /* 259 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 260 */ "trigger_time ::= BEFORE|AFTER",
- /* 261 */ "trigger_time ::= INSTEAD OF",
- /* 262 */ "trigger_time ::=",
- /* 263 */ "trigger_event ::= DELETE|INSERT",
- /* 264 */ "trigger_event ::= UPDATE",
- /* 265 */ "trigger_event ::= UPDATE OF idlist",
- /* 266 */ "when_clause ::=",
- /* 267 */ "when_clause ::= WHEN expr",
- /* 268 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
- /* 269 */ "trigger_cmd_list ::= trigger_cmd SEMI",
- /* 270 */ "trnm ::= nm DOT nm",
- /* 271 */ "tridxby ::= INDEXED BY nm",
- /* 272 */ "tridxby ::= NOT INDEXED",
- /* 273 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
- /* 274 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
- /* 275 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
- /* 276 */ "trigger_cmd ::= scanpt select scanpt",
- /* 277 */ "expr ::= RAISE LP IGNORE RP",
- /* 278 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 279 */ "raisetype ::= ROLLBACK",
- /* 280 */ "raisetype ::= ABORT",
- /* 281 */ "raisetype ::= FAIL",
- /* 282 */ "cmd ::= DROP TRIGGER ifexists fullname",
- /* 283 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
- /* 284 */ "cmd ::= DETACH database_kw_opt expr",
- /* 285 */ "key_opt ::=",
- /* 286 */ "key_opt ::= KEY expr",
- /* 287 */ "cmd ::= REINDEX",
- /* 288 */ "cmd ::= REINDEX nm dbnm",
- /* 289 */ "cmd ::= ANALYZE",
- /* 290 */ "cmd ::= ANALYZE nm dbnm",
- /* 291 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 292 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
- /* 293 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm",
- /* 294 */ "add_column_fullname ::= fullname",
- /* 295 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
- /* 296 */ "cmd ::= create_vtab",
- /* 297 */ "cmd ::= create_vtab LP vtabarglist RP",
- /* 298 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
- /* 299 */ "vtabarg ::=",
- /* 300 */ "vtabargtoken ::= ANY",
- /* 301 */ "vtabargtoken ::= lp anylist RP",
- /* 302 */ "lp ::= LP",
- /* 303 */ "with ::= WITH wqlist",
- /* 304 */ "with ::= WITH RECURSIVE wqlist",
- /* 305 */ "wqas ::= AS",
- /* 306 */ "wqas ::= AS MATERIALIZED",
- /* 307 */ "wqas ::= AS NOT MATERIALIZED",
- /* 308 */ "wqitem ::= nm eidlist_opt wqas LP select RP",
- /* 309 */ "wqlist ::= wqitem",
- /* 310 */ "wqlist ::= wqlist COMMA wqitem",
- /* 311 */ "windowdefn_list ::= windowdefn",
- /* 312 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
- /* 313 */ "windowdefn ::= nm AS LP window RP",
- /* 314 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
- /* 315 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
- /* 316 */ "window ::= ORDER BY sortlist frame_opt",
- /* 317 */ "window ::= nm ORDER BY sortlist frame_opt",
- /* 318 */ "window ::= frame_opt",
- /* 319 */ "window ::= nm frame_opt",
- /* 320 */ "frame_opt ::=",
- /* 321 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
- /* 322 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
- /* 323 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
- /* 324 */ "frame_bound_s ::= frame_bound",
- /* 325 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
- /* 326 */ "frame_bound_e ::= frame_bound",
- /* 327 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
- /* 328 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
- /* 329 */ "frame_bound ::= CURRENT ROW",
- /* 330 */ "frame_exclude_opt ::=",
- /* 331 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
- /* 332 */ "frame_exclude ::= NO OTHERS",
- /* 333 */ "frame_exclude ::= CURRENT ROW",
- /* 334 */ "frame_exclude ::= GROUP|TIES",
- /* 335 */ "window_clause ::= WINDOW windowdefn_list",
- /* 336 */ "filter_over ::= filter_clause over_clause",
- /* 337 */ "filter_over ::= over_clause",
- /* 338 */ "filter_over ::= filter_clause",
- /* 339 */ "over_clause ::= OVER LP window RP",
- /* 340 */ "over_clause ::= OVER nm",
- /* 341 */ "filter_clause ::= FILTER LP WHERE expr RP",
- /* 342 */ "input ::= cmdlist",
- /* 343 */ "cmdlist ::= cmdlist ecmd",
- /* 344 */ "cmdlist ::= ecmd",
- /* 345 */ "ecmd ::= SEMI",
- /* 346 */ "ecmd ::= cmdx SEMI",
- /* 347 */ "ecmd ::= explain cmdx SEMI",
- /* 348 */ "trans_opt ::=",
- /* 349 */ "trans_opt ::= TRANSACTION",
- /* 350 */ "trans_opt ::= TRANSACTION nm",
- /* 351 */ "savepoint_opt ::= SAVEPOINT",
- /* 352 */ "savepoint_opt ::=",
- /* 353 */ "cmd ::= create_table create_table_args",
- /* 354 */ "table_option_set ::= table_option",
- /* 355 */ "columnlist ::= columnlist COMMA columnname carglist",
- /* 356 */ "columnlist ::= columnname carglist",
- /* 357 */ "nm ::= ID|INDEXED",
- /* 358 */ "nm ::= STRING",
- /* 359 */ "nm ::= JOIN_KW",
- /* 360 */ "typetoken ::= typename",
- /* 361 */ "typename ::= ID|STRING",
- /* 362 */ "signed ::= plus_num",
- /* 363 */ "signed ::= minus_num",
- /* 364 */ "carglist ::= carglist ccons",
- /* 365 */ "carglist ::=",
- /* 366 */ "ccons ::= NULL onconf",
- /* 367 */ "ccons ::= GENERATED ALWAYS AS generated",
- /* 368 */ "ccons ::= AS generated",
- /* 369 */ "conslist_opt ::= COMMA conslist",
- /* 370 */ "conslist ::= conslist tconscomma tcons",
- /* 371 */ "conslist ::= tcons",
- /* 372 */ "tconscomma ::=",
- /* 373 */ "defer_subclause_opt ::= defer_subclause",
- /* 374 */ "resolvetype ::= raisetype",
- /* 375 */ "selectnowith ::= oneselect",
- /* 376 */ "oneselect ::= values",
- /* 377 */ "sclp ::= selcollist COMMA",
- /* 378 */ "as ::= ID|STRING",
- /* 379 */ "indexed_opt ::= indexed_by",
- /* 380 */ "returning ::=",
- /* 381 */ "expr ::= term",
- /* 382 */ "likeop ::= LIKE_KW|MATCH",
- /* 383 */ "exprlist ::= nexprlist",
- /* 384 */ "nmnum ::= plus_num",
- /* 385 */ "nmnum ::= nm",
- /* 386 */ "nmnum ::= ON",
- /* 387 */ "nmnum ::= DELETE",
- /* 388 */ "nmnum ::= DEFAULT",
- /* 389 */ "plus_num ::= INTEGER|FLOAT",
- /* 390 */ "foreach_clause ::=",
- /* 391 */ "foreach_clause ::= FOR EACH ROW",
- /* 392 */ "trnm ::= nm",
- /* 393 */ "tridxby ::=",
- /* 394 */ "database_kw_opt ::= DATABASE",
- /* 395 */ "database_kw_opt ::=",
- /* 396 */ "kwcolumn_opt ::=",
- /* 397 */ "kwcolumn_opt ::= COLUMNKW",
- /* 398 */ "vtabarglist ::= vtabarg",
- /* 399 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
- /* 400 */ "vtabarg ::= vtabarg vtabargtoken",
- /* 401 */ "anylist ::=",
- /* 402 */ "anylist ::= anylist LP anylist RP",
- /* 403 */ "anylist ::= anylist ANY",
- /* 404 */ "with ::=",
+ /* 95 */ "oneselect ::= mvalues",
+ /* 96 */ "mvalues ::= values COMMA LP nexprlist RP",
+ /* 97 */ "mvalues ::= mvalues COMMA LP nexprlist RP",
+ /* 98 */ "distinct ::= DISTINCT",
+ /* 99 */ "distinct ::= ALL",
+ /* 100 */ "distinct ::=",
+ /* 101 */ "sclp ::=",
+ /* 102 */ "selcollist ::= sclp scanpt expr scanpt as",
+ /* 103 */ "selcollist ::= sclp scanpt STAR",
+ /* 104 */ "selcollist ::= sclp scanpt nm DOT STAR",
+ /* 105 */ "as ::= AS nm",
+ /* 106 */ "as ::=",
+ /* 107 */ "from ::=",
+ /* 108 */ "from ::= FROM seltablist",
+ /* 109 */ "stl_prefix ::= seltablist joinop",
+ /* 110 */ "stl_prefix ::=",
+ /* 111 */ "seltablist ::= stl_prefix nm dbnm as on_using",
+ /* 112 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using",
+ /* 113 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using",
+ /* 114 */ "seltablist ::= stl_prefix LP select RP as on_using",
+ /* 115 */ "seltablist ::= stl_prefix LP seltablist RP as on_using",
+ /* 116 */ "dbnm ::=",
+ /* 117 */ "dbnm ::= DOT nm",
+ /* 118 */ "fullname ::= nm",
+ /* 119 */ "fullname ::= nm DOT nm",
+ /* 120 */ "xfullname ::= nm",
+ /* 121 */ "xfullname ::= nm DOT nm",
+ /* 122 */ "xfullname ::= nm DOT nm AS nm",
+ /* 123 */ "xfullname ::= nm AS nm",
+ /* 124 */ "joinop ::= COMMA|JOIN",
+ /* 125 */ "joinop ::= JOIN_KW JOIN",
+ /* 126 */ "joinop ::= JOIN_KW nm JOIN",
+ /* 127 */ "joinop ::= JOIN_KW nm nm JOIN",
+ /* 128 */ "on_using ::= ON expr",
+ /* 129 */ "on_using ::= USING LP idlist RP",
+ /* 130 */ "on_using ::=",
+ /* 131 */ "indexed_opt ::=",
+ /* 132 */ "indexed_by ::= INDEXED BY nm",
+ /* 133 */ "indexed_by ::= NOT INDEXED",
+ /* 134 */ "orderby_opt ::=",
+ /* 135 */ "orderby_opt ::= ORDER BY sortlist",
+ /* 136 */ "sortlist ::= sortlist COMMA expr sortorder nulls",
+ /* 137 */ "sortlist ::= expr sortorder nulls",
+ /* 138 */ "sortorder ::= ASC",
+ /* 139 */ "sortorder ::= DESC",
+ /* 140 */ "sortorder ::=",
+ /* 141 */ "nulls ::= NULLS FIRST",
+ /* 142 */ "nulls ::= NULLS LAST",
+ /* 143 */ "nulls ::=",
+ /* 144 */ "groupby_opt ::=",
+ /* 145 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 146 */ "having_opt ::=",
+ /* 147 */ "having_opt ::= HAVING expr",
+ /* 148 */ "limit_opt ::=",
+ /* 149 */ "limit_opt ::= LIMIT expr",
+ /* 150 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 151 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 152 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret",
+ /* 153 */ "where_opt ::=",
+ /* 154 */ "where_opt ::= WHERE expr",
+ /* 155 */ "where_opt_ret ::=",
+ /* 156 */ "where_opt_ret ::= WHERE expr",
+ /* 157 */ "where_opt_ret ::= RETURNING selcollist",
+ /* 158 */ "where_opt_ret ::= WHERE expr RETURNING selcollist",
+ /* 159 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret",
+ /* 160 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 161 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
+ /* 162 */ "setlist ::= nm EQ expr",
+ /* 163 */ "setlist ::= LP idlist RP EQ expr",
+ /* 164 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
+ /* 165 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning",
+ /* 166 */ "upsert ::=",
+ /* 167 */ "upsert ::= RETURNING selcollist",
+ /* 168 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert",
+ /* 169 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert",
+ /* 170 */ "upsert ::= ON CONFLICT DO NOTHING returning",
+ /* 171 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning",
+ /* 172 */ "returning ::= RETURNING selcollist",
+ /* 173 */ "insert_cmd ::= INSERT orconf",
+ /* 174 */ "insert_cmd ::= REPLACE",
+ /* 175 */ "idlist_opt ::=",
+ /* 176 */ "idlist_opt ::= LP idlist RP",
+ /* 177 */ "idlist ::= idlist COMMA nm",
+ /* 178 */ "idlist ::= nm",
+ /* 179 */ "expr ::= LP expr RP",
+ /* 180 */ "expr ::= ID|INDEXED|JOIN_KW",
+ /* 181 */ "expr ::= nm DOT nm",
+ /* 182 */ "expr ::= nm DOT nm DOT nm",
+ /* 183 */ "term ::= NULL|FLOAT|BLOB",
+ /* 184 */ "term ::= STRING",
+ /* 185 */ "term ::= INTEGER",
+ /* 186 */ "expr ::= VARIABLE",
+ /* 187 */ "expr ::= expr COLLATE ID|STRING",
+ /* 188 */ "expr ::= CAST LP expr AS typetoken RP",
+ /* 189 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP",
+ /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP",
+ /* 191 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP",
+ /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over",
+ /* 193 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over",
+ /* 194 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over",
+ /* 195 */ "term ::= CTIME_KW",
+ /* 196 */ "expr ::= LP nexprlist COMMA expr RP",
+ /* 197 */ "expr ::= expr AND expr",
+ /* 198 */ "expr ::= expr OR expr",
+ /* 199 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 200 */ "expr ::= expr EQ|NE expr",
+ /* 201 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 202 */ "expr ::= expr PLUS|MINUS expr",
+ /* 203 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 204 */ "expr ::= expr CONCAT expr",
+ /* 205 */ "likeop ::= NOT LIKE_KW|MATCH",
+ /* 206 */ "expr ::= expr likeop expr",
+ /* 207 */ "expr ::= expr likeop expr ESCAPE expr",
+ /* 208 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 209 */ "expr ::= expr NOT NULL",
+ /* 210 */ "expr ::= expr IS expr",
+ /* 211 */ "expr ::= expr IS NOT expr",
+ /* 212 */ "expr ::= expr IS NOT DISTINCT FROM expr",
+ /* 213 */ "expr ::= expr IS DISTINCT FROM expr",
+ /* 214 */ "expr ::= NOT expr",
+ /* 215 */ "expr ::= BITNOT expr",
+ /* 216 */ "expr ::= PLUS|MINUS expr",
+ /* 217 */ "expr ::= expr PTR expr",
+ /* 218 */ "between_op ::= BETWEEN",
+ /* 219 */ "between_op ::= NOT BETWEEN",
+ /* 220 */ "expr ::= expr between_op expr AND expr",
+ /* 221 */ "in_op ::= IN",
+ /* 222 */ "in_op ::= NOT IN",
+ /* 223 */ "expr ::= expr in_op LP exprlist RP",
+ /* 224 */ "expr ::= LP select RP",
+ /* 225 */ "expr ::= expr in_op LP select RP",
+ /* 226 */ "expr ::= expr in_op nm dbnm paren_exprlist",
+ /* 227 */ "expr ::= EXISTS LP select RP",
+ /* 228 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 229 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 230 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 231 */ "case_else ::= ELSE expr",
+ /* 232 */ "case_else ::=",
+ /* 233 */ "case_operand ::=",
+ /* 234 */ "exprlist ::=",
+ /* 235 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 236 */ "nexprlist ::= expr",
+ /* 237 */ "paren_exprlist ::=",
+ /* 238 */ "paren_exprlist ::= LP exprlist RP",
+ /* 239 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
+ /* 240 */ "uniqueflag ::= UNIQUE",
+ /* 241 */ "uniqueflag ::=",
+ /* 242 */ "eidlist_opt ::=",
+ /* 243 */ "eidlist_opt ::= LP eidlist RP",
+ /* 244 */ "eidlist ::= eidlist COMMA nm collate sortorder",
+ /* 245 */ "eidlist ::= nm collate sortorder",
+ /* 246 */ "collate ::=",
+ /* 247 */ "collate ::= COLLATE ID|STRING",
+ /* 248 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 249 */ "cmd ::= VACUUM vinto",
+ /* 250 */ "cmd ::= VACUUM nm vinto",
+ /* 251 */ "vinto ::= INTO expr",
+ /* 252 */ "vinto ::=",
+ /* 253 */ "cmd ::= PRAGMA nm dbnm",
+ /* 254 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 255 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 256 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 257 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
+ /* 258 */ "plus_num ::= PLUS INTEGER|FLOAT",
+ /* 259 */ "minus_num ::= MINUS INTEGER|FLOAT",
+ /* 260 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
+ /* 261 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 262 */ "trigger_time ::= BEFORE|AFTER",
+ /* 263 */ "trigger_time ::= INSTEAD OF",
+ /* 264 */ "trigger_time ::=",
+ /* 265 */ "trigger_event ::= DELETE|INSERT",
+ /* 266 */ "trigger_event ::= UPDATE",
+ /* 267 */ "trigger_event ::= UPDATE OF idlist",
+ /* 268 */ "when_clause ::=",
+ /* 269 */ "when_clause ::= WHEN expr",
+ /* 270 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 271 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 272 */ "trnm ::= nm DOT nm",
+ /* 273 */ "tridxby ::= INDEXED BY nm",
+ /* 274 */ "tridxby ::= NOT INDEXED",
+ /* 275 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
+ /* 276 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
+ /* 277 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
+ /* 278 */ "trigger_cmd ::= scanpt select scanpt",
+ /* 279 */ "expr ::= RAISE LP IGNORE RP",
+ /* 280 */ "expr ::= RAISE LP raisetype COMMA expr RP",
+ /* 281 */ "raisetype ::= ROLLBACK",
+ /* 282 */ "raisetype ::= ABORT",
+ /* 283 */ "raisetype ::= FAIL",
+ /* 284 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 285 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 286 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 287 */ "key_opt ::=",
+ /* 288 */ "key_opt ::= KEY expr",
+ /* 289 */ "cmd ::= REINDEX",
+ /* 290 */ "cmd ::= REINDEX nm dbnm",
+ /* 291 */ "cmd ::= ANALYZE",
+ /* 292 */ "cmd ::= ANALYZE nm dbnm",
+ /* 293 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 294 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
+ /* 295 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm",
+ /* 296 */ "add_column_fullname ::= fullname",
+ /* 297 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
+ /* 298 */ "cmd ::= create_vtab",
+ /* 299 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 300 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
+ /* 301 */ "vtabarg ::=",
+ /* 302 */ "vtabargtoken ::= ANY",
+ /* 303 */ "vtabargtoken ::= lp anylist RP",
+ /* 304 */ "lp ::= LP",
+ /* 305 */ "with ::= WITH wqlist",
+ /* 306 */ "with ::= WITH RECURSIVE wqlist",
+ /* 307 */ "wqas ::= AS",
+ /* 308 */ "wqas ::= AS MATERIALIZED",
+ /* 309 */ "wqas ::= AS NOT MATERIALIZED",
+ /* 310 */ "wqitem ::= withnm eidlist_opt wqas LP select RP",
+ /* 311 */ "withnm ::= nm",
+ /* 312 */ "wqlist ::= wqitem",
+ /* 313 */ "wqlist ::= wqlist COMMA wqitem",
+ /* 314 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
+ /* 315 */ "windowdefn ::= nm AS LP window RP",
+ /* 316 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 317 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 318 */ "window ::= ORDER BY sortlist frame_opt",
+ /* 319 */ "window ::= nm ORDER BY sortlist frame_opt",
+ /* 320 */ "window ::= nm frame_opt",
+ /* 321 */ "frame_opt ::=",
+ /* 322 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
+ /* 323 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
+ /* 324 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
+ /* 325 */ "frame_bound_s ::= frame_bound",
+ /* 326 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
+ /* 327 */ "frame_bound_e ::= frame_bound",
+ /* 328 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
+ /* 329 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
+ /* 330 */ "frame_bound ::= CURRENT ROW",
+ /* 331 */ "frame_exclude_opt ::=",
+ /* 332 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
+ /* 333 */ "frame_exclude ::= NO OTHERS",
+ /* 334 */ "frame_exclude ::= CURRENT ROW",
+ /* 335 */ "frame_exclude ::= GROUP|TIES",
+ /* 336 */ "window_clause ::= WINDOW windowdefn_list",
+ /* 337 */ "filter_over ::= filter_clause over_clause",
+ /* 338 */ "filter_over ::= over_clause",
+ /* 339 */ "filter_over ::= filter_clause",
+ /* 340 */ "over_clause ::= OVER LP window RP",
+ /* 341 */ "over_clause ::= OVER nm",
+ /* 342 */ "filter_clause ::= FILTER LP WHERE expr RP",
+ /* 343 */ "term ::= QNUMBER",
+ /* 344 */ "input ::= cmdlist",
+ /* 345 */ "cmdlist ::= cmdlist ecmd",
+ /* 346 */ "cmdlist ::= ecmd",
+ /* 347 */ "ecmd ::= SEMI",
+ /* 348 */ "ecmd ::= cmdx SEMI",
+ /* 349 */ "ecmd ::= explain cmdx SEMI",
+ /* 350 */ "trans_opt ::=",
+ /* 351 */ "trans_opt ::= TRANSACTION",
+ /* 352 */ "trans_opt ::= TRANSACTION nm",
+ /* 353 */ "savepoint_opt ::= SAVEPOINT",
+ /* 354 */ "savepoint_opt ::=",
+ /* 355 */ "cmd ::= create_table create_table_args",
+ /* 356 */ "table_option_set ::= table_option",
+ /* 357 */ "columnlist ::= columnlist COMMA columnname carglist",
+ /* 358 */ "columnlist ::= columnname carglist",
+ /* 359 */ "nm ::= ID|INDEXED|JOIN_KW",
+ /* 360 */ "nm ::= STRING",
+ /* 361 */ "typetoken ::= typename",
+ /* 362 */ "typename ::= ID|STRING",
+ /* 363 */ "signed ::= plus_num",
+ /* 364 */ "signed ::= minus_num",
+ /* 365 */ "carglist ::= carglist ccons",
+ /* 366 */ "carglist ::=",
+ /* 367 */ "ccons ::= NULL onconf",
+ /* 368 */ "ccons ::= GENERATED ALWAYS AS generated",
+ /* 369 */ "ccons ::= AS generated",
+ /* 370 */ "conslist_opt ::= COMMA conslist",
+ /* 371 */ "conslist ::= conslist tconscomma tcons",
+ /* 372 */ "conslist ::= tcons",
+ /* 373 */ "tconscomma ::=",
+ /* 374 */ "defer_subclause_opt ::= defer_subclause",
+ /* 375 */ "resolvetype ::= raisetype",
+ /* 376 */ "selectnowith ::= oneselect",
+ /* 377 */ "oneselect ::= values",
+ /* 378 */ "sclp ::= selcollist COMMA",
+ /* 379 */ "as ::= ID|STRING",
+ /* 380 */ "indexed_opt ::= indexed_by",
+ /* 381 */ "returning ::=",
+ /* 382 */ "expr ::= term",
+ /* 383 */ "likeop ::= LIKE_KW|MATCH",
+ /* 384 */ "case_operand ::= expr",
+ /* 385 */ "exprlist ::= nexprlist",
+ /* 386 */ "nmnum ::= plus_num",
+ /* 387 */ "nmnum ::= nm",
+ /* 388 */ "nmnum ::= ON",
+ /* 389 */ "nmnum ::= DELETE",
+ /* 390 */ "nmnum ::= DEFAULT",
+ /* 391 */ "plus_num ::= INTEGER|FLOAT",
+ /* 392 */ "foreach_clause ::=",
+ /* 393 */ "foreach_clause ::= FOR EACH ROW",
+ /* 394 */ "trnm ::= nm",
+ /* 395 */ "tridxby ::=",
+ /* 396 */ "database_kw_opt ::= DATABASE",
+ /* 397 */ "database_kw_opt ::=",
+ /* 398 */ "kwcolumn_opt ::=",
+ /* 399 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 400 */ "vtabarglist ::= vtabarg",
+ /* 401 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 402 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 403 */ "anylist ::=",
+ /* 404 */ "anylist ::= anylist LP anylist RP",
+ /* 405 */ "anylist ::= anylist ANY",
+ /* 406 */ "with ::=",
+ /* 407 */ "windowdefn_list ::= windowdefn",
+ /* 408 */ "window ::= frame_opt",
};
#endif /* NDEBUG */
-#if YYSTACKDEPTH<=0
+#if YYGROWABLESTACK
/*
** Try to increase the size of the parser stack. Return the number
** of errors. Return 0 on success.
*/
static int yyGrowStack(yyParser *p){
+ int oldSize = 1 + (int)(p->yystackEnd - p->yystack);
int newSize;
int idx;
yyStackEntry *pNew;
- newSize = p->yystksz*2 + 100;
- idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
- if( p->yystack==&p->yystk0 ){
- pNew = malloc(newSize*sizeof(pNew[0]));
- if( pNew ) pNew[0] = p->yystk0;
+ newSize = oldSize*2 + 100;
+ idx = (int)(p->yytos - p->yystack);
+ if( p->yystack==p->yystk0 ){
+ pNew = YYREALLOC(0, newSize*sizeof(pNew[0]));
+ if( pNew==0 ) return 1;
+ memcpy(pNew, p->yystack, oldSize*sizeof(pNew[0]));
}else{
- pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0]));
+ if( pNew==0 ) return 1;
}
- if( pNew ){
- p->yystack = pNew;
- p->yytos = &p->yystack[idx];
+ p->yystack = pNew;
+ p->yytos = &p->yystack[idx];
#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
- yyTracePrompt, p->yystksz, newSize);
- }
-#endif
- p->yystksz = newSize;
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
+ yyTracePrompt, oldSize, newSize);
}
- return pNew==0;
+#endif
+ p->yystackEnd = &p->yystack[newSize-1];
+ return 0;
}
+#endif /* YYGROWABLESTACK */
+
+#if !YYGROWABLESTACK
+/* For builds that do no have a growable stack, yyGrowStack always
+** returns an error.
+*/
+# define yyGrowStack(X) 1
#endif
/* Datatype of the argument to the memory allocated passed as the
@@ -169197,24 +176321,14 @@ SQLITE_PRIVATE void wx_sqlite3ParserInit(void *yypRawParser wx_sqlite3ParserCTX_
#ifdef YYTRACKMAXSTACKDEPTH
yypParser->yyhwm = 0;
#endif
-#if YYSTACKDEPTH<=0
- yypParser->yytos = NULL;
- yypParser->yystack = NULL;
- yypParser->yystksz = 0;
- if( yyGrowStack(yypParser) ){
- yypParser->yystack = &yypParser->yystk0;
- yypParser->yystksz = 1;
- }
-#endif
+ yypParser->yystack = yypParser->yystk0;
+ yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt = -1;
#endif
yypParser->yytos = yypParser->yystack;
yypParser->yystack[0].stateno = 0;
yypParser->yystack[0].major = 0;
-#if YYSTACKDEPTH>0
- yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
-#endif
}
#ifndef wx_sqlite3Parser_ENGINEALWAYSONSTACK
@@ -169268,97 +176382,98 @@ static void yy_destructor(
** inside the C code.
*/
/********* Begin destructor definitions ***************************************/
- case 204: /* select */
- case 239: /* selectnowith */
- case 240: /* oneselect */
- case 252: /* values */
+ case 205: /* select */
+ case 240: /* selectnowith */
+ case 241: /* oneselect */
+ case 253: /* values */
+ case 255: /* mvalues */
{
-wx_sqlite3SelectDelete(pParse->db, (yypminor->yy47));
+wx_sqlite3SelectDelete(pParse->db, (yypminor->yy555));
}
break;
- case 216: /* term */
- case 217: /* expr */
- case 246: /* where_opt */
- case 248: /* having_opt */
- case 267: /* where_opt_ret */
- case 278: /* case_operand */
- case 280: /* case_else */
- case 283: /* vinto */
- case 290: /* when_clause */
- case 295: /* key_opt */
- case 311: /* filter_clause */
+ case 217: /* term */
+ case 218: /* expr */
+ case 247: /* where_opt */
+ case 249: /* having_opt */
+ case 269: /* where_opt_ret */
+ case 280: /* case_operand */
+ case 282: /* case_else */
+ case 285: /* vinto */
+ case 292: /* when_clause */
+ case 297: /* key_opt */
+ case 314: /* filter_clause */
{
-wx_sqlite3ExprDelete(pParse->db, (yypminor->yy528));
+wx_sqlite3ExprDelete(pParse->db, (yypminor->yy454));
}
break;
- case 221: /* eidlist_opt */
- case 231: /* sortlist */
- case 232: /* eidlist */
- case 244: /* selcollist */
- case 247: /* groupby_opt */
- case 249: /* orderby_opt */
- case 253: /* nexprlist */
- case 254: /* sclp */
- case 261: /* exprlist */
- case 268: /* setlist */
- case 277: /* paren_exprlist */
- case 279: /* case_exprlist */
- case 310: /* part_opt */
+ case 222: /* eidlist_opt */
+ case 232: /* sortlist */
+ case 233: /* eidlist */
+ case 245: /* selcollist */
+ case 248: /* groupby_opt */
+ case 250: /* orderby_opt */
+ case 254: /* nexprlist */
+ case 256: /* sclp */
+ case 263: /* exprlist */
+ case 270: /* setlist */
+ case 279: /* paren_exprlist */
+ case 281: /* case_exprlist */
+ case 313: /* part_opt */
{
-wx_sqlite3ExprListDelete(pParse->db, (yypminor->yy322));
+wx_sqlite3ExprListDelete(pParse->db, (yypminor->yy14));
}
break;
- case 238: /* fullname */
- case 245: /* from */
- case 256: /* seltablist */
- case 257: /* stl_prefix */
- case 262: /* xfullname */
+ case 239: /* fullname */
+ case 246: /* from */
+ case 258: /* seltablist */
+ case 259: /* stl_prefix */
+ case 264: /* xfullname */
{
-wx_sqlite3SrcListDelete(pParse->db, (yypminor->yy131));
+wx_sqlite3SrcListDelete(pParse->db, (yypminor->yy203));
}
break;
- case 241: /* wqlist */
+ case 242: /* wqlist */
{
-wx_sqlite3WithDelete(pParse->db, (yypminor->yy521));
+wx_sqlite3WithDelete(pParse->db, (yypminor->yy59));
}
break;
- case 251: /* window_clause */
- case 306: /* windowdefn_list */
+ case 252: /* window_clause */
+ case 309: /* windowdefn_list */
{
-wx_sqlite3WindowListDelete(pParse->db, (yypminor->yy41));
+wx_sqlite3WindowListDelete(pParse->db, (yypminor->yy211));
}
break;
- case 263: /* idlist */
- case 270: /* idlist_opt */
+ case 265: /* idlist */
+ case 272: /* idlist_opt */
{
-wx_sqlite3IdListDelete(pParse->db, (yypminor->yy254));
+wx_sqlite3IdListDelete(pParse->db, (yypminor->yy132));
}
break;
- case 273: /* filter_over */
- case 307: /* windowdefn */
- case 308: /* window */
- case 309: /* frame_opt */
- case 312: /* over_clause */
+ case 275: /* filter_over */
+ case 310: /* windowdefn */
+ case 311: /* window */
+ case 312: /* frame_opt */
+ case 315: /* over_clause */
{
-wx_sqlite3WindowDelete(pParse->db, (yypminor->yy41));
+wx_sqlite3WindowDelete(pParse->db, (yypminor->yy211));
}
break;
- case 286: /* trigger_cmd_list */
- case 291: /* trigger_cmd */
+ case 288: /* trigger_cmd_list */
+ case 293: /* trigger_cmd */
{
-wx_sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy33));
+wx_sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy427));
}
break;
- case 288: /* trigger_event */
+ case 290: /* trigger_event */
{
-wx_sqlite3IdListDelete(pParse->db, (yypminor->yy180).b);
+wx_sqlite3IdListDelete(pParse->db, (yypminor->yy286).b);
}
break;
- case 314: /* frame_bound */
- case 315: /* frame_bound_s */
- case 316: /* frame_bound_e */
+ case 317: /* frame_bound */
+ case 318: /* frame_bound_s */
+ case 319: /* frame_bound_e */
{
-wx_sqlite3ExprDelete(pParse->db, (yypminor->yy595).pExpr);
+wx_sqlite3ExprDelete(pParse->db, (yypminor->yy509).pExpr);
}
break;
/********* End destructor definitions *****************************************/
@@ -169392,9 +176507,26 @@ static void yy_pop_parser_stack(yyParser *pParser){
*/
SQLITE_PRIVATE void wx_sqlite3ParserFinalize(void *p){
yyParser *pParser = (yyParser*)p;
- while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
-#if YYSTACKDEPTH<=0
- if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
+
+ /* In-lined version of calling yy_pop_parser_stack() for each
+ ** element left in the stack */
+ yyStackEntry *yytos = pParser->yytos;
+ while( yytos>pParser->yystack ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sPopping %s\n",
+ yyTracePrompt,
+ yyTokenName[yytos->major]);
+ }
+#endif
+ if( yytos->major>=YY_MIN_DSTRCTR ){
+ yy_destructor(pParser, yytos->major, &yytos->minor);
+ }
+ yytos--;
+ }
+
+#if YYGROWABLESTACK
+ if( pParser->yystack!=pParser->yystk0 ) YYFREE(pParser->yystack);
#endif
}
@@ -169577,7 +176709,7 @@ static void yyStackOverflow(yyParser *yypParser){
** stack every overflows */
/******** Begin %stack_overflow code ******************************************/
- wx_sqlite3ErrorMsg(pParse, "parser stack overflow");
+ wx_sqlite3OomFault(pParse->db);
/******** End %stack_overflow code ********************************************/
wx_sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument var */
wx_sqlite3ParserCTX_STORE
@@ -169621,25 +176753,19 @@ static void yy_shift(
assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
}
#endif
-#if YYSTACKDEPTH>0
- if( yypParser->yytos>yypParser->yystackEnd ){
- yypParser->yytos--;
- yyStackOverflow(yypParser);
- return;
- }
-#else
- if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
+ yytos = yypParser->yytos;
+ if( yytos>yypParser->yystackEnd ){
if( yyGrowStack(yypParser) ){
yypParser->yytos--;
yyStackOverflow(yypParser);
return;
}
+ yytos = yypParser->yytos;
+ assert( yytos <= yypParser->yystackEnd );
}
-#endif
if( yyNewState > YY_MAX_SHIFT ){
yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
}
- yytos = yypParser->yytos;
yytos->stateno = yyNewState;
yytos->major = yyMajor;
yytos->minor.yy0 = yyMinor;
@@ -169649,411 +176775,415 @@ static void yy_shift(
/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
** of that rule */
static const YYCODETYPE yyRuleInfoLhs[] = {
- 189, /* (0) explain ::= EXPLAIN */
- 189, /* (1) explain ::= EXPLAIN QUERY PLAN */
- 188, /* (2) cmdx ::= cmd */
- 190, /* (3) cmd ::= BEGIN transtype trans_opt */
- 191, /* (4) transtype ::= */
- 191, /* (5) transtype ::= DEFERRED */
- 191, /* (6) transtype ::= IMMEDIATE */
- 191, /* (7) transtype ::= EXCLUSIVE */
- 190, /* (8) cmd ::= COMMIT|END trans_opt */
- 190, /* (9) cmd ::= ROLLBACK trans_opt */
- 190, /* (10) cmd ::= SAVEPOINT nm */
- 190, /* (11) cmd ::= RELEASE savepoint_opt nm */
- 190, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
- 195, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
- 197, /* (14) createkw ::= CREATE */
- 199, /* (15) ifnotexists ::= */
- 199, /* (16) ifnotexists ::= IF NOT EXISTS */
- 198, /* (17) temp ::= TEMP */
- 198, /* (18) temp ::= */
- 196, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
- 196, /* (20) create_table_args ::= AS select */
- 203, /* (21) table_option_set ::= */
- 203, /* (22) table_option_set ::= table_option_set COMMA table_option */
- 205, /* (23) table_option ::= WITHOUT nm */
- 205, /* (24) table_option ::= nm */
- 206, /* (25) columnname ::= nm typetoken */
- 208, /* (26) typetoken ::= */
- 208, /* (27) typetoken ::= typename LP signed RP */
- 208, /* (28) typetoken ::= typename LP signed COMMA signed RP */
- 209, /* (29) typename ::= typename ID|STRING */
- 213, /* (30) scanpt ::= */
- 214, /* (31) scantok ::= */
- 215, /* (32) ccons ::= CONSTRAINT nm */
- 215, /* (33) ccons ::= DEFAULT scantok term */
- 215, /* (34) ccons ::= DEFAULT LP expr RP */
- 215, /* (35) ccons ::= DEFAULT PLUS scantok term */
- 215, /* (36) ccons ::= DEFAULT MINUS scantok term */
- 215, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */
- 215, /* (38) ccons ::= NOT NULL onconf */
- 215, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */
- 215, /* (40) ccons ::= UNIQUE onconf */
- 215, /* (41) ccons ::= CHECK LP expr RP */
- 215, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */
- 215, /* (43) ccons ::= defer_subclause */
- 215, /* (44) ccons ::= COLLATE ID|STRING */
- 224, /* (45) generated ::= LP expr RP */
- 224, /* (46) generated ::= LP expr RP ID */
- 220, /* (47) autoinc ::= */
- 220, /* (48) autoinc ::= AUTOINCR */
- 222, /* (49) refargs ::= */
- 222, /* (50) refargs ::= refargs refarg */
- 225, /* (51) refarg ::= MATCH nm */
- 225, /* (52) refarg ::= ON INSERT refact */
- 225, /* (53) refarg ::= ON DELETE refact */
- 225, /* (54) refarg ::= ON UPDATE refact */
- 226, /* (55) refact ::= SET NULL */
- 226, /* (56) refact ::= SET DEFAULT */
- 226, /* (57) refact ::= CASCADE */
- 226, /* (58) refact ::= RESTRICT */
- 226, /* (59) refact ::= NO ACTION */
- 223, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
- 223, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
- 227, /* (62) init_deferred_pred_opt ::= */
- 227, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */
- 227, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
- 202, /* (65) conslist_opt ::= */
- 229, /* (66) tconscomma ::= COMMA */
- 230, /* (67) tcons ::= CONSTRAINT nm */
- 230, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
- 230, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */
- 230, /* (70) tcons ::= CHECK LP expr RP onconf */
- 230, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
- 233, /* (72) defer_subclause_opt ::= */
- 218, /* (73) onconf ::= */
- 218, /* (74) onconf ::= ON CONFLICT resolvetype */
- 234, /* (75) orconf ::= */
- 234, /* (76) orconf ::= OR resolvetype */
- 235, /* (77) resolvetype ::= IGNORE */
- 235, /* (78) resolvetype ::= REPLACE */
- 190, /* (79) cmd ::= DROP TABLE ifexists fullname */
- 237, /* (80) ifexists ::= IF EXISTS */
- 237, /* (81) ifexists ::= */
- 190, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
- 190, /* (83) cmd ::= DROP VIEW ifexists fullname */
- 190, /* (84) cmd ::= select */
- 204, /* (85) select ::= WITH wqlist selectnowith */
- 204, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */
- 204, /* (87) select ::= selectnowith */
- 239, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */
- 242, /* (89) multiselect_op ::= UNION */
- 242, /* (90) multiselect_op ::= UNION ALL */
- 242, /* (91) multiselect_op ::= EXCEPT|INTERSECT */
- 240, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
- 240, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
- 252, /* (94) values ::= VALUES LP nexprlist RP */
- 252, /* (95) values ::= values COMMA LP nexprlist RP */
- 243, /* (96) distinct ::= DISTINCT */
- 243, /* (97) distinct ::= ALL */
- 243, /* (98) distinct ::= */
- 254, /* (99) sclp ::= */
- 244, /* (100) selcollist ::= sclp scanpt expr scanpt as */
- 244, /* (101) selcollist ::= sclp scanpt STAR */
- 244, /* (102) selcollist ::= sclp scanpt nm DOT STAR */
- 255, /* (103) as ::= AS nm */
- 255, /* (104) as ::= */
- 245, /* (105) from ::= */
- 245, /* (106) from ::= FROM seltablist */
- 257, /* (107) stl_prefix ::= seltablist joinop */
- 257, /* (108) stl_prefix ::= */
- 256, /* (109) seltablist ::= stl_prefix nm dbnm as on_using */
- 256, /* (110) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
- 256, /* (111) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
- 256, /* (112) seltablist ::= stl_prefix LP select RP as on_using */
- 256, /* (113) seltablist ::= stl_prefix LP seltablist RP as on_using */
- 200, /* (114) dbnm ::= */
- 200, /* (115) dbnm ::= DOT nm */
- 238, /* (116) fullname ::= nm */
- 238, /* (117) fullname ::= nm DOT nm */
- 262, /* (118) xfullname ::= nm */
- 262, /* (119) xfullname ::= nm DOT nm */
- 262, /* (120) xfullname ::= nm DOT nm AS nm */
- 262, /* (121) xfullname ::= nm AS nm */
- 258, /* (122) joinop ::= COMMA|JOIN */
- 258, /* (123) joinop ::= JOIN_KW JOIN */
- 258, /* (124) joinop ::= JOIN_KW nm JOIN */
- 258, /* (125) joinop ::= JOIN_KW nm nm JOIN */
- 259, /* (126) on_using ::= ON expr */
- 259, /* (127) on_using ::= USING LP idlist RP */
- 259, /* (128) on_using ::= */
- 264, /* (129) indexed_opt ::= */
- 260, /* (130) indexed_by ::= INDEXED BY nm */
- 260, /* (131) indexed_by ::= NOT INDEXED */
- 249, /* (132) orderby_opt ::= */
- 249, /* (133) orderby_opt ::= ORDER BY sortlist */
- 231, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */
- 231, /* (135) sortlist ::= expr sortorder nulls */
- 219, /* (136) sortorder ::= ASC */
- 219, /* (137) sortorder ::= DESC */
- 219, /* (138) sortorder ::= */
- 265, /* (139) nulls ::= NULLS FIRST */
- 265, /* (140) nulls ::= NULLS LAST */
- 265, /* (141) nulls ::= */
- 247, /* (142) groupby_opt ::= */
- 247, /* (143) groupby_opt ::= GROUP BY nexprlist */
- 248, /* (144) having_opt ::= */
- 248, /* (145) having_opt ::= HAVING expr */
- 250, /* (146) limit_opt ::= */
- 250, /* (147) limit_opt ::= LIMIT expr */
- 250, /* (148) limit_opt ::= LIMIT expr OFFSET expr */
- 250, /* (149) limit_opt ::= LIMIT expr COMMA expr */
- 190, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
- 246, /* (151) where_opt ::= */
- 246, /* (152) where_opt ::= WHERE expr */
- 267, /* (153) where_opt_ret ::= */
- 267, /* (154) where_opt_ret ::= WHERE expr */
- 267, /* (155) where_opt_ret ::= RETURNING selcollist */
- 267, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */
- 190, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
- 268, /* (158) setlist ::= setlist COMMA nm EQ expr */
- 268, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */
- 268, /* (160) setlist ::= nm EQ expr */
- 268, /* (161) setlist ::= LP idlist RP EQ expr */
- 190, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
- 190, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
- 271, /* (164) upsert ::= */
- 271, /* (165) upsert ::= RETURNING selcollist */
- 271, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
- 271, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
- 271, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */
- 271, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
- 272, /* (170) returning ::= RETURNING selcollist */
- 269, /* (171) insert_cmd ::= INSERT orconf */
- 269, /* (172) insert_cmd ::= REPLACE */
- 270, /* (173) idlist_opt ::= */
- 270, /* (174) idlist_opt ::= LP idlist RP */
- 263, /* (175) idlist ::= idlist COMMA nm */
- 263, /* (176) idlist ::= nm */
- 217, /* (177) expr ::= LP expr RP */
- 217, /* (178) expr ::= ID|INDEXED */
- 217, /* (179) expr ::= JOIN_KW */
- 217, /* (180) expr ::= nm DOT nm */
- 217, /* (181) expr ::= nm DOT nm DOT nm */
- 216, /* (182) term ::= NULL|FLOAT|BLOB */
- 216, /* (183) term ::= STRING */
- 216, /* (184) term ::= INTEGER */
- 217, /* (185) expr ::= VARIABLE */
- 217, /* (186) expr ::= expr COLLATE ID|STRING */
- 217, /* (187) expr ::= CAST LP expr AS typetoken RP */
- 217, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
- 217, /* (189) expr ::= ID|INDEXED LP STAR RP */
- 217, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
- 217, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
- 216, /* (192) term ::= CTIME_KW */
- 217, /* (193) expr ::= LP nexprlist COMMA expr RP */
- 217, /* (194) expr ::= expr AND expr */
- 217, /* (195) expr ::= expr OR expr */
- 217, /* (196) expr ::= expr LT|GT|GE|LE expr */
- 217, /* (197) expr ::= expr EQ|NE expr */
- 217, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
- 217, /* (199) expr ::= expr PLUS|MINUS expr */
- 217, /* (200) expr ::= expr STAR|SLASH|REM expr */
- 217, /* (201) expr ::= expr CONCAT expr */
- 274, /* (202) likeop ::= NOT LIKE_KW|MATCH */
- 217, /* (203) expr ::= expr likeop expr */
- 217, /* (204) expr ::= expr likeop expr ESCAPE expr */
- 217, /* (205) expr ::= expr ISNULL|NOTNULL */
- 217, /* (206) expr ::= expr NOT NULL */
- 217, /* (207) expr ::= expr IS expr */
- 217, /* (208) expr ::= expr IS NOT expr */
- 217, /* (209) expr ::= expr IS NOT DISTINCT FROM expr */
- 217, /* (210) expr ::= expr IS DISTINCT FROM expr */
- 217, /* (211) expr ::= NOT expr */
- 217, /* (212) expr ::= BITNOT expr */
- 217, /* (213) expr ::= PLUS|MINUS expr */
- 217, /* (214) expr ::= expr PTR expr */
- 275, /* (215) between_op ::= BETWEEN */
- 275, /* (216) between_op ::= NOT BETWEEN */
- 217, /* (217) expr ::= expr between_op expr AND expr */
- 276, /* (218) in_op ::= IN */
- 276, /* (219) in_op ::= NOT IN */
- 217, /* (220) expr ::= expr in_op LP exprlist RP */
- 217, /* (221) expr ::= LP select RP */
- 217, /* (222) expr ::= expr in_op LP select RP */
- 217, /* (223) expr ::= expr in_op nm dbnm paren_exprlist */
- 217, /* (224) expr ::= EXISTS LP select RP */
- 217, /* (225) expr ::= CASE case_operand case_exprlist case_else END */
- 279, /* (226) case_exprlist ::= case_exprlist WHEN expr THEN expr */
- 279, /* (227) case_exprlist ::= WHEN expr THEN expr */
- 280, /* (228) case_else ::= ELSE expr */
- 280, /* (229) case_else ::= */
- 278, /* (230) case_operand ::= expr */
- 278, /* (231) case_operand ::= */
- 261, /* (232) exprlist ::= */
- 253, /* (233) nexprlist ::= nexprlist COMMA expr */
- 253, /* (234) nexprlist ::= expr */
- 277, /* (235) paren_exprlist ::= */
- 277, /* (236) paren_exprlist ::= LP exprlist RP */
- 190, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
- 281, /* (238) uniqueflag ::= UNIQUE */
- 281, /* (239) uniqueflag ::= */
- 221, /* (240) eidlist_opt ::= */
- 221, /* (241) eidlist_opt ::= LP eidlist RP */
- 232, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */
- 232, /* (243) eidlist ::= nm collate sortorder */
- 282, /* (244) collate ::= */
- 282, /* (245) collate ::= COLLATE ID|STRING */
- 190, /* (246) cmd ::= DROP INDEX ifexists fullname */
- 190, /* (247) cmd ::= VACUUM vinto */
- 190, /* (248) cmd ::= VACUUM nm vinto */
- 283, /* (249) vinto ::= INTO expr */
- 283, /* (250) vinto ::= */
- 190, /* (251) cmd ::= PRAGMA nm dbnm */
- 190, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */
- 190, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */
- 190, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */
- 190, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */
- 211, /* (256) plus_num ::= PLUS INTEGER|FLOAT */
- 212, /* (257) minus_num ::= MINUS INTEGER|FLOAT */
- 190, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
- 285, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
- 287, /* (260) trigger_time ::= BEFORE|AFTER */
- 287, /* (261) trigger_time ::= INSTEAD OF */
- 287, /* (262) trigger_time ::= */
- 288, /* (263) trigger_event ::= DELETE|INSERT */
- 288, /* (264) trigger_event ::= UPDATE */
- 288, /* (265) trigger_event ::= UPDATE OF idlist */
- 290, /* (266) when_clause ::= */
- 290, /* (267) when_clause ::= WHEN expr */
- 286, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
- 286, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */
- 292, /* (270) trnm ::= nm DOT nm */
- 293, /* (271) tridxby ::= INDEXED BY nm */
- 293, /* (272) tridxby ::= NOT INDEXED */
- 291, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
- 291, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
- 291, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
- 291, /* (276) trigger_cmd ::= scanpt select scanpt */
- 217, /* (277) expr ::= RAISE LP IGNORE RP */
- 217, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */
- 236, /* (279) raisetype ::= ROLLBACK */
- 236, /* (280) raisetype ::= ABORT */
- 236, /* (281) raisetype ::= FAIL */
- 190, /* (282) cmd ::= DROP TRIGGER ifexists fullname */
- 190, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
- 190, /* (284) cmd ::= DETACH database_kw_opt expr */
- 295, /* (285) key_opt ::= */
- 295, /* (286) key_opt ::= KEY expr */
- 190, /* (287) cmd ::= REINDEX */
- 190, /* (288) cmd ::= REINDEX nm dbnm */
- 190, /* (289) cmd ::= ANALYZE */
- 190, /* (290) cmd ::= ANALYZE nm dbnm */
- 190, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */
- 190, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
- 190, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
- 296, /* (294) add_column_fullname ::= fullname */
- 190, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
- 190, /* (296) cmd ::= create_vtab */
- 190, /* (297) cmd ::= create_vtab LP vtabarglist RP */
- 298, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
- 300, /* (299) vtabarg ::= */
- 301, /* (300) vtabargtoken ::= ANY */
- 301, /* (301) vtabargtoken ::= lp anylist RP */
- 302, /* (302) lp ::= LP */
- 266, /* (303) with ::= WITH wqlist */
- 266, /* (304) with ::= WITH RECURSIVE wqlist */
- 305, /* (305) wqas ::= AS */
- 305, /* (306) wqas ::= AS MATERIALIZED */
- 305, /* (307) wqas ::= AS NOT MATERIALIZED */
- 304, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */
- 241, /* (309) wqlist ::= wqitem */
- 241, /* (310) wqlist ::= wqlist COMMA wqitem */
- 306, /* (311) windowdefn_list ::= windowdefn */
- 306, /* (312) windowdefn_list ::= windowdefn_list COMMA windowdefn */
- 307, /* (313) windowdefn ::= nm AS LP window RP */
- 308, /* (314) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
- 308, /* (315) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
- 308, /* (316) window ::= ORDER BY sortlist frame_opt */
- 308, /* (317) window ::= nm ORDER BY sortlist frame_opt */
- 308, /* (318) window ::= frame_opt */
- 308, /* (319) window ::= nm frame_opt */
- 309, /* (320) frame_opt ::= */
- 309, /* (321) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
- 309, /* (322) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
- 313, /* (323) range_or_rows ::= RANGE|ROWS|GROUPS */
- 315, /* (324) frame_bound_s ::= frame_bound */
- 315, /* (325) frame_bound_s ::= UNBOUNDED PRECEDING */
- 316, /* (326) frame_bound_e ::= frame_bound */
- 316, /* (327) frame_bound_e ::= UNBOUNDED FOLLOWING */
- 314, /* (328) frame_bound ::= expr PRECEDING|FOLLOWING */
- 314, /* (329) frame_bound ::= CURRENT ROW */
- 317, /* (330) frame_exclude_opt ::= */
- 317, /* (331) frame_exclude_opt ::= EXCLUDE frame_exclude */
- 318, /* (332) frame_exclude ::= NO OTHERS */
- 318, /* (333) frame_exclude ::= CURRENT ROW */
- 318, /* (334) frame_exclude ::= GROUP|TIES */
- 251, /* (335) window_clause ::= WINDOW windowdefn_list */
- 273, /* (336) filter_over ::= filter_clause over_clause */
- 273, /* (337) filter_over ::= over_clause */
- 273, /* (338) filter_over ::= filter_clause */
- 312, /* (339) over_clause ::= OVER LP window RP */
- 312, /* (340) over_clause ::= OVER nm */
- 311, /* (341) filter_clause ::= FILTER LP WHERE expr RP */
- 185, /* (342) input ::= cmdlist */
- 186, /* (343) cmdlist ::= cmdlist ecmd */
- 186, /* (344) cmdlist ::= ecmd */
- 187, /* (345) ecmd ::= SEMI */
- 187, /* (346) ecmd ::= cmdx SEMI */
- 187, /* (347) ecmd ::= explain cmdx SEMI */
- 192, /* (348) trans_opt ::= */
- 192, /* (349) trans_opt ::= TRANSACTION */
- 192, /* (350) trans_opt ::= TRANSACTION nm */
- 194, /* (351) savepoint_opt ::= SAVEPOINT */
- 194, /* (352) savepoint_opt ::= */
- 190, /* (353) cmd ::= create_table create_table_args */
- 203, /* (354) table_option_set ::= table_option */
- 201, /* (355) columnlist ::= columnlist COMMA columnname carglist */
- 201, /* (356) columnlist ::= columnname carglist */
- 193, /* (357) nm ::= ID|INDEXED */
- 193, /* (358) nm ::= STRING */
- 193, /* (359) nm ::= JOIN_KW */
- 208, /* (360) typetoken ::= typename */
- 209, /* (361) typename ::= ID|STRING */
- 210, /* (362) signed ::= plus_num */
- 210, /* (363) signed ::= minus_num */
- 207, /* (364) carglist ::= carglist ccons */
- 207, /* (365) carglist ::= */
- 215, /* (366) ccons ::= NULL onconf */
- 215, /* (367) ccons ::= GENERATED ALWAYS AS generated */
- 215, /* (368) ccons ::= AS generated */
- 202, /* (369) conslist_opt ::= COMMA conslist */
- 228, /* (370) conslist ::= conslist tconscomma tcons */
- 228, /* (371) conslist ::= tcons */
- 229, /* (372) tconscomma ::= */
- 233, /* (373) defer_subclause_opt ::= defer_subclause */
- 235, /* (374) resolvetype ::= raisetype */
- 239, /* (375) selectnowith ::= oneselect */
- 240, /* (376) oneselect ::= values */
- 254, /* (377) sclp ::= selcollist COMMA */
- 255, /* (378) as ::= ID|STRING */
- 264, /* (379) indexed_opt ::= indexed_by */
- 272, /* (380) returning ::= */
- 217, /* (381) expr ::= term */
- 274, /* (382) likeop ::= LIKE_KW|MATCH */
- 261, /* (383) exprlist ::= nexprlist */
- 284, /* (384) nmnum ::= plus_num */
- 284, /* (385) nmnum ::= nm */
- 284, /* (386) nmnum ::= ON */
- 284, /* (387) nmnum ::= DELETE */
- 284, /* (388) nmnum ::= DEFAULT */
- 211, /* (389) plus_num ::= INTEGER|FLOAT */
- 289, /* (390) foreach_clause ::= */
- 289, /* (391) foreach_clause ::= FOR EACH ROW */
- 292, /* (392) trnm ::= nm */
- 293, /* (393) tridxby ::= */
- 294, /* (394) database_kw_opt ::= DATABASE */
- 294, /* (395) database_kw_opt ::= */
- 297, /* (396) kwcolumn_opt ::= */
- 297, /* (397) kwcolumn_opt ::= COLUMNKW */
- 299, /* (398) vtabarglist ::= vtabarg */
- 299, /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */
- 300, /* (400) vtabarg ::= vtabarg vtabargtoken */
- 303, /* (401) anylist ::= */
- 303, /* (402) anylist ::= anylist LP anylist RP */
- 303, /* (403) anylist ::= anylist ANY */
- 266, /* (404) with ::= */
+ 190, /* (0) explain ::= EXPLAIN */
+ 190, /* (1) explain ::= EXPLAIN QUERY PLAN */
+ 189, /* (2) cmdx ::= cmd */
+ 191, /* (3) cmd ::= BEGIN transtype trans_opt */
+ 192, /* (4) transtype ::= */
+ 192, /* (5) transtype ::= DEFERRED */
+ 192, /* (6) transtype ::= IMMEDIATE */
+ 192, /* (7) transtype ::= EXCLUSIVE */
+ 191, /* (8) cmd ::= COMMIT|END trans_opt */
+ 191, /* (9) cmd ::= ROLLBACK trans_opt */
+ 191, /* (10) cmd ::= SAVEPOINT nm */
+ 191, /* (11) cmd ::= RELEASE savepoint_opt nm */
+ 191, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ 196, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+ 198, /* (14) createkw ::= CREATE */
+ 200, /* (15) ifnotexists ::= */
+ 200, /* (16) ifnotexists ::= IF NOT EXISTS */
+ 199, /* (17) temp ::= TEMP */
+ 199, /* (18) temp ::= */
+ 197, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
+ 197, /* (20) create_table_args ::= AS select */
+ 204, /* (21) table_option_set ::= */
+ 204, /* (22) table_option_set ::= table_option_set COMMA table_option */
+ 206, /* (23) table_option ::= WITHOUT nm */
+ 206, /* (24) table_option ::= nm */
+ 207, /* (25) columnname ::= nm typetoken */
+ 209, /* (26) typetoken ::= */
+ 209, /* (27) typetoken ::= typename LP signed RP */
+ 209, /* (28) typetoken ::= typename LP signed COMMA signed RP */
+ 210, /* (29) typename ::= typename ID|STRING */
+ 214, /* (30) scanpt ::= */
+ 215, /* (31) scantok ::= */
+ 216, /* (32) ccons ::= CONSTRAINT nm */
+ 216, /* (33) ccons ::= DEFAULT scantok term */
+ 216, /* (34) ccons ::= DEFAULT LP expr RP */
+ 216, /* (35) ccons ::= DEFAULT PLUS scantok term */
+ 216, /* (36) ccons ::= DEFAULT MINUS scantok term */
+ 216, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */
+ 216, /* (38) ccons ::= NOT NULL onconf */
+ 216, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */
+ 216, /* (40) ccons ::= UNIQUE onconf */
+ 216, /* (41) ccons ::= CHECK LP expr RP */
+ 216, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */
+ 216, /* (43) ccons ::= defer_subclause */
+ 216, /* (44) ccons ::= COLLATE ID|STRING */
+ 225, /* (45) generated ::= LP expr RP */
+ 225, /* (46) generated ::= LP expr RP ID */
+ 221, /* (47) autoinc ::= */
+ 221, /* (48) autoinc ::= AUTOINCR */
+ 223, /* (49) refargs ::= */
+ 223, /* (50) refargs ::= refargs refarg */
+ 226, /* (51) refarg ::= MATCH nm */
+ 226, /* (52) refarg ::= ON INSERT refact */
+ 226, /* (53) refarg ::= ON DELETE refact */
+ 226, /* (54) refarg ::= ON UPDATE refact */
+ 227, /* (55) refact ::= SET NULL */
+ 227, /* (56) refact ::= SET DEFAULT */
+ 227, /* (57) refact ::= CASCADE */
+ 227, /* (58) refact ::= RESTRICT */
+ 227, /* (59) refact ::= NO ACTION */
+ 224, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+ 224, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ 228, /* (62) init_deferred_pred_opt ::= */
+ 228, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */
+ 228, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+ 203, /* (65) conslist_opt ::= */
+ 230, /* (66) tconscomma ::= COMMA */
+ 231, /* (67) tcons ::= CONSTRAINT nm */
+ 231, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
+ 231, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */
+ 231, /* (70) tcons ::= CHECK LP expr RP onconf */
+ 231, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+ 234, /* (72) defer_subclause_opt ::= */
+ 219, /* (73) onconf ::= */
+ 219, /* (74) onconf ::= ON CONFLICT resolvetype */
+ 235, /* (75) orconf ::= */
+ 235, /* (76) orconf ::= OR resolvetype */
+ 236, /* (77) resolvetype ::= IGNORE */
+ 236, /* (78) resolvetype ::= REPLACE */
+ 191, /* (79) cmd ::= DROP TABLE ifexists fullname */
+ 238, /* (80) ifexists ::= IF EXISTS */
+ 238, /* (81) ifexists ::= */
+ 191, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+ 191, /* (83) cmd ::= DROP VIEW ifexists fullname */
+ 191, /* (84) cmd ::= select */
+ 205, /* (85) select ::= WITH wqlist selectnowith */
+ 205, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */
+ 205, /* (87) select ::= selectnowith */
+ 240, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */
+ 243, /* (89) multiselect_op ::= UNION */
+ 243, /* (90) multiselect_op ::= UNION ALL */
+ 243, /* (91) multiselect_op ::= EXCEPT|INTERSECT */
+ 241, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+ 241, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
+ 253, /* (94) values ::= VALUES LP nexprlist RP */
+ 241, /* (95) oneselect ::= mvalues */
+ 255, /* (96) mvalues ::= values COMMA LP nexprlist RP */
+ 255, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */
+ 244, /* (98) distinct ::= DISTINCT */
+ 244, /* (99) distinct ::= ALL */
+ 244, /* (100) distinct ::= */
+ 256, /* (101) sclp ::= */
+ 245, /* (102) selcollist ::= sclp scanpt expr scanpt as */
+ 245, /* (103) selcollist ::= sclp scanpt STAR */
+ 245, /* (104) selcollist ::= sclp scanpt nm DOT STAR */
+ 257, /* (105) as ::= AS nm */
+ 257, /* (106) as ::= */
+ 246, /* (107) from ::= */
+ 246, /* (108) from ::= FROM seltablist */
+ 259, /* (109) stl_prefix ::= seltablist joinop */
+ 259, /* (110) stl_prefix ::= */
+ 258, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */
+ 258, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
+ 258, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
+ 258, /* (114) seltablist ::= stl_prefix LP select RP as on_using */
+ 258, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */
+ 201, /* (116) dbnm ::= */
+ 201, /* (117) dbnm ::= DOT nm */
+ 239, /* (118) fullname ::= nm */
+ 239, /* (119) fullname ::= nm DOT nm */
+ 264, /* (120) xfullname ::= nm */
+ 264, /* (121) xfullname ::= nm DOT nm */
+ 264, /* (122) xfullname ::= nm DOT nm AS nm */
+ 264, /* (123) xfullname ::= nm AS nm */
+ 260, /* (124) joinop ::= COMMA|JOIN */
+ 260, /* (125) joinop ::= JOIN_KW JOIN */
+ 260, /* (126) joinop ::= JOIN_KW nm JOIN */
+ 260, /* (127) joinop ::= JOIN_KW nm nm JOIN */
+ 261, /* (128) on_using ::= ON expr */
+ 261, /* (129) on_using ::= USING LP idlist RP */
+ 261, /* (130) on_using ::= */
+ 266, /* (131) indexed_opt ::= */
+ 262, /* (132) indexed_by ::= INDEXED BY nm */
+ 262, /* (133) indexed_by ::= NOT INDEXED */
+ 250, /* (134) orderby_opt ::= */
+ 250, /* (135) orderby_opt ::= ORDER BY sortlist */
+ 232, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */
+ 232, /* (137) sortlist ::= expr sortorder nulls */
+ 220, /* (138) sortorder ::= ASC */
+ 220, /* (139) sortorder ::= DESC */
+ 220, /* (140) sortorder ::= */
+ 267, /* (141) nulls ::= NULLS FIRST */
+ 267, /* (142) nulls ::= NULLS LAST */
+ 267, /* (143) nulls ::= */
+ 248, /* (144) groupby_opt ::= */
+ 248, /* (145) groupby_opt ::= GROUP BY nexprlist */
+ 249, /* (146) having_opt ::= */
+ 249, /* (147) having_opt ::= HAVING expr */
+ 251, /* (148) limit_opt ::= */
+ 251, /* (149) limit_opt ::= LIMIT expr */
+ 251, /* (150) limit_opt ::= LIMIT expr OFFSET expr */
+ 251, /* (151) limit_opt ::= LIMIT expr COMMA expr */
+ 191, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
+ 247, /* (153) where_opt ::= */
+ 247, /* (154) where_opt ::= WHERE expr */
+ 269, /* (155) where_opt_ret ::= */
+ 269, /* (156) where_opt_ret ::= WHERE expr */
+ 269, /* (157) where_opt_ret ::= RETURNING selcollist */
+ 269, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */
+ 191, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
+ 270, /* (160) setlist ::= setlist COMMA nm EQ expr */
+ 270, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */
+ 270, /* (162) setlist ::= nm EQ expr */
+ 270, /* (163) setlist ::= LP idlist RP EQ expr */
+ 191, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ 191, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
+ 273, /* (166) upsert ::= */
+ 273, /* (167) upsert ::= RETURNING selcollist */
+ 273, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
+ 273, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
+ 273, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */
+ 273, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
+ 274, /* (172) returning ::= RETURNING selcollist */
+ 271, /* (173) insert_cmd ::= INSERT orconf */
+ 271, /* (174) insert_cmd ::= REPLACE */
+ 272, /* (175) idlist_opt ::= */
+ 272, /* (176) idlist_opt ::= LP idlist RP */
+ 265, /* (177) idlist ::= idlist COMMA nm */
+ 265, /* (178) idlist ::= nm */
+ 218, /* (179) expr ::= LP expr RP */
+ 218, /* (180) expr ::= ID|INDEXED|JOIN_KW */
+ 218, /* (181) expr ::= nm DOT nm */
+ 218, /* (182) expr ::= nm DOT nm DOT nm */
+ 217, /* (183) term ::= NULL|FLOAT|BLOB */
+ 217, /* (184) term ::= STRING */
+ 217, /* (185) term ::= INTEGER */
+ 218, /* (186) expr ::= VARIABLE */
+ 218, /* (187) expr ::= expr COLLATE ID|STRING */
+ 218, /* (188) expr ::= CAST LP expr AS typetoken RP */
+ 218, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+ 218, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
+ 218, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
+ 218, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
+ 218, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
+ 218, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
+ 217, /* (195) term ::= CTIME_KW */
+ 218, /* (196) expr ::= LP nexprlist COMMA expr RP */
+ 218, /* (197) expr ::= expr AND expr */
+ 218, /* (198) expr ::= expr OR expr */
+ 218, /* (199) expr ::= expr LT|GT|GE|LE expr */
+ 218, /* (200) expr ::= expr EQ|NE expr */
+ 218, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ 218, /* (202) expr ::= expr PLUS|MINUS expr */
+ 218, /* (203) expr ::= expr STAR|SLASH|REM expr */
+ 218, /* (204) expr ::= expr CONCAT expr */
+ 276, /* (205) likeop ::= NOT LIKE_KW|MATCH */
+ 218, /* (206) expr ::= expr likeop expr */
+ 218, /* (207) expr ::= expr likeop expr ESCAPE expr */
+ 218, /* (208) expr ::= expr ISNULL|NOTNULL */
+ 218, /* (209) expr ::= expr NOT NULL */
+ 218, /* (210) expr ::= expr IS expr */
+ 218, /* (211) expr ::= expr IS NOT expr */
+ 218, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */
+ 218, /* (213) expr ::= expr IS DISTINCT FROM expr */
+ 218, /* (214) expr ::= NOT expr */
+ 218, /* (215) expr ::= BITNOT expr */
+ 218, /* (216) expr ::= PLUS|MINUS expr */
+ 218, /* (217) expr ::= expr PTR expr */
+ 277, /* (218) between_op ::= BETWEEN */
+ 277, /* (219) between_op ::= NOT BETWEEN */
+ 218, /* (220) expr ::= expr between_op expr AND expr */
+ 278, /* (221) in_op ::= IN */
+ 278, /* (222) in_op ::= NOT IN */
+ 218, /* (223) expr ::= expr in_op LP exprlist RP */
+ 218, /* (224) expr ::= LP select RP */
+ 218, /* (225) expr ::= expr in_op LP select RP */
+ 218, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */
+ 218, /* (227) expr ::= EXISTS LP select RP */
+ 218, /* (228) expr ::= CASE case_operand case_exprlist case_else END */
+ 281, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ 281, /* (230) case_exprlist ::= WHEN expr THEN expr */
+ 282, /* (231) case_else ::= ELSE expr */
+ 282, /* (232) case_else ::= */
+ 280, /* (233) case_operand ::= */
+ 263, /* (234) exprlist ::= */
+ 254, /* (235) nexprlist ::= nexprlist COMMA expr */
+ 254, /* (236) nexprlist ::= expr */
+ 279, /* (237) paren_exprlist ::= */
+ 279, /* (238) paren_exprlist ::= LP exprlist RP */
+ 191, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ 283, /* (240) uniqueflag ::= UNIQUE */
+ 283, /* (241) uniqueflag ::= */
+ 222, /* (242) eidlist_opt ::= */
+ 222, /* (243) eidlist_opt ::= LP eidlist RP */
+ 233, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */
+ 233, /* (245) eidlist ::= nm collate sortorder */
+ 284, /* (246) collate ::= */
+ 284, /* (247) collate ::= COLLATE ID|STRING */
+ 191, /* (248) cmd ::= DROP INDEX ifexists fullname */
+ 191, /* (249) cmd ::= VACUUM vinto */
+ 191, /* (250) cmd ::= VACUUM nm vinto */
+ 285, /* (251) vinto ::= INTO expr */
+ 285, /* (252) vinto ::= */
+ 191, /* (253) cmd ::= PRAGMA nm dbnm */
+ 191, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */
+ 191, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ 191, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */
+ 191, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ 212, /* (258) plus_num ::= PLUS INTEGER|FLOAT */
+ 213, /* (259) minus_num ::= MINUS INTEGER|FLOAT */
+ 191, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ 287, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ 289, /* (262) trigger_time ::= BEFORE|AFTER */
+ 289, /* (263) trigger_time ::= INSTEAD OF */
+ 289, /* (264) trigger_time ::= */
+ 290, /* (265) trigger_event ::= DELETE|INSERT */
+ 290, /* (266) trigger_event ::= UPDATE */
+ 290, /* (267) trigger_event ::= UPDATE OF idlist */
+ 292, /* (268) when_clause ::= */
+ 292, /* (269) when_clause ::= WHEN expr */
+ 288, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ 288, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */
+ 294, /* (272) trnm ::= nm DOT nm */
+ 295, /* (273) tridxby ::= INDEXED BY nm */
+ 295, /* (274) tridxby ::= NOT INDEXED */
+ 293, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ 293, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ 293, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ 293, /* (278) trigger_cmd ::= scanpt select scanpt */
+ 218, /* (279) expr ::= RAISE LP IGNORE RP */
+ 218, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */
+ 237, /* (281) raisetype ::= ROLLBACK */
+ 237, /* (282) raisetype ::= ABORT */
+ 237, /* (283) raisetype ::= FAIL */
+ 191, /* (284) cmd ::= DROP TRIGGER ifexists fullname */
+ 191, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ 191, /* (286) cmd ::= DETACH database_kw_opt expr */
+ 297, /* (287) key_opt ::= */
+ 297, /* (288) key_opt ::= KEY expr */
+ 191, /* (289) cmd ::= REINDEX */
+ 191, /* (290) cmd ::= REINDEX nm dbnm */
+ 191, /* (291) cmd ::= ANALYZE */
+ 191, /* (292) cmd ::= ANALYZE nm dbnm */
+ 191, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */
+ 191, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ 191, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ 298, /* (296) add_column_fullname ::= fullname */
+ 191, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ 191, /* (298) cmd ::= create_vtab */
+ 191, /* (299) cmd ::= create_vtab LP vtabarglist RP */
+ 300, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ 302, /* (301) vtabarg ::= */
+ 303, /* (302) vtabargtoken ::= ANY */
+ 303, /* (303) vtabargtoken ::= lp anylist RP */
+ 304, /* (304) lp ::= LP */
+ 268, /* (305) with ::= WITH wqlist */
+ 268, /* (306) with ::= WITH RECURSIVE wqlist */
+ 307, /* (307) wqas ::= AS */
+ 307, /* (308) wqas ::= AS MATERIALIZED */
+ 307, /* (309) wqas ::= AS NOT MATERIALIZED */
+ 306, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */
+ 308, /* (311) withnm ::= nm */
+ 242, /* (312) wqlist ::= wqitem */
+ 242, /* (313) wqlist ::= wqlist COMMA wqitem */
+ 309, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ 310, /* (315) windowdefn ::= nm AS LP window RP */
+ 311, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ 311, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ 311, /* (318) window ::= ORDER BY sortlist frame_opt */
+ 311, /* (319) window ::= nm ORDER BY sortlist frame_opt */
+ 311, /* (320) window ::= nm frame_opt */
+ 312, /* (321) frame_opt ::= */
+ 312, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ 312, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ 316, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */
+ 318, /* (325) frame_bound_s ::= frame_bound */
+ 318, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */
+ 319, /* (327) frame_bound_e ::= frame_bound */
+ 319, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ 317, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */
+ 317, /* (330) frame_bound ::= CURRENT ROW */
+ 320, /* (331) frame_exclude_opt ::= */
+ 320, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ 321, /* (333) frame_exclude ::= NO OTHERS */
+ 321, /* (334) frame_exclude ::= CURRENT ROW */
+ 321, /* (335) frame_exclude ::= GROUP|TIES */
+ 252, /* (336) window_clause ::= WINDOW windowdefn_list */
+ 275, /* (337) filter_over ::= filter_clause over_clause */
+ 275, /* (338) filter_over ::= over_clause */
+ 275, /* (339) filter_over ::= filter_clause */
+ 315, /* (340) over_clause ::= OVER LP window RP */
+ 315, /* (341) over_clause ::= OVER nm */
+ 314, /* (342) filter_clause ::= FILTER LP WHERE expr RP */
+ 217, /* (343) term ::= QNUMBER */
+ 186, /* (344) input ::= cmdlist */
+ 187, /* (345) cmdlist ::= cmdlist ecmd */
+ 187, /* (346) cmdlist ::= ecmd */
+ 188, /* (347) ecmd ::= SEMI */
+ 188, /* (348) ecmd ::= cmdx SEMI */
+ 188, /* (349) ecmd ::= explain cmdx SEMI */
+ 193, /* (350) trans_opt ::= */
+ 193, /* (351) trans_opt ::= TRANSACTION */
+ 193, /* (352) trans_opt ::= TRANSACTION nm */
+ 195, /* (353) savepoint_opt ::= SAVEPOINT */
+ 195, /* (354) savepoint_opt ::= */
+ 191, /* (355) cmd ::= create_table create_table_args */
+ 204, /* (356) table_option_set ::= table_option */
+ 202, /* (357) columnlist ::= columnlist COMMA columnname carglist */
+ 202, /* (358) columnlist ::= columnname carglist */
+ 194, /* (359) nm ::= ID|INDEXED|JOIN_KW */
+ 194, /* (360) nm ::= STRING */
+ 209, /* (361) typetoken ::= typename */
+ 210, /* (362) typename ::= ID|STRING */
+ 211, /* (363) signed ::= plus_num */
+ 211, /* (364) signed ::= minus_num */
+ 208, /* (365) carglist ::= carglist ccons */
+ 208, /* (366) carglist ::= */
+ 216, /* (367) ccons ::= NULL onconf */
+ 216, /* (368) ccons ::= GENERATED ALWAYS AS generated */
+ 216, /* (369) ccons ::= AS generated */
+ 203, /* (370) conslist_opt ::= COMMA conslist */
+ 229, /* (371) conslist ::= conslist tconscomma tcons */
+ 229, /* (372) conslist ::= tcons */
+ 230, /* (373) tconscomma ::= */
+ 234, /* (374) defer_subclause_opt ::= defer_subclause */
+ 236, /* (375) resolvetype ::= raisetype */
+ 240, /* (376) selectnowith ::= oneselect */
+ 241, /* (377) oneselect ::= values */
+ 256, /* (378) sclp ::= selcollist COMMA */
+ 257, /* (379) as ::= ID|STRING */
+ 266, /* (380) indexed_opt ::= indexed_by */
+ 274, /* (381) returning ::= */
+ 218, /* (382) expr ::= term */
+ 276, /* (383) likeop ::= LIKE_KW|MATCH */
+ 280, /* (384) case_operand ::= expr */
+ 263, /* (385) exprlist ::= nexprlist */
+ 286, /* (386) nmnum ::= plus_num */
+ 286, /* (387) nmnum ::= nm */
+ 286, /* (388) nmnum ::= ON */
+ 286, /* (389) nmnum ::= DELETE */
+ 286, /* (390) nmnum ::= DEFAULT */
+ 212, /* (391) plus_num ::= INTEGER|FLOAT */
+ 291, /* (392) foreach_clause ::= */
+ 291, /* (393) foreach_clause ::= FOR EACH ROW */
+ 294, /* (394) trnm ::= nm */
+ 295, /* (395) tridxby ::= */
+ 296, /* (396) database_kw_opt ::= DATABASE */
+ 296, /* (397) database_kw_opt ::= */
+ 299, /* (398) kwcolumn_opt ::= */
+ 299, /* (399) kwcolumn_opt ::= COLUMNKW */
+ 301, /* (400) vtabarglist ::= vtabarg */
+ 301, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */
+ 302, /* (402) vtabarg ::= vtabarg vtabargtoken */
+ 305, /* (403) anylist ::= */
+ 305, /* (404) anylist ::= anylist LP anylist RP */
+ 305, /* (405) anylist ::= anylist ANY */
+ 268, /* (406) with ::= */
+ 309, /* (407) windowdefn_list ::= windowdefn */
+ 311, /* (408) window ::= frame_opt */
};
/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
@@ -170154,316 +177284,320 @@ static const signed char yyRuleInfoNRhs[] = {
-9, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
-10, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
-4, /* (94) values ::= VALUES LP nexprlist RP */
- -5, /* (95) values ::= values COMMA LP nexprlist RP */
- -1, /* (96) distinct ::= DISTINCT */
- -1, /* (97) distinct ::= ALL */
- 0, /* (98) distinct ::= */
- 0, /* (99) sclp ::= */
- -5, /* (100) selcollist ::= sclp scanpt expr scanpt as */
- -3, /* (101) selcollist ::= sclp scanpt STAR */
- -5, /* (102) selcollist ::= sclp scanpt nm DOT STAR */
- -2, /* (103) as ::= AS nm */
- 0, /* (104) as ::= */
- 0, /* (105) from ::= */
- -2, /* (106) from ::= FROM seltablist */
- -2, /* (107) stl_prefix ::= seltablist joinop */
- 0, /* (108) stl_prefix ::= */
- -5, /* (109) seltablist ::= stl_prefix nm dbnm as on_using */
- -6, /* (110) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
- -8, /* (111) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
- -6, /* (112) seltablist ::= stl_prefix LP select RP as on_using */
- -6, /* (113) seltablist ::= stl_prefix LP seltablist RP as on_using */
- 0, /* (114) dbnm ::= */
- -2, /* (115) dbnm ::= DOT nm */
- -1, /* (116) fullname ::= nm */
- -3, /* (117) fullname ::= nm DOT nm */
- -1, /* (118) xfullname ::= nm */
- -3, /* (119) xfullname ::= nm DOT nm */
- -5, /* (120) xfullname ::= nm DOT nm AS nm */
- -3, /* (121) xfullname ::= nm AS nm */
- -1, /* (122) joinop ::= COMMA|JOIN */
- -2, /* (123) joinop ::= JOIN_KW JOIN */
- -3, /* (124) joinop ::= JOIN_KW nm JOIN */
- -4, /* (125) joinop ::= JOIN_KW nm nm JOIN */
- -2, /* (126) on_using ::= ON expr */
- -4, /* (127) on_using ::= USING LP idlist RP */
- 0, /* (128) on_using ::= */
- 0, /* (129) indexed_opt ::= */
- -3, /* (130) indexed_by ::= INDEXED BY nm */
- -2, /* (131) indexed_by ::= NOT INDEXED */
- 0, /* (132) orderby_opt ::= */
- -3, /* (133) orderby_opt ::= ORDER BY sortlist */
- -5, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */
- -3, /* (135) sortlist ::= expr sortorder nulls */
- -1, /* (136) sortorder ::= ASC */
- -1, /* (137) sortorder ::= DESC */
- 0, /* (138) sortorder ::= */
- -2, /* (139) nulls ::= NULLS FIRST */
- -2, /* (140) nulls ::= NULLS LAST */
- 0, /* (141) nulls ::= */
- 0, /* (142) groupby_opt ::= */
- -3, /* (143) groupby_opt ::= GROUP BY nexprlist */
- 0, /* (144) having_opt ::= */
- -2, /* (145) having_opt ::= HAVING expr */
- 0, /* (146) limit_opt ::= */
- -2, /* (147) limit_opt ::= LIMIT expr */
- -4, /* (148) limit_opt ::= LIMIT expr OFFSET expr */
- -4, /* (149) limit_opt ::= LIMIT expr COMMA expr */
- -6, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
- 0, /* (151) where_opt ::= */
- -2, /* (152) where_opt ::= WHERE expr */
- 0, /* (153) where_opt_ret ::= */
- -2, /* (154) where_opt_ret ::= WHERE expr */
- -2, /* (155) where_opt_ret ::= RETURNING selcollist */
- -4, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */
- -9, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
- -5, /* (158) setlist ::= setlist COMMA nm EQ expr */
- -7, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */
- -3, /* (160) setlist ::= nm EQ expr */
- -5, /* (161) setlist ::= LP idlist RP EQ expr */
- -7, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
- -8, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
- 0, /* (164) upsert ::= */
- -2, /* (165) upsert ::= RETURNING selcollist */
- -12, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
- -9, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
- -5, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */
- -8, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
- -2, /* (170) returning ::= RETURNING selcollist */
- -2, /* (171) insert_cmd ::= INSERT orconf */
- -1, /* (172) insert_cmd ::= REPLACE */
- 0, /* (173) idlist_opt ::= */
- -3, /* (174) idlist_opt ::= LP idlist RP */
- -3, /* (175) idlist ::= idlist COMMA nm */
- -1, /* (176) idlist ::= nm */
- -3, /* (177) expr ::= LP expr RP */
- -1, /* (178) expr ::= ID|INDEXED */
- -1, /* (179) expr ::= JOIN_KW */
- -3, /* (180) expr ::= nm DOT nm */
- -5, /* (181) expr ::= nm DOT nm DOT nm */
- -1, /* (182) term ::= NULL|FLOAT|BLOB */
- -1, /* (183) term ::= STRING */
- -1, /* (184) term ::= INTEGER */
- -1, /* (185) expr ::= VARIABLE */
- -3, /* (186) expr ::= expr COLLATE ID|STRING */
- -6, /* (187) expr ::= CAST LP expr AS typetoken RP */
- -5, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
- -4, /* (189) expr ::= ID|INDEXED LP STAR RP */
- -6, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
- -5, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
- -1, /* (192) term ::= CTIME_KW */
- -5, /* (193) expr ::= LP nexprlist COMMA expr RP */
- -3, /* (194) expr ::= expr AND expr */
- -3, /* (195) expr ::= expr OR expr */
- -3, /* (196) expr ::= expr LT|GT|GE|LE expr */
- -3, /* (197) expr ::= expr EQ|NE expr */
- -3, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
- -3, /* (199) expr ::= expr PLUS|MINUS expr */
- -3, /* (200) expr ::= expr STAR|SLASH|REM expr */
- -3, /* (201) expr ::= expr CONCAT expr */
- -2, /* (202) likeop ::= NOT LIKE_KW|MATCH */
- -3, /* (203) expr ::= expr likeop expr */
- -5, /* (204) expr ::= expr likeop expr ESCAPE expr */
- -2, /* (205) expr ::= expr ISNULL|NOTNULL */
- -3, /* (206) expr ::= expr NOT NULL */
- -3, /* (207) expr ::= expr IS expr */
- -4, /* (208) expr ::= expr IS NOT expr */
- -6, /* (209) expr ::= expr IS NOT DISTINCT FROM expr */
- -5, /* (210) expr ::= expr IS DISTINCT FROM expr */
- -2, /* (211) expr ::= NOT expr */
- -2, /* (212) expr ::= BITNOT expr */
- -2, /* (213) expr ::= PLUS|MINUS expr */
- -3, /* (214) expr ::= expr PTR expr */
- -1, /* (215) between_op ::= BETWEEN */
- -2, /* (216) between_op ::= NOT BETWEEN */
- -5, /* (217) expr ::= expr between_op expr AND expr */
- -1, /* (218) in_op ::= IN */
- -2, /* (219) in_op ::= NOT IN */
- -5, /* (220) expr ::= expr in_op LP exprlist RP */
- -3, /* (221) expr ::= LP select RP */
- -5, /* (222) expr ::= expr in_op LP select RP */
- -5, /* (223) expr ::= expr in_op nm dbnm paren_exprlist */
- -4, /* (224) expr ::= EXISTS LP select RP */
- -5, /* (225) expr ::= CASE case_operand case_exprlist case_else END */
- -5, /* (226) case_exprlist ::= case_exprlist WHEN expr THEN expr */
- -4, /* (227) case_exprlist ::= WHEN expr THEN expr */
- -2, /* (228) case_else ::= ELSE expr */
- 0, /* (229) case_else ::= */
- -1, /* (230) case_operand ::= expr */
- 0, /* (231) case_operand ::= */
- 0, /* (232) exprlist ::= */
- -3, /* (233) nexprlist ::= nexprlist COMMA expr */
- -1, /* (234) nexprlist ::= expr */
- 0, /* (235) paren_exprlist ::= */
- -3, /* (236) paren_exprlist ::= LP exprlist RP */
- -12, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
- -1, /* (238) uniqueflag ::= UNIQUE */
- 0, /* (239) uniqueflag ::= */
- 0, /* (240) eidlist_opt ::= */
- -3, /* (241) eidlist_opt ::= LP eidlist RP */
- -5, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */
- -3, /* (243) eidlist ::= nm collate sortorder */
- 0, /* (244) collate ::= */
- -2, /* (245) collate ::= COLLATE ID|STRING */
- -4, /* (246) cmd ::= DROP INDEX ifexists fullname */
- -2, /* (247) cmd ::= VACUUM vinto */
- -3, /* (248) cmd ::= VACUUM nm vinto */
- -2, /* (249) vinto ::= INTO expr */
- 0, /* (250) vinto ::= */
- -3, /* (251) cmd ::= PRAGMA nm dbnm */
- -5, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */
- -6, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */
- -5, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */
- -6, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */
- -2, /* (256) plus_num ::= PLUS INTEGER|FLOAT */
- -2, /* (257) minus_num ::= MINUS INTEGER|FLOAT */
- -5, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
- -11, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
- -1, /* (260) trigger_time ::= BEFORE|AFTER */
- -2, /* (261) trigger_time ::= INSTEAD OF */
- 0, /* (262) trigger_time ::= */
- -1, /* (263) trigger_event ::= DELETE|INSERT */
- -1, /* (264) trigger_event ::= UPDATE */
- -3, /* (265) trigger_event ::= UPDATE OF idlist */
- 0, /* (266) when_clause ::= */
- -2, /* (267) when_clause ::= WHEN expr */
- -3, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
- -2, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */
- -3, /* (270) trnm ::= nm DOT nm */
- -3, /* (271) tridxby ::= INDEXED BY nm */
- -2, /* (272) tridxby ::= NOT INDEXED */
- -9, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
- -8, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
- -6, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
- -3, /* (276) trigger_cmd ::= scanpt select scanpt */
- -4, /* (277) expr ::= RAISE LP IGNORE RP */
- -6, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */
- -1, /* (279) raisetype ::= ROLLBACK */
- -1, /* (280) raisetype ::= ABORT */
- -1, /* (281) raisetype ::= FAIL */
- -4, /* (282) cmd ::= DROP TRIGGER ifexists fullname */
- -6, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
- -3, /* (284) cmd ::= DETACH database_kw_opt expr */
- 0, /* (285) key_opt ::= */
- -2, /* (286) key_opt ::= KEY expr */
- -1, /* (287) cmd ::= REINDEX */
- -3, /* (288) cmd ::= REINDEX nm dbnm */
- -1, /* (289) cmd ::= ANALYZE */
- -3, /* (290) cmd ::= ANALYZE nm dbnm */
- -6, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */
- -7, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
- -6, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
- -1, /* (294) add_column_fullname ::= fullname */
- -8, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
- -1, /* (296) cmd ::= create_vtab */
- -4, /* (297) cmd ::= create_vtab LP vtabarglist RP */
- -8, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
- 0, /* (299) vtabarg ::= */
- -1, /* (300) vtabargtoken ::= ANY */
- -3, /* (301) vtabargtoken ::= lp anylist RP */
- -1, /* (302) lp ::= LP */
- -2, /* (303) with ::= WITH wqlist */
- -3, /* (304) with ::= WITH RECURSIVE wqlist */
- -1, /* (305) wqas ::= AS */
- -2, /* (306) wqas ::= AS MATERIALIZED */
- -3, /* (307) wqas ::= AS NOT MATERIALIZED */
- -6, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */
- -1, /* (309) wqlist ::= wqitem */
- -3, /* (310) wqlist ::= wqlist COMMA wqitem */
- -1, /* (311) windowdefn_list ::= windowdefn */
- -3, /* (312) windowdefn_list ::= windowdefn_list COMMA windowdefn */
- -5, /* (313) windowdefn ::= nm AS LP window RP */
- -5, /* (314) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
- -6, /* (315) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
- -4, /* (316) window ::= ORDER BY sortlist frame_opt */
- -5, /* (317) window ::= nm ORDER BY sortlist frame_opt */
- -1, /* (318) window ::= frame_opt */
- -2, /* (319) window ::= nm frame_opt */
- 0, /* (320) frame_opt ::= */
- -3, /* (321) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
- -6, /* (322) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
- -1, /* (323) range_or_rows ::= RANGE|ROWS|GROUPS */
- -1, /* (324) frame_bound_s ::= frame_bound */
- -2, /* (325) frame_bound_s ::= UNBOUNDED PRECEDING */
- -1, /* (326) frame_bound_e ::= frame_bound */
- -2, /* (327) frame_bound_e ::= UNBOUNDED FOLLOWING */
- -2, /* (328) frame_bound ::= expr PRECEDING|FOLLOWING */
- -2, /* (329) frame_bound ::= CURRENT ROW */
- 0, /* (330) frame_exclude_opt ::= */
- -2, /* (331) frame_exclude_opt ::= EXCLUDE frame_exclude */
- -2, /* (332) frame_exclude ::= NO OTHERS */
- -2, /* (333) frame_exclude ::= CURRENT ROW */
- -1, /* (334) frame_exclude ::= GROUP|TIES */
- -2, /* (335) window_clause ::= WINDOW windowdefn_list */
- -2, /* (336) filter_over ::= filter_clause over_clause */
- -1, /* (337) filter_over ::= over_clause */
- -1, /* (338) filter_over ::= filter_clause */
- -4, /* (339) over_clause ::= OVER LP window RP */
- -2, /* (340) over_clause ::= OVER nm */
- -5, /* (341) filter_clause ::= FILTER LP WHERE expr RP */
- -1, /* (342) input ::= cmdlist */
- -2, /* (343) cmdlist ::= cmdlist ecmd */
- -1, /* (344) cmdlist ::= ecmd */
- -1, /* (345) ecmd ::= SEMI */
- -2, /* (346) ecmd ::= cmdx SEMI */
- -3, /* (347) ecmd ::= explain cmdx SEMI */
- 0, /* (348) trans_opt ::= */
- -1, /* (349) trans_opt ::= TRANSACTION */
- -2, /* (350) trans_opt ::= TRANSACTION nm */
- -1, /* (351) savepoint_opt ::= SAVEPOINT */
- 0, /* (352) savepoint_opt ::= */
- -2, /* (353) cmd ::= create_table create_table_args */
- -1, /* (354) table_option_set ::= table_option */
- -4, /* (355) columnlist ::= columnlist COMMA columnname carglist */
- -2, /* (356) columnlist ::= columnname carglist */
- -1, /* (357) nm ::= ID|INDEXED */
- -1, /* (358) nm ::= STRING */
- -1, /* (359) nm ::= JOIN_KW */
- -1, /* (360) typetoken ::= typename */
- -1, /* (361) typename ::= ID|STRING */
- -1, /* (362) signed ::= plus_num */
- -1, /* (363) signed ::= minus_num */
- -2, /* (364) carglist ::= carglist ccons */
- 0, /* (365) carglist ::= */
- -2, /* (366) ccons ::= NULL onconf */
- -4, /* (367) ccons ::= GENERATED ALWAYS AS generated */
- -2, /* (368) ccons ::= AS generated */
- -2, /* (369) conslist_opt ::= COMMA conslist */
- -3, /* (370) conslist ::= conslist tconscomma tcons */
- -1, /* (371) conslist ::= tcons */
- 0, /* (372) tconscomma ::= */
- -1, /* (373) defer_subclause_opt ::= defer_subclause */
- -1, /* (374) resolvetype ::= raisetype */
- -1, /* (375) selectnowith ::= oneselect */
- -1, /* (376) oneselect ::= values */
- -2, /* (377) sclp ::= selcollist COMMA */
- -1, /* (378) as ::= ID|STRING */
- -1, /* (379) indexed_opt ::= indexed_by */
- 0, /* (380) returning ::= */
- -1, /* (381) expr ::= term */
- -1, /* (382) likeop ::= LIKE_KW|MATCH */
- -1, /* (383) exprlist ::= nexprlist */
- -1, /* (384) nmnum ::= plus_num */
- -1, /* (385) nmnum ::= nm */
- -1, /* (386) nmnum ::= ON */
- -1, /* (387) nmnum ::= DELETE */
- -1, /* (388) nmnum ::= DEFAULT */
- -1, /* (389) plus_num ::= INTEGER|FLOAT */
- 0, /* (390) foreach_clause ::= */
- -3, /* (391) foreach_clause ::= FOR EACH ROW */
- -1, /* (392) trnm ::= nm */
- 0, /* (393) tridxby ::= */
- -1, /* (394) database_kw_opt ::= DATABASE */
- 0, /* (395) database_kw_opt ::= */
- 0, /* (396) kwcolumn_opt ::= */
- -1, /* (397) kwcolumn_opt ::= COLUMNKW */
- -1, /* (398) vtabarglist ::= vtabarg */
- -3, /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */
- -2, /* (400) vtabarg ::= vtabarg vtabargtoken */
- 0, /* (401) anylist ::= */
- -4, /* (402) anylist ::= anylist LP anylist RP */
- -2, /* (403) anylist ::= anylist ANY */
- 0, /* (404) with ::= */
+ -1, /* (95) oneselect ::= mvalues */
+ -5, /* (96) mvalues ::= values COMMA LP nexprlist RP */
+ -5, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */
+ -1, /* (98) distinct ::= DISTINCT */
+ -1, /* (99) distinct ::= ALL */
+ 0, /* (100) distinct ::= */
+ 0, /* (101) sclp ::= */
+ -5, /* (102) selcollist ::= sclp scanpt expr scanpt as */
+ -3, /* (103) selcollist ::= sclp scanpt STAR */
+ -5, /* (104) selcollist ::= sclp scanpt nm DOT STAR */
+ -2, /* (105) as ::= AS nm */
+ 0, /* (106) as ::= */
+ 0, /* (107) from ::= */
+ -2, /* (108) from ::= FROM seltablist */
+ -2, /* (109) stl_prefix ::= seltablist joinop */
+ 0, /* (110) stl_prefix ::= */
+ -5, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */
+ -6, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
+ -8, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
+ -6, /* (114) seltablist ::= stl_prefix LP select RP as on_using */
+ -6, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */
+ 0, /* (116) dbnm ::= */
+ -2, /* (117) dbnm ::= DOT nm */
+ -1, /* (118) fullname ::= nm */
+ -3, /* (119) fullname ::= nm DOT nm */
+ -1, /* (120) xfullname ::= nm */
+ -3, /* (121) xfullname ::= nm DOT nm */
+ -5, /* (122) xfullname ::= nm DOT nm AS nm */
+ -3, /* (123) xfullname ::= nm AS nm */
+ -1, /* (124) joinop ::= COMMA|JOIN */
+ -2, /* (125) joinop ::= JOIN_KW JOIN */
+ -3, /* (126) joinop ::= JOIN_KW nm JOIN */
+ -4, /* (127) joinop ::= JOIN_KW nm nm JOIN */
+ -2, /* (128) on_using ::= ON expr */
+ -4, /* (129) on_using ::= USING LP idlist RP */
+ 0, /* (130) on_using ::= */
+ 0, /* (131) indexed_opt ::= */
+ -3, /* (132) indexed_by ::= INDEXED BY nm */
+ -2, /* (133) indexed_by ::= NOT INDEXED */
+ 0, /* (134) orderby_opt ::= */
+ -3, /* (135) orderby_opt ::= ORDER BY sortlist */
+ -5, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */
+ -3, /* (137) sortlist ::= expr sortorder nulls */
+ -1, /* (138) sortorder ::= ASC */
+ -1, /* (139) sortorder ::= DESC */
+ 0, /* (140) sortorder ::= */
+ -2, /* (141) nulls ::= NULLS FIRST */
+ -2, /* (142) nulls ::= NULLS LAST */
+ 0, /* (143) nulls ::= */
+ 0, /* (144) groupby_opt ::= */
+ -3, /* (145) groupby_opt ::= GROUP BY nexprlist */
+ 0, /* (146) having_opt ::= */
+ -2, /* (147) having_opt ::= HAVING expr */
+ 0, /* (148) limit_opt ::= */
+ -2, /* (149) limit_opt ::= LIMIT expr */
+ -4, /* (150) limit_opt ::= LIMIT expr OFFSET expr */
+ -4, /* (151) limit_opt ::= LIMIT expr COMMA expr */
+ -6, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
+ 0, /* (153) where_opt ::= */
+ -2, /* (154) where_opt ::= WHERE expr */
+ 0, /* (155) where_opt_ret ::= */
+ -2, /* (156) where_opt_ret ::= WHERE expr */
+ -2, /* (157) where_opt_ret ::= RETURNING selcollist */
+ -4, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */
+ -9, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
+ -5, /* (160) setlist ::= setlist COMMA nm EQ expr */
+ -7, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */
+ -3, /* (162) setlist ::= nm EQ expr */
+ -5, /* (163) setlist ::= LP idlist RP EQ expr */
+ -7, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ -8, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
+ 0, /* (166) upsert ::= */
+ -2, /* (167) upsert ::= RETURNING selcollist */
+ -12, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
+ -9, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
+ -5, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */
+ -8, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
+ -2, /* (172) returning ::= RETURNING selcollist */
+ -2, /* (173) insert_cmd ::= INSERT orconf */
+ -1, /* (174) insert_cmd ::= REPLACE */
+ 0, /* (175) idlist_opt ::= */
+ -3, /* (176) idlist_opt ::= LP idlist RP */
+ -3, /* (177) idlist ::= idlist COMMA nm */
+ -1, /* (178) idlist ::= nm */
+ -3, /* (179) expr ::= LP expr RP */
+ -1, /* (180) expr ::= ID|INDEXED|JOIN_KW */
+ -3, /* (181) expr ::= nm DOT nm */
+ -5, /* (182) expr ::= nm DOT nm DOT nm */
+ -1, /* (183) term ::= NULL|FLOAT|BLOB */
+ -1, /* (184) term ::= STRING */
+ -1, /* (185) term ::= INTEGER */
+ -1, /* (186) expr ::= VARIABLE */
+ -3, /* (187) expr ::= expr COLLATE ID|STRING */
+ -6, /* (188) expr ::= CAST LP expr AS typetoken RP */
+ -5, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+ -8, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
+ -4, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
+ -6, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
+ -9, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
+ -5, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
+ -1, /* (195) term ::= CTIME_KW */
+ -5, /* (196) expr ::= LP nexprlist COMMA expr RP */
+ -3, /* (197) expr ::= expr AND expr */
+ -3, /* (198) expr ::= expr OR expr */
+ -3, /* (199) expr ::= expr LT|GT|GE|LE expr */
+ -3, /* (200) expr ::= expr EQ|NE expr */
+ -3, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ -3, /* (202) expr ::= expr PLUS|MINUS expr */
+ -3, /* (203) expr ::= expr STAR|SLASH|REM expr */
+ -3, /* (204) expr ::= expr CONCAT expr */
+ -2, /* (205) likeop ::= NOT LIKE_KW|MATCH */
+ -3, /* (206) expr ::= expr likeop expr */
+ -5, /* (207) expr ::= expr likeop expr ESCAPE expr */
+ -2, /* (208) expr ::= expr ISNULL|NOTNULL */
+ -3, /* (209) expr ::= expr NOT NULL */
+ -3, /* (210) expr ::= expr IS expr */
+ -4, /* (211) expr ::= expr IS NOT expr */
+ -6, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */
+ -5, /* (213) expr ::= expr IS DISTINCT FROM expr */
+ -2, /* (214) expr ::= NOT expr */
+ -2, /* (215) expr ::= BITNOT expr */
+ -2, /* (216) expr ::= PLUS|MINUS expr */
+ -3, /* (217) expr ::= expr PTR expr */
+ -1, /* (218) between_op ::= BETWEEN */
+ -2, /* (219) between_op ::= NOT BETWEEN */
+ -5, /* (220) expr ::= expr between_op expr AND expr */
+ -1, /* (221) in_op ::= IN */
+ -2, /* (222) in_op ::= NOT IN */
+ -5, /* (223) expr ::= expr in_op LP exprlist RP */
+ -3, /* (224) expr ::= LP select RP */
+ -5, /* (225) expr ::= expr in_op LP select RP */
+ -5, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */
+ -4, /* (227) expr ::= EXISTS LP select RP */
+ -5, /* (228) expr ::= CASE case_operand case_exprlist case_else END */
+ -5, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ -4, /* (230) case_exprlist ::= WHEN expr THEN expr */
+ -2, /* (231) case_else ::= ELSE expr */
+ 0, /* (232) case_else ::= */
+ 0, /* (233) case_operand ::= */
+ 0, /* (234) exprlist ::= */
+ -3, /* (235) nexprlist ::= nexprlist COMMA expr */
+ -1, /* (236) nexprlist ::= expr */
+ 0, /* (237) paren_exprlist ::= */
+ -3, /* (238) paren_exprlist ::= LP exprlist RP */
+ -12, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ -1, /* (240) uniqueflag ::= UNIQUE */
+ 0, /* (241) uniqueflag ::= */
+ 0, /* (242) eidlist_opt ::= */
+ -3, /* (243) eidlist_opt ::= LP eidlist RP */
+ -5, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */
+ -3, /* (245) eidlist ::= nm collate sortorder */
+ 0, /* (246) collate ::= */
+ -2, /* (247) collate ::= COLLATE ID|STRING */
+ -4, /* (248) cmd ::= DROP INDEX ifexists fullname */
+ -2, /* (249) cmd ::= VACUUM vinto */
+ -3, /* (250) cmd ::= VACUUM nm vinto */
+ -2, /* (251) vinto ::= INTO expr */
+ 0, /* (252) vinto ::= */
+ -3, /* (253) cmd ::= PRAGMA nm dbnm */
+ -5, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */
+ -6, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ -5, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */
+ -6, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ -2, /* (258) plus_num ::= PLUS INTEGER|FLOAT */
+ -2, /* (259) minus_num ::= MINUS INTEGER|FLOAT */
+ -5, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ -11, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ -1, /* (262) trigger_time ::= BEFORE|AFTER */
+ -2, /* (263) trigger_time ::= INSTEAD OF */
+ 0, /* (264) trigger_time ::= */
+ -1, /* (265) trigger_event ::= DELETE|INSERT */
+ -1, /* (266) trigger_event ::= UPDATE */
+ -3, /* (267) trigger_event ::= UPDATE OF idlist */
+ 0, /* (268) when_clause ::= */
+ -2, /* (269) when_clause ::= WHEN expr */
+ -3, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ -2, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */
+ -3, /* (272) trnm ::= nm DOT nm */
+ -3, /* (273) tridxby ::= INDEXED BY nm */
+ -2, /* (274) tridxby ::= NOT INDEXED */
+ -9, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ -8, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ -6, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ -3, /* (278) trigger_cmd ::= scanpt select scanpt */
+ -4, /* (279) expr ::= RAISE LP IGNORE RP */
+ -6, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */
+ -1, /* (281) raisetype ::= ROLLBACK */
+ -1, /* (282) raisetype ::= ABORT */
+ -1, /* (283) raisetype ::= FAIL */
+ -4, /* (284) cmd ::= DROP TRIGGER ifexists fullname */
+ -6, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ -3, /* (286) cmd ::= DETACH database_kw_opt expr */
+ 0, /* (287) key_opt ::= */
+ -2, /* (288) key_opt ::= KEY expr */
+ -1, /* (289) cmd ::= REINDEX */
+ -3, /* (290) cmd ::= REINDEX nm dbnm */
+ -1, /* (291) cmd ::= ANALYZE */
+ -3, /* (292) cmd ::= ANALYZE nm dbnm */
+ -6, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */
+ -7, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ -6, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ -1, /* (296) add_column_fullname ::= fullname */
+ -8, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ -1, /* (298) cmd ::= create_vtab */
+ -4, /* (299) cmd ::= create_vtab LP vtabarglist RP */
+ -8, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ 0, /* (301) vtabarg ::= */
+ -1, /* (302) vtabargtoken ::= ANY */
+ -3, /* (303) vtabargtoken ::= lp anylist RP */
+ -1, /* (304) lp ::= LP */
+ -2, /* (305) with ::= WITH wqlist */
+ -3, /* (306) with ::= WITH RECURSIVE wqlist */
+ -1, /* (307) wqas ::= AS */
+ -2, /* (308) wqas ::= AS MATERIALIZED */
+ -3, /* (309) wqas ::= AS NOT MATERIALIZED */
+ -6, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */
+ -1, /* (311) withnm ::= nm */
+ -1, /* (312) wqlist ::= wqitem */
+ -3, /* (313) wqlist ::= wqlist COMMA wqitem */
+ -3, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ -5, /* (315) windowdefn ::= nm AS LP window RP */
+ -5, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ -6, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ -4, /* (318) window ::= ORDER BY sortlist frame_opt */
+ -5, /* (319) window ::= nm ORDER BY sortlist frame_opt */
+ -2, /* (320) window ::= nm frame_opt */
+ 0, /* (321) frame_opt ::= */
+ -3, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ -6, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ -1, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */
+ -1, /* (325) frame_bound_s ::= frame_bound */
+ -2, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */
+ -1, /* (327) frame_bound_e ::= frame_bound */
+ -2, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ -2, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */
+ -2, /* (330) frame_bound ::= CURRENT ROW */
+ 0, /* (331) frame_exclude_opt ::= */
+ -2, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ -2, /* (333) frame_exclude ::= NO OTHERS */
+ -2, /* (334) frame_exclude ::= CURRENT ROW */
+ -1, /* (335) frame_exclude ::= GROUP|TIES */
+ -2, /* (336) window_clause ::= WINDOW windowdefn_list */
+ -2, /* (337) filter_over ::= filter_clause over_clause */
+ -1, /* (338) filter_over ::= over_clause */
+ -1, /* (339) filter_over ::= filter_clause */
+ -4, /* (340) over_clause ::= OVER LP window RP */
+ -2, /* (341) over_clause ::= OVER nm */
+ -5, /* (342) filter_clause ::= FILTER LP WHERE expr RP */
+ -1, /* (343) term ::= QNUMBER */
+ -1, /* (344) input ::= cmdlist */
+ -2, /* (345) cmdlist ::= cmdlist ecmd */
+ -1, /* (346) cmdlist ::= ecmd */
+ -1, /* (347) ecmd ::= SEMI */
+ -2, /* (348) ecmd ::= cmdx SEMI */
+ -3, /* (349) ecmd ::= explain cmdx SEMI */
+ 0, /* (350) trans_opt ::= */
+ -1, /* (351) trans_opt ::= TRANSACTION */
+ -2, /* (352) trans_opt ::= TRANSACTION nm */
+ -1, /* (353) savepoint_opt ::= SAVEPOINT */
+ 0, /* (354) savepoint_opt ::= */
+ -2, /* (355) cmd ::= create_table create_table_args */
+ -1, /* (356) table_option_set ::= table_option */
+ -4, /* (357) columnlist ::= columnlist COMMA columnname carglist */
+ -2, /* (358) columnlist ::= columnname carglist */
+ -1, /* (359) nm ::= ID|INDEXED|JOIN_KW */
+ -1, /* (360) nm ::= STRING */
+ -1, /* (361) typetoken ::= typename */
+ -1, /* (362) typename ::= ID|STRING */
+ -1, /* (363) signed ::= plus_num */
+ -1, /* (364) signed ::= minus_num */
+ -2, /* (365) carglist ::= carglist ccons */
+ 0, /* (366) carglist ::= */
+ -2, /* (367) ccons ::= NULL onconf */
+ -4, /* (368) ccons ::= GENERATED ALWAYS AS generated */
+ -2, /* (369) ccons ::= AS generated */
+ -2, /* (370) conslist_opt ::= COMMA conslist */
+ -3, /* (371) conslist ::= conslist tconscomma tcons */
+ -1, /* (372) conslist ::= tcons */
+ 0, /* (373) tconscomma ::= */
+ -1, /* (374) defer_subclause_opt ::= defer_subclause */
+ -1, /* (375) resolvetype ::= raisetype */
+ -1, /* (376) selectnowith ::= oneselect */
+ -1, /* (377) oneselect ::= values */
+ -2, /* (378) sclp ::= selcollist COMMA */
+ -1, /* (379) as ::= ID|STRING */
+ -1, /* (380) indexed_opt ::= indexed_by */
+ 0, /* (381) returning ::= */
+ -1, /* (382) expr ::= term */
+ -1, /* (383) likeop ::= LIKE_KW|MATCH */
+ -1, /* (384) case_operand ::= expr */
+ -1, /* (385) exprlist ::= nexprlist */
+ -1, /* (386) nmnum ::= plus_num */
+ -1, /* (387) nmnum ::= nm */
+ -1, /* (388) nmnum ::= ON */
+ -1, /* (389) nmnum ::= DELETE */
+ -1, /* (390) nmnum ::= DEFAULT */
+ -1, /* (391) plus_num ::= INTEGER|FLOAT */
+ 0, /* (392) foreach_clause ::= */
+ -3, /* (393) foreach_clause ::= FOR EACH ROW */
+ -1, /* (394) trnm ::= nm */
+ 0, /* (395) tridxby ::= */
+ -1, /* (396) database_kw_opt ::= DATABASE */
+ 0, /* (397) database_kw_opt ::= */
+ 0, /* (398) kwcolumn_opt ::= */
+ -1, /* (399) kwcolumn_opt ::= COLUMNKW */
+ -1, /* (400) vtabarglist ::= vtabarg */
+ -3, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */
+ -2, /* (402) vtabarg ::= vtabarg vtabargtoken */
+ 0, /* (403) anylist ::= */
+ -4, /* (404) anylist ::= anylist LP anylist RP */
+ -2, /* (405) anylist ::= anylist ANY */
+ 0, /* (406) with ::= */
+ -1, /* (407) windowdefn_list ::= windowdefn */
+ -1, /* (408) window ::= frame_opt */
};
static void yy_accept(yyParser*); /* Forward Declaration */
@@ -170506,25 +177640,25 @@ static YYACTIONTYPE yy_reduce(
/********** Begin reduce actions **********************************************/
YYMINORTYPE yylhsminor;
case 0: /* explain ::= EXPLAIN */
-{ pParse->explain = 1; }
+{ if( pParse->pReprepare==0 ) pParse->explain = 1; }
break;
case 1: /* explain ::= EXPLAIN QUERY PLAN */
-{ pParse->explain = 2; }
+{ if( pParse->pReprepare==0 ) pParse->explain = 2; }
break;
case 2: /* cmdx ::= cmd */
{ wx_sqlite3FinishCoding(pParse); }
break;
case 3: /* cmd ::= BEGIN transtype trans_opt */
-{wx_sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy394);}
+{wx_sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy144);}
break;
case 4: /* transtype ::= */
-{yymsp[1].minor.yy394 = TK_DEFERRED;}
+{yymsp[1].minor.yy144 = TK_DEFERRED;}
break;
case 5: /* transtype ::= DEFERRED */
case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
- case 323: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==323);
-{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/}
+ case 324: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==324);
+{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/}
break;
case 8: /* cmd ::= COMMIT|END trans_opt */
case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9);
@@ -170547,7 +177681,7 @@ static YYACTIONTYPE yy_reduce(
break;
case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
- wx_sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy394,0,0,yymsp[-2].minor.yy394);
+ wx_sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy144,0,0,yymsp[-2].minor.yy144);
}
break;
case 14: /* createkw ::= CREATE */
@@ -170559,40 +177693,40 @@ static YYACTIONTYPE yy_reduce(
case 62: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==62);
case 72: /* defer_subclause_opt ::= */ yytestcase(yyruleno==72);
case 81: /* ifexists ::= */ yytestcase(yyruleno==81);
- case 98: /* distinct ::= */ yytestcase(yyruleno==98);
- case 244: /* collate ::= */ yytestcase(yyruleno==244);
-{yymsp[1].minor.yy394 = 0;}
+ case 100: /* distinct ::= */ yytestcase(yyruleno==100);
+ case 246: /* collate ::= */ yytestcase(yyruleno==246);
+{yymsp[1].minor.yy144 = 0;}
break;
case 16: /* ifnotexists ::= IF NOT EXISTS */
-{yymsp[-2].minor.yy394 = 1;}
+{yymsp[-2].minor.yy144 = 1;}
break;
case 17: /* temp ::= TEMP */
-{yymsp[0].minor.yy394 = pParse->db->init.busy==0;}
+{yymsp[0].minor.yy144 = pParse->db->init.busy==0;}
break;
case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */
{
- wx_sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy285,0);
+ wx_sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy391,0);
}
break;
case 20: /* create_table_args ::= AS select */
{
- wx_sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy47);
- wx_sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47);
+ wx_sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy555);
+ wx_sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555);
}
break;
case 21: /* table_option_set ::= */
-{yymsp[1].minor.yy285 = 0;}
+{yymsp[1].minor.yy391 = 0;}
break;
case 22: /* table_option_set ::= table_option_set COMMA table_option */
-{yylhsminor.yy285 = yymsp[-2].minor.yy285|yymsp[0].minor.yy285;}
- yymsp[-2].minor.yy285 = yylhsminor.yy285;
+{yylhsminor.yy391 = yymsp[-2].minor.yy391|yymsp[0].minor.yy391;}
+ yymsp[-2].minor.yy391 = yylhsminor.yy391;
break;
case 23: /* table_option ::= WITHOUT nm */
{
if( yymsp[0].minor.yy0.n==5 && wx_sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
- yymsp[-1].minor.yy285 = TF_WithoutRowid | TF_NoVisibleRowid;
+ yymsp[-1].minor.yy391 = TF_WithoutRowid | TF_NoVisibleRowid;
}else{
- yymsp[-1].minor.yy285 = 0;
+ yymsp[-1].minor.yy391 = 0;
wx_sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
@@ -170600,20 +177734,20 @@ static YYACTIONTYPE yy_reduce(
case 24: /* table_option ::= nm */
{
if( yymsp[0].minor.yy0.n==6 && wx_sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){
- yylhsminor.yy285 = TF_Strict;
+ yylhsminor.yy391 = TF_Strict;
}else{
- yylhsminor.yy285 = 0;
+ yylhsminor.yy391 = 0;
wx_sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
- yymsp[0].minor.yy285 = yylhsminor.yy285;
+ yymsp[0].minor.yy391 = yylhsminor.yy391;
break;
case 25: /* columnname ::= nm typetoken */
{wx_sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);}
break;
case 26: /* typetoken ::= */
case 65: /* conslist_opt ::= */ yytestcase(yyruleno==65);
- case 104: /* as ::= */ yytestcase(yyruleno==104);
+ case 106: /* as ::= */ yytestcase(yyruleno==106);
{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
break;
case 27: /* typetoken ::= typename LP signed RP */
@@ -170632,7 +177766,7 @@ static YYACTIONTYPE yy_reduce(
case 30: /* scanpt ::= */
{
assert( yyLookahead!=YYNOCODE );
- yymsp[1].minor.yy522 = yyLookaheadToken.z;
+ yymsp[1].minor.yy168 = yyLookaheadToken.z;
}
break;
case 31: /* scantok ::= */
@@ -170646,17 +177780,17 @@ static YYACTIONTYPE yy_reduce(
{pParse->constraintName = yymsp[0].minor.yy0;}
break;
case 33: /* ccons ::= DEFAULT scantok term */
-{wx_sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
+{wx_sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
break;
case 34: /* ccons ::= DEFAULT LP expr RP */
-{wx_sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
+{wx_sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
break;
case 35: /* ccons ::= DEFAULT PLUS scantok term */
-{wx_sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
+{wx_sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
break;
case 36: /* ccons ::= DEFAULT MINUS scantok term */
{
- Expr *p = wx_sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy528, 0);
+ Expr *p = wx_sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy454, 0);
wx_sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);
}
break;
@@ -170671,161 +177805,160 @@ static YYACTIONTYPE yy_reduce(
}
break;
case 38: /* ccons ::= NOT NULL onconf */
-{wx_sqlite3AddNotNull(pParse, yymsp[0].minor.yy394);}
+{wx_sqlite3AddNotNull(pParse, yymsp[0].minor.yy144);}
break;
case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
-{wx_sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy394,yymsp[0].minor.yy394,yymsp[-2].minor.yy394);}
+{wx_sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy144,yymsp[0].minor.yy144,yymsp[-2].minor.yy144);}
break;
case 40: /* ccons ::= UNIQUE onconf */
-{wx_sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy394,0,0,0,0,
+{wx_sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy144,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
break;
case 41: /* ccons ::= CHECK LP expr RP */
-{wx_sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);}
+{wx_sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);}
break;
case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */
-{wx_sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy394);}
+{wx_sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy14,yymsp[0].minor.yy144);}
break;
case 43: /* ccons ::= defer_subclause */
-{wx_sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy394);}
+{wx_sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy144);}
break;
case 44: /* ccons ::= COLLATE ID|STRING */
{wx_sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
break;
case 45: /* generated ::= LP expr RP */
-{wx_sqlite3AddGenerated(pParse,yymsp[-1].minor.yy528,0);}
+{wx_sqlite3AddGenerated(pParse,yymsp[-1].minor.yy454,0);}
break;
case 46: /* generated ::= LP expr RP ID */
-{wx_sqlite3AddGenerated(pParse,yymsp[-2].minor.yy528,&yymsp[0].minor.yy0);}
+{wx_sqlite3AddGenerated(pParse,yymsp[-2].minor.yy454,&yymsp[0].minor.yy0);}
break;
case 48: /* autoinc ::= AUTOINCR */
-{yymsp[0].minor.yy394 = 1;}
+{yymsp[0].minor.yy144 = 1;}
break;
case 49: /* refargs ::= */
-{ yymsp[1].minor.yy394 = OE_None*0x0101; /* EV: R-19803-45884 */}
+{ yymsp[1].minor.yy144 = OE_None*0x0101; /* EV: R-19803-45884 */}
break;
case 50: /* refargs ::= refargs refarg */
-{ yymsp[-1].minor.yy394 = (yymsp[-1].minor.yy394 & ~yymsp[0].minor.yy231.mask) | yymsp[0].minor.yy231.value; }
+{ yymsp[-1].minor.yy144 = (yymsp[-1].minor.yy144 & ~yymsp[0].minor.yy383.mask) | yymsp[0].minor.yy383.value; }
break;
case 51: /* refarg ::= MATCH nm */
-{ yymsp[-1].minor.yy231.value = 0; yymsp[-1].minor.yy231.mask = 0x000000; }
+{ yymsp[-1].minor.yy383.value = 0; yymsp[-1].minor.yy383.mask = 0x000000; }
break;
case 52: /* refarg ::= ON INSERT refact */
-{ yymsp[-2].minor.yy231.value = 0; yymsp[-2].minor.yy231.mask = 0x000000; }
+{ yymsp[-2].minor.yy383.value = 0; yymsp[-2].minor.yy383.mask = 0x000000; }
break;
case 53: /* refarg ::= ON DELETE refact */
-{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394; yymsp[-2].minor.yy231.mask = 0x0000ff; }
+{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144; yymsp[-2].minor.yy383.mask = 0x0000ff; }
break;
case 54: /* refarg ::= ON UPDATE refact */
-{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394<<8; yymsp[-2].minor.yy231.mask = 0x00ff00; }
+{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144<<8; yymsp[-2].minor.yy383.mask = 0x00ff00; }
break;
case 55: /* refact ::= SET NULL */
-{ yymsp[-1].minor.yy394 = OE_SetNull; /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy144 = OE_SetNull; /* EV: R-33326-45252 */}
break;
case 56: /* refact ::= SET DEFAULT */
-{ yymsp[-1].minor.yy394 = OE_SetDflt; /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy144 = OE_SetDflt; /* EV: R-33326-45252 */}
break;
case 57: /* refact ::= CASCADE */
-{ yymsp[0].minor.yy394 = OE_Cascade; /* EV: R-33326-45252 */}
+{ yymsp[0].minor.yy144 = OE_Cascade; /* EV: R-33326-45252 */}
break;
case 58: /* refact ::= RESTRICT */
-{ yymsp[0].minor.yy394 = OE_Restrict; /* EV: R-33326-45252 */}
+{ yymsp[0].minor.yy144 = OE_Restrict; /* EV: R-33326-45252 */}
break;
case 59: /* refact ::= NO ACTION */
-{ yymsp[-1].minor.yy394 = OE_None; /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy144 = OE_None; /* EV: R-33326-45252 */}
break;
case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
-{yymsp[-2].minor.yy394 = 0;}
+{yymsp[-2].minor.yy144 = 0;}
break;
case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76);
- case 171: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==171);
-{yymsp[-1].minor.yy394 = yymsp[0].minor.yy394;}
+ case 173: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==173);
+{yymsp[-1].minor.yy144 = yymsp[0].minor.yy144;}
break;
case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80);
- case 216: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==216);
- case 219: /* in_op ::= NOT IN */ yytestcase(yyruleno==219);
- case 245: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==245);
-{yymsp[-1].minor.yy394 = 1;}
+ case 219: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==219);
+ case 222: /* in_op ::= NOT IN */ yytestcase(yyruleno==222);
+ case 247: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==247);
+{yymsp[-1].minor.yy144 = 1;}
break;
case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
-{yymsp[-1].minor.yy394 = 0;}
+{yymsp[-1].minor.yy144 = 0;}
break;
case 66: /* tconscomma ::= COMMA */
{pParse->constraintName.n = 0;}
break;
case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
-{wx_sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy394,yymsp[-2].minor.yy394,0);}
+{wx_sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy144,yymsp[-2].minor.yy144,0);}
break;
case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */
-{wx_sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy394,0,0,0,0,
+{wx_sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy14,yymsp[0].minor.yy144,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
break;
case 70: /* tcons ::= CHECK LP expr RP onconf */
-{wx_sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy528,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);}
+{wx_sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy454,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);}
break;
case 71: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
{
- wx_sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy394);
- wx_sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy394);
+ wx_sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy14, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[-1].minor.yy144);
+ wx_sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy144);
}
break;
case 73: /* onconf ::= */
case 75: /* orconf ::= */ yytestcase(yyruleno==75);
-{yymsp[1].minor.yy394 = OE_Default;}
+{yymsp[1].minor.yy144 = OE_Default;}
break;
case 74: /* onconf ::= ON CONFLICT resolvetype */
-{yymsp[-2].minor.yy394 = yymsp[0].minor.yy394;}
+{yymsp[-2].minor.yy144 = yymsp[0].minor.yy144;}
break;
case 77: /* resolvetype ::= IGNORE */
-{yymsp[0].minor.yy394 = OE_Ignore;}
+{yymsp[0].minor.yy144 = OE_Ignore;}
break;
case 78: /* resolvetype ::= REPLACE */
- case 172: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==172);
-{yymsp[0].minor.yy394 = OE_Replace;}
+ case 174: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==174);
+{yymsp[0].minor.yy144 = OE_Replace;}
break;
case 79: /* cmd ::= DROP TABLE ifexists fullname */
{
- wx_sqlite3DropTable(pParse, yymsp[0].minor.yy131, 0, yymsp[-1].minor.yy394);
+ wx_sqlite3DropTable(pParse, yymsp[0].minor.yy203, 0, yymsp[-1].minor.yy144);
}
break;
case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
{
- wx_sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[0].minor.yy47, yymsp[-7].minor.yy394, yymsp[-5].minor.yy394);
+ wx_sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[0].minor.yy555, yymsp[-7].minor.yy144, yymsp[-5].minor.yy144);
}
break;
case 83: /* cmd ::= DROP VIEW ifexists fullname */
{
- wx_sqlite3DropTable(pParse, yymsp[0].minor.yy131, 1, yymsp[-1].minor.yy394);
+ wx_sqlite3DropTable(pParse, yymsp[0].minor.yy203, 1, yymsp[-1].minor.yy144);
}
break;
case 84: /* cmd ::= select */
{
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
- wx_sqlite3Select(pParse, yymsp[0].minor.yy47, &dest);
- wx_sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47);
+ wx_sqlite3Select(pParse, yymsp[0].minor.yy555, &dest);
+ wx_sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555);
}
break;
case 85: /* select ::= WITH wqlist selectnowith */
-{yymsp[-2].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);}
+{yymsp[-2].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);}
break;
case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */
-{yymsp[-3].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);}
+{yymsp[-3].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);}
break;
case 87: /* select ::= selectnowith */
{
- Select *p = yymsp[0].minor.yy47;
+ Select *p = yymsp[0].minor.yy555;
if( p ){
parserDoubleLinkSelect(pParse, p);
}
- yymsp[0].minor.yy47 = p; /*A-overwrites-X*/
}
break;
case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */
{
- Select *pRhs = yymsp[0].minor.yy47;
- Select *pLhs = yymsp[-2].minor.yy47;
+ Select *pRhs = yymsp[0].minor.yy555;
+ Select *pLhs = yymsp[-2].minor.yy555;
if( pRhs && pRhs->pPrior ){
SrcList *pFrom;
Token x;
@@ -170835,150 +177968,160 @@ static YYACTIONTYPE yy_reduce(
pRhs = wx_sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
}
if( pRhs ){
- pRhs->op = (u8)yymsp[-1].minor.yy394;
+ pRhs->op = (u8)yymsp[-1].minor.yy144;
pRhs->pPrior = pLhs;
if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
pRhs->selFlags &= ~SF_MultiValue;
- if( yymsp[-1].minor.yy394!=TK_ALL ) pParse->hasCompound = 1;
+ if( yymsp[-1].minor.yy144!=TK_ALL ) pParse->hasCompound = 1;
}else{
wx_sqlite3SelectDelete(pParse->db, pLhs);
}
- yymsp[-2].minor.yy47 = pRhs;
+ yymsp[-2].minor.yy555 = pRhs;
}
break;
case 89: /* multiselect_op ::= UNION */
case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91);
-{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-OP*/}
+{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-OP*/}
break;
case 90: /* multiselect_op ::= UNION ALL */
-{yymsp[-1].minor.yy394 = TK_ALL;}
+{yymsp[-1].minor.yy144 = TK_ALL;}
break;
case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
- yymsp[-8].minor.yy47 = wx_sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy131,yymsp[-4].minor.yy528,yymsp[-3].minor.yy322,yymsp[-2].minor.yy528,yymsp[-1].minor.yy322,yymsp[-7].minor.yy394,yymsp[0].minor.yy528);
+ yymsp[-8].minor.yy555 = wx_sqlite3SelectNew(pParse,yymsp[-6].minor.yy14,yymsp[-5].minor.yy203,yymsp[-4].minor.yy454,yymsp[-3].minor.yy14,yymsp[-2].minor.yy454,yymsp[-1].minor.yy14,yymsp[-7].minor.yy144,yymsp[0].minor.yy454);
}
break;
case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
{
- yymsp[-9].minor.yy47 = wx_sqlite3SelectNew(pParse,yymsp[-7].minor.yy322,yymsp[-6].minor.yy131,yymsp[-5].minor.yy528,yymsp[-4].minor.yy322,yymsp[-3].minor.yy528,yymsp[-1].minor.yy322,yymsp[-8].minor.yy394,yymsp[0].minor.yy528);
- if( yymsp[-9].minor.yy47 ){
- yymsp[-9].minor.yy47->pWinDefn = yymsp[-2].minor.yy41;
+ yymsp[-9].minor.yy555 = wx_sqlite3SelectNew(pParse,yymsp[-7].minor.yy14,yymsp[-6].minor.yy203,yymsp[-5].minor.yy454,yymsp[-4].minor.yy14,yymsp[-3].minor.yy454,yymsp[-1].minor.yy14,yymsp[-8].minor.yy144,yymsp[0].minor.yy454);
+ if( yymsp[-9].minor.yy555 ){
+ yymsp[-9].minor.yy555->pWinDefn = yymsp[-2].minor.yy211;
}else{
- wx_sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy41);
+ wx_sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy211);
}
}
break;
case 94: /* values ::= VALUES LP nexprlist RP */
{
- yymsp[-3].minor.yy47 = wx_sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0);
+ yymsp[-3].minor.yy555 = wx_sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values,0);
}
break;
- case 95: /* values ::= values COMMA LP nexprlist RP */
+ case 95: /* oneselect ::= mvalues */
{
- Select *pRight, *pLeft = yymsp[-4].minor.yy47;
- pRight = wx_sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values|SF_MultiValue,0);
- if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
- if( pRight ){
- pRight->op = TK_ALL;
- pRight->pPrior = pLeft;
- yymsp[-4].minor.yy47 = pRight;
- }else{
- yymsp[-4].minor.yy47 = pLeft;
- }
+ wx_sqlite3MultiValuesEnd(pParse, yymsp[0].minor.yy555);
+}
+ break;
+ case 96: /* mvalues ::= values COMMA LP nexprlist RP */
+ case 97: /* mvalues ::= mvalues COMMA LP nexprlist RP */ yytestcase(yyruleno==97);
+{
+ yymsp[-4].minor.yy555 = wx_sqlite3MultiValues(pParse, yymsp[-4].minor.yy555, yymsp[-1].minor.yy14);
}
break;
- case 96: /* distinct ::= DISTINCT */
-{yymsp[0].minor.yy394 = SF_Distinct;}
+ case 98: /* distinct ::= DISTINCT */
+{yymsp[0].minor.yy144 = SF_Distinct;}
break;
- case 97: /* distinct ::= ALL */
-{yymsp[0].minor.yy394 = SF_All;}
+ case 99: /* distinct ::= ALL */
+{yymsp[0].minor.yy144 = SF_All;}
break;
- case 99: /* sclp ::= */
- case 132: /* orderby_opt ::= */ yytestcase(yyruleno==132);
- case 142: /* groupby_opt ::= */ yytestcase(yyruleno==142);
- case 232: /* exprlist ::= */ yytestcase(yyruleno==232);
- case 235: /* paren_exprlist ::= */ yytestcase(yyruleno==235);
- case 240: /* eidlist_opt ::= */ yytestcase(yyruleno==240);
-{yymsp[1].minor.yy322 = 0;}
+ case 101: /* sclp ::= */
+ case 134: /* orderby_opt ::= */ yytestcase(yyruleno==134);
+ case 144: /* groupby_opt ::= */ yytestcase(yyruleno==144);
+ case 234: /* exprlist ::= */ yytestcase(yyruleno==234);
+ case 237: /* paren_exprlist ::= */ yytestcase(yyruleno==237);
+ case 242: /* eidlist_opt ::= */ yytestcase(yyruleno==242);
+{yymsp[1].minor.yy14 = 0;}
break;
- case 100: /* selcollist ::= sclp scanpt expr scanpt as */
+ case 102: /* selcollist ::= sclp scanpt expr scanpt as */
{
- yymsp[-4].minor.yy322 = wx_sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[-2].minor.yy528);
- if( yymsp[0].minor.yy0.n>0 ) wx_sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[0].minor.yy0, 1);
- wx_sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy322,yymsp[-3].minor.yy522,yymsp[-1].minor.yy522);
+ yymsp[-4].minor.yy14 = wx_sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[-2].minor.yy454);
+ if( yymsp[0].minor.yy0.n>0 ) wx_sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[0].minor.yy0, 1);
+ wx_sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy14,yymsp[-3].minor.yy168,yymsp[-1].minor.yy168);
}
break;
- case 101: /* selcollist ::= sclp scanpt STAR */
+ case 103: /* selcollist ::= sclp scanpt STAR */
{
Expr *p = wx_sqlite3Expr(pParse->db, TK_ASTERISK, 0);
- yymsp[-2].minor.yy322 = wx_sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, p);
+ wx_sqlite3ExprSetErrorOffset(p, (int)(yymsp[0].minor.yy0.z - pParse->zTail));
+ yymsp[-2].minor.yy14 = wx_sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy14, p);
}
break;
- case 102: /* selcollist ::= sclp scanpt nm DOT STAR */
+ case 104: /* selcollist ::= sclp scanpt nm DOT STAR */
{
- Expr *pRight = wx_sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
- Expr *pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0);
- Expr *pDot = wx_sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
- yymsp[-4].minor.yy322 = wx_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, pDot);
+ Expr *pRight, *pLeft, *pDot;
+ pRight = wx_sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
+ wx_sqlite3ExprSetErrorOffset(pRight, (int)(yymsp[0].minor.yy0.z - pParse->zTail));
+ pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0);
+ pDot = wx_sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
+ yymsp[-4].minor.yy14 = wx_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, pDot);
}
break;
- case 103: /* as ::= AS nm */
- case 115: /* dbnm ::= DOT nm */ yytestcase(yyruleno==115);
- case 256: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==256);
- case 257: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==257);
+ case 105: /* as ::= AS nm */
+ case 117: /* dbnm ::= DOT nm */ yytestcase(yyruleno==117);
+ case 258: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==258);
+ case 259: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==259);
{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
break;
- case 105: /* from ::= */
- case 108: /* stl_prefix ::= */ yytestcase(yyruleno==108);
-{yymsp[1].minor.yy131 = 0;}
+ case 107: /* from ::= */
+ case 110: /* stl_prefix ::= */ yytestcase(yyruleno==110);
+{yymsp[1].minor.yy203 = 0;}
break;
- case 106: /* from ::= FROM seltablist */
+ case 108: /* from ::= FROM seltablist */
{
- yymsp[-1].minor.yy131 = yymsp[0].minor.yy131;
- wx_sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy131);
+ yymsp[-1].minor.yy203 = yymsp[0].minor.yy203;
+ wx_sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy203);
}
break;
- case 107: /* stl_prefix ::= seltablist joinop */
+ case 109: /* stl_prefix ::= seltablist joinop */
{
- if( ALWAYS(yymsp[-1].minor.yy131 && yymsp[-1].minor.yy131->nSrc>0) ) yymsp[-1].minor.yy131->a[yymsp[-1].minor.yy131->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy394;
+ if( ALWAYS(yymsp[-1].minor.yy203 && yymsp[-1].minor.yy203->nSrc>0) ) yymsp[-1].minor.yy203->a[yymsp[-1].minor.yy203->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy144;
}
break;
- case 109: /* seltablist ::= stl_prefix nm dbnm as on_using */
+ case 111: /* seltablist ::= stl_prefix nm dbnm as on_using */
{
- yymsp[-4].minor.yy131 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy131,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561);
+ yymsp[-4].minor.yy203 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy203,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
}
break;
- case 110: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
+ case 112: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
{
- yymsp[-5].minor.yy131 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy561);
- wx_sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-1].minor.yy0);
+ yymsp[-5].minor.yy203 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy269);
+ wx_sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-1].minor.yy0);
}
break;
- case 111: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
+ case 113: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
{
- yymsp[-7].minor.yy131 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy131,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561);
- wx_sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy131, yymsp[-3].minor.yy322);
+ yymsp[-7].minor.yy203 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy203,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
+ wx_sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy203, yymsp[-3].minor.yy14);
}
break;
- case 112: /* seltablist ::= stl_prefix LP select RP as on_using */
+ case 114: /* seltablist ::= stl_prefix LP select RP as on_using */
{
- yymsp[-5].minor.yy131 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy47,&yymsp[0].minor.yy561);
+ yymsp[-5].minor.yy203 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy555,&yymsp[0].minor.yy269);
}
break;
- case 113: /* seltablist ::= stl_prefix LP seltablist RP as on_using */
+ case 115: /* seltablist ::= stl_prefix LP seltablist RP as on_using */
{
- if( yymsp[-5].minor.yy131==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy561.pOn==0 && yymsp[0].minor.yy561.pUsing==0 ){
- yymsp[-5].minor.yy131 = yymsp[-3].minor.yy131;
- }else if( yymsp[-3].minor.yy131->nSrc==1 ){
- yymsp[-5].minor.yy131 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561);
- if( yymsp[-5].minor.yy131 ){
- SrcItem *pNew = &yymsp[-5].minor.yy131->a[yymsp[-5].minor.yy131->nSrc-1];
- SrcItem *pOld = yymsp[-3].minor.yy131->a;
+ if( yymsp[-5].minor.yy203==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy269.pOn==0 && yymsp[0].minor.yy269.pUsing==0 ){
+ yymsp[-5].minor.yy203 = yymsp[-3].minor.yy203;
+ }else if( ALWAYS(yymsp[-3].minor.yy203!=0) && yymsp[-3].minor.yy203->nSrc==1 ){
+ yymsp[-5].minor.yy203 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
+ if( yymsp[-5].minor.yy203 ){
+ SrcItem *pNew = &yymsp[-5].minor.yy203->a[yymsp[-5].minor.yy203->nSrc-1];
+ SrcItem *pOld = yymsp[-3].minor.yy203->a;
+ assert( pOld->fg.fixedSchema==0 );
pNew->zName = pOld->zName;
- pNew->zDatabase = pOld->zDatabase;
- pNew->pSelect = pOld->pSelect;
- if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){
- pNew->fg.isNestedFrom = 1;
+ assert( pOld->fg.fixedSchema==0 );
+ if( pOld->fg.isSubquery ){
+ pNew->fg.isSubquery = 1;
+ pNew->u4.pSubq = pOld->u4.pSubq;
+ pOld->u4.pSubq = 0;
+ pOld->fg.isSubquery = 0;
+ assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 );
+ if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){
+ pNew->fg.isNestedFrom = 1;
+ }
+ }else{
+ pNew->u4.zDatabase = pOld->u4.zDatabase;
+ pOld->u4.zDatabase = 0;
}
if( pOld->fg.isTabFunc ){
pNew->u1.pFuncArg = pOld->u1.pFuncArg;
@@ -170986,156 +178129,155 @@ static YYACTIONTYPE yy_reduce(
pOld->fg.isTabFunc = 0;
pNew->fg.isTabFunc = 1;
}
- pOld->zName = pOld->zDatabase = 0;
- pOld->pSelect = 0;
+ pOld->zName = 0;
}
- wx_sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy131);
+ wx_sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203);
}else{
Select *pSubquery;
- wx_sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy131);
- pSubquery = wx_sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy131,0,0,0,0,SF_NestedFrom,0);
- yymsp[-5].minor.yy131 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy561);
+ wx_sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy203);
+ pSubquery = wx_sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy203,0,0,0,0,SF_NestedFrom,0);
+ yymsp[-5].minor.yy203 = wx_sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy269);
}
}
break;
- case 114: /* dbnm ::= */
- case 129: /* indexed_opt ::= */ yytestcase(yyruleno==129);
+ case 116: /* dbnm ::= */
+ case 131: /* indexed_opt ::= */ yytestcase(yyruleno==131);
{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
break;
- case 116: /* fullname ::= nm */
+ case 118: /* fullname ::= nm */
{
- yylhsminor.yy131 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
- if( IN_RENAME_OBJECT && yylhsminor.yy131 ) wx_sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0);
+ yylhsminor.yy203 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
+ if( IN_RENAME_OBJECT && yylhsminor.yy203 ) wx_sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0);
}
- yymsp[0].minor.yy131 = yylhsminor.yy131;
+ yymsp[0].minor.yy203 = yylhsminor.yy203;
break;
- case 117: /* fullname ::= nm DOT nm */
+ case 119: /* fullname ::= nm DOT nm */
{
- yylhsminor.yy131 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
- if( IN_RENAME_OBJECT && yylhsminor.yy131 ) wx_sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0);
+ yylhsminor.yy203 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
+ if( IN_RENAME_OBJECT && yylhsminor.yy203 ) wx_sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0);
}
- yymsp[-2].minor.yy131 = yylhsminor.yy131;
+ yymsp[-2].minor.yy203 = yylhsminor.yy203;
break;
- case 118: /* xfullname ::= nm */
-{yymsp[0].minor.yy131 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
+ case 120: /* xfullname ::= nm */
+{yymsp[0].minor.yy203 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
break;
- case 119: /* xfullname ::= nm DOT nm */
-{yymsp[-2].minor.yy131 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 121: /* xfullname ::= nm DOT nm */
+{yymsp[-2].minor.yy203 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 120: /* xfullname ::= nm DOT nm AS nm */
+ case 122: /* xfullname ::= nm DOT nm AS nm */
{
- yymsp[-4].minor.yy131 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
- if( yymsp[-4].minor.yy131 ) yymsp[-4].minor.yy131->a[0].zAlias = wx_sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+ yymsp[-4].minor.yy203 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
+ if( yymsp[-4].minor.yy203 ) yymsp[-4].minor.yy203->a[0].zAlias = wx_sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
break;
- case 121: /* xfullname ::= nm AS nm */
+ case 123: /* xfullname ::= nm AS nm */
{
- yymsp[-2].minor.yy131 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
- if( yymsp[-2].minor.yy131 ) yymsp[-2].minor.yy131->a[0].zAlias = wx_sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+ yymsp[-2].minor.yy203 = wx_sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
+ if( yymsp[-2].minor.yy203 ) yymsp[-2].minor.yy203->a[0].zAlias = wx_sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
break;
- case 122: /* joinop ::= COMMA|JOIN */
-{ yymsp[0].minor.yy394 = JT_INNER; }
+ case 124: /* joinop ::= COMMA|JOIN */
+{ yymsp[0].minor.yy144 = JT_INNER; }
break;
- case 123: /* joinop ::= JOIN_KW JOIN */
-{yymsp[-1].minor.yy394 = wx_sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
+ case 125: /* joinop ::= JOIN_KW JOIN */
+{yymsp[-1].minor.yy144 = wx_sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
break;
- case 124: /* joinop ::= JOIN_KW nm JOIN */
-{yymsp[-2].minor.yy394 = wx_sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
+ case 126: /* joinop ::= JOIN_KW nm JOIN */
+{yymsp[-2].minor.yy144 = wx_sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
break;
- case 125: /* joinop ::= JOIN_KW nm nm JOIN */
-{yymsp[-3].minor.yy394 = wx_sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
+ case 127: /* joinop ::= JOIN_KW nm nm JOIN */
+{yymsp[-3].minor.yy144 = wx_sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
break;
- case 126: /* on_using ::= ON expr */
-{yymsp[-1].minor.yy561.pOn = yymsp[0].minor.yy528; yymsp[-1].minor.yy561.pUsing = 0;}
+ case 128: /* on_using ::= ON expr */
+{yymsp[-1].minor.yy269.pOn = yymsp[0].minor.yy454; yymsp[-1].minor.yy269.pUsing = 0;}
break;
- case 127: /* on_using ::= USING LP idlist RP */
-{yymsp[-3].minor.yy561.pOn = 0; yymsp[-3].minor.yy561.pUsing = yymsp[-1].minor.yy254;}
+ case 129: /* on_using ::= USING LP idlist RP */
+{yymsp[-3].minor.yy269.pOn = 0; yymsp[-3].minor.yy269.pUsing = yymsp[-1].minor.yy132;}
break;
- case 128: /* on_using ::= */
-{yymsp[1].minor.yy561.pOn = 0; yymsp[1].minor.yy561.pUsing = 0;}
+ case 130: /* on_using ::= */
+{yymsp[1].minor.yy269.pOn = 0; yymsp[1].minor.yy269.pUsing = 0;}
break;
- case 130: /* indexed_by ::= INDEXED BY nm */
+ case 132: /* indexed_by ::= INDEXED BY nm */
{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
break;
- case 131: /* indexed_by ::= NOT INDEXED */
+ case 133: /* indexed_by ::= NOT INDEXED */
{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
break;
- case 133: /* orderby_opt ::= ORDER BY sortlist */
- case 143: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==143);
-{yymsp[-2].minor.yy322 = yymsp[0].minor.yy322;}
+ case 135: /* orderby_opt ::= ORDER BY sortlist */
+ case 145: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==145);
+{yymsp[-2].minor.yy14 = yymsp[0].minor.yy14;}
break;
- case 134: /* sortlist ::= sortlist COMMA expr sortorder nulls */
+ case 136: /* sortlist ::= sortlist COMMA expr sortorder nulls */
{
- yymsp[-4].minor.yy322 = wx_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322,yymsp[-2].minor.yy528);
- wx_sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394);
+ yymsp[-4].minor.yy14 = wx_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14,yymsp[-2].minor.yy454);
+ wx_sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144);
}
break;
- case 135: /* sortlist ::= expr sortorder nulls */
+ case 137: /* sortlist ::= expr sortorder nulls */
{
- yymsp[-2].minor.yy322 = wx_sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy528); /*A-overwrites-Y*/
- wx_sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394);
+ yymsp[-2].minor.yy14 = wx_sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy454); /*A-overwrites-Y*/
+ wx_sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144);
}
break;
- case 136: /* sortorder ::= ASC */
-{yymsp[0].minor.yy394 = SQLITE_SO_ASC;}
+ case 138: /* sortorder ::= ASC */
+{yymsp[0].minor.yy144 = SQLITE_SO_ASC;}
break;
- case 137: /* sortorder ::= DESC */
-{yymsp[0].minor.yy394 = SQLITE_SO_DESC;}
+ case 139: /* sortorder ::= DESC */
+{yymsp[0].minor.yy144 = SQLITE_SO_DESC;}
break;
- case 138: /* sortorder ::= */
- case 141: /* nulls ::= */ yytestcase(yyruleno==141);
-{yymsp[1].minor.yy394 = SQLITE_SO_UNDEFINED;}
+ case 140: /* sortorder ::= */
+ case 143: /* nulls ::= */ yytestcase(yyruleno==143);
+{yymsp[1].minor.yy144 = SQLITE_SO_UNDEFINED;}
break;
- case 139: /* nulls ::= NULLS FIRST */
-{yymsp[-1].minor.yy394 = SQLITE_SO_ASC;}
+ case 141: /* nulls ::= NULLS FIRST */
+{yymsp[-1].minor.yy144 = SQLITE_SO_ASC;}
break;
- case 140: /* nulls ::= NULLS LAST */
-{yymsp[-1].minor.yy394 = SQLITE_SO_DESC;}
+ case 142: /* nulls ::= NULLS LAST */
+{yymsp[-1].minor.yy144 = SQLITE_SO_DESC;}
break;
- case 144: /* having_opt ::= */
- case 146: /* limit_opt ::= */ yytestcase(yyruleno==146);
- case 151: /* where_opt ::= */ yytestcase(yyruleno==151);
- case 153: /* where_opt_ret ::= */ yytestcase(yyruleno==153);
- case 229: /* case_else ::= */ yytestcase(yyruleno==229);
- case 231: /* case_operand ::= */ yytestcase(yyruleno==231);
- case 250: /* vinto ::= */ yytestcase(yyruleno==250);
-{yymsp[1].minor.yy528 = 0;}
+ case 146: /* having_opt ::= */
+ case 148: /* limit_opt ::= */ yytestcase(yyruleno==148);
+ case 153: /* where_opt ::= */ yytestcase(yyruleno==153);
+ case 155: /* where_opt_ret ::= */ yytestcase(yyruleno==155);
+ case 232: /* case_else ::= */ yytestcase(yyruleno==232);
+ case 233: /* case_operand ::= */ yytestcase(yyruleno==233);
+ case 252: /* vinto ::= */ yytestcase(yyruleno==252);
+{yymsp[1].minor.yy454 = 0;}
break;
- case 145: /* having_opt ::= HAVING expr */
- case 152: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==152);
- case 154: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==154);
- case 228: /* case_else ::= ELSE expr */ yytestcase(yyruleno==228);
- case 249: /* vinto ::= INTO expr */ yytestcase(yyruleno==249);
-{yymsp[-1].minor.yy528 = yymsp[0].minor.yy528;}
+ case 147: /* having_opt ::= HAVING expr */
+ case 154: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==154);
+ case 156: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==156);
+ case 231: /* case_else ::= ELSE expr */ yytestcase(yyruleno==231);
+ case 251: /* vinto ::= INTO expr */ yytestcase(yyruleno==251);
+{yymsp[-1].minor.yy454 = yymsp[0].minor.yy454;}
break;
- case 147: /* limit_opt ::= LIMIT expr */
-{yymsp[-1].minor.yy528 = wx_sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,0);}
+ case 149: /* limit_opt ::= LIMIT expr */
+{yymsp[-1].minor.yy454 = wx_sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,0);}
break;
- case 148: /* limit_opt ::= LIMIT expr OFFSET expr */
-{yymsp[-3].minor.yy528 = wx_sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
+ case 150: /* limit_opt ::= LIMIT expr OFFSET expr */
+{yymsp[-3].minor.yy454 = wx_sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
break;
- case 149: /* limit_opt ::= LIMIT expr COMMA expr */
-{yymsp[-3].minor.yy528 = wx_sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,yymsp[-2].minor.yy528);}
+ case 151: /* limit_opt ::= LIMIT expr COMMA expr */
+{yymsp[-3].minor.yy454 = wx_sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,yymsp[-2].minor.yy454);}
break;
- case 150: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
+ case 152: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
{
- wx_sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy131, &yymsp[-1].minor.yy0);
- wx_sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy131,yymsp[0].minor.yy528,0,0);
+ wx_sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy203, &yymsp[-1].minor.yy0);
+ wx_sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy203,yymsp[0].minor.yy454,0,0);
}
break;
- case 155: /* where_opt_ret ::= RETURNING selcollist */
-{wx_sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-1].minor.yy528 = 0;}
+ case 157: /* where_opt_ret ::= RETURNING selcollist */
+{wx_sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-1].minor.yy454 = 0;}
break;
- case 156: /* where_opt_ret ::= WHERE expr RETURNING selcollist */
-{wx_sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-3].minor.yy528 = yymsp[-2].minor.yy528;}
+ case 158: /* where_opt_ret ::= WHERE expr RETURNING selcollist */
+{wx_sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-3].minor.yy454 = yymsp[-2].minor.yy454;}
break;
- case 157: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
+ case 159: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
{
- wx_sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-4].minor.yy0);
- wx_sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy322,"set list");
- if( yymsp[-1].minor.yy131 ){
- SrcList *pFromClause = yymsp[-1].minor.yy131;
+ wx_sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-4].minor.yy0);
+ wx_sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy14,"set list");
+ if( yymsp[-1].minor.yy203 ){
+ SrcList *pFromClause = yymsp[-1].minor.yy203;
if( pFromClause->nSrc>1 ){
Select *pSubquery;
Token as;
@@ -171144,93 +178286,92 @@ static YYACTIONTYPE yy_reduce(
as.z = 0;
pFromClause = wx_sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0);
}
- yymsp[-5].minor.yy131 = wx_sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy131, pFromClause);
+ yymsp[-5].minor.yy203 = wx_sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy203, pFromClause);
}
- wx_sqlite3Update(pParse,yymsp[-5].minor.yy131,yymsp[-2].minor.yy322,yymsp[0].minor.yy528,yymsp[-6].minor.yy394,0,0,0);
+ wx_sqlite3Update(pParse,yymsp[-5].minor.yy203,yymsp[-2].minor.yy14,yymsp[0].minor.yy454,yymsp[-6].minor.yy144,0,0,0);
}
break;
- case 158: /* setlist ::= setlist COMMA nm EQ expr */
+ case 160: /* setlist ::= setlist COMMA nm EQ expr */
{
- yymsp[-4].minor.yy322 = wx_sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy528);
- wx_sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, 1);
+ yymsp[-4].minor.yy14 = wx_sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[0].minor.yy454);
+ wx_sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, 1);
}
break;
- case 159: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
+ case 161: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
{
- yymsp[-6].minor.yy322 = wx_sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy322, yymsp[-3].minor.yy254, yymsp[0].minor.yy528);
+ yymsp[-6].minor.yy14 = wx_sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy14, yymsp[-3].minor.yy132, yymsp[0].minor.yy454);
}
break;
- case 160: /* setlist ::= nm EQ expr */
+ case 162: /* setlist ::= nm EQ expr */
{
- yylhsminor.yy322 = wx_sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy528);
- wx_sqlite3ExprListSetName(pParse, yylhsminor.yy322, &yymsp[-2].minor.yy0, 1);
+ yylhsminor.yy14 = wx_sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy454);
+ wx_sqlite3ExprListSetName(pParse, yylhsminor.yy14, &yymsp[-2].minor.yy0, 1);
}
- yymsp[-2].minor.yy322 = yylhsminor.yy322;
+ yymsp[-2].minor.yy14 = yylhsminor.yy14;
break;
- case 161: /* setlist ::= LP idlist RP EQ expr */
+ case 163: /* setlist ::= LP idlist RP EQ expr */
{
- yymsp[-4].minor.yy322 = wx_sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy528);
+ yymsp[-4].minor.yy14 = wx_sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy132, yymsp[0].minor.yy454);
}
break;
- case 162: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ case 164: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
{
- wx_sqlite3Insert(pParse, yymsp[-3].minor.yy131, yymsp[-1].minor.yy47, yymsp[-2].minor.yy254, yymsp[-5].minor.yy394, yymsp[0].minor.yy444);
+ wx_sqlite3Insert(pParse, yymsp[-3].minor.yy203, yymsp[-1].minor.yy555, yymsp[-2].minor.yy132, yymsp[-5].minor.yy144, yymsp[0].minor.yy122);
}
break;
- case 163: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
+ case 165: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
{
- wx_sqlite3Insert(pParse, yymsp[-4].minor.yy131, 0, yymsp[-3].minor.yy254, yymsp[-6].minor.yy394, 0);
+ wx_sqlite3Insert(pParse, yymsp[-4].minor.yy203, 0, yymsp[-3].minor.yy132, yymsp[-6].minor.yy144, 0);
}
break;
- case 164: /* upsert ::= */
-{ yymsp[1].minor.yy444 = 0; }
+ case 166: /* upsert ::= */
+{ yymsp[1].minor.yy122 = 0; }
break;
- case 165: /* upsert ::= RETURNING selcollist */
-{ yymsp[-1].minor.yy444 = 0; wx_sqlite3AddReturning(pParse,yymsp[0].minor.yy322); }
+ case 167: /* upsert ::= RETURNING selcollist */
+{ yymsp[-1].minor.yy122 = 0; wx_sqlite3AddReturning(pParse,yymsp[0].minor.yy14); }
break;
- case 166: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
-{ yymsp[-11].minor.yy444 = wx_sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy322,yymsp[-6].minor.yy528,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,yymsp[0].minor.yy444);}
+ case 168: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
+{ yymsp[-11].minor.yy122 = wx_sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy14,yymsp[-6].minor.yy454,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,yymsp[0].minor.yy122);}
break;
- case 167: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
-{ yymsp[-8].minor.yy444 = wx_sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy322,yymsp[-3].minor.yy528,0,0,yymsp[0].minor.yy444); }
+ case 169: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
+{ yymsp[-8].minor.yy122 = wx_sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy14,yymsp[-3].minor.yy454,0,0,yymsp[0].minor.yy122); }
break;
- case 168: /* upsert ::= ON CONFLICT DO NOTHING returning */
-{ yymsp[-4].minor.yy444 = wx_sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
+ case 170: /* upsert ::= ON CONFLICT DO NOTHING returning */
+{ yymsp[-4].minor.yy122 = wx_sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
break;
- case 169: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
-{ yymsp[-7].minor.yy444 = wx_sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,0);}
+ case 171: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
+{ yymsp[-7].minor.yy122 = wx_sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,0);}
break;
- case 170: /* returning ::= RETURNING selcollist */
-{wx_sqlite3AddReturning(pParse,yymsp[0].minor.yy322);}
+ case 172: /* returning ::= RETURNING selcollist */
+{wx_sqlite3AddReturning(pParse,yymsp[0].minor.yy14);}
break;
- case 173: /* idlist_opt ::= */
-{yymsp[1].minor.yy254 = 0;}
+ case 175: /* idlist_opt ::= */
+{yymsp[1].minor.yy132 = 0;}
break;
- case 174: /* idlist_opt ::= LP idlist RP */
-{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;}
+ case 176: /* idlist_opt ::= LP idlist RP */
+{yymsp[-2].minor.yy132 = yymsp[-1].minor.yy132;}
break;
- case 175: /* idlist ::= idlist COMMA nm */
-{yymsp[-2].minor.yy254 = wx_sqlite3IdListAppend(pParse,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);}
+ case 177: /* idlist ::= idlist COMMA nm */
+{yymsp[-2].minor.yy132 = wx_sqlite3IdListAppend(pParse,yymsp[-2].minor.yy132,&yymsp[0].minor.yy0);}
break;
- case 176: /* idlist ::= nm */
-{yymsp[0].minor.yy254 = wx_sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
+ case 178: /* idlist ::= nm */
+{yymsp[0].minor.yy132 = wx_sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
break;
- case 177: /* expr ::= LP expr RP */
-{yymsp[-2].minor.yy528 = yymsp[-1].minor.yy528;}
+ case 179: /* expr ::= LP expr RP */
+{yymsp[-2].minor.yy454 = yymsp[-1].minor.yy454;}
break;
- case 178: /* expr ::= ID|INDEXED */
- case 179: /* expr ::= JOIN_KW */ yytestcase(yyruleno==179);
-{yymsp[0].minor.yy528=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 180: /* expr ::= ID|INDEXED|JOIN_KW */
+{yymsp[0].minor.yy454=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 180: /* expr ::= nm DOT nm */
+ case 181: /* expr ::= nm DOT nm */
{
Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0);
- yylhsminor.yy528 = wx_sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
+ yylhsminor.yy454 = wx_sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
}
- yymsp[-2].minor.yy528 = yylhsminor.yy528;
+ yymsp[-2].minor.yy454 = yylhsminor.yy454;
break;
- case 181: /* expr ::= nm DOT nm DOT nm */
+ case 182: /* expr ::= nm DOT nm DOT nm */
{
Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-4].minor.yy0);
Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
@@ -171239,27 +178380,27 @@ static YYACTIONTYPE yy_reduce(
if( IN_RENAME_OBJECT ){
wx_sqlite3RenameTokenRemap(pParse, 0, temp1);
}
- yylhsminor.yy528 = wx_sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
+ yylhsminor.yy454 = wx_sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
}
- yymsp[-4].minor.yy528 = yylhsminor.yy528;
+ yymsp[-4].minor.yy454 = yylhsminor.yy454;
break;
- case 182: /* term ::= NULL|FLOAT|BLOB */
- case 183: /* term ::= STRING */ yytestcase(yyruleno==183);
-{yymsp[0].minor.yy528=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 183: /* term ::= NULL|FLOAT|BLOB */
+ case 184: /* term ::= STRING */ yytestcase(yyruleno==184);
+{yymsp[0].minor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 184: /* term ::= INTEGER */
+ case 185: /* term ::= INTEGER */
{
- yylhsminor.yy528 = wx_sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
- if( yylhsminor.yy528 ) yylhsminor.yy528->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail);
+ yylhsminor.yy454 = wx_sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
+ if( yylhsminor.yy454 ) yylhsminor.yy454->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail);
}
- yymsp[0].minor.yy528 = yylhsminor.yy528;
+ yymsp[0].minor.yy454 = yylhsminor.yy454;
break;
- case 185: /* expr ::= VARIABLE */
+ case 186: /* expr ::= VARIABLE */
{
if( !(yymsp[0].minor.yy0.z[0]=='#' && wx_sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
u32 n = yymsp[0].minor.yy0.n;
- yymsp[0].minor.yy528 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
- wx_sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy528, n);
+ yymsp[0].minor.yy454 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
+ wx_sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy454, n);
}else{
/* When doing a nested parse, one can include terms in an expression
** that look like this: #1 #2 ... These terms refer to registers
@@ -171268,179 +178409,203 @@ static YYACTIONTYPE yy_reduce(
assert( t.n>=2 );
if( pParse->nested==0 ){
wx_sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
- yymsp[0].minor.yy528 = 0;
+ yymsp[0].minor.yy454 = 0;
}else{
- yymsp[0].minor.yy528 = wx_sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
- if( yymsp[0].minor.yy528 ) wx_sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy528->iTable);
+ yymsp[0].minor.yy454 = wx_sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
+ if( yymsp[0].minor.yy454 ) wx_sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy454->iTable);
}
}
}
break;
- case 186: /* expr ::= expr COLLATE ID|STRING */
+ case 187: /* expr ::= expr COLLATE ID|STRING */
{
- yymsp[-2].minor.yy528 = wx_sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy528, &yymsp[0].minor.yy0, 1);
+ yymsp[-2].minor.yy454 = wx_sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy454, &yymsp[0].minor.yy0, 1);
}
break;
- case 187: /* expr ::= CAST LP expr AS typetoken RP */
+ case 188: /* expr ::= CAST LP expr AS typetoken RP */
{
- yymsp[-5].minor.yy528 = wx_sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
- wx_sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy528, yymsp[-3].minor.yy528, 0);
+ yymsp[-5].minor.yy454 = wx_sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
+ wx_sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy454, yymsp[-3].minor.yy454, 0);
}
break;
- case 188: /* expr ::= ID|INDEXED LP distinct exprlist RP */
+ case 189: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
{
- yylhsminor.yy528 = wx_sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy394);
+ yylhsminor.yy454 = wx_sqlite3ExprFunction(pParse, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy144);
}
- yymsp[-4].minor.yy528 = yylhsminor.yy528;
+ yymsp[-4].minor.yy454 = yylhsminor.yy454;
break;
- case 189: /* expr ::= ID|INDEXED LP STAR RP */
+ case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
{
- yylhsminor.yy528 = wx_sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
+ yylhsminor.yy454 = wx_sqlite3ExprFunction(pParse, yymsp[-4].minor.yy14, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy144);
+ wx_sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-1].minor.yy14);
}
- yymsp[-3].minor.yy528 = yylhsminor.yy528;
+ yymsp[-7].minor.yy454 = yylhsminor.yy454;
break;
- case 190: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
+ case 191: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
{
- yylhsminor.yy528 = wx_sqlite3ExprFunction(pParse, yymsp[-2].minor.yy322, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy394);
- wx_sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41);
+ yylhsminor.yy454 = wx_sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
}
- yymsp[-5].minor.yy528 = yylhsminor.yy528;
+ yymsp[-3].minor.yy454 = yylhsminor.yy454;
break;
- case 191: /* expr ::= ID|INDEXED LP STAR RP filter_over */
+ case 192: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
{
- yylhsminor.yy528 = wx_sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
- wx_sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41);
+ yylhsminor.yy454 = wx_sqlite3ExprFunction(pParse, yymsp[-2].minor.yy14, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy144);
+ wx_sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
}
- yymsp[-4].minor.yy528 = yylhsminor.yy528;
+ yymsp[-5].minor.yy454 = yylhsminor.yy454;
break;
- case 192: /* term ::= CTIME_KW */
+ case 193: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
{
- yylhsminor.yy528 = wx_sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
+ yylhsminor.yy454 = wx_sqlite3ExprFunction(pParse, yymsp[-5].minor.yy14, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy144);
+ wx_sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
+ wx_sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-2].minor.yy14);
}
- yymsp[0].minor.yy528 = yylhsminor.yy528;
+ yymsp[-8].minor.yy454 = yylhsminor.yy454;
break;
- case 193: /* expr ::= LP nexprlist COMMA expr RP */
+ case 194: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
{
- ExprList *pList = wx_sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528);
- yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
- if( yymsp[-4].minor.yy528 ){
- yymsp[-4].minor.yy528->x.pList = pList;
+ yylhsminor.yy454 = wx_sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
+ wx_sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
+}
+ yymsp[-4].minor.yy454 = yylhsminor.yy454;
+ break;
+ case 195: /* term ::= CTIME_KW */
+{
+ yylhsminor.yy454 = wx_sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
+}
+ yymsp[0].minor.yy454 = yylhsminor.yy454;
+ break;
+ case 196: /* expr ::= LP nexprlist COMMA expr RP */
+{
+ ExprList *pList = wx_sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454);
+ yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
+ if( yymsp[-4].minor.yy454 ){
+ yymsp[-4].minor.yy454->x.pList = pList;
if( ALWAYS(pList->nExpr) ){
- yymsp[-4].minor.yy528->flags |= pList->a[0].pExpr->flags & EP_Propagate;
+ yymsp[-4].minor.yy454->flags |= pList->a[0].pExpr->flags & EP_Propagate;
}
}else{
wx_sqlite3ExprListDelete(pParse->db, pList);
}
}
break;
- case 194: /* expr ::= expr AND expr */
-{yymsp[-2].minor.yy528=wx_sqlite3ExprAnd(pParse,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
+ case 197: /* expr ::= expr AND expr */
+{yymsp[-2].minor.yy454=wx_sqlite3ExprAnd(pParse,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
break;
- case 195: /* expr ::= expr OR expr */
- case 196: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==196);
- case 197: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==197);
- case 198: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==198);
- case 199: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==199);
- case 200: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==200);
- case 201: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==201);
-{yymsp[-2].minor.yy528=wx_sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
+ case 198: /* expr ::= expr OR expr */
+ case 199: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==199);
+ case 200: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==200);
+ case 201: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==201);
+ case 202: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==202);
+ case 203: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==203);
+ case 204: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==204);
+{yymsp[-2].minor.yy454=wx_sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
break;
- case 202: /* likeop ::= NOT LIKE_KW|MATCH */
+ case 205: /* likeop ::= NOT LIKE_KW|MATCH */
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
break;
- case 203: /* expr ::= expr likeop expr */
+ case 206: /* expr ::= expr likeop expr */
{
ExprList *pList;
int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
yymsp[-1].minor.yy0.n &= 0x7fffffff;
- pList = wx_sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy528);
- pList = wx_sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy528);
- yymsp[-2].minor.yy528 = wx_sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
- if( bNot ) yymsp[-2].minor.yy528 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy528, 0);
- if( yymsp[-2].minor.yy528 ) yymsp[-2].minor.yy528->flags |= EP_InfixFunc;
+ pList = wx_sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy454);
+ pList = wx_sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy454);
+ yymsp[-2].minor.yy454 = wx_sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
+ if( bNot ) yymsp[-2].minor.yy454 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy454, 0);
+ if( yymsp[-2].minor.yy454 ) yymsp[-2].minor.yy454->flags |= EP_InfixFunc;
}
break;
- case 204: /* expr ::= expr likeop expr ESCAPE expr */
+ case 207: /* expr ::= expr likeop expr ESCAPE expr */
{
ExprList *pList;
int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
yymsp[-3].minor.yy0.n &= 0x7fffffff;
- pList = wx_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
- pList = wx_sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy528);
- pList = wx_sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528);
- yymsp[-4].minor.yy528 = wx_sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
- if( bNot ) yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
- if( yymsp[-4].minor.yy528 ) yymsp[-4].minor.yy528->flags |= EP_InfixFunc;
+ pList = wx_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
+ pList = wx_sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy454);
+ pList = wx_sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454);
+ yymsp[-4].minor.yy454 = wx_sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
+ if( bNot ) yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454 ) yymsp[-4].minor.yy454->flags |= EP_InfixFunc;
}
break;
- case 205: /* expr ::= expr ISNULL|NOTNULL */
-{yymsp[-1].minor.yy528 = wx_sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy528,0);}
+ case 208: /* expr ::= expr ISNULL|NOTNULL */
+{yymsp[-1].minor.yy454 = wx_sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy454,0);}
break;
- case 206: /* expr ::= expr NOT NULL */
-{yymsp[-2].minor.yy528 = wx_sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy528,0);}
+ case 209: /* expr ::= expr NOT NULL */
+{yymsp[-2].minor.yy454 = wx_sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy454,0);}
break;
- case 207: /* expr ::= expr IS expr */
+ case 210: /* expr ::= expr IS expr */
{
- yymsp[-2].minor.yy528 = wx_sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-2].minor.yy528, TK_ISNULL);
+ yymsp[-2].minor.yy454 = wx_sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-2].minor.yy454, TK_ISNULL);
}
break;
- case 208: /* expr ::= expr IS NOT expr */
+ case 211: /* expr ::= expr IS NOT expr */
{
- yymsp[-3].minor.yy528 = wx_sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy528,yymsp[0].minor.yy528);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-3].minor.yy528, TK_NOTNULL);
+ yymsp[-3].minor.yy454 = wx_sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-3].minor.yy454, TK_NOTNULL);
}
break;
- case 209: /* expr ::= expr IS NOT DISTINCT FROM expr */
+ case 212: /* expr ::= expr IS NOT DISTINCT FROM expr */
{
- yymsp[-5].minor.yy528 = wx_sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy528,yymsp[0].minor.yy528);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-5].minor.yy528, TK_ISNULL);
+ yymsp[-5].minor.yy454 = wx_sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-5].minor.yy454, TK_ISNULL);
}
break;
- case 210: /* expr ::= expr IS DISTINCT FROM expr */
+ case 213: /* expr ::= expr IS DISTINCT FROM expr */
{
- yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy528,yymsp[0].minor.yy528);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-4].minor.yy528, TK_NOTNULL);
+ yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-4].minor.yy454, TK_NOTNULL);
}
break;
- case 211: /* expr ::= NOT expr */
- case 212: /* expr ::= BITNOT expr */ yytestcase(yyruleno==212);
-{yymsp[-1].minor.yy528 = wx_sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy528, 0);/*A-overwrites-B*/}
+ case 214: /* expr ::= NOT expr */
+ case 215: /* expr ::= BITNOT expr */ yytestcase(yyruleno==215);
+{yymsp[-1].minor.yy454 = wx_sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy454, 0);/*A-overwrites-B*/}
break;
- case 213: /* expr ::= PLUS|MINUS expr */
+ case 216: /* expr ::= PLUS|MINUS expr */
{
- yymsp[-1].minor.yy528 = wx_sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy528, 0);
- /*A-overwrites-B*/
+ Expr *p = yymsp[0].minor.yy454;
+ u8 op = yymsp[-1].major + (TK_UPLUS-TK_PLUS);
+ assert( TK_UPLUS>TK_PLUS );
+ assert( TK_UMINUS == TK_MINUS + (TK_UPLUS - TK_PLUS) );
+ if( p && p->op==TK_UPLUS ){
+ p->op = op;
+ yymsp[-1].minor.yy454 = p;
+ }else{
+ yymsp[-1].minor.yy454 = wx_sqlite3PExpr(pParse, op, p, 0);
+ /*A-overwrites-B*/
+ }
}
break;
- case 214: /* expr ::= expr PTR expr */
+ case 217: /* expr ::= expr PTR expr */
{
- ExprList *pList = wx_sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy528);
- pList = wx_sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy528);
- yylhsminor.yy528 = wx_sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
+ ExprList *pList = wx_sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy454);
+ pList = wx_sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy454);
+ yylhsminor.yy454 = wx_sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
}
- yymsp[-2].minor.yy528 = yylhsminor.yy528;
+ yymsp[-2].minor.yy454 = yylhsminor.yy454;
break;
- case 215: /* between_op ::= BETWEEN */
- case 218: /* in_op ::= IN */ yytestcase(yyruleno==218);
-{yymsp[0].minor.yy394 = 0;}
+ case 218: /* between_op ::= BETWEEN */
+ case 221: /* in_op ::= IN */ yytestcase(yyruleno==221);
+{yymsp[0].minor.yy144 = 0;}
break;
- case 217: /* expr ::= expr between_op expr AND expr */
+ case 220: /* expr ::= expr between_op expr AND expr */
{
- ExprList *pList = wx_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
- pList = wx_sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528);
- yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy528, 0);
- if( yymsp[-4].minor.yy528 ){
- yymsp[-4].minor.yy528->x.pList = pList;
+ ExprList *pList = wx_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
+ pList = wx_sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454);
+ yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454 ){
+ yymsp[-4].minor.yy454->x.pList = pList;
}else{
wx_sqlite3ExprListDelete(pParse->db, pList);
}
- if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
break;
- case 220: /* expr ::= expr in_op LP exprlist RP */
+ case 223: /* expr ::= expr in_op LP exprlist RP */
{
- if( yymsp[-1].minor.yy322==0 ){
+ if( yymsp[-1].minor.yy14==0 ){
/* Expressions of the form
**
** expr1 IN ()
@@ -171449,211 +178614,208 @@ static YYACTIONTYPE yy_reduce(
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
- wx_sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy528);
- yymsp[-4].minor.yy528 = wx_sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy394 ? "true" : "false");
- if( yymsp[-4].minor.yy528 ) wx_sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy528);
+ wx_sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy454);
+ yymsp[-4].minor.yy454 = wx_sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy144 ? "true" : "false");
+ if( yymsp[-4].minor.yy454 ) wx_sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy454);
}else{
- Expr *pRHS = yymsp[-1].minor.yy322->a[0].pExpr;
- if( yymsp[-1].minor.yy322->nExpr==1 && wx_sqlite3ExprIsConstant(pRHS) && yymsp[-4].minor.yy528->op!=TK_VECTOR ){
- yymsp[-1].minor.yy322->a[0].pExpr = 0;
- wx_sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
+ Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr;
+ if( yymsp[-1].minor.yy14->nExpr==1 && wx_sqlite3ExprIsConstant(pParse,pRHS) && yymsp[-4].minor.yy454->op!=TK_VECTOR ){
+ yymsp[-1].minor.yy14->a[0].pExpr = 0;
+ wx_sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
pRHS = wx_sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
- yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy528, pRHS);
- }else if( yymsp[-1].minor.yy322->nExpr==1 && pRHS->op==TK_SELECT ){
- yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
- wx_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pRHS->x.pSelect);
+ yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy454, pRHS);
+ }else if( yymsp[-1].minor.yy14->nExpr==1 && pRHS->op==TK_SELECT ){
+ yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ wx_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pRHS->x.pSelect);
pRHS->x.pSelect = 0;
- wx_sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
+ wx_sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
}else{
- yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
- if( yymsp[-4].minor.yy528==0 ){
- wx_sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
- }else if( yymsp[-4].minor.yy528->pLeft->op==TK_VECTOR ){
- int nExpr = yymsp[-4].minor.yy528->pLeft->x.pList->nExpr;
- Select *pSelectRHS = wx_sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy322);
+ yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454==0 ){
+ wx_sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
+ }else if( yymsp[-4].minor.yy454->pLeft->op==TK_VECTOR ){
+ int nExpr = yymsp[-4].minor.yy454->pLeft->x.pList->nExpr;
+ Select *pSelectRHS = wx_sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy14);
if( pSelectRHS ){
parserDoubleLinkSelect(pParse, pSelectRHS);
- wx_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelectRHS);
+ wx_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelectRHS);
}
}else{
- yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy322;
- wx_sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528);
+ yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy14;
+ wx_sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454);
}
}
- if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
}
break;
- case 221: /* expr ::= LP select RP */
+ case 224: /* expr ::= LP select RP */
{
- yymsp[-2].minor.yy528 = wx_sqlite3PExpr(pParse, TK_SELECT, 0, 0);
- wx_sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy528, yymsp[-1].minor.yy47);
+ yymsp[-2].minor.yy454 = wx_sqlite3PExpr(pParse, TK_SELECT, 0, 0);
+ wx_sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy454, yymsp[-1].minor.yy555);
}
break;
- case 222: /* expr ::= expr in_op LP select RP */
+ case 225: /* expr ::= expr in_op LP select RP */
{
- yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
- wx_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, yymsp[-1].minor.yy47);
- if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
+ yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ wx_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, yymsp[-1].minor.yy555);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
break;
- case 223: /* expr ::= expr in_op nm dbnm paren_exprlist */
+ case 226: /* expr ::= expr in_op nm dbnm paren_exprlist */
{
SrcList *pSrc = wx_sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
Select *pSelect = wx_sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
- if( yymsp[0].minor.yy322 ) wx_sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy322);
- yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
- wx_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelect);
- if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
+ if( yymsp[0].minor.yy14 ) wx_sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy14);
+ yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ wx_sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelect);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
break;
- case 224: /* expr ::= EXISTS LP select RP */
+ case 227: /* expr ::= EXISTS LP select RP */
{
Expr *p;
- p = yymsp[-3].minor.yy528 = wx_sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
- wx_sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy47);
+ p = yymsp[-3].minor.yy454 = wx_sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
+ wx_sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy555);
}
break;
- case 225: /* expr ::= CASE case_operand case_exprlist case_else END */
+ case 228: /* expr ::= CASE case_operand case_exprlist case_else END */
{
- yymsp[-4].minor.yy528 = wx_sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy528, 0);
- if( yymsp[-4].minor.yy528 ){
- yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy528 ? wx_sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528) : yymsp[-2].minor.yy322;
- wx_sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528);
+ yymsp[-4].minor.yy454 = wx_sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454 ){
+ yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy454 ? wx_sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454) : yymsp[-2].minor.yy14;
+ wx_sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454);
}else{
- wx_sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322);
- wx_sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528);
+ wx_sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14);
+ wx_sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454);
}
}
break;
- case 226: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ case 229: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
- yymsp[-4].minor.yy322 = wx_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy528);
- yymsp[-4].minor.yy322 = wx_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy528);
+ yymsp[-4].minor.yy14 = wx_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[-2].minor.yy454);
+ yymsp[-4].minor.yy14 = wx_sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[0].minor.yy454);
}
break;
- case 227: /* case_exprlist ::= WHEN expr THEN expr */
+ case 230: /* case_exprlist ::= WHEN expr THEN expr */
{
- yymsp[-3].minor.yy322 = wx_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
- yymsp[-3].minor.yy322 = wx_sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy528);
+ yymsp[-3].minor.yy14 = wx_sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
+ yymsp[-3].minor.yy14 = wx_sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14, yymsp[0].minor.yy454);
}
break;
- case 230: /* case_operand ::= expr */
-{yymsp[0].minor.yy528 = yymsp[0].minor.yy528; /*A-overwrites-X*/}
+ case 235: /* nexprlist ::= nexprlist COMMA expr */
+{yymsp[-2].minor.yy14 = wx_sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[0].minor.yy454);}
break;
- case 233: /* nexprlist ::= nexprlist COMMA expr */
-{yymsp[-2].minor.yy322 = wx_sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy528);}
+ case 236: /* nexprlist ::= expr */
+{yymsp[0].minor.yy14 = wx_sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy454); /*A-overwrites-Y*/}
break;
- case 234: /* nexprlist ::= expr */
-{yymsp[0].minor.yy322 = wx_sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy528); /*A-overwrites-Y*/}
+ case 238: /* paren_exprlist ::= LP exprlist RP */
+ case 243: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==243);
+{yymsp[-2].minor.yy14 = yymsp[-1].minor.yy14;}
break;
- case 236: /* paren_exprlist ::= LP exprlist RP */
- case 241: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==241);
-{yymsp[-2].minor.yy322 = yymsp[-1].minor.yy322;}
- break;
- case 237: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ case 239: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
{
wx_sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
- wx_sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy394,
- &yymsp[-11].minor.yy0, yymsp[0].minor.yy528, SQLITE_SO_ASC, yymsp[-8].minor.yy394, SQLITE_IDXTYPE_APPDEF);
+ wx_sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy14, yymsp[-10].minor.yy144,
+ &yymsp[-11].minor.yy0, yymsp[0].minor.yy454, SQLITE_SO_ASC, yymsp[-8].minor.yy144, SQLITE_IDXTYPE_APPDEF);
if( IN_RENAME_OBJECT && pParse->pNewIndex ){
wx_sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0);
}
}
break;
- case 238: /* uniqueflag ::= UNIQUE */
- case 280: /* raisetype ::= ABORT */ yytestcase(yyruleno==280);
-{yymsp[0].minor.yy394 = OE_Abort;}
+ case 240: /* uniqueflag ::= UNIQUE */
+ case 282: /* raisetype ::= ABORT */ yytestcase(yyruleno==282);
+{yymsp[0].minor.yy144 = OE_Abort;}
break;
- case 239: /* uniqueflag ::= */
-{yymsp[1].minor.yy394 = OE_None;}
+ case 241: /* uniqueflag ::= */
+{yymsp[1].minor.yy144 = OE_None;}
break;
- case 242: /* eidlist ::= eidlist COMMA nm collate sortorder */
+ case 244: /* eidlist ::= eidlist COMMA nm collate sortorder */
{
- yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394);
+ yymsp[-4].minor.yy14 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144);
}
break;
- case 243: /* eidlist ::= nm collate sortorder */
+ case 245: /* eidlist ::= nm collate sortorder */
{
- yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); /*A-overwrites-Y*/
+ yymsp[-2].minor.yy14 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144); /*A-overwrites-Y*/
}
break;
- case 246: /* cmd ::= DROP INDEX ifexists fullname */
-{wx_sqlite3DropIndex(pParse, yymsp[0].minor.yy131, yymsp[-1].minor.yy394);}
+ case 248: /* cmd ::= DROP INDEX ifexists fullname */
+{wx_sqlite3DropIndex(pParse, yymsp[0].minor.yy203, yymsp[-1].minor.yy144);}
break;
- case 247: /* cmd ::= VACUUM vinto */
-{wx_sqlite3Vacuum(pParse,0,yymsp[0].minor.yy528);}
+ case 249: /* cmd ::= VACUUM vinto */
+{wx_sqlite3Vacuum(pParse,0,yymsp[0].minor.yy454);}
break;
- case 248: /* cmd ::= VACUUM nm vinto */
-{wx_sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy528);}
+ case 250: /* cmd ::= VACUUM nm vinto */
+{wx_sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy454);}
break;
- case 251: /* cmd ::= PRAGMA nm dbnm */
+ case 253: /* cmd ::= PRAGMA nm dbnm */
{wx_sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
break;
- case 252: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+ case 254: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{wx_sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
break;
- case 253: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ case 255: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{wx_sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
break;
- case 254: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
+ case 256: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{wx_sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
break;
- case 255: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ case 257: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
{wx_sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
break;
- case 258: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ case 260: /* 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;
- wx_sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy33, &all);
+ wx_sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy427, &all);
}
break;
- case 259: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ case 261: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
{
- wx_sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy394, yymsp[-4].minor.yy180.a, yymsp[-4].minor.yy180.b, yymsp[-2].minor.yy131, yymsp[0].minor.yy528, yymsp[-10].minor.yy394, yymsp[-8].minor.yy394);
+ wx_sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy144, yymsp[-4].minor.yy286.a, yymsp[-4].minor.yy286.b, yymsp[-2].minor.yy203, yymsp[0].minor.yy454, yymsp[-10].minor.yy144, yymsp[-8].minor.yy144);
yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
}
break;
- case 260: /* trigger_time ::= BEFORE|AFTER */
-{ yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/ }
+ case 262: /* trigger_time ::= BEFORE|AFTER */
+{ yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/ }
break;
- case 261: /* trigger_time ::= INSTEAD OF */
-{ yymsp[-1].minor.yy394 = TK_INSTEAD;}
+ case 263: /* trigger_time ::= INSTEAD OF */
+{ yymsp[-1].minor.yy144 = TK_INSTEAD;}
break;
- case 262: /* trigger_time ::= */
-{ yymsp[1].minor.yy394 = TK_BEFORE; }
+ case 264: /* trigger_time ::= */
+{ yymsp[1].minor.yy144 = TK_BEFORE; }
break;
- case 263: /* trigger_event ::= DELETE|INSERT */
- case 264: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==264);
-{yymsp[0].minor.yy180.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy180.b = 0;}
+ case 265: /* trigger_event ::= DELETE|INSERT */
+ case 266: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==266);
+{yymsp[0].minor.yy286.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy286.b = 0;}
break;
- case 265: /* trigger_event ::= UPDATE OF idlist */
-{yymsp[-2].minor.yy180.a = TK_UPDATE; yymsp[-2].minor.yy180.b = yymsp[0].minor.yy254;}
+ case 267: /* trigger_event ::= UPDATE OF idlist */
+{yymsp[-2].minor.yy286.a = TK_UPDATE; yymsp[-2].minor.yy286.b = yymsp[0].minor.yy132;}
break;
- case 266: /* when_clause ::= */
- case 285: /* key_opt ::= */ yytestcase(yyruleno==285);
-{ yymsp[1].minor.yy528 = 0; }
+ case 268: /* when_clause ::= */
+ case 287: /* key_opt ::= */ yytestcase(yyruleno==287);
+{ yymsp[1].minor.yy454 = 0; }
break;
- case 267: /* when_clause ::= WHEN expr */
- case 286: /* key_opt ::= KEY expr */ yytestcase(yyruleno==286);
-{ yymsp[-1].minor.yy528 = yymsp[0].minor.yy528; }
+ case 269: /* when_clause ::= WHEN expr */
+ case 288: /* key_opt ::= KEY expr */ yytestcase(yyruleno==288);
+{ yymsp[-1].minor.yy454 = yymsp[0].minor.yy454; }
break;
- case 268: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ case 270: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
- assert( yymsp[-2].minor.yy33!=0 );
- yymsp[-2].minor.yy33->pLast->pNext = yymsp[-1].minor.yy33;
- yymsp[-2].minor.yy33->pLast = yymsp[-1].minor.yy33;
+ assert( yymsp[-2].minor.yy427!=0 );
+ yymsp[-2].minor.yy427->pLast->pNext = yymsp[-1].minor.yy427;
+ yymsp[-2].minor.yy427->pLast = yymsp[-1].minor.yy427;
}
break;
- case 269: /* trigger_cmd_list ::= trigger_cmd SEMI */
+ case 271: /* trigger_cmd_list ::= trigger_cmd SEMI */
{
- assert( yymsp[-1].minor.yy33!=0 );
- yymsp[-1].minor.yy33->pLast = yymsp[-1].minor.yy33;
+ assert( yymsp[-1].minor.yy427!=0 );
+ yymsp[-1].minor.yy427->pLast = yymsp[-1].minor.yy427;
}
break;
- case 270: /* trnm ::= nm DOT nm */
+ case 272: /* trnm ::= nm DOT nm */
{
yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
wx_sqlite3ErrorMsg(pParse,
@@ -171661,370 +178823,377 @@ static YYACTIONTYPE yy_reduce(
"statements within triggers");
}
break;
- case 271: /* tridxby ::= INDEXED BY nm */
+ case 273: /* tridxby ::= INDEXED BY nm */
{
wx_sqlite3ErrorMsg(pParse,
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 272: /* tridxby ::= NOT INDEXED */
+ case 274: /* tridxby ::= NOT INDEXED */
{
wx_sqlite3ErrorMsg(pParse,
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 273: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
-{yylhsminor.yy33 = wx_sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy131, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528, yymsp[-7].minor.yy394, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy522);}
- yymsp[-8].minor.yy33 = yylhsminor.yy33;
+ case 275: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+{yylhsminor.yy427 = wx_sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy203, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454, yymsp[-7].minor.yy144, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy168);}
+ yymsp[-8].minor.yy427 = yylhsminor.yy427;
break;
- case 274: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ case 276: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
{
- yylhsminor.yy33 = wx_sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy254,yymsp[-2].minor.yy47,yymsp[-6].minor.yy394,yymsp[-1].minor.yy444,yymsp[-7].minor.yy522,yymsp[0].minor.yy522);/*yylhsminor.yy33-overwrites-yymsp[-6].minor.yy394*/
+ yylhsminor.yy427 = wx_sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy132,yymsp[-2].minor.yy555,yymsp[-6].minor.yy144,yymsp[-1].minor.yy122,yymsp[-7].minor.yy168,yymsp[0].minor.yy168);/*yylhsminor.yy427-overwrites-yymsp[-6].minor.yy144*/
}
- yymsp[-7].minor.yy33 = yylhsminor.yy33;
+ yymsp[-7].minor.yy427 = yylhsminor.yy427;
break;
- case 275: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
-{yylhsminor.yy33 = wx_sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy528, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy522);}
- yymsp[-5].minor.yy33 = yylhsminor.yy33;
+ case 277: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+{yylhsminor.yy427 = wx_sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy454, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy168);}
+ yymsp[-5].minor.yy427 = yylhsminor.yy427;
break;
- case 276: /* trigger_cmd ::= scanpt select scanpt */
-{yylhsminor.yy33 = wx_sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy47, yymsp[-2].minor.yy522, yymsp[0].minor.yy522); /*yylhsminor.yy33-overwrites-yymsp[-1].minor.yy47*/}
- yymsp[-2].minor.yy33 = yylhsminor.yy33;
+ case 278: /* trigger_cmd ::= scanpt select scanpt */
+{yylhsminor.yy427 = wx_sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy555, yymsp[-2].minor.yy168, yymsp[0].minor.yy168); /*yylhsminor.yy427-overwrites-yymsp[-1].minor.yy555*/}
+ yymsp[-2].minor.yy427 = yylhsminor.yy427;
break;
- case 277: /* expr ::= RAISE LP IGNORE RP */
+ case 279: /* expr ::= RAISE LP IGNORE RP */
{
- yymsp[-3].minor.yy528 = wx_sqlite3PExpr(pParse, TK_RAISE, 0, 0);
- if( yymsp[-3].minor.yy528 ){
- yymsp[-3].minor.yy528->affExpr = OE_Ignore;
+ yymsp[-3].minor.yy454 = wx_sqlite3PExpr(pParse, TK_RAISE, 0, 0);
+ if( yymsp[-3].minor.yy454 ){
+ yymsp[-3].minor.yy454->affExpr = OE_Ignore;
}
}
break;
- case 278: /* expr ::= RAISE LP raisetype COMMA nm RP */
+ case 280: /* expr ::= RAISE LP raisetype COMMA expr RP */
{
- yymsp[-5].minor.yy528 = wx_sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
- if( yymsp[-5].minor.yy528 ) {
- yymsp[-5].minor.yy528->affExpr = (char)yymsp[-3].minor.yy394;
+ yymsp[-5].minor.yy454 = wx_sqlite3PExpr(pParse, TK_RAISE, yymsp[-1].minor.yy454, 0);
+ if( yymsp[-5].minor.yy454 ) {
+ yymsp[-5].minor.yy454->affExpr = (char)yymsp[-3].minor.yy144;
}
}
break;
- case 279: /* raisetype ::= ROLLBACK */
-{yymsp[0].minor.yy394 = OE_Rollback;}
+ case 281: /* raisetype ::= ROLLBACK */
+{yymsp[0].minor.yy144 = OE_Rollback;}
break;
- case 281: /* raisetype ::= FAIL */
-{yymsp[0].minor.yy394 = OE_Fail;}
+ case 283: /* raisetype ::= FAIL */
+{yymsp[0].minor.yy144 = OE_Fail;}
break;
- case 282: /* cmd ::= DROP TRIGGER ifexists fullname */
+ case 284: /* cmd ::= DROP TRIGGER ifexists fullname */
{
- wx_sqlite3DropTrigger(pParse,yymsp[0].minor.yy131,yymsp[-1].minor.yy394);
+ wx_sqlite3DropTrigger(pParse,yymsp[0].minor.yy203,yymsp[-1].minor.yy144);
}
break;
- case 283: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ case 285: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
- wx_sqlite3Attach(pParse, yymsp[-3].minor.yy528, yymsp[-1].minor.yy528, yymsp[0].minor.yy528);
+ wx_sqlite3Attach(pParse, yymsp[-3].minor.yy454, yymsp[-1].minor.yy454, yymsp[0].minor.yy454);
}
break;
- case 284: /* cmd ::= DETACH database_kw_opt expr */
+ case 286: /* cmd ::= DETACH database_kw_opt expr */
{
- wx_sqlite3Detach(pParse, yymsp[0].minor.yy528);
+ wx_sqlite3Detach(pParse, yymsp[0].minor.yy454);
}
break;
- case 287: /* cmd ::= REINDEX */
+ case 289: /* cmd ::= REINDEX */
{wx_sqlite3Reindex(pParse, 0, 0);}
break;
- case 288: /* cmd ::= REINDEX nm dbnm */
+ case 290: /* cmd ::= REINDEX nm dbnm */
{wx_sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 289: /* cmd ::= ANALYZE */
+ case 291: /* cmd ::= ANALYZE */
{wx_sqlite3Analyze(pParse, 0, 0);}
break;
- case 290: /* cmd ::= ANALYZE nm dbnm */
+ case 292: /* cmd ::= ANALYZE nm dbnm */
{wx_sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 291: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+ case 293: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
- wx_sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy131,&yymsp[0].minor.yy0);
+ wx_sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy203,&yymsp[0].minor.yy0);
}
break;
- case 292: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ case 294: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
{
yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
wx_sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
}
break;
- case 293: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ case 295: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
{
- wx_sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy131, &yymsp[0].minor.yy0);
+ wx_sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy203, &yymsp[0].minor.yy0);
}
break;
- case 294: /* add_column_fullname ::= fullname */
+ case 296: /* add_column_fullname ::= fullname */
{
disableLookaside(pParse);
- wx_sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy131);
+ wx_sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy203);
}
break;
- case 295: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ case 297: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
{
- wx_sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy131, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
+ wx_sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy203, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
}
break;
- case 296: /* cmd ::= create_vtab */
+ case 298: /* cmd ::= create_vtab */
{wx_sqlite3VtabFinishParse(pParse,0);}
break;
- case 297: /* cmd ::= create_vtab LP vtabarglist RP */
+ case 299: /* cmd ::= create_vtab LP vtabarglist RP */
{wx_sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
break;
- case 298: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ case 300: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
{
- wx_sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy394);
+ wx_sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy144);
}
break;
- case 299: /* vtabarg ::= */
+ case 301: /* vtabarg ::= */
{wx_sqlite3VtabArgInit(pParse);}
break;
- case 300: /* vtabargtoken ::= ANY */
- case 301: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==301);
- case 302: /* lp ::= LP */ yytestcase(yyruleno==302);
+ case 302: /* vtabargtoken ::= ANY */
+ case 303: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==303);
+ case 304: /* lp ::= LP */ yytestcase(yyruleno==304);
{wx_sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
break;
- case 303: /* with ::= WITH wqlist */
- case 304: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==304);
-{ wx_sqlite3WithPush(pParse, yymsp[0].minor.yy521, 1); }
+ case 305: /* with ::= WITH wqlist */
+ case 306: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==306);
+{ wx_sqlite3WithPush(pParse, yymsp[0].minor.yy59, 1); }
break;
- case 305: /* wqas ::= AS */
-{yymsp[0].minor.yy516 = M10d_Any;}
+ case 307: /* wqas ::= AS */
+{yymsp[0].minor.yy462 = M10d_Any;}
break;
- case 306: /* wqas ::= AS MATERIALIZED */
-{yymsp[-1].minor.yy516 = M10d_Yes;}
+ case 308: /* wqas ::= AS MATERIALIZED */
+{yymsp[-1].minor.yy462 = M10d_Yes;}
break;
- case 307: /* wqas ::= AS NOT MATERIALIZED */
-{yymsp[-2].minor.yy516 = M10d_No;}
+ case 309: /* wqas ::= AS NOT MATERIALIZED */
+{yymsp[-2].minor.yy462 = M10d_No;}
break;
- case 308: /* wqitem ::= nm eidlist_opt wqas LP select RP */
+ case 310: /* wqitem ::= withnm eidlist_opt wqas LP select RP */
{
- yymsp[-5].minor.yy385 = wx_sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy47, yymsp[-3].minor.yy516); /*A-overwrites-X*/
+ yymsp[-5].minor.yy67 = wx_sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy555, yymsp[-3].minor.yy462); /*A-overwrites-X*/
}
break;
- case 309: /* wqlist ::= wqitem */
-{
- yymsp[0].minor.yy521 = wx_sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy385); /*A-overwrites-X*/
-}
+ case 311: /* withnm ::= nm */
+{pParse->bHasWith = 1;}
break;
- case 310: /* wqlist ::= wqlist COMMA wqitem */
+ case 312: /* wqlist ::= wqitem */
{
- yymsp[-2].minor.yy521 = wx_sqlite3WithAdd(pParse, yymsp[-2].minor.yy521, yymsp[0].minor.yy385);
+ yymsp[0].minor.yy59 = wx_sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy67); /*A-overwrites-X*/
}
break;
- case 311: /* windowdefn_list ::= windowdefn */
-{ yylhsminor.yy41 = yymsp[0].minor.yy41; }
- yymsp[0].minor.yy41 = yylhsminor.yy41;
- break;
- case 312: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ case 313: /* wqlist ::= wqlist COMMA wqitem */
{
- assert( yymsp[0].minor.yy41!=0 );
- wx_sqlite3WindowChain(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy41);
- yymsp[0].minor.yy41->pNextWin = yymsp[-2].minor.yy41;
- yylhsminor.yy41 = yymsp[0].minor.yy41;
+ yymsp[-2].minor.yy59 = wx_sqlite3WithAdd(pParse, yymsp[-2].minor.yy59, yymsp[0].minor.yy67);
}
- yymsp[-2].minor.yy41 = yylhsminor.yy41;
break;
- case 313: /* windowdefn ::= nm AS LP window RP */
+ case 314: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
{
- if( ALWAYS(yymsp[-1].minor.yy41) ){
- yymsp[-1].minor.yy41->zName = wx_sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
- }
- yylhsminor.yy41 = yymsp[-1].minor.yy41;
+ assert( yymsp[0].minor.yy211!=0 );
+ wx_sqlite3WindowChain(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy211);
+ yymsp[0].minor.yy211->pNextWin = yymsp[-2].minor.yy211;
+ yylhsminor.yy211 = yymsp[0].minor.yy211;
}
- yymsp[-4].minor.yy41 = yylhsminor.yy41;
+ yymsp[-2].minor.yy211 = yylhsminor.yy211;
break;
- case 314: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ case 315: /* windowdefn ::= nm AS LP window RP */
{
- yymsp[-4].minor.yy41 = wx_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, 0);
+ if( ALWAYS(yymsp[-1].minor.yy211) ){
+ yymsp[-1].minor.yy211->zName = wx_sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
+ }
+ yylhsminor.yy211 = yymsp[-1].minor.yy211;
}
+ yymsp[-4].minor.yy211 = yylhsminor.yy211;
break;
- case 315: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ case 316: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
{
- yylhsminor.yy41 = wx_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, &yymsp[-5].minor.yy0);
+ yymsp[-4].minor.yy211 = wx_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, 0);
}
- yymsp[-5].minor.yy41 = yylhsminor.yy41;
break;
- case 316: /* window ::= ORDER BY sortlist frame_opt */
+ case 317: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
{
- yymsp[-3].minor.yy41 = wx_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, 0);
+ yylhsminor.yy211 = wx_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, &yymsp[-5].minor.yy0);
}
+ yymsp[-5].minor.yy211 = yylhsminor.yy211;
break;
- case 317: /* window ::= nm ORDER BY sortlist frame_opt */
+ case 318: /* window ::= ORDER BY sortlist frame_opt */
{
- yylhsminor.yy41 = wx_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0);
+ yymsp[-3].minor.yy211 = wx_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, 0);
}
- yymsp[-4].minor.yy41 = yylhsminor.yy41;
break;
- case 318: /* window ::= frame_opt */
- case 337: /* filter_over ::= over_clause */ yytestcase(yyruleno==337);
+ case 319: /* window ::= nm ORDER BY sortlist frame_opt */
{
- yylhsminor.yy41 = yymsp[0].minor.yy41;
+ yylhsminor.yy211 = wx_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0);
}
- yymsp[0].minor.yy41 = yylhsminor.yy41;
+ yymsp[-4].minor.yy211 = yylhsminor.yy211;
break;
- case 319: /* window ::= nm frame_opt */
+ case 320: /* window ::= nm frame_opt */
{
- yylhsminor.yy41 = wx_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, 0, &yymsp[-1].minor.yy0);
+ yylhsminor.yy211 = wx_sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, 0, &yymsp[-1].minor.yy0);
}
- yymsp[-1].minor.yy41 = yylhsminor.yy41;
+ yymsp[-1].minor.yy211 = yylhsminor.yy211;
break;
- case 320: /* frame_opt ::= */
+ case 321: /* frame_opt ::= */
{
- yymsp[1].minor.yy41 = wx_sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
+ yymsp[1].minor.yy211 = wx_sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
}
break;
- case 321: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ case 322: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
{
- yylhsminor.yy41 = wx_sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy394, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy516);
+ yylhsminor.yy211 = wx_sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy144, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy462);
}
- yymsp[-2].minor.yy41 = yylhsminor.yy41;
+ yymsp[-2].minor.yy211 = yylhsminor.yy211;
break;
- case 322: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ case 323: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
{
- yylhsminor.yy41 = wx_sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy394, yymsp[-3].minor.yy595.eType, yymsp[-3].minor.yy595.pExpr, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, yymsp[0].minor.yy516);
+ yylhsminor.yy211 = wx_sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy144, yymsp[-3].minor.yy509.eType, yymsp[-3].minor.yy509.pExpr, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, yymsp[0].minor.yy462);
}
- yymsp[-5].minor.yy41 = yylhsminor.yy41;
+ yymsp[-5].minor.yy211 = yylhsminor.yy211;
break;
- case 324: /* frame_bound_s ::= frame_bound */
- case 326: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==326);
-{yylhsminor.yy595 = yymsp[0].minor.yy595;}
- yymsp[0].minor.yy595 = yylhsminor.yy595;
+ case 325: /* frame_bound_s ::= frame_bound */
+ case 327: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==327);
+{yylhsminor.yy509 = yymsp[0].minor.yy509;}
+ yymsp[0].minor.yy509 = yylhsminor.yy509;
break;
- case 325: /* frame_bound_s ::= UNBOUNDED PRECEDING */
- case 327: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==327);
- case 329: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==329);
-{yylhsminor.yy595.eType = yymsp[-1].major; yylhsminor.yy595.pExpr = 0;}
- yymsp[-1].minor.yy595 = yylhsminor.yy595;
+ case 326: /* frame_bound_s ::= UNBOUNDED PRECEDING */
+ case 328: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==328);
+ case 330: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==330);
+{yylhsminor.yy509.eType = yymsp[-1].major; yylhsminor.yy509.pExpr = 0;}
+ yymsp[-1].minor.yy509 = yylhsminor.yy509;
break;
- case 328: /* frame_bound ::= expr PRECEDING|FOLLOWING */
-{yylhsminor.yy595.eType = yymsp[0].major; yylhsminor.yy595.pExpr = yymsp[-1].minor.yy528;}
- yymsp[-1].minor.yy595 = yylhsminor.yy595;
+ case 329: /* frame_bound ::= expr PRECEDING|FOLLOWING */
+{yylhsminor.yy509.eType = yymsp[0].major; yylhsminor.yy509.pExpr = yymsp[-1].minor.yy454;}
+ yymsp[-1].minor.yy509 = yylhsminor.yy509;
break;
- case 330: /* frame_exclude_opt ::= */
-{yymsp[1].minor.yy516 = 0;}
+ case 331: /* frame_exclude_opt ::= */
+{yymsp[1].minor.yy462 = 0;}
break;
- case 331: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
-{yymsp[-1].minor.yy516 = yymsp[0].minor.yy516;}
+ case 332: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
+{yymsp[-1].minor.yy462 = yymsp[0].minor.yy462;}
break;
- case 332: /* frame_exclude ::= NO OTHERS */
- case 333: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==333);
-{yymsp[-1].minor.yy516 = yymsp[-1].major; /*A-overwrites-X*/}
+ case 333: /* frame_exclude ::= NO OTHERS */
+ case 334: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==334);
+{yymsp[-1].minor.yy462 = yymsp[-1].major; /*A-overwrites-X*/}
break;
- case 334: /* frame_exclude ::= GROUP|TIES */
-{yymsp[0].minor.yy516 = yymsp[0].major; /*A-overwrites-X*/}
+ case 335: /* frame_exclude ::= GROUP|TIES */
+{yymsp[0].minor.yy462 = yymsp[0].major; /*A-overwrites-X*/}
break;
- case 335: /* window_clause ::= WINDOW windowdefn_list */
-{ yymsp[-1].minor.yy41 = yymsp[0].minor.yy41; }
+ case 336: /* window_clause ::= WINDOW windowdefn_list */
+{ yymsp[-1].minor.yy211 = yymsp[0].minor.yy211; }
break;
- case 336: /* filter_over ::= filter_clause over_clause */
+ case 337: /* filter_over ::= filter_clause over_clause */
{
- if( yymsp[0].minor.yy41 ){
- yymsp[0].minor.yy41->pFilter = yymsp[-1].minor.yy528;
+ if( yymsp[0].minor.yy211 ){
+ yymsp[0].minor.yy211->pFilter = yymsp[-1].minor.yy454;
}else{
- wx_sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528);
+ wx_sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454);
}
- yylhsminor.yy41 = yymsp[0].minor.yy41;
+ yylhsminor.yy211 = yymsp[0].minor.yy211;
}
- yymsp[-1].minor.yy41 = yylhsminor.yy41;
+ yymsp[-1].minor.yy211 = yylhsminor.yy211;
break;
- case 338: /* filter_over ::= filter_clause */
+ case 338: /* filter_over ::= over_clause */
{
- yylhsminor.yy41 = (Window*)wx_sqlite3DbMallocZero(pParse->db, sizeof(Window));
- if( yylhsminor.yy41 ){
- yylhsminor.yy41->eFrmType = TK_FILTER;
- yylhsminor.yy41->pFilter = yymsp[0].minor.yy528;
+ yylhsminor.yy211 = yymsp[0].minor.yy211;
+}
+ yymsp[0].minor.yy211 = yylhsminor.yy211;
+ break;
+ case 339: /* filter_over ::= filter_clause */
+{
+ yylhsminor.yy211 = (Window*)wx_sqlite3DbMallocZero(pParse->db, sizeof(Window));
+ if( yylhsminor.yy211 ){
+ yylhsminor.yy211->eFrmType = TK_FILTER;
+ yylhsminor.yy211->pFilter = yymsp[0].minor.yy454;
}else{
- wx_sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy528);
+ wx_sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy454);
}
}
- yymsp[0].minor.yy41 = yylhsminor.yy41;
+ yymsp[0].minor.yy211 = yylhsminor.yy211;
break;
- case 339: /* over_clause ::= OVER LP window RP */
+ case 340: /* over_clause ::= OVER LP window RP */
{
- yymsp[-3].minor.yy41 = yymsp[-1].minor.yy41;
- assert( yymsp[-3].minor.yy41!=0 );
+ yymsp[-3].minor.yy211 = yymsp[-1].minor.yy211;
+ assert( yymsp[-3].minor.yy211!=0 );
}
break;
- case 340: /* over_clause ::= OVER nm */
+ case 341: /* over_clause ::= OVER nm */
{
- yymsp[-1].minor.yy41 = (Window*)wx_sqlite3DbMallocZero(pParse->db, sizeof(Window));
- if( yymsp[-1].minor.yy41 ){
- yymsp[-1].minor.yy41->zName = wx_sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
+ yymsp[-1].minor.yy211 = (Window*)wx_sqlite3DbMallocZero(pParse->db, sizeof(Window));
+ if( yymsp[-1].minor.yy211 ){
+ yymsp[-1].minor.yy211->zName = wx_sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
}
}
break;
- case 341: /* filter_clause ::= FILTER LP WHERE expr RP */
-{ yymsp[-4].minor.yy528 = yymsp[-1].minor.yy528; }
+ case 342: /* filter_clause ::= FILTER LP WHERE expr RP */
+{ yymsp[-4].minor.yy454 = yymsp[-1].minor.yy454; }
+ break;
+ case 343: /* term ::= QNUMBER */
+{
+ yylhsminor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0);
+ wx_sqlite3DequoteNumber(pParse, yylhsminor.yy454);
+}
+ yymsp[0].minor.yy454 = yylhsminor.yy454;
break;
default:
- /* (342) input ::= cmdlist */ yytestcase(yyruleno==342);
- /* (343) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==343);
- /* (344) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=344);
- /* (345) ecmd ::= SEMI */ yytestcase(yyruleno==345);
- /* (346) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==346);
- /* (347) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=347);
- /* (348) trans_opt ::= */ yytestcase(yyruleno==348);
- /* (349) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==349);
- /* (350) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==350);
- /* (351) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==351);
- /* (352) savepoint_opt ::= */ yytestcase(yyruleno==352);
- /* (353) cmd ::= create_table create_table_args */ yytestcase(yyruleno==353);
- /* (354) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=354);
- /* (355) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==355);
- /* (356) columnlist ::= columnname carglist */ yytestcase(yyruleno==356);
- /* (357) nm ::= ID|INDEXED */ yytestcase(yyruleno==357);
- /* (358) nm ::= STRING */ yytestcase(yyruleno==358);
- /* (359) nm ::= JOIN_KW */ yytestcase(yyruleno==359);
- /* (360) typetoken ::= typename */ yytestcase(yyruleno==360);
- /* (361) typename ::= ID|STRING */ yytestcase(yyruleno==361);
- /* (362) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=362);
- /* (363) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=363);
- /* (364) carglist ::= carglist ccons */ yytestcase(yyruleno==364);
- /* (365) carglist ::= */ yytestcase(yyruleno==365);
- /* (366) ccons ::= NULL onconf */ yytestcase(yyruleno==366);
- /* (367) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==367);
- /* (368) ccons ::= AS generated */ yytestcase(yyruleno==368);
- /* (369) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==369);
- /* (370) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==370);
- /* (371) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=371);
- /* (372) tconscomma ::= */ yytestcase(yyruleno==372);
- /* (373) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=373);
- /* (374) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=374);
- /* (375) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=375);
- /* (376) oneselect ::= values */ yytestcase(yyruleno==376);
- /* (377) sclp ::= selcollist COMMA */ yytestcase(yyruleno==377);
- /* (378) as ::= ID|STRING */ yytestcase(yyruleno==378);
- /* (379) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=379);
- /* (380) returning ::= */ yytestcase(yyruleno==380);
- /* (381) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=381);
- /* (382) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==382);
- /* (383) exprlist ::= nexprlist */ yytestcase(yyruleno==383);
- /* (384) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=384);
- /* (385) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=385);
- /* (386) nmnum ::= ON */ yytestcase(yyruleno==386);
- /* (387) nmnum ::= DELETE */ yytestcase(yyruleno==387);
- /* (388) nmnum ::= DEFAULT */ yytestcase(yyruleno==388);
- /* (389) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==389);
- /* (390) foreach_clause ::= */ yytestcase(yyruleno==390);
- /* (391) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==391);
- /* (392) trnm ::= nm */ yytestcase(yyruleno==392);
- /* (393) tridxby ::= */ yytestcase(yyruleno==393);
- /* (394) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==394);
- /* (395) database_kw_opt ::= */ yytestcase(yyruleno==395);
- /* (396) kwcolumn_opt ::= */ yytestcase(yyruleno==396);
- /* (397) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==397);
- /* (398) vtabarglist ::= vtabarg */ yytestcase(yyruleno==398);
- /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==399);
- /* (400) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==400);
- /* (401) anylist ::= */ yytestcase(yyruleno==401);
- /* (402) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==402);
- /* (403) anylist ::= anylist ANY */ yytestcase(yyruleno==403);
- /* (404) with ::= */ yytestcase(yyruleno==404);
+ /* (344) input ::= cmdlist */ yytestcase(yyruleno==344);
+ /* (345) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==345);
+ /* (346) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=346);
+ /* (347) ecmd ::= SEMI */ yytestcase(yyruleno==347);
+ /* (348) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==348);
+ /* (349) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=349);
+ /* (350) trans_opt ::= */ yytestcase(yyruleno==350);
+ /* (351) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==351);
+ /* (352) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==352);
+ /* (353) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==353);
+ /* (354) savepoint_opt ::= */ yytestcase(yyruleno==354);
+ /* (355) cmd ::= create_table create_table_args */ yytestcase(yyruleno==355);
+ /* (356) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=356);
+ /* (357) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==357);
+ /* (358) columnlist ::= columnname carglist */ yytestcase(yyruleno==358);
+ /* (359) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==359);
+ /* (360) nm ::= STRING */ yytestcase(yyruleno==360);
+ /* (361) typetoken ::= typename */ yytestcase(yyruleno==361);
+ /* (362) typename ::= ID|STRING */ yytestcase(yyruleno==362);
+ /* (363) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=363);
+ /* (364) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=364);
+ /* (365) carglist ::= carglist ccons */ yytestcase(yyruleno==365);
+ /* (366) carglist ::= */ yytestcase(yyruleno==366);
+ /* (367) ccons ::= NULL onconf */ yytestcase(yyruleno==367);
+ /* (368) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==368);
+ /* (369) ccons ::= AS generated */ yytestcase(yyruleno==369);
+ /* (370) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==370);
+ /* (371) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==371);
+ /* (372) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=372);
+ /* (373) tconscomma ::= */ yytestcase(yyruleno==373);
+ /* (374) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=374);
+ /* (375) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=375);
+ /* (376) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=376);
+ /* (377) oneselect ::= values */ yytestcase(yyruleno==377);
+ /* (378) sclp ::= selcollist COMMA */ yytestcase(yyruleno==378);
+ /* (379) as ::= ID|STRING */ yytestcase(yyruleno==379);
+ /* (380) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=380);
+ /* (381) returning ::= */ yytestcase(yyruleno==381);
+ /* (382) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=382);
+ /* (383) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==383);
+ /* (384) case_operand ::= expr */ yytestcase(yyruleno==384);
+ /* (385) exprlist ::= nexprlist */ yytestcase(yyruleno==385);
+ /* (386) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=386);
+ /* (387) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=387);
+ /* (388) nmnum ::= ON */ yytestcase(yyruleno==388);
+ /* (389) nmnum ::= DELETE */ yytestcase(yyruleno==389);
+ /* (390) nmnum ::= DEFAULT */ yytestcase(yyruleno==390);
+ /* (391) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==391);
+ /* (392) foreach_clause ::= */ yytestcase(yyruleno==392);
+ /* (393) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==393);
+ /* (394) trnm ::= nm */ yytestcase(yyruleno==394);
+ /* (395) tridxby ::= */ yytestcase(yyruleno==395);
+ /* (396) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==396);
+ /* (397) database_kw_opt ::= */ yytestcase(yyruleno==397);
+ /* (398) kwcolumn_opt ::= */ yytestcase(yyruleno==398);
+ /* (399) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==399);
+ /* (400) vtabarglist ::= vtabarg */ yytestcase(yyruleno==400);
+ /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==401);
+ /* (402) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==402);
+ /* (403) anylist ::= */ yytestcase(yyruleno==403);
+ /* (404) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==404);
+ /* (405) anylist ::= anylist ANY */ yytestcase(yyruleno==405);
+ /* (406) with ::= */ yytestcase(yyruleno==406);
+ /* (407) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=407);
+ /* (408) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=408);
break;
/********** End reduce actions ************************************************/
};
@@ -172211,19 +179380,12 @@ SQLITE_PRIVATE void wx_sqlite3Parser(
(int)(yypParser->yytos - yypParser->yystack));
}
#endif
-#if YYSTACKDEPTH>0
if( yypParser->yytos>=yypParser->yystackEnd ){
- yyStackOverflow(yypParser);
- break;
- }
-#else
- if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
if( yyGrowStack(yypParser) ){
yyStackOverflow(yypParser);
break;
}
}
-#endif
}
yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor wx_sqlite3ParserCTX_PARAM);
}else if( yyact <= YY_MAX_SHIFTREDUCE ){
@@ -172600,7 +179762,7 @@ static const unsigned char aKWHash[127] = {
/* aKWNext[] forms the hash collision chain. If aKWHash[i]==0
** then the i-th keyword has no more hash collisions. Otherwise,
** the next keyword with the same hash is aKWHash[i]-1. */
-static const unsigned char aKWNext[147] = {
+static const unsigned char aKWNext[148] = {0,
0, 0, 0, 0, 4, 0, 43, 0, 0, 106, 114, 0, 0,
0, 2, 0, 0, 143, 0, 0, 0, 13, 0, 0, 0, 0,
141, 0, 0, 119, 52, 0, 0, 137, 12, 0, 0, 62, 0,
@@ -172615,7 +179777,7 @@ static const unsigned char aKWNext[147] = {
102, 0, 0, 87,
};
/* aKWLen[i] is the length (in bytes) of the i-th keyword */
-static const unsigned char aKWLen[147] = {
+static const unsigned char aKWLen[148] = {0,
7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6,
7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7,
6, 9, 4, 2, 6, 5, 9, 9, 4, 7, 3, 2, 4,
@@ -172631,7 +179793,7 @@ static const unsigned char aKWLen[147] = {
};
/* aKWOffset[i] is the index into zKWText[] of the start of
** the text for the i-th keyword. */
-static const unsigned short int aKWOffset[147] = {
+static const unsigned short int aKWOffset[148] = {0,
0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33,
36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81,
86, 90, 90, 94, 99, 101, 105, 111, 119, 123, 123, 123, 126,
@@ -172646,7 +179808,7 @@ static const unsigned short int aKWOffset[147] = {
648, 650, 655, 659,
};
/* aKWCode[i] is the parser symbol code for the i-th keyword */
-static const unsigned char aKWCode[147] = {
+static const unsigned char aKWCode[148] = {0,
TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE,
TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN,
TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD,
@@ -172813,185 +179975,185 @@ static const unsigned char aKWCode[147] = {
static int keywordCode(const char *z, int n, int *pType){
int i, j;
const char *zKW;
- if( n>=2 ){
- i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127;
- for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){
- if( aKWLen[i]!=n ) continue;
- zKW = &zKWText[aKWOffset[i]];
+ assert( n>=2 );
+ i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127;
+ for(i=(int)aKWHash[i]; i>0; i=aKWNext[i]){
+ if( aKWLen[i]!=n ) continue;
+ zKW = &zKWText[aKWOffset[i]];
#ifdef SQLITE_ASCII
- if( (z[0]&~0x20)!=zKW[0] ) continue;
- if( (z[1]&~0x20)!=zKW[1] ) continue;
- j = 2;
- while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
+ if( (z[0]&~0x20)!=zKW[0] ) continue;
+ if( (z[1]&~0x20)!=zKW[1] ) continue;
+ j = 2;
+ while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
#endif
#ifdef SQLITE_EBCDIC
- if( toupper(z[0])!=zKW[0] ) continue;
- if( toupper(z[1])!=zKW[1] ) continue;
- j = 2;
- while( j<n && toupper(z[j])==zKW[j] ){ j++; }
-#endif
- if( j<n ) continue;
- testcase( i==0 ); /* REINDEX */
- testcase( i==1 ); /* INDEXED */
- testcase( i==2 ); /* INDEX */
- testcase( i==3 ); /* DESC */
- testcase( i==4 ); /* ESCAPE */
- testcase( i==5 ); /* EACH */
- testcase( i==6 ); /* CHECK */
- testcase( i==7 ); /* KEY */
- testcase( i==8 ); /* BEFORE */
- testcase( i==9 ); /* FOREIGN */
- testcase( i==10 ); /* FOR */
- testcase( i==11 ); /* IGNORE */
- testcase( i==12 ); /* REGEXP */
- testcase( i==13 ); /* EXPLAIN */
- testcase( i==14 ); /* INSTEAD */
- testcase( i==15 ); /* ADD */
- testcase( i==16 ); /* DATABASE */
- testcase( i==17 ); /* AS */
- testcase( i==18 ); /* SELECT */
- testcase( i==19 ); /* TABLE */
- testcase( i==20 ); /* LEFT */
- testcase( i==21 ); /* THEN */
- testcase( i==22 ); /* END */
- testcase( i==23 ); /* DEFERRABLE */
- testcase( i==24 ); /* ELSE */
- testcase( i==25 ); /* EXCLUDE */
- testcase( i==26 ); /* DELETE */
- testcase( i==27 ); /* TEMPORARY */
- testcase( i==28 ); /* TEMP */
- testcase( i==29 ); /* OR */
- testcase( i==30 ); /* ISNULL */
- testcase( i==31 ); /* NULLS */
- testcase( i==32 ); /* SAVEPOINT */
- testcase( i==33 ); /* INTERSECT */
- testcase( i==34 ); /* TIES */
- testcase( i==35 ); /* NOTNULL */
- testcase( i==36 ); /* NOT */
- testcase( i==37 ); /* NO */
- testcase( i==38 ); /* NULL */
- testcase( i==39 ); /* LIKE */
- testcase( i==40 ); /* EXCEPT */
- testcase( i==41 ); /* TRANSACTION */
- testcase( i==42 ); /* ACTION */
- testcase( i==43 ); /* ON */
- testcase( i==44 ); /* NATURAL */
- testcase( i==45 ); /* ALTER */
- testcase( i==46 ); /* RAISE */
- testcase( i==47 ); /* EXCLUSIVE */
- testcase( i==48 ); /* EXISTS */
- testcase( i==49 ); /* CONSTRAINT */
- testcase( i==50 ); /* INTO */
- testcase( i==51 ); /* OFFSET */
- testcase( i==52 ); /* OF */
- testcase( i==53 ); /* SET */
- testcase( i==54 ); /* TRIGGER */
- testcase( i==55 ); /* RANGE */
- testcase( i==56 ); /* GENERATED */
- testcase( i==57 ); /* DETACH */
- testcase( i==58 ); /* HAVING */
- testcase( i==59 ); /* GLOB */
- testcase( i==60 ); /* BEGIN */
- testcase( i==61 ); /* INNER */
- testcase( i==62 ); /* REFERENCES */
- testcase( i==63 ); /* UNIQUE */
- testcase( i==64 ); /* QUERY */
- testcase( i==65 ); /* WITHOUT */
- testcase( i==66 ); /* WITH */
- testcase( i==67 ); /* OUTER */
- testcase( i==68 ); /* RELEASE */
- testcase( i==69 ); /* ATTACH */
- testcase( i==70 ); /* BETWEEN */
- testcase( i==71 ); /* NOTHING */
- testcase( i==72 ); /* GROUPS */
- testcase( i==73 ); /* GROUP */
- testcase( i==74 ); /* CASCADE */
- testcase( i==75 ); /* ASC */
- testcase( i==76 ); /* DEFAULT */
- testcase( i==77 ); /* CASE */
- testcase( i==78 ); /* COLLATE */
- testcase( i==79 ); /* CREATE */
- testcase( i==80 ); /* CURRENT_DATE */
- testcase( i==81 ); /* IMMEDIATE */
- testcase( i==82 ); /* JOIN */
- testcase( i==83 ); /* INSERT */
- testcase( i==84 ); /* MATCH */
- testcase( i==85 ); /* PLAN */
- testcase( i==86 ); /* ANALYZE */
- testcase( i==87 ); /* PRAGMA */
- testcase( i==88 ); /* MATERIALIZED */
- testcase( i==89 ); /* DEFERRED */
- testcase( i==90 ); /* DISTINCT */
- testcase( i==91 ); /* IS */
- testcase( i==92 ); /* UPDATE */
- testcase( i==93 ); /* VALUES */
- testcase( i==94 ); /* VIRTUAL */
- testcase( i==95 ); /* ALWAYS */
- testcase( i==96 ); /* WHEN */
- testcase( i==97 ); /* WHERE */
- testcase( i==98 ); /* RECURSIVE */
- testcase( i==99 ); /* ABORT */
- testcase( i==100 ); /* AFTER */
- testcase( i==101 ); /* RENAME */
- testcase( i==102 ); /* AND */
- testcase( i==103 ); /* DROP */
- testcase( i==104 ); /* PARTITION */
- testcase( i==105 ); /* AUTOINCREMENT */
- testcase( i==106 ); /* TO */
- testcase( i==107 ); /* IN */
- testcase( i==108 ); /* CAST */
- testcase( i==109 ); /* COLUMN */
- testcase( i==110 ); /* COMMIT */
- testcase( i==111 ); /* CONFLICT */
- testcase( i==112 ); /* CROSS */
- testcase( i==113 ); /* CURRENT_TIMESTAMP */
- testcase( i==114 ); /* CURRENT_TIME */
- testcase( i==115 ); /* CURRENT */
- testcase( i==116 ); /* PRECEDING */
- testcase( i==117 ); /* FAIL */
- testcase( i==118 ); /* LAST */
- testcase( i==119 ); /* FILTER */
- testcase( i==120 ); /* REPLACE */
- testcase( i==121 ); /* FIRST */
- testcase( i==122 ); /* FOLLOWING */
- testcase( i==123 ); /* FROM */
- testcase( i==124 ); /* FULL */
- testcase( i==125 ); /* LIMIT */
- testcase( i==126 ); /* IF */
- testcase( i==127 ); /* ORDER */
- testcase( i==128 ); /* RESTRICT */
- testcase( i==129 ); /* OTHERS */
- testcase( i==130 ); /* OVER */
- testcase( i==131 ); /* RETURNING */
- testcase( i==132 ); /* RIGHT */
- testcase( i==133 ); /* ROLLBACK */
- testcase( i==134 ); /* ROWS */
- testcase( i==135 ); /* ROW */
- testcase( i==136 ); /* UNBOUNDED */
- testcase( i==137 ); /* UNION */
- testcase( i==138 ); /* USING */
- testcase( i==139 ); /* VACUUM */
- testcase( i==140 ); /* VIEW */
- testcase( i==141 ); /* WINDOW */
- testcase( i==142 ); /* DO */
- testcase( i==143 ); /* BY */
- testcase( i==144 ); /* INITIALLY */
- testcase( i==145 ); /* ALL */
- testcase( i==146 ); /* PRIMARY */
- *pType = aKWCode[i];
- break;
- }
+ if( toupper(z[0])!=zKW[0] ) continue;
+ if( toupper(z[1])!=zKW[1] ) continue;
+ j = 2;
+ while( j<n && toupper(z[j])==zKW[j] ){ j++; }
+#endif
+ if( j<n ) continue;
+ testcase( i==1 ); /* REINDEX */
+ testcase( i==2 ); /* INDEXED */
+ testcase( i==3 ); /* INDEX */
+ testcase( i==4 ); /* DESC */
+ testcase( i==5 ); /* ESCAPE */
+ testcase( i==6 ); /* EACH */
+ testcase( i==7 ); /* CHECK */
+ testcase( i==8 ); /* KEY */
+ testcase( i==9 ); /* BEFORE */
+ testcase( i==10 ); /* FOREIGN */
+ testcase( i==11 ); /* FOR */
+ testcase( i==12 ); /* IGNORE */
+ testcase( i==13 ); /* REGEXP */
+ testcase( i==14 ); /* EXPLAIN */
+ testcase( i==15 ); /* INSTEAD */
+ testcase( i==16 ); /* ADD */
+ testcase( i==17 ); /* DATABASE */
+ testcase( i==18 ); /* AS */
+ testcase( i==19 ); /* SELECT */
+ testcase( i==20 ); /* TABLE */
+ testcase( i==21 ); /* LEFT */
+ testcase( i==22 ); /* THEN */
+ testcase( i==23 ); /* END */
+ testcase( i==24 ); /* DEFERRABLE */
+ testcase( i==25 ); /* ELSE */
+ testcase( i==26 ); /* EXCLUDE */
+ testcase( i==27 ); /* DELETE */
+ testcase( i==28 ); /* TEMPORARY */
+ testcase( i==29 ); /* TEMP */
+ testcase( i==30 ); /* OR */
+ testcase( i==31 ); /* ISNULL */
+ testcase( i==32 ); /* NULLS */
+ testcase( i==33 ); /* SAVEPOINT */
+ testcase( i==34 ); /* INTERSECT */
+ testcase( i==35 ); /* TIES */
+ testcase( i==36 ); /* NOTNULL */
+ testcase( i==37 ); /* NOT */
+ testcase( i==38 ); /* NO */
+ testcase( i==39 ); /* NULL */
+ testcase( i==40 ); /* LIKE */
+ testcase( i==41 ); /* EXCEPT */
+ testcase( i==42 ); /* TRANSACTION */
+ testcase( i==43 ); /* ACTION */
+ testcase( i==44 ); /* ON */
+ testcase( i==45 ); /* NATURAL */
+ testcase( i==46 ); /* ALTER */
+ testcase( i==47 ); /* RAISE */
+ testcase( i==48 ); /* EXCLUSIVE */
+ testcase( i==49 ); /* EXISTS */
+ testcase( i==50 ); /* CONSTRAINT */
+ testcase( i==51 ); /* INTO */
+ testcase( i==52 ); /* OFFSET */
+ testcase( i==53 ); /* OF */
+ testcase( i==54 ); /* SET */
+ testcase( i==55 ); /* TRIGGER */
+ testcase( i==56 ); /* RANGE */
+ testcase( i==57 ); /* GENERATED */
+ testcase( i==58 ); /* DETACH */
+ testcase( i==59 ); /* HAVING */
+ testcase( i==60 ); /* GLOB */
+ testcase( i==61 ); /* BEGIN */
+ testcase( i==62 ); /* INNER */
+ testcase( i==63 ); /* REFERENCES */
+ testcase( i==64 ); /* UNIQUE */
+ testcase( i==65 ); /* QUERY */
+ testcase( i==66 ); /* WITHOUT */
+ testcase( i==67 ); /* WITH */
+ testcase( i==68 ); /* OUTER */
+ testcase( i==69 ); /* RELEASE */
+ testcase( i==70 ); /* ATTACH */
+ testcase( i==71 ); /* BETWEEN */
+ testcase( i==72 ); /* NOTHING */
+ testcase( i==73 ); /* GROUPS */
+ testcase( i==74 ); /* GROUP */
+ testcase( i==75 ); /* CASCADE */
+ testcase( i==76 ); /* ASC */
+ testcase( i==77 ); /* DEFAULT */
+ testcase( i==78 ); /* CASE */
+ testcase( i==79 ); /* COLLATE */
+ testcase( i==80 ); /* CREATE */
+ testcase( i==81 ); /* CURRENT_DATE */
+ testcase( i==82 ); /* IMMEDIATE */
+ testcase( i==83 ); /* JOIN */
+ testcase( i==84 ); /* INSERT */
+ testcase( i==85 ); /* MATCH */
+ testcase( i==86 ); /* PLAN */
+ testcase( i==87 ); /* ANALYZE */
+ testcase( i==88 ); /* PRAGMA */
+ testcase( i==89 ); /* MATERIALIZED */
+ testcase( i==90 ); /* DEFERRED */
+ testcase( i==91 ); /* DISTINCT */
+ testcase( i==92 ); /* IS */
+ testcase( i==93 ); /* UPDATE */
+ testcase( i==94 ); /* VALUES */
+ testcase( i==95 ); /* VIRTUAL */
+ testcase( i==96 ); /* ALWAYS */
+ testcase( i==97 ); /* WHEN */
+ testcase( i==98 ); /* WHERE */
+ testcase( i==99 ); /* RECURSIVE */
+ testcase( i==100 ); /* ABORT */
+ testcase( i==101 ); /* AFTER */
+ testcase( i==102 ); /* RENAME */
+ testcase( i==103 ); /* AND */
+ testcase( i==104 ); /* DROP */
+ testcase( i==105 ); /* PARTITION */
+ testcase( i==106 ); /* AUTOINCREMENT */
+ testcase( i==107 ); /* TO */
+ testcase( i==108 ); /* IN */
+ testcase( i==109 ); /* CAST */
+ testcase( i==110 ); /* COLUMN */
+ testcase( i==111 ); /* COMMIT */
+ testcase( i==112 ); /* CONFLICT */
+ testcase( i==113 ); /* CROSS */
+ testcase( i==114 ); /* CURRENT_TIMESTAMP */
+ testcase( i==115 ); /* CURRENT_TIME */
+ testcase( i==116 ); /* CURRENT */
+ testcase( i==117 ); /* PRECEDING */
+ testcase( i==118 ); /* FAIL */
+ testcase( i==119 ); /* LAST */
+ testcase( i==120 ); /* FILTER */
+ testcase( i==121 ); /* REPLACE */
+ testcase( i==122 ); /* FIRST */
+ testcase( i==123 ); /* FOLLOWING */
+ testcase( i==124 ); /* FROM */
+ testcase( i==125 ); /* FULL */
+ testcase( i==126 ); /* LIMIT */
+ testcase( i==127 ); /* IF */
+ testcase( i==128 ); /* ORDER */
+ testcase( i==129 ); /* RESTRICT */
+ testcase( i==130 ); /* OTHERS */
+ testcase( i==131 ); /* OVER */
+ testcase( i==132 ); /* RETURNING */
+ testcase( i==133 ); /* RIGHT */
+ testcase( i==134 ); /* ROLLBACK */
+ testcase( i==135 ); /* ROWS */
+ testcase( i==136 ); /* ROW */
+ testcase( i==137 ); /* UNBOUNDED */
+ testcase( i==138 ); /* UNION */
+ testcase( i==139 ); /* USING */
+ testcase( i==140 ); /* VACUUM */
+ testcase( i==141 ); /* VIEW */
+ testcase( i==142 ); /* WINDOW */
+ testcase( i==143 ); /* DO */
+ testcase( i==144 ); /* BY */
+ testcase( i==145 ); /* INITIALLY */
+ testcase( i==146 ); /* ALL */
+ testcase( i==147 ); /* PRIMARY */
+ *pType = aKWCode[i];
+ break;
}
return n;
}
SQLITE_PRIVATE int wx_sqlite3KeywordCode(const unsigned char *z, int n){
int id = TK_ID;
- keywordCode((char*)z, n, &id);
+ if( n>=2 ) keywordCode((char*)z, n, &id);
return id;
}
#define SQLITE_N_KEYWORD 147
SQLITE_API int wx_sqlite3_keyword_name(int i,const char **pzName,int *pnName){
if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR;
+ i++;
*pzName = zKWText + aKWOffset[i];
*pnName = aKWLen[i];
return SQLITE_OK;
@@ -173290,31 +180452,62 @@ SQLITE_PRIVATE int wx_sqlite3GetToken(const unsigned char *z, int *tokenType){
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
- testcase( z[0]=='9' );
+ testcase( z[0]=='9' ); testcase( z[0]=='.' );
*tokenType = TK_INTEGER;
#ifndef SQLITE_OMIT_HEX_INTEGER
if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && wx_sqlite3Isxdigit(z[2]) ){
- for(i=3; wx_sqlite3Isxdigit(z[i]); i++){}
- return i;
- }
+ for(i=3; 1; i++){
+ if( wx_sqlite3Isxdigit(z[i])==0 ){
+ if( z[i]==SQLITE_DIGIT_SEPARATOR ){
+ *tokenType = TK_QNUMBER;
+ }else{
+ break;
+ }
+ }
+ }
+ }else
#endif
- for(i=0; wx_sqlite3Isdigit(z[i]); i++){}
+ {
+ for(i=0; 1; i++){
+ if( wx_sqlite3Isdigit(z[i])==0 ){
+ if( z[i]==SQLITE_DIGIT_SEPARATOR ){
+ *tokenType = TK_QNUMBER;
+ }else{
+ break;
+ }
+ }
+ }
#ifndef SQLITE_OMIT_FLOATING_POINT
- if( z[i]=='.' ){
- i++;
- while( wx_sqlite3Isdigit(z[i]) ){ i++; }
- *tokenType = TK_FLOAT;
- }
- if( (z[i]=='e' || z[i]=='E') &&
- ( wx_sqlite3Isdigit(z[i+1])
- || ((z[i+1]=='+' || z[i+1]=='-') && wx_sqlite3Isdigit(z[i+2]))
- )
- ){
- i += 2;
- while( wx_sqlite3Isdigit(z[i]) ){ i++; }
- *tokenType = TK_FLOAT;
- }
+ if( z[i]=='.' ){
+ if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
+ for(i++; 1; i++){
+ if( wx_sqlite3Isdigit(z[i])==0 ){
+ if( z[i]==SQLITE_DIGIT_SEPARATOR ){
+ *tokenType = TK_QNUMBER;
+ }else{
+ break;
+ }
+ }
+ }
+ }
+ if( (z[i]=='e' || z[i]=='E') &&
+ ( wx_sqlite3Isdigit(z[i+1])
+ || ((z[i+1]=='+' || z[i+1]=='-') && wx_sqlite3Isdigit(z[i+2]))
+ )
+ ){
+ if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
+ for(i+=2; 1; i++){
+ if( wx_sqlite3Isdigit(z[i])==0 ){
+ if( z[i]==SQLITE_DIGIT_SEPARATOR ){
+ *tokenType = TK_QNUMBER;
+ }else{
+ break;
+ }
+ }
+ }
+ }
#endif
+ }
while( IdChar(z[i]) ){
*tokenType = TK_ILLEGAL;
i++;
@@ -173362,7 +180555,8 @@ SQLITE_PRIVATE int wx_sqlite3GetToken(const unsigned char *z, int *tokenType){
return i;
}
case CC_KYWD0: {
- for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
+ if( aiClass[z[1]]>CC_KYWD ){ i = 1; break; }
+ for(i=2; aiClass[z[i]]<=CC_KYWD; i++){}
if( IdChar(z[i]) ){
/* This token started out using characters that can appear in keywords,
** but z[i] is a character not allowed within keywords, so this must
@@ -173478,10 +180672,13 @@ SQLITE_PRIVATE int wx_sqlite3RunParser(Parse *pParse, const char *zSql){
if( tokenType>=TK_WINDOW ){
assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
|| tokenType==TK_ILLEGAL || tokenType==TK_WINDOW
+ || tokenType==TK_QNUMBER
);
#else
if( tokenType>=TK_SPACE ){
- assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
+ assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL
+ || tokenType==TK_QNUMBER
+ );
#endif /* SQLITE_OMIT_WINDOWFUNC */
if( AtomicLoad(&db->u1.isInterrupted) ){
pParse->rc = SQLITE_INTERRUPT;
@@ -173514,7 +180711,7 @@ SQLITE_PRIVATE int wx_sqlite3RunParser(Parse *pParse, const char *zSql){
assert( n==6 );
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
#endif /* SQLITE_OMIT_WINDOWFUNC */
- }else{
+ }else if( tokenType!=TK_QNUMBER ){
Token x;
x.z = zSql;
x.n = n;
@@ -174141,30 +181338,20 @@ static int wx_sqlite3TestExtInit(wx_sqlite3 *db){
** Forward declarations of external module initializer functions
** for modules that need them.
*/
-#ifdef SQLITE_ENABLE_FTS1
-SQLITE_PRIVATE int wx_sqlite3Fts1Init(wx_sqlite3*);
-#endif
-#ifdef SQLITE_ENABLE_FTS2
-SQLITE_PRIVATE int wx_sqlite3Fts2Init(wx_sqlite3*);
-#endif
#ifdef SQLITE_ENABLE_FTS5
SQLITE_PRIVATE int wx_sqlite3Fts5Init(wx_sqlite3*);
#endif
#ifdef SQLITE_ENABLE_STMTVTAB
SQLITE_PRIVATE int wx_sqlite3StmtVtabInit(wx_sqlite3*);
#endif
-
+#ifdef SQLITE_EXTRA_AUTOEXT
+int SQLITE_EXTRA_AUTOEXT(wx_sqlite3*);
+#endif
/*
** An array of pointers to extension initializer functions for
** built-in extensions.
*/
static int (*const wx_sqlite3BuiltinExtensions[])(wx_sqlite3*) = {
-#ifdef SQLITE_ENABLE_FTS1
- wx_sqlite3Fts1Init,
-#endif
-#ifdef SQLITE_ENABLE_FTS2
- wx_sqlite3Fts2Init,
-#endif
#ifdef SQLITE_ENABLE_FTS3
wx_sqlite3Fts3Init,
#endif
@@ -174193,6 +181380,9 @@ static int (*const wx_sqlite3BuiltinExtensions[])(wx_sqlite3*) = {
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
wx_sqlite3VdbeBytecodeVtabInit,
#endif
+#ifdef SQLITE_EXTRA_AUTOEXT
+ SQLITE_EXTRA_AUTOEXT,
+#endif
};
#ifndef SQLITE_AMALGAMATION
@@ -174460,7 +181650,6 @@ SQLITE_API int wx_sqlite3_initialize(void){
rc = SQLITE_EXTRA_INIT(0);
}
#endif
-
return rc;
}
@@ -174530,9 +181719,21 @@ SQLITE_API int wx_sqlite3_config(int op, ...){
va_list ap;
int rc = SQLITE_OK;
- /* wx_sqlite3_config() shall return SQLITE_MISUSE if it is invoked while
- ** the SQLite library is in use. */
- if( wx_sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT;
+ /* wx_sqlite3_config() normally returns SQLITE_MISUSE if it is invoked while
+ ** the SQLite library is in use. Except, a few selected opcodes
+ ** are allowed.
+ */
+ if( wx_sqlite3GlobalConfig.isInit ){
+ static const u64 mAnytimeConfigOption = 0
+ | MASKBIT64( SQLITE_CONFIG_LOG )
+ | MASKBIT64( SQLITE_CONFIG_PCACHE_HDRSZ )
+ ;
+ if( op<0 || op>63 || (MASKBIT64(op) & mAnytimeConfigOption)==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+ testcase( op==SQLITE_CONFIG_LOG );
+ testcase( op==SQLITE_CONFIG_PCACHE_HDRSZ );
+ }
va_start(ap, op);
switch( op ){
@@ -174601,6 +181802,7 @@ SQLITE_API int wx_sqlite3_config(int op, ...){
break;
}
case SQLITE_CONFIG_MEMSTATUS: {
+ assert( !wx_sqlite3GlobalConfig.isInit ); /* Cannot change at runtime */
/* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes
** single argument of type int, interpreted as a boolean, which enables
** or disables the collection of memory allocation statistics. */
@@ -174724,8 +181926,10 @@ SQLITE_API int wx_sqlite3_config(int op, ...){
** wx_sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*));
*/
typedef void(*LOGFUNC_t)(void*,int,const char*);
- wx_sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t);
- wx_sqlite3GlobalConfig.pLogArg = va_arg(ap, void*);
+ LOGFUNC_t xLog = va_arg(ap, LOGFUNC_t);
+ void *pLogArg = va_arg(ap, void*);
+ AtomicStore(&wx_sqlite3GlobalConfig.xLog, xLog);
+ AtomicStore(&wx_sqlite3GlobalConfig.pLogArg, pLogArg);
break;
}
@@ -174739,7 +181943,8 @@ SQLITE_API int wx_sqlite3_config(int op, ...){
** argument of type int. If non-zero, then URI handling is globally
** enabled. If the parameter is zero, then URI handling is globally
** disabled. */
- wx_sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
+ int bOpenUri = va_arg(ap, int);
+ AtomicStore(&wx_sqlite3GlobalConfig.bOpenUri, bOpenUri);
break;
}
@@ -174824,6 +182029,18 @@ SQLITE_API int wx_sqlite3_config(int op, ...){
}
#endif /* SQLITE_OMIT_DESERIALIZE */
+ case SQLITE_CONFIG_ROWID_IN_VIEW: {
+ int *pVal = va_arg(ap,int*);
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ if( 0==*pVal ) wx_sqlite3GlobalConfig.mNoVisibleRowid = TF_NoVisibleRowid;
+ if( 1==*pVal ) wx_sqlite3GlobalConfig.mNoVisibleRowid = 0;
+ *pVal = (wx_sqlite3GlobalConfig.mNoVisibleRowid==0);
+#else
+ *pVal = 0;
+#endif
+ break;
+ }
+
default: {
rc = SQLITE_ERROR;
break;
@@ -175015,6 +182232,10 @@ SQLITE_API int wx_sqlite3_db_cacheflush(wx_sqlite3 *db){
SQLITE_API int wx_sqlite3_db_config(wx_sqlite3 *db, int op, ...){
va_list ap;
int rc;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !wx_sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
wx_sqlite3_mutex_enter(db->mutex);
va_start(ap, op);
switch( op ){
@@ -175054,6 +182275,8 @@ SQLITE_API int wx_sqlite3_db_config(wx_sqlite3 *db, int op, ...){
{ SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML },
{ SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, SQLITE_LegacyFileFmt },
{ SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema },
+ { SQLITE_DBCONFIG_STMT_SCANSTATUS, SQLITE_StmtScanStatus },
+ { SQLITE_DBCONFIG_REVERSE_SCANORDER, SQLITE_ReverseOrder },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -175342,6 +182565,14 @@ static int wx_sqlite3Close(wx_sqlite3 *db, int forceZombie){
}
#endif
+ while( db->pDbData ){
+ DbClientData *p = db->pDbData;
+ db->pDbData = p->pNext;
+ assert( p->pData!=0 );
+ if( p->xDestructor ) p->xDestructor(p->pData);
+ wx_sqlite3_free(p);
+ }
+
/* Convert the connection into a zombie and then close it.
*/
db->eOpenState = SQLITE_STATE_ZOMBIE;
@@ -175759,9 +182990,9 @@ static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
){
-#if SQLITE_OS_WIN || HAVE_USLEEP
+#if SQLITE_OS_WIN || !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP
/* This case is for systems that have support for sleeping for fractions of
- ** a second. Examples: All windows systems, unix systems with usleep() */
+ ** a second. Examples: All windows systems, unix systems with nanosleep() */
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
@@ -175959,7 +183190,8 @@ SQLITE_PRIVATE int wx_sqlite3CreateFunc(
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
- SQLITE_SUBTYPE|SQLITE_INNOCUOUS);
+ SQLITE_SUBTYPE|SQLITE_INNOCUOUS|
+ SQLITE_RESULT_SUBTYPE|SQLITE_SELFORDER1);
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
/* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
@@ -176416,6 +183648,12 @@ SQLITE_API void *wx_sqlite3_preupdate_hook(
void *pArg /* First callback argument */
){
void *pRet;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 ){
+ return 0;
+ }
+#endif
wx_sqlite3_mutex_enter(db->mutex);
pRet = db->pPreUpdateArg;
db->xPreUpdateCallback = xCallback;
@@ -176562,7 +183800,7 @@ SQLITE_API int wx_sqlite3_wal_checkpoint_v2(
if( eMode<SQLITE_CHECKPOINT_PASSIVE || eMode>SQLITE_CHECKPOINT_TRUNCATE ){
/* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint
** mode: */
- return SQLITE_MISUSE;
+ return SQLITE_MISUSE_BKPT;
}
wx_sqlite3_mutex_enter(db->mutex);
@@ -177039,9 +184277,9 @@ SQLITE_PRIVATE int wx_sqlite3ParseUri(
assert( *pzErrMsg==0 );
- if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */
- || wx_sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */
- && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
+ if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */
+ || AtomicLoad(&wx_sqlite3GlobalConfig.bOpenUri)) /* IMP: R-51689-46548 */
+ && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
){
char *zOpt;
int eState; /* Parser state when parsing URI */
@@ -177402,7 +184640,7 @@ static int openDatabase(
** 0 off off
**
** Legacy behavior is 3 (double-quoted string literals are allowed anywhere)
-** and so that is the default. But developers are encouranged to use
+** and so that is the default. But developers are encouraged to use
** -DSQLITE_DQS=0 (best) or -DSQLITE_DQS=1 (second choice) if possible.
*/
#if !defined(SQLITE_DQS)
@@ -177451,6 +184689,9 @@ static int openDatabase(
#if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
| SQLITE_LegacyAlter
#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ | SQLITE_StmtScanStatus
+#endif
;
wx_sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -177508,6 +184749,7 @@ static int openDatabase(
if( ((1<<(flags&7)) & 0x46)==0 ){
rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
}else{
+ if( zFilename==0 ) zFilename = ":memory:";
rc = wx_sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
}
if( rc!=SQLITE_OK ){
@@ -177804,6 +185046,69 @@ SQLITE_API int wx_sqlite3_collation_needed16(
}
#endif /* SQLITE_OMIT_UTF16 */
+/*
+** Find existing client data.
+*/
+SQLITE_API void *wx_sqlite3_get_clientdata(wx_sqlite3 *db, const char *zName){
+ DbClientData *p;
+ wx_sqlite3_mutex_enter(db->mutex);
+ for(p=db->pDbData; p; p=p->pNext){
+ if( strcmp(p->zName, zName)==0 ){
+ void *pResult = p->pData;
+ wx_sqlite3_mutex_leave(db->mutex);
+ return pResult;
+ }
+ }
+ wx_sqlite3_mutex_leave(db->mutex);
+ return 0;
+}
+
+/*
+** Add new client data to a database connection.
+*/
+SQLITE_API int wx_sqlite3_set_clientdata(
+ wx_sqlite3 *db, /* Attach client data to this connection */
+ const char *zName, /* Name of the client data */
+ void *pData, /* The client data itself */
+ void (*xDestructor)(void*) /* Destructor */
+){
+ DbClientData *p, **pp;
+ wx_sqlite3_mutex_enter(db->mutex);
+ pp = &db->pDbData;
+ for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){
+ pp = &p->pNext;
+ }
+ if( p ){
+ assert( p->pData!=0 );
+ if( p->xDestructor ) p->xDestructor(p->pData);
+ if( pData==0 ){
+ *pp = p->pNext;
+ wx_sqlite3_free(p);
+ wx_sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+ }
+ }else if( pData==0 ){
+ wx_sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+ }else{
+ size_t n = strlen(zName);
+ p = wx_sqlite3_malloc64( sizeof(DbClientData)+n+1 );
+ if( p==0 ){
+ if( xDestructor ) xDestructor(pData);
+ wx_sqlite3_mutex_leave(db->mutex);
+ return SQLITE_NOMEM;
+ }
+ memcpy(p->zName, zName, n+1);
+ p->pNext = db->pDbData;
+ db->pDbData = p;
+ }
+ p->pData = pData;
+ p->xDestructor = xDestructor;
+ wx_sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+}
+
+
#ifndef SQLITE_OMIT_DEPRECATED
/*
** This function is now an anachronism. It used to be used to recover from a
@@ -177939,7 +185244,7 @@ SQLITE_API int wx_sqlite3_table_column_metadata(
/* Find the column for which info is requested */
if( zColumnName==0 ){
- /* Query for existance of table only */
+ /* Query for existence of table only */
}else{
for(iCol=0; iCol<pTab->nCol; iCol++){
pCol = &pTab->aCol[iCol];
@@ -178020,7 +185325,7 @@ SQLITE_API int wx_sqlite3_sleep(int ms){
/* This function works in milliseconds, but the underlying OsSleep()
** API uses microseconds. Hence the 1000's.
*/
- rc = (wx_sqlite3OsSleep(pVfs, 1000*ms)/1000);
+ rc = (wx_sqlite3OsSleep(pVfs, ms<0 ? 0 : 1000*ms)/1000);
return rc;
}
@@ -178153,6 +185458,28 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...){
}
#endif
+ /* wx_sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, wx_sqlite3 *db, int b);
+ **
+ ** If b is true, then activate the SQLITE_FkNoAction setting. If b is
+ ** false then clearn that setting. If the SQLITE_FkNoAction setting is
+ ** abled, all foreign key ON DELETE and ON UPDATE actions behave as if
+ ** they were NO ACTION, regardless of how they are defined.
+ **
+ ** NB: One must usually run "PRAGMA writable_schema=RESET" after
+ ** using this test-control, before it will take full effect. failing
+ ** to reset the schema can result in some unexpected behavior.
+ */
+ case SQLITE_TESTCTRL_FK_NO_ACTION: {
+ wx_sqlite3 *db = va_arg(ap, wx_sqlite3*);
+ int b = va_arg(ap, int);
+ if( b ){
+ db->flags |= SQLITE_FkNoAction;
+ }else{
+ db->flags &= ~SQLITE_FkNoAction;
+ }
+ break;
+ }
+
/*
** wx_sqlite3_test_control(BITVEC_TEST, size, program)
**
@@ -178259,10 +185586,12 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...){
wx_sqlite3ShowSrcList(0);
wx_sqlite3ShowWith(0);
wx_sqlite3ShowUpsert(0);
+#ifndef SQLITE_OMIT_TRIGGER
wx_sqlite3ShowTriggerStep(0);
wx_sqlite3ShowTriggerStepList(0);
wx_sqlite3ShowTrigger(0);
wx_sqlite3ShowTriggerList(0);
+#endif
#ifndef SQLITE_OMIT_WINDOWFUNC
wx_sqlite3ShowWindow(0);
wx_sqlite3ShowWinFunc(0);
@@ -178338,6 +185667,18 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...){
break;
}
+ /* wx_sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, wx_sqlite3 *db, int *N)
+ **
+ ** Write the current optimization settings into *N. A zero bit means that
+ ** the optimization is on, and a 1 bit means that the optimization is off.
+ */
+ case SQLITE_TESTCTRL_GETOPT: {
+ wx_sqlite3 *db = va_arg(ap, wx_sqlite3*);
+ int *pN = va_arg(ap, int*);
+ *pN = db->dbOptFlags;
+ break;
+ }
+
/* wx_sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt);
**
** If parameter onoff is 1, subsequent calls to localtime() fail.
@@ -178379,7 +185720,7 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...){
** formed and never corrupt. This flag is clear by default, indicating that
** database files might have arbitrary corruption. Setting the flag during
** testing causes certain assert() statements in the code to be activated
- ** that demonstrat invariants on well-formed database files.
+ ** that demonstrate invariants on well-formed database files.
*/
case SQLITE_TESTCTRL_NEVER_CORRUPT: {
wx_sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int);
@@ -178533,7 +185874,7 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...){
**
** op==0 Store the current wx_sqlite3TreeTrace in *ptr
** op==1 Set wx_sqlite3TreeTrace to the value *ptr
- ** op==3 Store the current wx_sqlite3WhereTrace in *ptr
+ ** op==2 Store the current wx_sqlite3WhereTrace in *ptr
** op==3 Set wx_sqlite3WhereTrace to the value *ptr
*/
case SQLITE_TESTCTRL_TRACEFLAGS: {
@@ -178569,7 +185910,6 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...){
break;
}
-
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
/* wx_sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
**
@@ -178599,6 +185939,28 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...){
break;
}
#endif
+
+ /* wx_sqlite3_test_control(SQLITE_TESTCTRL_JSON_SELFCHECK, &onOff);
+ **
+ ** Activate or deactivate validation of JSONB that is generated from
+ ** text. Off by default, as the validation is slow. Validation is
+ ** only available if compiled using SQLITE_DEBUG.
+ **
+ ** If onOff is initially 1, then turn it on. If onOff is initially
+ ** off, turn it off. If onOff is initially -1, then change onOff
+ ** to be the current setting.
+ */
+ case SQLITE_TESTCTRL_JSON_SELFCHECK: {
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
+ int *pOnOff = va_arg(ap, int*);
+ if( *pOnOff<0 ){
+ *pOnOff = wx_sqlite3Config.bJsonSelfcheck;
+ }else{
+ wx_sqlite3Config.bJsonSelfcheck = (u8)((*pOnOff)&0xff);
+ }
+#endif
+ break;
+ }
}
va_end(ap);
#endif /* SQLITE_UNTESTABLE */
@@ -178855,7 +186217,11 @@ SQLITE_API int wx_sqlite3_snapshot_get(
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
if( SQLITE_TXN_WRITE!=wx_sqlite3BtreeTxnState(pBt) ){
+ Pager *pPager = wx_sqlite3BtreePager(pBt);
+ i64 dummy = 0;
+ wx_sqlite3PagerSnapshotOpen(pPager, (wx_sqlite3_snapshot*)&dummy);
rc = wx_sqlite3BtreeBeginTrans(pBt, 0, 0);
+ wx_sqlite3PagerSnapshotOpen(pPager, 0);
if( rc==SQLITE_OK ){
rc = wx_sqlite3PagerSnapshotGet(wx_sqlite3BtreePager(pBt), ppSnapshot);
}
@@ -178869,7 +186235,7 @@ SQLITE_API int wx_sqlite3_snapshot_get(
}
/*
-** Open a read-transaction on the snapshot idendified by pSnapshot.
+** Open a read-transaction on the snapshot identified by pSnapshot.
*/
SQLITE_API int wx_sqlite3_snapshot_open(
wx_sqlite3 *db,
@@ -178976,7 +186342,7 @@ SQLITE_API int wx_sqlite3_compileoption_used(const char *zOptName){
int nOpt;
const char **azCompileOpt;
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( zOptName==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
@@ -179171,6 +186537,9 @@ SQLITE_API int wx_sqlite3_unlock_notify(
){
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !wx_sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
wx_sqlite3_mutex_enter(db->mutex);
enterMutex();
@@ -180192,6 +187561,7 @@ struct Fts3Table {
int nPgsz; /* Page size for host database */
char *zSegmentsTbl; /* Name of %_segments table */
wx_sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
+ int iSavepoint;
/*
** The following array of hash tables is used to buffer pending index
@@ -180579,6 +187949,8 @@ SQLITE_PRIVATE int wx_sqlite3FtsUnicodeIsdiacritic(int);
SQLITE_PRIVATE int wx_sqlite3Fts3ExprIterate(Fts3Expr*, int (*x)(Fts3Expr*,int,void*), void*);
+SQLITE_PRIVATE int wx_sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk);
+
#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
#endif /* _FTSINT_H */
@@ -180935,6 +188307,7 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid");
wx_sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ wx_sqlite3_vtab_config(p->db, SQLITE_VTAB_INNOCUOUS);
/* Create a list of user columns for the virtual table */
zCols = wx_sqlite3_mprintf("%Q, ", p->azColumn[0]);
@@ -182638,10 +190011,15 @@ static int fts3PoslistPhraseMerge(
if( *p1==POS_COLUMN ){
p1++;
p1 += fts3GetVarint32(p1, &iCol1);
+ /* iCol1==0 indicates corruption. Column 0 does not have a POS_COLUMN
+ ** entry, so this is actually end-of-doclist. */
+ if( iCol1==0 ) return 0;
}
if( *p2==POS_COLUMN ){
p2++;
p2 += fts3GetVarint32(p2, &iCol2);
+ /* As above, iCol2==0 indicates corruption. */
+ if( iCol2==0 ) return 0;
}
while( 1 ){
@@ -184184,6 +191562,8 @@ static int fts3RenameMethod(
rc = wx_sqlite3Fts3PendingTermsFlush(p);
}
+ p->bIgnoreSavepoint = 1;
+
if( p->zContentTbl==0 ){
fts3DbExec(&rc, db,
"ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
@@ -184211,6 +191591,8 @@ static int fts3RenameMethod(
"ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';",
p->zDb, p->zName, zName
);
+
+ p->bIgnoreSavepoint = 0;
return rc;
}
@@ -184221,12 +191603,28 @@ static int fts3RenameMethod(
*/
static int fts3SavepointMethod(wx_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 );
- if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){
- rc = fts3SyncMethod(pVtab);
+ Fts3Table *pTab = (Fts3Table*)pVtab;
+ assert( pTab->inTransaction );
+ assert( pTab->mxSavepoint<=iSavepoint );
+ TESTONLY( pTab->mxSavepoint = iSavepoint );
+
+ if( pTab->bIgnoreSavepoint==0 ){
+ if( fts3HashCount(&pTab->aIndex[0].hPending)>0 ){
+ char *zSql = wx_sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')",
+ pTab->zDb, pTab->zName, pTab->zName
+ );
+ if( zSql ){
+ pTab->bIgnoreSavepoint = 1;
+ rc = wx_sqlite3_exec(pTab->db, zSql, 0, 0, 0);
+ pTab->bIgnoreSavepoint = 0;
+ wx_sqlite3_free(zSql);
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint+1;
+ }
}
return rc;
}
@@ -184237,12 +191635,11 @@ static int fts3SavepointMethod(wx_sqlite3_vtab *pVtab, int iSavepoint){
** This is a no-op.
*/
static int fts3ReleaseMethod(wx_sqlite3_vtab *pVtab, int iSavepoint){
- TESTONLY( Fts3Table *p = (Fts3Table*)pVtab );
- UNUSED_PARAMETER(iSavepoint);
- UNUSED_PARAMETER(pVtab);
- assert( p->inTransaction );
- assert( p->mxSavepoint >= iSavepoint );
- TESTONLY( p->mxSavepoint = iSavepoint-1 );
+ Fts3Table *pTab = (Fts3Table*)pVtab;
+ assert( pTab->inTransaction );
+ assert( pTab->mxSavepoint >= iSavepoint );
+ TESTONLY( pTab->mxSavepoint = iSavepoint-1 );
+ pTab->iSavepoint = iSavepoint;
return SQLITE_OK;
}
@@ -184252,11 +191649,13 @@ static int fts3ReleaseMethod(wx_sqlite3_vtab *pVtab, int iSavepoint){
** Discard the contents of the pending terms table.
*/
static int fts3RollbackToMethod(wx_sqlite3_vtab *pVtab, int iSavepoint){
- Fts3Table *p = (Fts3Table*)pVtab;
+ Fts3Table *pTab = (Fts3Table*)pVtab;
UNUSED_PARAMETER(iSavepoint);
- assert( p->inTransaction );
- TESTONLY( p->mxSavepoint = iSavepoint );
- wx_sqlite3Fts3PendingTermsClear(p);
+ assert( pTab->inTransaction );
+ TESTONLY( pTab->mxSavepoint = iSavepoint );
+ if( (iSavepoint+1)<=pTab->iSavepoint ){
+ wx_sqlite3Fts3PendingTermsClear(pTab);
+ }
return SQLITE_OK;
}
@@ -184275,8 +191674,42 @@ static int fts3ShadowName(const char *zName){
return 0;
}
+/*
+** Implementation of the xIntegrity() method on the FTS3/FTS4 virtual
+** table.
+*/
+static int fts3IntegrityMethod(
+ wx_sqlite3_vtab *pVtab, /* The virtual table to be checked */
+ const char *zSchema, /* Name of schema in which pVtab lives */
+ const char *zTabname, /* Name of the pVTab table */
+ int isQuick, /* True if this is a quick_check */
+ char **pzErr /* Write error message here */
+){
+ Fts3Table *p = (Fts3Table*)pVtab;
+ int rc = SQLITE_OK;
+ int bOk = 0;
+
+ UNUSED_PARAMETER(isQuick);
+ rc = wx_sqlite3Fts3IntegrityCheck(p, &bOk);
+ assert( rc!=SQLITE_CORRUPT_VTAB );
+ if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){
+ *pzErr = wx_sqlite3_mprintf("unable to validate the inverted index for"
+ " FTS%d table %s.%s: %s",
+ p->bFts4 ? 4 : 3, zSchema, zTabname, wx_sqlite3_errstr(rc));
+ if( *pzErr ) rc = SQLITE_OK;
+ }else if( rc==SQLITE_OK && bOk==0 ){
+ *pzErr = wx_sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s",
+ p->bFts4 ? 4 : 3, zSchema, zTabname);
+ if( *pzErr==0 ) rc = SQLITE_NOMEM;
+ }
+ wx_sqlite3Fts3SegmentsClose(p);
+ return rc;
+}
+
+
+
static const wx_sqlite3_module fts3Module = {
- /* iVersion */ 3,
+ /* iVersion */ 4,
/* xCreate */ fts3CreateMethod,
/* xConnect */ fts3ConnectMethod,
/* xBestIndex */ fts3BestIndexMethod,
@@ -184300,6 +191733,7 @@ static const wx_sqlite3_module fts3Module = {
/* xRelease */ fts3ReleaseMethod,
/* xRollbackTo */ fts3RollbackToMethod,
/* xShadowName */ fts3ShadowName,
+ /* xIntegrity */ fts3IntegrityMethod,
};
/*
@@ -185756,7 +193190,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
nTmp += p->pRight->pPhrase->doclist.nList;
}
nTmp += p->pPhrase->doclist.nList;
- aTmp = wx_sqlite3_malloc64(nTmp*2);
+ aTmp = wx_sqlite3_malloc64(nTmp*2 + FTS3_VARINT_MAX);
if( !aTmp ){
*pRc = SQLITE_NOMEM;
res = 0;
@@ -186975,7 +194409,8 @@ SQLITE_PRIVATE int wx_sqlite3Fts3InitAux(wx_sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
int rc; /* Return code */
@@ -187308,10 +194743,11 @@ static int getNextString(
Fts3PhraseToken *pToken;
p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken));
- if( !p ) goto no_mem;
-
zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte);
- if( !zTemp ) goto no_mem;
+ if( !zTemp || !p ){
+ rc = SQLITE_NOMEM;
+ goto getnextstring_out;
+ }
assert( nToken==ii );
pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii];
@@ -187326,9 +194762,6 @@ static int getNextString(
nToken = ii+1;
}
}
-
- pModule->xClose(pCursor);
- pCursor = 0;
}
if( rc==SQLITE_DONE ){
@@ -187336,7 +194769,10 @@ static int getNextString(
char *zBuf = 0;
p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp);
- if( !p ) goto no_mem;
+ if( !p ){
+ rc = SQLITE_NOMEM;
+ goto getnextstring_out;
+ }
memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p);
p->eType = FTSQUERY_PHRASE;
p->pPhrase = (Fts3Phrase *)&p[1];
@@ -187344,11 +194780,9 @@ static int getNextString(
p->pPhrase->nToken = nToken;
zBuf = (char *)&p->pPhrase->aToken[nToken];
+ assert( nTemp==0 || zTemp );
if( zTemp ){
memcpy(zBuf, zTemp, nTemp);
- wx_sqlite3_free(zTemp);
- }else{
- assert( nTemp==0 );
}
for(jj=0; jj<p->pPhrase->nToken; jj++){
@@ -187358,17 +194792,17 @@ static int getNextString(
rc = SQLITE_OK;
}
- *ppExpr = p;
- return rc;
-no_mem:
-
+ getnextstring_out:
if( pCursor ){
pModule->xClose(pCursor);
}
wx_sqlite3_free(zTemp);
- wx_sqlite3_free(p);
- *ppExpr = 0;
- return SQLITE_NOMEM;
+ if( rc!=SQLITE_OK ){
+ wx_sqlite3_free(p);
+ p = 0;
+ }
+ *ppExpr = p;
+ return rc;
}
/*
@@ -189562,11 +196996,7 @@ SQLITE_PRIVATE int wx_sqlite3Fts3InitTokenizer(
#ifdef SQLITE_TEST
-#if defined(INCLUDE_SQLITE_TCL_H)
-# include "sqlite_tcl.h"
-#else
-# include "tcl.h"
-#endif
+#include "tclsqlite.h"
/* #include <string.h> */
/*
@@ -190541,7 +197971,8 @@ SQLITE_PRIVATE int wx_sqlite3Fts3InitTok(wx_sqlite3 *db, Fts3Hash *pHash, void(*
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
int rc; /* Return code */
@@ -193882,7 +201313,6 @@ SQLITE_PRIVATE int wx_sqlite3Fts3PendingTermsFlush(Fts3Table *p){
rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
}
- wx_sqlite3Fts3PendingTermsClear(p);
/* Determine the auto-incr-merge setting if unknown. If enabled,
** estimate the number of leaf blocks of content to be written
@@ -193904,6 +201334,10 @@ SQLITE_PRIVATE int wx_sqlite3Fts3PendingTermsFlush(Fts3Table *p){
rc = wx_sqlite3_reset(pStmt);
}
}
+
+ if( rc==SQLITE_OK ){
+ wx_sqlite3Fts3PendingTermsClear(p);
+ }
return rc;
}
@@ -194535,6 +201969,8 @@ static int fts3AppendToNode(
blobGrowBuffer(pPrev, nTerm, &rc);
if( rc!=SQLITE_OK ) return rc;
+ assert( pPrev!=0 );
+ assert( pPrev->a!=0 );
nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm);
nSuffix = nTerm - nPrefix;
@@ -194591,9 +202027,13 @@ static int fts3IncrmergeAppend(
nSpace += wx_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 ){
+ ** to the current block would make it larger than Fts3Table.nNodeSize bytes,
+ ** and if there is still room for another leaf page, write this block out to
+ ** the database. */
+ if( pLeaf->block.n>0
+ && (pLeaf->block.n + nSpace)>p->nNodeSize
+ && pLeaf->iBlock < (pWriter->iStart + pWriter->nLeafEst)
+ ){
rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n);
pWriter->nWork++;
@@ -194904,6 +202344,7 @@ static int fts3IncrmergeLoad(
for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){
NodeReader reader;
+ memset(&reader, 0, sizeof(reader));
pNode = &pWriter->aNodeWriter[i];
if( pNode->block.a){
@@ -194924,7 +202365,7 @@ static int fts3IncrmergeLoad(
rc = wx_sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock,0);
blobGrowBuffer(&pNode->block,
MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc
- );
+ );
if( rc==SQLITE_OK ){
memcpy(pNode->block.a, aBlock, nBlock);
pNode->block.n = nBlock;
@@ -195774,7 +203215,7 @@ static u64 fts3ChecksumIndex(
int rc;
u64 cksum = 0;
- assert( *pRc==SQLITE_OK );
+ if( *pRc ) return 0;
memset(&filter, 0, sizeof(filter));
memset(&csr, 0, sizeof(csr));
@@ -195841,7 +203282,7 @@ static u64 fts3ChecksumIndex(
** 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){
+SQLITE_PRIVATE int wx_sqlite3Fts3IntegrityCheck(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 */
@@ -195919,7 +203360,12 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
wx_sqlite3_finalize(pStmt);
}
- *pbOk = (cksum1==cksum2);
+ if( rc==SQLITE_CORRUPT_VTAB ){
+ rc = SQLITE_OK;
+ *pbOk = 0;
+ }else{
+ *pbOk = (rc==SQLITE_OK && cksum1==cksum2);
+ }
return rc;
}
@@ -195959,7 +203405,7 @@ static int fts3DoIntegrityCheck(
){
int rc;
int bOk = 0;
- rc = fts3IntegrityCheck(p, &bOk);
+ rc = wx_sqlite3Fts3IntegrityCheck(p, &bOk);
if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB;
return rc;
}
@@ -195989,8 +203435,11 @@ static int fts3SpecialInsert(Fts3Table *p, wx_sqlite3_value *pVal){
rc = fts3DoIncrmerge(p, &zVal[6]);
}else if( nVal>10 && 0==wx_sqlite3_strnicmp(zVal, "automerge=", 10) ){
rc = fts3DoAutoincrmerge(p, &zVal[10]);
+ }else if( nVal==5 && 0==wx_sqlite3_strnicmp(zVal, "flush", 5) ){
+ rc = wx_sqlite3Fts3PendingTermsFlush(p);
+ }
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
- }else{
+ else{
int v;
if( nVal>9 && 0==wx_sqlite3_strnicmp(zVal, "nodesize=", 9) ){
v = atoi(&zVal[9]);
@@ -196008,8 +203457,8 @@ static int fts3SpecialInsert(Fts3Table *p, wx_sqlite3_value *pVal){
if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v;
rc = SQLITE_OK;
}
-#endif
}
+#endif
return rc;
}
@@ -196774,6 +204223,7 @@ static int fts3SnippetNextCandidate(SnippetIter *pIter){
return 1;
}
+ assert( pIter->nSnippet>=0 );
pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1;
for(i=0; i<pIter->nPhrase; i++){
SnippetPhrase *pPhrase = &pIter->aPhrase[i];
@@ -196822,7 +204272,7 @@ static void fts3SnippetDetails(
}
mCover |= mPhrase;
- for(j=0; j<pPhrase->nToken; j++){
+ for(j=0; j<pPhrase->nToken && j<pIter->nSnippet; j++){
mHighlight |= (mPos>>j);
}
@@ -198930,59 +206380,242 @@ SQLITE_PRIVATE int wx_sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
**
******************************************************************************
**
-** This SQLite JSON functions.
+** SQLite JSON functions.
**
** This file began as an extension in ext/misc/json1.c in 2015. That
** extension proved so useful that it has now been moved into the core.
**
-** For the time being, all JSON is stored as pure text. (We might add
-** a JSONB type in the future which stores a binary encoding of JSON in
-** a BLOB, but there is no support for JSONB in the current implementation.
-** This implementation parses JSON text at 250 MB/s, so it is hard to see
-** how JSONB might improve on that.)
+** The original design stored all JSON as pure text, canonical RFC-8259.
+** Support for JSON-5 extensions was added with version 3.42.0 (2023-05-16).
+** All generated JSON text still conforms strictly to RFC-8259, but text
+** with JSON-5 extensions is accepted as input.
+**
+** Beginning with version 3.45.0 (circa 2024-01-01), these routines also
+** accept BLOB values that have JSON encoded using a binary representation
+** called "JSONB". The name JSONB comes from PostgreSQL, however the on-disk
+** format SQLite JSONB is completely different and incompatible with
+** PostgreSQL JSONB.
+**
+** Decoding and interpreting JSONB is still O(N) where N is the size of
+** the input, the same as text JSON. However, the constant of proportionality
+** for JSONB is much smaller due to faster parsing. The size of each
+** element in JSONB is encoded in its header, so there is no need to search
+** for delimiters using persnickety syntax rules. JSONB seems to be about
+** 3x faster than text JSON as a result. JSONB is also tends to be slightly
+** smaller than text JSON, by 5% or 10%, but there are corner cases where
+** JSONB can be slightly larger. So you are not far mistaken to say that
+** a JSONB blob is the same size as the equivalent RFC-8259 text.
+**
+**
+** THE JSONB ENCODING:
+**
+** Every JSON element is encoded in JSONB as a header and a payload.
+** The header is between 1 and 9 bytes in size. The payload is zero
+** or more bytes.
+**
+** The lower 4 bits of the first byte of the header determines the
+** element type:
+**
+** 0: NULL
+** 1: TRUE
+** 2: FALSE
+** 3: INT -- RFC-8259 integer literal
+** 4: INT5 -- JSON5 integer literal
+** 5: FLOAT -- RFC-8259 floating point literal
+** 6: FLOAT5 -- JSON5 floating point literal
+** 7: TEXT -- Text literal acceptable to both SQL and JSON
+** 8: TEXTJ -- Text containing RFC-8259 escapes
+** 9: TEXT5 -- Text containing JSON5 and/or RFC-8259 escapes
+** 10: TEXTRAW -- Text containing unescaped syntax characters
+** 11: ARRAY
+** 12: OBJECT
+**
+** The other three possible values (13-15) are reserved for future
+** enhancements.
+**
+** The upper 4 bits of the first byte determine the size of the header
+** and sometimes also the size of the payload. If X is the first byte
+** of the element and if X>>4 is between 0 and 11, then the payload
+** will be that many bytes in size and the header is exactly one byte
+** in size. Other four values for X>>4 (12-15) indicate that the header
+** is more than one byte in size and that the payload size is determined
+** by the remainder of the header, interpreted as a unsigned big-endian
+** integer.
+**
+** Value of X>>4 Size integer Total header size
+** ------------- -------------------- -----------------
+** 12 1 byte (0-255) 2
+** 13 2 byte (0-65535) 3
+** 14 4 byte (0-4294967295) 5
+** 15 8 byte (0-1.8e19) 9
+**
+** The payload size need not be expressed in its minimal form. For example,
+** if the payload size is 10, the size can be expressed in any of 5 different
+** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte,
+** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by
+** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and
+** a single byte of 0x0a. The shorter forms are preferred, of course, but
+** sometimes when generating JSONB, the payload size is not known in advance
+** and it is convenient to reserve sufficient header space to cover the
+** largest possible payload size and then come back later and patch up
+** the size when it becomes known, resulting in a non-minimal encoding.
+**
+** The value (X>>4)==15 is not actually used in the current implementation
+** (as SQLite is currently unable handle BLOBs larger than about 2GB)
+** but is included in the design to allow for future enhancements.
+**
+** The payload follows the header. NULL, TRUE, and FALSE have no payload and
+** their payload size must always be zero. The payload for INT, INT5,
+** FLOAT, FLOAT5, TEXT, TEXTJ, TEXT5, and TEXTROW is text. Note that the
+** "..." or '...' delimiters are omitted from the various text encodings.
+** The payload for ARRAY and OBJECT is a list of additional elements that
+** are the content for the array or object. The payload for an OBJECT
+** must be an even number of elements. The first element of each pair is
+** the label and must be of type TEXT, TEXTJ, TEXT5, or TEXTRAW.
+**
+** A valid JSONB blob consists of a single element, as described above.
+** Usually this will be an ARRAY or OBJECT element which has many more
+** elements as its content. But the overall blob is just a single element.
+**
+** Input validation for JSONB blobs simply checks that the element type
+** code is between 0 and 12 and that the total size of the element
+** (header plus payload) is the same as the size of the BLOB. If those
+** checks are true, the BLOB is assumed to be JSONB and processing continues.
+** Errors are only raised if some other miscoding is discovered during
+** processing.
+**
+** Additional information can be found in the doc/jsonb.md file of the
+** canonical SQLite source tree.
*/
#ifndef SQLITE_OMIT_JSON
/* #include "sqliteInt.h" */
+/* JSONB element types
+*/
+#define JSONB_NULL 0 /* "null" */
+#define JSONB_TRUE 1 /* "true" */
+#define JSONB_FALSE 2 /* "false" */
+#define JSONB_INT 3 /* integer acceptable to JSON and SQL */
+#define JSONB_INT5 4 /* integer in 0x000 notation */
+#define JSONB_FLOAT 5 /* float acceptable to JSON and SQL */
+#define JSONB_FLOAT5 6 /* float with JSON5 extensions */
+#define JSONB_TEXT 7 /* Text compatible with both JSON and SQL */
+#define JSONB_TEXTJ 8 /* Text with JSON escapes */
+#define JSONB_TEXT5 9 /* Text with JSON-5 escape */
+#define JSONB_TEXTRAW 10 /* SQL text that needs escaping for JSON */
+#define JSONB_ARRAY 11 /* An array */
+#define JSONB_OBJECT 12 /* An object */
+
+/* Human-readable names for the JSONB values. The index for each
+** string must correspond to the JSONB_* integer above.
+*/
+static const char * const jsonbType[] = {
+ "null", "true", "false", "integer", "integer",
+ "real", "real", "text", "text", "text",
+ "text", "array", "object", "", "", "", ""
+};
+
/*
** Growing our own isspace() routine this way is twice as fast as
** the library isspace() function, resulting in a 7% overall performance
-** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
+** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
*/
static const char jsonIsSpace[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define jsonIsspace(x) (jsonIsSpace[(unsigned char)x])
+
+/*
+** The set of all space characters recognized by jsonIsspace().
+** Useful as the second argument to strspn().
+*/
+static const char jsonSpaces[] = "\011\012\015\040";
+
+/*
+** Characters that are special to JSON. Control characters,
+** '"' and '\\' and '\''. Actually, '\'' is not special to
+** canonical JSON, but it is special in JSON-5, so we include
+** it in the set of special characters.
+*/
+static const char jsonIsOk[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
-#define fast_isspace(x) (jsonIsSpace[(unsigned char)x])
-
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST)
-# define VVA(X)
-#else
-# define VVA(X) X
-#endif
/* Objects */
+typedef struct JsonCache JsonCache;
typedef struct JsonString JsonString;
-typedef struct JsonNode JsonNode;
typedef struct JsonParse JsonParse;
+/*
+** Magic number used for the JSON parse cache in wx_sqlite3_get_auxdata()
+*/
+#define JSON_CACHE_ID (-429938) /* Cache entry */
+#define JSON_CACHE_SIZE 4 /* Max number of cache entries */
+
+/*
+** jsonUnescapeOneChar() returns this invalid code point if it encounters
+** a syntax error.
+*/
+#define JSON_INVALID_CHAR 0x99999
+
+/* A cache mapping JSON text into JSONB blobs.
+**
+** Each cache entry is a JsonParse object with the following restrictions:
+**
+** * The bReadOnly flag must be set
+**
+** * The aBlob[] array must be owned by the JsonParse object. In other
+** words, nBlobAlloc must be non-zero.
+**
+** * eEdit and delta must be zero.
+**
+** * zJson must be an RCStr. In other words bJsonIsRCStr must be true.
+*/
+struct JsonCache {
+ wx_sqlite3 *db; /* Database connection */
+ int nUsed; /* Number of active entries in the cache */
+ JsonParse *a[JSON_CACHE_SIZE]; /* One line for each cache entry */
+};
+
/* An instance of this object represents a JSON string
** under construction. Really, this is a generic string accumulator
** that can be and is used to create strings other than JSON.
+**
+** If the generated string is longer than will fit into the zSpace[] buffer,
+** then it will be an RCStr string. This aids with caching of large
+** JSON strings.
*/
struct JsonString {
wx_sqlite3_context *pCtx; /* Function context - put error messages here */
@@ -198990,89 +206623,227 @@ struct JsonString {
u64 nAlloc; /* Bytes of storage available in zBuf[] */
u64 nUsed; /* Bytes of zBuf[] currently used */
u8 bStatic; /* True if zBuf is static space */
- u8 bErr; /* True if an error has been encountered */
+ u8 eErr; /* True if an error has been encountered */
char zSpace[100]; /* Initial static space */
};
-/* JSON type values
-*/
-#define JSON_NULL 0
-#define JSON_TRUE 1
-#define JSON_FALSE 2
-#define JSON_INT 3
-#define JSON_REAL 4
-#define JSON_STRING 5
-#define JSON_ARRAY 6
-#define JSON_OBJECT 7
+/* Allowed values for JsonString.eErr */
+#define JSTRING_OOM 0x01 /* Out of memory */
+#define JSTRING_MALFORMED 0x02 /* Malformed JSONB */
+#define JSTRING_ERR 0x04 /* Error already sent to wx_sqlite3_result */
-/* The "subtype" set for JSON values */
+/* The "subtype" set for text JSON values passed through using
+** wx_sqlite3_result_subtype() and wx_sqlite3_value_subtype().
+*/
#define JSON_SUBTYPE 74 /* Ascii for "J" */
/*
-** Names of the various JSON types:
-*/
-static const char * const jsonType[] = {
- "null", "true", "false", "integer", "real", "text", "array", "object"
-};
-
-/* Bit values for the JsonNode.jnFlag field
+** Bit values for the flags passed into various SQL function implementations
+** via the wx_sqlite3_user_data() value.
*/
-#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
-#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */
-#define JNODE_REMOVE 0x04 /* Do not output */
-#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */
-#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */
-#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */
-#define JNODE_LABEL 0x40 /* Is a label of an object */
+#define JSON_JSON 0x01 /* Result is always JSON */
+#define JSON_SQL 0x02 /* Result is always SQL */
+#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */
+#define JSON_ISSET 0x04 /* json_set(), not json_insert() */
+#define JSON_BLOB 0x08 /* Use the BLOB output format */
-/* A single node of parsed JSON
-*/
-struct JsonNode {
- u8 eType; /* One of the JSON_ type values */
- u8 jnFlags; /* JNODE flags */
- u8 eU; /* Which union element to use */
- u32 n; /* Bytes of content, or number of sub-nodes */
- union {
- const char *zJContent; /* 1: Content for INT, REAL, and STRING */
- u32 iAppend; /* 2: More terms for ARRAY and OBJECT */
- u32 iKey; /* 3: Key for ARRAY objects in json_tree() */
- u32 iReplace; /* 4: Replacement content for JNODE_REPLACE */
- JsonNode *pPatch; /* 5: Node chain of patch for JNODE_PATCH */
- } u;
-};
-
-/* A completely parsed JSON string
+/* A parsed JSON value. Lifecycle:
+**
+** 1. JSON comes in and is parsed into a JSONB value in aBlob. The
+** original text is stored in zJson. This step is skipped if the
+** input is JSONB instead of text JSON.
+**
+** 2. The aBlob[] array is searched using the JSON path notation, if needed.
+**
+** 3. Zero or more changes are made to aBlob[] (via json_remove() or
+** json_replace() or json_patch() or similar).
+**
+** 4. New JSON text is generated from the aBlob[] for output. This step
+** is skipped if the function is one of the jsonb_* functions that
+** returns JSONB instead of text JSON.
*/
struct JsonParse {
- u32 nNode; /* Number of slots of aNode[] used */
- u32 nAlloc; /* Number of slots of aNode[] allocated */
- JsonNode *aNode; /* Array of nodes containing the parse */
- const char *zJson; /* Original JSON string */
- u32 *aUp; /* Index of parent of each node */
- u8 oom; /* Set to true if out of memory */
- u8 nErr; /* Number of errors seen */
- u16 iDepth; /* Nesting depth */
+ u8 *aBlob; /* JSONB representation of JSON value */
+ u32 nBlob; /* Bytes of aBlob[] actually used */
+ u32 nBlobAlloc; /* Bytes allocated to aBlob[]. 0 if aBlob is external */
+ char *zJson; /* Json text used for parsing */
+ wx_sqlite3 *db; /* The database connection to which this object belongs */
int nJson; /* Length of the zJson string in bytes */
- u32 iHold; /* Replace cache line with the lowest iHold value */
+ u32 nJPRef; /* Number of references to this object */
+ u32 iErr; /* Error location in zJson[] */
+ u16 iDepth; /* Nesting depth */
+ u8 nErr; /* Number of errors seen */
+ u8 oom; /* Set to true if out of memory */
+ u8 bJsonIsRCStr; /* True if zJson is an RCStr */
+ u8 hasNonstd; /* True if input uses non-standard features like JSON5 */
+ u8 bReadOnly; /* Do not modify. */
+ /* Search and edit information. See jsonLookupStep() */
+ u8 eEdit; /* Edit operation to apply */
+ int delta; /* Size change due to the edit */
+ u32 nIns; /* Number of bytes to insert */
+ u32 iLabel; /* Location of label if search landed on an object value */
+ u8 *aIns; /* Content to be inserted */
};
+/* Allowed values for JsonParse.eEdit */
+#define JEDIT_DEL 1 /* Delete if exists */
+#define JEDIT_REPL 2 /* Overwrite if exists */
+#define JEDIT_INS 3 /* Insert if not exists */
+#define JEDIT_SET 4 /* Insert or overwrite */
+
/*
** Maximum nesting depth of JSON for this implementation.
**
** This limit is needed to avoid a stack overflow in the recursive
-** descent parser. A depth of 2000 is far deeper than any sane JSON
-** should go.
+** descent parser. A depth of 1000 is far deeper than any sane JSON
+** should go. Historical note: This limit was 2000 prior to version 3.42.0
*/
-#define JSON_MAX_DEPTH 2000
+#ifndef SQLITE_JSON_MAX_DEPTH
+# define JSON_MAX_DEPTH 1000
+#else
+# define JSON_MAX_DEPTH SQLITE_JSON_MAX_DEPTH
+#endif
+
+/*
+** Allowed values for the flgs argument to jsonParseFuncArg();
+*/
+#define JSON_EDITABLE 0x01 /* Generate a writable JsonParse object */
+#define JSON_KEEPERROR 0x02 /* Return non-NULL even if there is an error */
+
+/**************************************************************************
+** Forward references
+**************************************************************************/
+static void jsonReturnStringAsBlob(JsonString*);
+static int jsonFuncArgMightBeBinary(wx_sqlite3_value *pJson);
+static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*);
+static void jsonReturnParse(wx_sqlite3_context*,JsonParse*);
+static JsonParse *jsonParseFuncArg(wx_sqlite3_context*,wx_sqlite3_value*,u32);
+static void jsonParseFree(JsonParse*);
+static u32 jsonbPayloadSize(const JsonParse*, u32, u32*);
+static u32 jsonUnescapeOneChar(const char*, u32, u32*);
+
+/**************************************************************************
+** Utility routines for dealing with JsonCache objects
+**************************************************************************/
+
+/*
+** Free a JsonCache object.
+*/
+static void jsonCacheDelete(JsonCache *p){
+ int i;
+ for(i=0; i<p->nUsed; i++){
+ jsonParseFree(p->a[i]);
+ }
+ wx_sqlite3DbFree(p->db, p);
+}
+static void jsonCacheDeleteGeneric(void *p){
+ jsonCacheDelete((JsonCache*)p);
+}
+
+/*
+** Insert a new entry into the cache. If the cache is full, expel
+** the least recently used entry. Return SQLITE_OK on success or a
+** result code otherwise.
+**
+** Cache entries are stored in age order, oldest first.
+*/
+static int jsonCacheInsert(
+ wx_sqlite3_context *ctx, /* The SQL statement context holding the cache */
+ JsonParse *pParse /* The parse object to be added to the cache */
+){
+ JsonCache *p;
+
+ assert( pParse->zJson!=0 );
+ assert( pParse->bJsonIsRCStr );
+ assert( pParse->delta==0 );
+ p = wx_sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
+ if( p==0 ){
+ wx_sqlite3 *db = wx_sqlite3_context_db_handle(ctx);
+ p = wx_sqlite3DbMallocZero(db, sizeof(*p));
+ if( p==0 ) return SQLITE_NOMEM;
+ p->db = db;
+ wx_sqlite3_set_auxdata(ctx, JSON_CACHE_ID, p, jsonCacheDeleteGeneric);
+ p = wx_sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
+ if( p==0 ) return SQLITE_NOMEM;
+ }
+ if( p->nUsed >= JSON_CACHE_SIZE ){
+ jsonParseFree(p->a[0]);
+ memmove(p->a, &p->a[1], (JSON_CACHE_SIZE-1)*sizeof(p->a[0]));
+ p->nUsed = JSON_CACHE_SIZE-1;
+ }
+ assert( pParse->nBlobAlloc>0 );
+ pParse->eEdit = 0;
+ pParse->nJPRef++;
+ pParse->bReadOnly = 1;
+ p->a[p->nUsed] = pParse;
+ p->nUsed++;
+ return SQLITE_OK;
+}
+
+/*
+** Search for a cached translation the json text supplied by pArg. Return
+** the JsonParse object if found. Return NULL if not found.
+**
+** When a match if found, the matching entry is moved to become the
+** most-recently used entry if it isn't so already.
+**
+** The JsonParse object returned still belongs to the Cache and might
+** be deleted at any moment. If the caller whants the JsonParse to
+** linger, it needs to increment the nPJRef reference counter.
+*/
+static JsonParse *jsonCacheSearch(
+ wx_sqlite3_context *ctx, /* The SQL statement context holding the cache */
+ wx_sqlite3_value *pArg /* Function argument containing SQL text */
+){
+ JsonCache *p;
+ int i;
+ const char *zJson;
+ int nJson;
+
+ if( wx_sqlite3_value_type(pArg)!=SQLITE_TEXT ){
+ return 0;
+ }
+ zJson = (const char*)wx_sqlite3_value_text(pArg);
+ if( zJson==0 ) return 0;
+ nJson = wx_sqlite3_value_bytes(pArg);
+
+ p = wx_sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
+ if( p==0 ){
+ return 0;
+ }
+ for(i=0; i<p->nUsed; i++){
+ if( p->a[i]->zJson==zJson ) break;
+ }
+ if( i>=p->nUsed ){
+ for(i=0; i<p->nUsed; i++){
+ if( p->a[i]->nJson!=nJson ) continue;
+ if( memcmp(p->a[i]->zJson, zJson, nJson)==0 ) break;
+ }
+ }
+ if( i<p->nUsed ){
+ if( i<p->nUsed-1 ){
+ /* Make the matching entry the most recently used entry */
+ JsonParse *tmp = p->a[i];
+ memmove(&p->a[i], &p->a[i+1], (p->nUsed-i-1)*sizeof(tmp));
+ p->a[p->nUsed-1] = tmp;
+ i = p->nUsed - 1;
+ }
+ assert( p->a[i]->delta==0 );
+ return p->a[i];
+ }else{
+ return 0;
+ }
+}
/**************************************************************************
** Utility routines for dealing with JsonString objects
**************************************************************************/
-/* Set the JsonString object to an empty string
+/* Turn uninitialized bulk memory into a valid JsonString object
+** holding a zero-length string.
*/
-static void jsonZero(JsonString *p){
+static void jsonStringZero(JsonString *p){
p->zBuf = p->zSpace;
p->nAlloc = sizeof(p->zSpace);
p->nUsed = 0;
@@ -199081,53 +206852,51 @@ static void jsonZero(JsonString *p){
/* Initialize the JsonString object
*/
-static void jsonInit(JsonString *p, wx_sqlite3_context *pCtx){
+static void jsonStringInit(JsonString *p, wx_sqlite3_context *pCtx){
p->pCtx = pCtx;
- p->bErr = 0;
- jsonZero(p);
+ p->eErr = 0;
+ jsonStringZero(p);
}
-
/* Free all allocated memory and reset the JsonString object back to its
** initial state.
*/
-static void jsonReset(JsonString *p){
- if( !p->bStatic ) wx_sqlite3_free(p->zBuf);
- jsonZero(p);
+static void jsonStringReset(JsonString *p){
+ if( !p->bStatic ) wx_sqlite3RCStrUnref(p->zBuf);
+ jsonStringZero(p);
}
-
/* Report an out-of-memory (OOM) condition
*/
-static void jsonOom(JsonString *p){
- p->bErr = 1;
- wx_sqlite3_result_error_nomem(p->pCtx);
- jsonReset(p);
+static void jsonStringOom(JsonString *p){
+ p->eErr |= JSTRING_OOM;
+ if( p->pCtx ) wx_sqlite3_result_error_nomem(p->pCtx);
+ jsonStringReset(p);
}
/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
** Return zero on success. Return non-zero on an OOM error
*/
-static int jsonGrow(JsonString *p, u32 N){
+static int jsonStringGrow(JsonString *p, u32 N){
u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
char *zNew;
if( p->bStatic ){
- if( p->bErr ) return 1;
- zNew = wx_sqlite3_malloc64(nTotal);
+ if( p->eErr ) return 1;
+ zNew = wx_sqlite3RCStrNew(nTotal);
if( zNew==0 ){
- jsonOom(p);
+ jsonStringOom(p);
return SQLITE_NOMEM;
}
memcpy(zNew, p->zBuf, (size_t)p->nUsed);
p->zBuf = zNew;
p->bStatic = 0;
}else{
- zNew = wx_sqlite3_realloc64(p->zBuf, nTotal);
- if( zNew==0 ){
- jsonOom(p);
+ p->zBuf = wx_sqlite3RCStrResize(p->zBuf, nTotal);
+ if( p->zBuf==0 ){
+ p->eErr |= JSTRING_OOM;
+ jsonStringZero(p);
return SQLITE_NOMEM;
}
- p->zBuf = zNew;
}
p->nAlloc = nTotal;
return SQLITE_OK;
@@ -199135,18 +206904,40 @@ static int jsonGrow(JsonString *p, u32 N){
/* Append N bytes from zIn onto the end of the JsonString string.
*/
-static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
- if( N==0 ) return;
- if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
+static SQLITE_NOINLINE void jsonStringExpandAndAppend(
+ JsonString *p,
+ const char *zIn,
+ u32 N
+){
+ assert( N>0 );
+ if( jsonStringGrow(p,N) ) return;
memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N;
}
+static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
+ if( N==0 ) return;
+ if( N+p->nUsed >= p->nAlloc ){
+ jsonStringExpandAndAppend(p,zIn,N);
+ }else{
+ memcpy(p->zBuf+p->nUsed, zIn, N);
+ p->nUsed += N;
+ }
+}
+static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){
+ assert( N>0 );
+ if( N+p->nUsed >= p->nAlloc ){
+ jsonStringExpandAndAppend(p,zIn,N);
+ }else{
+ memcpy(p->zBuf+p->nUsed, zIn, N);
+ p->nUsed += N;
+ }
+}
/* Append formatted text (not to exceed N bytes) to the JsonString.
*/
static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
va_list ap;
- if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
+ if( (p->nUsed + N >= p->nAlloc) && jsonStringGrow(p, N) ) return;
va_start(ap, zFormat);
wx_sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
va_end(ap);
@@ -199155,10 +206946,38 @@ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
/* Append a single character
*/
-static void jsonAppendChar(JsonString *p, char c){
- if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
+static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){
+ if( jsonStringGrow(p,1) ) return;
p->zBuf[p->nUsed++] = c;
}
+static void jsonAppendChar(JsonString *p, char c){
+ if( p->nUsed>=p->nAlloc ){
+ jsonAppendCharExpand(p,c);
+ }else{
+ p->zBuf[p->nUsed++] = c;
+ }
+}
+
+/* Remove a single character from the end of the string
+*/
+static void jsonStringTrimOneChar(JsonString *p){
+ if( p->eErr==0 ){
+ assert( p->nUsed>0 );
+ p->nUsed--;
+ }
+}
+
+
+/* Make sure there is a zero terminator on p->zBuf[]
+**
+** Return true on success. Return false if an OOM prevents this
+** from happening.
+*/
+static int jsonStringTerminate(JsonString *p){
+ jsonAppendChar(p, 0);
+ jsonStringTrimOneChar(p);
+ return p->eErr==0;
+}
/* Append a comma separator to the output buffer, if the previous
** character is not '[' or '{'.
@@ -199167,68 +206986,137 @@ static void jsonAppendSeparator(JsonString *p){
char c;
if( p->nUsed==0 ) return;
c = p->zBuf[p->nUsed-1];
- if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
+ if( c=='[' || c=='{' ) return;
+ jsonAppendChar(p, ',');
+}
+
+/* c is a control character. Append the canonical JSON representation
+** of that control character to p.
+**
+** This routine assumes that the output buffer has already been enlarged
+** sufficiently to hold the worst-case encoding plus a nul terminator.
+*/
+static void jsonAppendControlChar(JsonString *p, u8 c){
+ static const char aSpecial[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ assert( sizeof(aSpecial)==32 );
+ assert( aSpecial['\b']=='b' );
+ assert( aSpecial['\f']=='f' );
+ assert( aSpecial['\n']=='n' );
+ assert( aSpecial['\r']=='r' );
+ assert( aSpecial['\t']=='t' );
+ assert( c>=0 && c<sizeof(aSpecial) );
+ assert( p->nUsed+7 <= p->nAlloc );
+ if( aSpecial[c] ){
+ p->zBuf[p->nUsed] = '\\';
+ p->zBuf[p->nUsed+1] = aSpecial[c];
+ p->nUsed += 2;
+ }else{
+ p->zBuf[p->nUsed] = '\\';
+ p->zBuf[p->nUsed+1] = 'u';
+ p->zBuf[p->nUsed+2] = '0';
+ p->zBuf[p->nUsed+3] = '0';
+ p->zBuf[p->nUsed+4] = "0123456789abcdef"[c>>4];
+ p->zBuf[p->nUsed+5] = "0123456789abcdef"[c&0xf];
+ p->nUsed += 6;
+ }
}
/* Append the N-byte string in zIn to the end of the JsonString string
-** under construction. Enclose the string in "..." and escape
-** any double-quotes or backslash characters contained within the
+** under construction. Enclose the string in double-quotes ("...") and
+** escape any double-quotes or backslash characters contained within the
** string.
+**
+** This routine is a high-runner. There is a measurable performance
+** increase associated with unwinding the jsonIsOk[] loop.
*/
static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
- u32 i;
- if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return;
+ u32 k;
+ u8 c;
+ const u8 *z = (const u8*)zIn;
+ if( z==0 ) return;
+ if( (N+p->nUsed+2 >= p->nAlloc) && jsonStringGrow(p,N+2)!=0 ) return;
p->zBuf[p->nUsed++] = '"';
- for(i=0; i<N; i++){
- unsigned char c = ((unsigned const char*)zIn)[i];
+ while( 1 /*exit-by-break*/ ){
+ k = 0;
+ /* The following while() is the 4-way unwound equivalent of
+ **
+ ** while( k<N && jsonIsOk[z[k]] ){ k++; }
+ */
+ while( 1 /* Exit by break */ ){
+ if( k+3>=N ){
+ while( k<N && jsonIsOk[z[k]] ){ k++; }
+ break;
+ }
+ if( !jsonIsOk[z[k]] ){
+ break;
+ }
+ if( !jsonIsOk[z[k+1]] ){
+ k += 1;
+ break;
+ }
+ if( !jsonIsOk[z[k+2]] ){
+ k += 2;
+ break;
+ }
+ if( !jsonIsOk[z[k+3]] ){
+ k += 3;
+ break;
+ }else{
+ k += 4;
+ }
+ }
+ if( k>=N ){
+ if( k>0 ){
+ memcpy(&p->zBuf[p->nUsed], z, k);
+ p->nUsed += k;
+ }
+ break;
+ }
+ if( k>0 ){
+ memcpy(&p->zBuf[p->nUsed], z, k);
+ p->nUsed += k;
+ z += k;
+ N -= k;
+ }
+ c = z[0];
if( c=='"' || c=='\\' ){
- json_simple_escape:
- if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
- p->zBuf[p->nUsed++] = '\\';
- }else if( c<=0x1f ){
- static const char aSpecial[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- assert( sizeof(aSpecial)==32 );
- assert( aSpecial['\b']=='b' );
- assert( aSpecial['\f']=='f' );
- assert( aSpecial['\n']=='n' );
- assert( aSpecial['\r']=='r' );
- assert( aSpecial['\t']=='t' );
- if( aSpecial[c] ){
- c = aSpecial[c];
- goto json_simple_escape;
- }
- if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
+ if( (p->nUsed+N+3 > p->nAlloc) && jsonStringGrow(p,N+3)!=0 ) return;
p->zBuf[p->nUsed++] = '\\';
- p->zBuf[p->nUsed++] = 'u';
- p->zBuf[p->nUsed++] = '0';
- p->zBuf[p->nUsed++] = '0';
- p->zBuf[p->nUsed++] = '0' + (c>>4);
- c = "0123456789abcdef"[c&0xf];
+ p->zBuf[p->nUsed++] = c;
+ }else if( c=='\'' ){
+ p->zBuf[p->nUsed++] = c;
+ }else{
+ if( (p->nUsed+N+7 > p->nAlloc) && jsonStringGrow(p,N+7)!=0 ) return;
+ jsonAppendControlChar(p, c);
}
- p->zBuf[p->nUsed++] = c;
+ z++;
+ N--;
}
p->zBuf[p->nUsed++] = '"';
assert( p->nUsed<p->nAlloc );
}
/*
-** Append a function parameter value to the JSON string under
-** construction.
+** Append an wx_sqlite3_value (such as a function parameter) to the JSON
+** string under construction in p.
*/
-static void jsonAppendValue(
+static void jsonAppendSqlValue(
JsonString *p, /* Append to this JSON string */
wx_sqlite3_value *pValue /* Value to append */
){
switch( wx_sqlite3_value_type(pValue) ){
case SQLITE_NULL: {
- jsonAppendRaw(p, "null", 4);
+ jsonAppendRawNZ(p, "null", 4);
break;
}
- case SQLITE_INTEGER:
case SQLITE_FLOAT: {
+ jsonPrintf(100, p, "%!0.15g", wx_sqlite3_value_double(pValue));
+ break;
+ }
+ case SQLITE_INTEGER: {
const char *z = (const char*)wx_sqlite3_value_text(pValue);
u32 n = (u32)wx_sqlite3_value_bytes(pValue);
jsonAppendRaw(p, z, n);
@@ -199245,184 +207133,127 @@ static void jsonAppendValue(
break;
}
default: {
- if( p->bErr==0 ){
+ if( jsonFuncArgMightBeBinary(pValue) ){
+ JsonParse px;
+ memset(&px, 0, sizeof(px));
+ px.aBlob = (u8*)wx_sqlite3_value_blob(pValue);
+ px.nBlob = wx_sqlite3_value_bytes(pValue);
+ jsonTranslateBlobToText(&px, 0, p);
+ }else if( p->eErr==0 ){
wx_sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
- p->bErr = 2;
- jsonReset(p);
+ p->eErr = JSTRING_ERR;
+ jsonStringReset(p);
}
break;
}
}
}
-
-/* Make the JSON in p the result of the SQL function.
+/* Make the text in p (which is probably a generated JSON text string)
+** the result of the SQL function.
+**
+** The JsonString is reset.
+**
+** If pParse and ctx are both non-NULL, then the SQL string in p is
+** loaded into the zJson field of the pParse object as a RCStr and the
+** pParse is added to the cache.
*/
-static void jsonResult(JsonString *p){
- if( p->bErr==0 ){
- wx_sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
- p->bStatic ? SQLITE_TRANSIENT : wx_sqlite3_free,
- SQLITE_UTF8);
- jsonZero(p);
+static void jsonReturnString(
+ JsonString *p, /* String to return */
+ JsonParse *pParse, /* JSONB source or NULL */
+ wx_sqlite3_context *ctx /* Where to cache */
+){
+ assert( (pParse!=0)==(ctx!=0) );
+ assert( ctx==0 || ctx==p->pCtx );
+ if( p->eErr==0 ){
+ int flags = SQLITE_PTR_TO_INT(wx_sqlite3_user_data(p->pCtx));
+ if( flags & JSON_BLOB ){
+ jsonReturnStringAsBlob(p);
+ }else if( p->bStatic ){
+ wx_sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
+ SQLITE_TRANSIENT, SQLITE_UTF8);
+ }else if( jsonStringTerminate(p) ){
+ if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){
+ int rc;
+ pParse->zJson = wx_sqlite3RCStrRef(p->zBuf);
+ pParse->nJson = p->nUsed;
+ pParse->bJsonIsRCStr = 1;
+ rc = jsonCacheInsert(ctx, pParse);
+ if( rc==SQLITE_NOMEM ){
+ wx_sqlite3_result_error_nomem(ctx);
+ jsonStringReset(p);
+ return;
+ }
+ }
+ wx_sqlite3_result_text64(p->pCtx, wx_sqlite3RCStrRef(p->zBuf), p->nUsed,
+ wx_sqlite3RCStrUnref,
+ SQLITE_UTF8);
+ }else{
+ wx_sqlite3_result_error_nomem(p->pCtx);
+ }
+ }else if( p->eErr & JSTRING_OOM ){
+ wx_sqlite3_result_error_nomem(p->pCtx);
+ }else if( p->eErr & JSTRING_MALFORMED ){
+ wx_sqlite3_result_error(p->pCtx, "malformed JSON", -1);
}
- assert( p->bStatic );
+ jsonStringReset(p);
}
/**************************************************************************
-** Utility routines for dealing with JsonNode and JsonParse objects
+** Utility routines for dealing with JsonParse objects
**************************************************************************/
/*
-** Return the number of consecutive JsonNode slots need to represent
-** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and
-** OBJECT types, the number might be larger.
-**
-** Appended elements are not counted. The value returned is the number
-** by which the JsonNode counter should increment in order to go to the
-** next peer value.
-*/
-static u32 jsonNodeSize(JsonNode *pNode){
- return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
-}
-
-/*
** Reclaim all memory allocated by a JsonParse object. But do not
** delete the JsonParse object itself.
*/
static void jsonParseReset(JsonParse *pParse){
- wx_sqlite3_free(pParse->aNode);
- pParse->aNode = 0;
- pParse->nNode = 0;
- pParse->nAlloc = 0;
- wx_sqlite3_free(pParse->aUp);
- pParse->aUp = 0;
+ assert( pParse->nJPRef<=1 );
+ if( pParse->bJsonIsRCStr ){
+ wx_sqlite3RCStrUnref(pParse->zJson);
+ pParse->zJson = 0;
+ pParse->nJson = 0;
+ pParse->bJsonIsRCStr = 0;
+ }
+ if( pParse->nBlobAlloc ){
+ wx_sqlite3DbFree(pParse->db, pParse->aBlob);
+ pParse->aBlob = 0;
+ pParse->nBlob = 0;
+ pParse->nBlobAlloc = 0;
+ }
}
/*
-** Free a JsonParse object that was obtained from wx_sqlite3_malloc().
+** Decrement the reference count on the JsonParse object. When the
+** count reaches zero, free the object.
*/
static void jsonParseFree(JsonParse *pParse){
- jsonParseReset(pParse);
- wx_sqlite3_free(pParse);
-}
-
-/*
-** Convert the JsonNode pNode into a pure JSON string and
-** append to pOut. Subsubstructure is also included. Return
-** the number of JsonNode objects that are encoded.
-*/
-static void jsonRenderNode(
- JsonNode *pNode, /* The node to render */
- JsonString *pOut, /* Write JSON here */
- wx_sqlite3_value **aReplace /* Replacement values */
-){
- assert( pNode!=0 );
- if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
- if( (pNode->jnFlags & JNODE_REPLACE)!=0 && ALWAYS(aReplace!=0) ){
- assert( pNode->eU==4 );
- jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
- return;
- }
- assert( pNode->eU==5 );
- pNode = pNode->u.pPatch;
- }
- switch( pNode->eType ){
- default: {
- assert( pNode->eType==JSON_NULL );
- jsonAppendRaw(pOut, "null", 4);
- break;
- }
- case JSON_TRUE: {
- jsonAppendRaw(pOut, "true", 4);
- break;
- }
- case JSON_FALSE: {
- jsonAppendRaw(pOut, "false", 5);
- break;
- }
- case JSON_STRING: {
- if( pNode->jnFlags & JNODE_RAW ){
- assert( pNode->eU==1 );
- jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
- break;
- }
- /* no break */ deliberate_fall_through
- }
- case JSON_REAL:
- case JSON_INT: {
- assert( pNode->eU==1 );
- jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
- break;
- }
- case JSON_ARRAY: {
- u32 j = 1;
- jsonAppendChar(pOut, '[');
- for(;;){
- while( j<=pNode->n ){
- if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
- jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
- }
- j += jsonNodeSize(&pNode[j]);
- }
- if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pNode->eU==2 );
- pNode = &pNode[pNode->u.iAppend];
- j = 1;
- }
- jsonAppendChar(pOut, ']');
- break;
- }
- case JSON_OBJECT: {
- u32 j = 1;
- jsonAppendChar(pOut, '{');
- for(;;){
- while( j<=pNode->n ){
- if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
- jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
- jsonAppendChar(pOut, ':');
- jsonRenderNode(&pNode[j+1], pOut, aReplace);
- }
- j += 1 + jsonNodeSize(&pNode[j+1]);
- }
- if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pNode->eU==2 );
- pNode = &pNode[pNode->u.iAppend];
- j = 1;
- }
- jsonAppendChar(pOut, '}');
- break;
+ if( pParse ){
+ if( pParse->nJPRef>1 ){
+ pParse->nJPRef--;
+ }else{
+ jsonParseReset(pParse);
+ wx_sqlite3DbFree(pParse->db, pParse);
}
}
}
-/*
-** Return a JsonNode and all its descendents as a JSON string.
-*/
-static void jsonReturnJson(
- JsonNode *pNode, /* Node to return */
- wx_sqlite3_context *pCtx, /* Return value for this function */
- wx_sqlite3_value **aReplace /* Array of replacement values */
-){
- JsonString s;
- jsonInit(&s, pCtx);
- jsonRenderNode(pNode, &s, aReplace);
- jsonResult(&s);
- wx_sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
-}
+/**************************************************************************
+** Utility routines for the JSON text parser
+**************************************************************************/
/*
** Translate a single byte of Hex into an integer.
-** This routine only works if h really is a valid hexadecimal
-** character: 0..9a..fA..F
+** This routine only gives a correct answer if h really is a valid hexadecimal
+** character: 0..9a..fA..F. But unlike wx_sqlite3HexToInt(), it does not
+** assert() if the digit is not hex.
*/
static u8 jsonHexToInt(int h){
- assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
+#ifdef SQLITE_ASCII
+ h += 9*(1&(h>>6));
+#endif
#ifdef SQLITE_EBCDIC
h += 9*(1&~(h>>4));
-#else
- h += 9*(1&(h>>6));
#endif
return (u8)(h & 0xf);
}
@@ -199432,10 +207263,6 @@ static u8 jsonHexToInt(int h){
*/
static u32 jsonHexToInt4(const char *z){
u32 v;
- assert( wx_sqlite3Isxdigit(z[0]) );
- assert( wx_sqlite3Isxdigit(z[1]) );
- assert( wx_sqlite3Isxdigit(z[2]) );
- assert( wx_sqlite3Isxdigit(z[3]) );
v = (jsonHexToInt(z[0])<<12)
+ (jsonHexToInt(z[1])<<8)
+ (jsonHexToInt(z[2])<<4)
@@ -199444,420 +207271,1108 @@ static u32 jsonHexToInt4(const char *z){
}
/*
-** Make the JsonNode the return value of the function.
+** Return true if z[] begins with 2 (or more) hexadecimal digits
*/
-static void jsonReturn(
- JsonNode *pNode, /* Node to return */
- wx_sqlite3_context *pCtx, /* Return value for this function */
- wx_sqlite3_value **aReplace /* Array of replacement values */
-){
- switch( pNode->eType ){
- default: {
- assert( pNode->eType==JSON_NULL );
- wx_sqlite3_result_null(pCtx);
- break;
- }
- case JSON_TRUE: {
- wx_sqlite3_result_int(pCtx, 1);
- break;
- }
- case JSON_FALSE: {
- wx_sqlite3_result_int(pCtx, 0);
- break;
- }
- case JSON_INT: {
- wx_sqlite3_int64 i = 0;
- const char *z;
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- if( z[0]=='-' ){ z++; }
- while( z[0]>='0' && z[0]<='9' ){
- unsigned v = *(z++) - '0';
- if( i>=LARGEST_INT64/10 ){
- if( i>LARGEST_INT64/10 ) goto int_as_real;
- if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
- if( v==9 ) goto int_as_real;
- if( v==8 ){
- if( pNode->u.zJContent[0]=='-' ){
- wx_sqlite3_result_int64(pCtx, SMALLEST_INT64);
- goto int_done;
- }else{
- goto int_as_real;
+static int jsonIs2Hex(const char *z){
+ return wx_sqlite3Isxdigit(z[0]) && wx_sqlite3Isxdigit(z[1]);
+}
+
+/*
+** Return true if z[] begins with 4 (or more) hexadecimal digits
+*/
+static int jsonIs4Hex(const char *z){
+ return jsonIs2Hex(z) && jsonIs2Hex(&z[2]);
+}
+
+/*
+** Return the number of bytes of JSON5 whitespace at the beginning of
+** the input string z[].
+**
+** JSON5 whitespace consists of any of the following characters:
+**
+** Unicode UTF-8 Name
+** U+0009 09 horizontal tab
+** U+000a 0a line feed
+** U+000b 0b vertical tab
+** U+000c 0c form feed
+** U+000d 0d carriage return
+** U+0020 20 space
+** U+00a0 c2 a0 non-breaking space
+** U+1680 e1 9a 80 ogham space mark
+** U+2000 e2 80 80 en quad
+** U+2001 e2 80 81 em quad
+** U+2002 e2 80 82 en space
+** U+2003 e2 80 83 em space
+** U+2004 e2 80 84 three-per-em space
+** U+2005 e2 80 85 four-per-em space
+** U+2006 e2 80 86 six-per-em space
+** U+2007 e2 80 87 figure space
+** U+2008 e2 80 88 punctuation space
+** U+2009 e2 80 89 thin space
+** U+200a e2 80 8a hair space
+** U+2028 e2 80 a8 line separator
+** U+2029 e2 80 a9 paragraph separator
+** U+202f e2 80 af narrow no-break space (NNBSP)
+** U+205f e2 81 9f medium mathematical space (MMSP)
+** U+3000 e3 80 80 ideographical space
+** U+FEFF ef bb bf byte order mark
+**
+** In addition, comments between '/', '*' and '*', '/' and
+** from '/', '/' to end-of-line are also considered to be whitespace.
+*/
+static int json5Whitespace(const char *zIn){
+ int n = 0;
+ const u8 *z = (u8*)zIn;
+ while( 1 /*exit by "goto whitespace_done"*/ ){
+ switch( z[n] ){
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x20: {
+ n++;
+ break;
+ }
+ case '/': {
+ if( z[n+1]=='*' && z[n+2]!=0 ){
+ int j;
+ for(j=n+3; z[j]!='/' || z[j-1]!='*'; j++){
+ if( z[j]==0 ) goto whitespace_done;
+ }
+ n = j+1;
+ break;
+ }else if( z[n+1]=='/' ){
+ int j;
+ char c;
+ for(j=n+2; (c = z[j])!=0; j++){
+ if( c=='\n' || c=='\r' ) break;
+ if( 0xe2==(u8)c && 0x80==(u8)z[j+1]
+ && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])
+ ){
+ j += 2;
+ break;
}
}
+ n = j;
+ if( z[n] ) n++;
+ break;
}
- i = i*10 + v;
+ goto whitespace_done;
}
- if( pNode->u.zJContent[0]=='-' ){ i = -i; }
- wx_sqlite3_result_int64(pCtx, i);
- int_done:
- break;
- int_as_real: ; /* no break */ deliberate_fall_through
- }
- case JSON_REAL: {
- double r;
-#ifdef SQLITE_AMALGAMATION
- const char *z;
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- wx_sqlite3AtoF(z, &r, wx_sqlite3Strlen30(z), SQLITE_UTF8);
-#else
- assert( pNode->eU==1 );
- r = strtod(pNode->u.zJContent, 0);
-#endif
- wx_sqlite3_result_double(pCtx, r);
- break;
- }
- case JSON_STRING: {
-#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
- ** json_insert() and json_replace() and those routines do not
- ** call jsonReturn() */
- if( pNode->jnFlags & JNODE_RAW ){
- assert( pNode->eU==1 );
- wx_sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
- SQLITE_TRANSIENT);
- }else
-#endif
- assert( (pNode->jnFlags & JNODE_RAW)==0 );
- if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
- /* JSON formatted without any backslash-escapes */
- assert( pNode->eU==1 );
- wx_sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
- SQLITE_TRANSIENT);
- }else{
- /* Translate JSON formatted string into raw text */
- u32 i;
- u32 n = pNode->n;
- const char *z;
- char *zOut;
- u32 j;
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- zOut = wx_sqlite3_malloc( n+1 );
- if( zOut==0 ){
- wx_sqlite3_result_error_nomem(pCtx);
+ case 0xc2: {
+ if( z[n+1]==0xa0 ){
+ n += 2;
break;
}
- for(i=1, j=0; i<n-1; i++){
- char c = z[i];
- if( c!='\\' ){
- zOut[j++] = c;
- }else{
- c = z[++i];
- if( c=='u' ){
- u32 v = jsonHexToInt4(z+i+1);
- i += 4;
- if( v==0 ) break;
- if( v<=0x7f ){
- zOut[j++] = (char)v;
- }else if( v<=0x7ff ){
- zOut[j++] = (char)(0xc0 | (v>>6));
- zOut[j++] = 0x80 | (v&0x3f);
- }else{
- u32 vlo;
- if( (v&0xfc00)==0xd800
- && i<n-6
- && z[i+1]=='\\'
- && z[i+2]=='u'
- && ((vlo = jsonHexToInt4(z+i+3))&0xfc00)==0xdc00
- ){
- /* We have a surrogate pair */
- v = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
- i += 6;
- zOut[j++] = 0xf0 | (v>>18);
- zOut[j++] = 0x80 | ((v>>12)&0x3f);
- zOut[j++] = 0x80 | ((v>>6)&0x3f);
- zOut[j++] = 0x80 | (v&0x3f);
- }else{
- zOut[j++] = 0xe0 | (v>>12);
- zOut[j++] = 0x80 | ((v>>6)&0x3f);
- zOut[j++] = 0x80 | (v&0x3f);
- }
- }
- }else{
- if( c=='b' ){
- c = '\b';
- }else if( c=='f' ){
- c = '\f';
- }else if( c=='n' ){
- c = '\n';
- }else if( c=='r' ){
- c = '\r';
- }else if( c=='t' ){
- c = '\t';
- }
- zOut[j++] = c;
- }
+ goto whitespace_done;
+ }
+ case 0xe1: {
+ if( z[n+1]==0x9a && z[n+2]==0x80 ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xe2: {
+ if( z[n+1]==0x80 ){
+ u8 c = z[n+2];
+ if( c<0x80 ) goto whitespace_done;
+ if( c<=0x8a || c==0xa8 || c==0xa9 || c==0xaf ){
+ n += 3;
+ break;
}
+ }else if( z[n+1]==0x81 && z[n+2]==0x9f ){
+ n += 3;
+ break;
}
- zOut[j] = 0;
- wx_sqlite3_result_text(pCtx, zOut, j, wx_sqlite3_free);
+ goto whitespace_done;
+ }
+ case 0xe3: {
+ if( z[n+1]==0x80 && z[n+2]==0x80 ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xef: {
+ if( z[n+1]==0xbb && z[n+2]==0xbf ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ default: {
+ goto whitespace_done;
}
- break;
- }
- case JSON_ARRAY:
- case JSON_OBJECT: {
- jsonReturnJson(pNode, pCtx, aReplace);
- break;
}
}
+ whitespace_done:
+ return n;
}
-/* Forward reference */
-static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
-
/*
-** A macro to hint to the compiler that a function should not be
-** inlined.
+** Extra floating-point literals to allow in JSON.
*/
-#if defined(__GNUC__)
-# define JSON_NOINLINE __attribute__((noinline))
-#elif defined(_MSC_VER) && _MSC_VER>=1310
-# define JSON_NOINLINE __declspec(noinline)
-#else
-# define JSON_NOINLINE
-#endif
+static const struct NanInfName {
+ char c1;
+ char c2;
+ char n;
+ char eType;
+ char nRepl;
+ char *zMatch;
+ char *zRepl;
+} aNanInfName[] = {
+ { 'i', 'I', 3, JSONB_FLOAT, 7, "inf", "9.0e999" },
+ { 'i', 'I', 8, JSONB_FLOAT, 7, "infinity", "9.0e999" },
+ { 'n', 'N', 3, JSONB_NULL, 4, "NaN", "null" },
+ { 'q', 'Q', 4, JSONB_NULL, 4, "QNaN", "null" },
+ { 's', 'S', 4, JSONB_NULL, 4, "SNaN", "null" },
+};
-static JSON_NOINLINE int jsonParseAddNodeExpand(
- JsonParse *pParse, /* Append the node to this object */
- u32 eType, /* Node type */
- u32 n, /* Content size or sub-node count */
- const char *zContent /* Content */
+/*
+** Report the wrong number of arguments for json_insert(), json_replace()
+** or json_set().
+*/
+static void jsonWrongNumArgs(
+ wx_sqlite3_context *pCtx,
+ const char *zFuncName
){
- u32 nNew;
- JsonNode *pNew;
- assert( pParse->nNode>=pParse->nAlloc );
- if( pParse->oom ) return -1;
- nNew = pParse->nAlloc*2 + 10;
- pNew = wx_sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew);
- if( pNew==0 ){
- pParse->oom = 1;
- return -1;
+ char *zMsg = wx_sqlite3_mprintf("json_%s() needs an odd number of arguments",
+ zFuncName);
+ wx_sqlite3_result_error(pCtx, zMsg, -1);
+ wx_sqlite3_free(zMsg);
+}
+
+/****************************************************************************
+** Utility routines for dealing with the binary BLOB representation of JSON
+****************************************************************************/
+
+/*
+** Expand pParse->aBlob so that it holds at least N bytes.
+**
+** Return the number of errors.
+*/
+static int jsonBlobExpand(JsonParse *pParse, u32 N){
+ u8 *aNew;
+ u32 t;
+ assert( N>pParse->nBlobAlloc );
+ if( pParse->nBlobAlloc==0 ){
+ t = 100;
+ }else{
+ t = pParse->nBlobAlloc*2;
}
- pParse->nAlloc = nNew;
- pParse->aNode = pNew;
- assert( pParse->nNode<pParse->nAlloc );
- return jsonParseAddNode(pParse, eType, n, zContent);
+ if( t<N ) t = N+100;
+ aNew = wx_sqlite3DbRealloc(pParse->db, pParse->aBlob, t);
+ if( aNew==0 ){ pParse->oom = 1; return 1; }
+ pParse->aBlob = aNew;
+ pParse->nBlobAlloc = t;
+ return 0;
}
/*
-** Create a new JsonNode instance based on the arguments and append that
-** instance to the JsonParse. Return the index in pParse->aNode[] of the
-** new node, or -1 if a memory allocation fails.
+** If pParse->aBlob is not previously editable (because it is taken
+** from wx_sqlite3_value_blob(), as indicated by the fact that
+** pParse->nBlobAlloc==0 and pParse->nBlob>0) then make it editable
+** by making a copy into space obtained from malloc.
+**
+** Return true on success. Return false on OOM.
+*/
+static int jsonBlobMakeEditable(JsonParse *pParse, u32 nExtra){
+ u8 *aOld;
+ u32 nSize;
+ assert( !pParse->bReadOnly );
+ if( pParse->oom ) return 0;
+ if( pParse->nBlobAlloc>0 ) return 1;
+ aOld = pParse->aBlob;
+ nSize = pParse->nBlob + nExtra;
+ pParse->aBlob = 0;
+ if( jsonBlobExpand(pParse, nSize) ){
+ return 0;
+ }
+ assert( pParse->nBlobAlloc >= pParse->nBlob + nExtra );
+ memcpy(pParse->aBlob, aOld, pParse->nBlob);
+ return 1;
+}
+
+/* Expand pParse->aBlob and append one bytes.
*/
-static int jsonParseAddNode(
- JsonParse *pParse, /* Append the node to this object */
- u32 eType, /* Node type */
- u32 n, /* Content size or sub-node count */
- const char *zContent /* Content */
+static SQLITE_NOINLINE void jsonBlobExpandAndAppendOneByte(
+ JsonParse *pParse,
+ u8 c
){
- JsonNode *p;
- if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){
- return jsonParseAddNodeExpand(pParse, eType, n, zContent);
+ jsonBlobExpand(pParse, pParse->nBlob+1);
+ if( pParse->oom==0 ){
+ assert( pParse->nBlob+1<=pParse->nBlobAlloc );
+ pParse->aBlob[pParse->nBlob++] = c;
}
- p = &pParse->aNode[pParse->nNode];
- p->eType = (u8)eType;
- p->jnFlags = 0;
- VVA( p->eU = zContent ? 1 : 0 );
- p->n = n;
- p->u.zJContent = zContent;
- return pParse->nNode++;
+}
+
+/* Append a single character.
+*/
+static void jsonBlobAppendOneByte(JsonParse *pParse, u8 c){
+ if( pParse->nBlob >= pParse->nBlobAlloc ){
+ jsonBlobExpandAndAppendOneByte(pParse, c);
+ }else{
+ pParse->aBlob[pParse->nBlob++] = c;
+ }
+}
+
+/* Slow version of jsonBlobAppendNode() that first resizes the
+** pParse->aBlob structure.
+*/
+static void jsonBlobAppendNode(JsonParse*,u8,u32,const void*);
+static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode(
+ JsonParse *pParse,
+ u8 eType,
+ u32 szPayload,
+ const void *aPayload
+){
+ if( jsonBlobExpand(pParse, pParse->nBlob+szPayload+9) ) return;
+ jsonBlobAppendNode(pParse, eType, szPayload, aPayload);
+}
+
+
+/* Append an node type byte together with the payload size and
+** possibly also the payload.
+**
+** If aPayload is not NULL, then it is a pointer to the payload which
+** is also appended. If aPayload is NULL, the pParse->aBlob[] array
+** is resized (if necessary) so that it is big enough to hold the
+** payload, but the payload is not appended and pParse->nBlob is left
+** pointing to where the first byte of payload will eventually be.
+*/
+static void jsonBlobAppendNode(
+ JsonParse *pParse, /* The JsonParse object under construction */
+ u8 eType, /* Node type. One of JSONB_* */
+ u32 szPayload, /* Number of bytes of payload */
+ const void *aPayload /* The payload. Might be NULL */
+){
+ u8 *a;
+ if( pParse->nBlob+szPayload+9 > pParse->nBlobAlloc ){
+ jsonBlobExpandAndAppendNode(pParse,eType,szPayload,aPayload);
+ return;
+ }
+ assert( pParse->aBlob!=0 );
+ a = &pParse->aBlob[pParse->nBlob];
+ if( szPayload<=11 ){
+ a[0] = eType | (szPayload<<4);
+ pParse->nBlob += 1;
+ }else if( szPayload<=0xff ){
+ a[0] = eType | 0xc0;
+ a[1] = szPayload & 0xff;
+ pParse->nBlob += 2;
+ }else if( szPayload<=0xffff ){
+ a[0] = eType | 0xd0;
+ a[1] = (szPayload >> 8) & 0xff;
+ a[2] = szPayload & 0xff;
+ pParse->nBlob += 3;
+ }else{
+ a[0] = eType | 0xe0;
+ a[1] = (szPayload >> 24) & 0xff;
+ a[2] = (szPayload >> 16) & 0xff;
+ a[3] = (szPayload >> 8) & 0xff;
+ a[4] = szPayload & 0xff;
+ pParse->nBlob += 5;
+ }
+ if( aPayload ){
+ pParse->nBlob += szPayload;
+ memcpy(&pParse->aBlob[pParse->nBlob-szPayload], aPayload, szPayload);
+ }
+}
+
+/* Change the payload size for the node at index i to be szPayload.
+*/
+static int jsonBlobChangePayloadSize(
+ JsonParse *pParse,
+ u32 i,
+ u32 szPayload
+){
+ u8 *a;
+ u8 szType;
+ u8 nExtra;
+ u8 nNeeded;
+ int delta;
+ if( pParse->oom ) return 0;
+ a = &pParse->aBlob[i];
+ szType = a[0]>>4;
+ if( szType<=11 ){
+ nExtra = 0;
+ }else if( szType==12 ){
+ nExtra = 1;
+ }else if( szType==13 ){
+ nExtra = 2;
+ }else{
+ nExtra = 4;
+ }
+ if( szPayload<=11 ){
+ nNeeded = 0;
+ }else if( szPayload<=0xff ){
+ nNeeded = 1;
+ }else if( szPayload<=0xffff ){
+ nNeeded = 2;
+ }else{
+ nNeeded = 4;
+ }
+ delta = nNeeded - nExtra;
+ if( delta ){
+ u32 newSize = pParse->nBlob + delta;
+ if( delta>0 ){
+ if( newSize>pParse->nBlobAlloc && jsonBlobExpand(pParse, newSize) ){
+ return 0; /* OOM error. Error state recorded in pParse->oom. */
+ }
+ a = &pParse->aBlob[i];
+ memmove(&a[1+delta], &a[1], pParse->nBlob - (i+1));
+ }else{
+ memmove(&a[1], &a[1-delta], pParse->nBlob - (i+1-delta));
+ }
+ pParse->nBlob = newSize;
+ }
+ if( nNeeded==0 ){
+ a[0] = (a[0] & 0x0f) | (szPayload<<4);
+ }else if( nNeeded==1 ){
+ a[0] = (a[0] & 0x0f) | 0xc0;
+ a[1] = szPayload & 0xff;
+ }else if( nNeeded==2 ){
+ a[0] = (a[0] & 0x0f) | 0xd0;
+ a[1] = (szPayload >> 8) & 0xff;
+ a[2] = szPayload & 0xff;
+ }else{
+ a[0] = (a[0] & 0x0f) | 0xe0;
+ a[1] = (szPayload >> 24) & 0xff;
+ a[2] = (szPayload >> 16) & 0xff;
+ a[3] = (szPayload >> 8) & 0xff;
+ a[4] = szPayload & 0xff;
+ }
+ return delta;
}
/*
-** Return true if z[] begins with 4 (or more) hexadecimal digits
+** If z[0] is 'u' and is followed by exactly 4 hexadecimal character,
+** then set *pOp to JSONB_TEXTJ and return true. If not, do not make
+** any changes to *pOp and return false.
*/
-static int jsonIs4Hex(const char *z){
- int i;
- for(i=0; i<4; i++) if( !wx_sqlite3Isxdigit(z[i]) ) return 0;
+static int jsonIs4HexB(const char *z, int *pOp){
+ if( z[0]!='u' ) return 0;
+ if( !jsonIs4Hex(&z[1]) ) return 0;
+ *pOp = JSONB_TEXTJ;
return 1;
}
/*
-** Parse a single JSON value which begins at pParse->zJson[i]. Return the
-** index of the first character past the end of the value parsed.
+** Check a single element of the JSONB in pParse for validity.
+**
+** The element to be checked starts at offset i and must end at on the
+** last byte before iEnd.
+**
+** Return 0 if everything is correct. Return the 1-based byte offset of the
+** error if a problem is detected. (In other words, if the error is at offset
+** 0, return 1).
+*/
+static u32 jsonbValidityCheck(
+ const JsonParse *pParse, /* Input JSONB. Only aBlob and nBlob are used */
+ u32 i, /* Start of element as pParse->aBlob[i] */
+ u32 iEnd, /* One more than the last byte of the element */
+ u32 iDepth /* Current nesting depth */
+){
+ u32 n, sz, j, k;
+ const u8 *z;
+ u8 x;
+ if( iDepth>JSON_MAX_DEPTH ) return i+1;
+ sz = 0;
+ n = jsonbPayloadSize(pParse, i, &sz);
+ if( NEVER(n==0) ) return i+1; /* Checked by caller */
+ if( NEVER(i+n+sz!=iEnd) ) return i+1; /* Checked by caller */
+ z = pParse->aBlob;
+ x = z[i] & 0x0f;
+ switch( x ){
+ case JSONB_NULL:
+ case JSONB_TRUE:
+ case JSONB_FALSE: {
+ return n+sz==1 ? 0 : i+1;
+ }
+ case JSONB_INT: {
+ if( sz<1 ) return i+1;
+ j = i+n;
+ if( z[j]=='-' ){
+ j++;
+ if( sz<2 ) return i+1;
+ }
+ k = i+n+sz;
+ while( j<k ){
+ if( wx_sqlite3Isdigit(z[j]) ){
+ j++;
+ }else{
+ return j+1;
+ }
+ }
+ return 0;
+ }
+ case JSONB_INT5: {
+ if( sz<3 ) return i+1;
+ j = i+n;
+ if( z[j]=='-' ){
+ if( sz<4 ) return i+1;
+ j++;
+ }
+ if( z[j]!='0' ) return i+1;
+ if( z[j+1]!='x' && z[j+1]!='X' ) return j+2;
+ j += 2;
+ k = i+n+sz;
+ while( j<k ){
+ if( wx_sqlite3Isxdigit(z[j]) ){
+ j++;
+ }else{
+ return j+1;
+ }
+ }
+ return 0;
+ }
+ case JSONB_FLOAT:
+ case JSONB_FLOAT5: {
+ u8 seen = 0; /* 0: initial. 1: '.' seen 2: 'e' seen */
+ if( sz<2 ) return i+1;
+ j = i+n;
+ k = j+sz;
+ if( z[j]=='-' ){
+ j++;
+ if( sz<3 ) return i+1;
+ }
+ if( z[j]=='.' ){
+ if( x==JSONB_FLOAT ) return j+1;
+ if( !wx_sqlite3Isdigit(z[j+1]) ) return j+1;
+ j += 2;
+ seen = 1;
+ }else if( z[j]=='0' && x==JSONB_FLOAT ){
+ if( j+3>k ) return j+1;
+ if( z[j+1]!='.' && z[j+1]!='e' && z[j+1]!='E' ) return j+1;
+ j++;
+ }
+ for(; j<k; j++){
+ if( wx_sqlite3Isdigit(z[j]) ) continue;
+ if( z[j]=='.' ){
+ if( seen>0 ) return j+1;
+ if( x==JSONB_FLOAT && (j==k-1 || !wx_sqlite3Isdigit(z[j+1])) ){
+ return j+1;
+ }
+ seen = 1;
+ continue;
+ }
+ if( z[j]=='e' || z[j]=='E' ){
+ if( seen==2 ) return j+1;
+ if( j==k-1 ) return j+1;
+ if( z[j+1]=='+' || z[j+1]=='-' ){
+ j++;
+ if( j==k-1 ) return j+1;
+ }
+ seen = 2;
+ continue;
+ }
+ return j+1;
+ }
+ if( seen==0 ) return i+1;
+ return 0;
+ }
+ case JSONB_TEXT: {
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ if( !jsonIsOk[z[j]] && z[j]!='\'' ) return j+1;
+ j++;
+ }
+ return 0;
+ }
+ case JSONB_TEXTJ:
+ case JSONB_TEXT5: {
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ if( !jsonIsOk[z[j]] && z[j]!='\'' ){
+ if( z[j]=='"' ){
+ if( x==JSONB_TEXTJ ) return j+1;
+ }else if( z[j]<=0x1f ){
+ /* Control characters in JSON5 string literals are ok */
+ if( x==JSONB_TEXTJ ) return j+1;
+ }else if( NEVER(z[j]!='\\') || j+1>=k ){
+ return j+1;
+ }else if( strchr("\"\\/bfnrt",z[j+1])!=0 ){
+ j++;
+ }else if( z[j+1]=='u' ){
+ if( j+5>=k ) return j+1;
+ if( !jsonIs4Hex((const char*)&z[j+2]) ) return j+1;
+ j++;
+ }else if( x!=JSONB_TEXT5 ){
+ return j+1;
+ }else{
+ u32 c = 0;
+ u32 szC = jsonUnescapeOneChar((const char*)&z[j], k-j, &c);
+ if( c==JSON_INVALID_CHAR ) return j+1;
+ j += szC - 1;
+ }
+ }
+ j++;
+ }
+ return 0;
+ }
+ case JSONB_TEXTRAW: {
+ return 0;
+ }
+ case JSONB_ARRAY: {
+ u32 sub;
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ sz = 0;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return j+1;
+ if( j+n+sz>k ) return j+1;
+ sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1);
+ if( sub ) return sub;
+ j += n + sz;
+ }
+ assert( j==k );
+ return 0;
+ }
+ case JSONB_OBJECT: {
+ u32 cnt = 0;
+ u32 sub;
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ sz = 0;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return j+1;
+ if( j+n+sz>k ) return j+1;
+ if( (cnt & 1)==0 ){
+ x = z[j] & 0x0f;
+ if( x<JSONB_TEXT || x>JSONB_TEXTRAW ) return j+1;
+ }
+ sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1);
+ if( sub ) return sub;
+ cnt++;
+ j += n + sz;
+ }
+ assert( j==k );
+ if( (cnt & 1)!=0 ) return j+1;
+ return 0;
+ }
+ default: {
+ return i+1;
+ }
+ }
+}
+
+/*
+** Translate a single element of JSON text at pParse->zJson[i] into
+** its equivalent binary JSONB representation. Append the translation into
+** pParse->aBlob[] beginning at pParse->nBlob. The size of
+** pParse->aBlob[] is increased as necessary.
+**
+** Return the index of the first character past the end of the element parsed,
+** or one of the following special result codes:
**
-** Return negative for a syntax error. Special cases: return -2 if the
-** first non-whitespace character is '}' and return -3 if the first
-** non-whitespace character is ']'.
+** 0 End of input
+** -1 Syntax error or OOM
+** -2 '}' seen \
+** -3 ']' seen \___ For these returns, pParse->iErr is set to
+** -4 ',' seen / the index in zJson[] of the seen character
+** -5 ':' seen /
*/
-static int jsonParseValue(JsonParse *pParse, u32 i){
+static int jsonTranslateTextToBlob(JsonParse *pParse, u32 i){
char c;
u32 j;
- int iThis;
+ u32 iThis, iStart;
int x;
- JsonNode *pNode;
+ u8 t;
const char *z = pParse->zJson;
- while( fast_isspace(z[i]) ){ i++; }
- if( (c = z[i])=='{' ){
+json_parse_restart:
+ switch( (u8)z[i] ){
+ case '{': {
/* Parse object */
- iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
- if( iThis<0 ) return -1;
+ iThis = pParse->nBlob;
+ jsonBlobAppendNode(pParse, JSONB_OBJECT, pParse->nJson-i, 0);
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+ pParse->iErr = i;
+ return -1;
+ }
+ iStart = pParse->nBlob;
for(j=i+1;;j++){
- while( fast_isspace(z[j]) ){ j++; }
- if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
- x = jsonParseValue(pParse, j);
- if( x<0 ){
- pParse->iDepth--;
- if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
- return -1;
+ u32 iBlob = pParse->nBlob;
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x<=0 ){
+ int op;
+ if( x==(-2) ){
+ j = pParse->iErr;
+ if( pParse->nBlob!=(u32)iStart ) pParse->hasNonstd = 1;
+ break;
+ }
+ j += json5Whitespace(&z[j]);
+ op = JSONB_TEXT;
+ if( wx_sqlite3JsonId1(z[j])
+ || (z[j]=='\\' && jsonIs4HexB(&z[j+1], &op))
+ ){
+ int k = j+1;
+ while( (wx_sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0)
+ || (z[k]=='\\' && jsonIs4HexB(&z[k+1], &op))
+ ){
+ k++;
+ }
+ assert( iBlob==pParse->nBlob );
+ jsonBlobAppendNode(pParse, op, k-j, &z[j]);
+ pParse->hasNonstd = 1;
+ x = k;
+ }else{
+ if( x!=-1 ) pParse->iErr = j;
+ return -1;
+ }
}
if( pParse->oom ) return -1;
- pNode = &pParse->aNode[pParse->nNode-1];
- if( pNode->eType!=JSON_STRING ) return -1;
- pNode->jnFlags |= JNODE_LABEL;
+ t = pParse->aBlob[iBlob] & 0x0f;
+ if( t<JSONB_TEXT || t>JSONB_TEXTRAW ){
+ pParse->iErr = j;
+ return -1;
+ }
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- if( z[j]!=':' ) return -1;
- j++;
- x = jsonParseValue(pParse, j);
- pParse->iDepth--;
- if( x<0 ) return -1;
+ if( z[j]==':' ){
+ j++;
+ }else{
+ if( jsonIsspace(z[j]) ){
+ /* strspn() is not helpful here */
+ do{ j++; }while( jsonIsspace(z[j]) );
+ if( z[j]==':' ){
+ j++;
+ goto parse_object_value;
+ }
+ }
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x!=(-5) ){
+ if( x!=(-1) ) pParse->iErr = j;
+ return -1;
+ }
+ j = pParse->iErr+1;
+ }
+ parse_object_value:
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x<=0 ){
+ if( x!=(-1) ) pParse->iErr = j;
+ return -1;
+ }
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- c = z[j];
- if( c==',' ) continue;
- if( c!='}' ) return -1;
- break;
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]=='}' ){
+ break;
+ }else{
+ if( jsonIsspace(z[j]) ){
+ j += 1 + (u32)strspn(&z[j+1], jsonSpaces);
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]=='}' ){
+ break;
+ }
+ }
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x==(-4) ){
+ j = pParse->iErr;
+ continue;
+ }
+ if( x==(-2) ){
+ j = pParse->iErr;
+ break;
+ }
+ }
+ pParse->iErr = j;
+ return -1;
}
- pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart);
+ pParse->iDepth--;
return j+1;
- }else if( c=='[' ){
+ }
+ case '[': {
/* Parse array */
- iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
- if( iThis<0 ) return -1;
- memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u));
+ iThis = pParse->nBlob;
+ assert( i<=(u32)pParse->nJson );
+ jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0);
+ iStart = pParse->nBlob;
+ if( pParse->oom ) return -1;
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+ pParse->iErr = i;
+ return -1;
+ }
for(j=i+1;;j++){
- while( fast_isspace(z[j]) ){ j++; }
- if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
- x = jsonParseValue(pParse, j);
- pParse->iDepth--;
- if( x<0 ){
- if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x<=0 ){
+ if( x==(-3) ){
+ j = pParse->iErr;
+ if( pParse->nBlob!=iStart ) pParse->hasNonstd = 1;
+ break;
+ }
+ if( x!=(-1) ) pParse->iErr = j;
return -1;
}
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- c = z[j];
- if( c==',' ) continue;
- if( c!=']' ) return -1;
- break;
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]==']' ){
+ break;
+ }else{
+ if( jsonIsspace(z[j]) ){
+ j += 1 + (u32)strspn(&z[j+1], jsonSpaces);
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]==']' ){
+ break;
+ }
+ }
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x==(-4) ){
+ j = pParse->iErr;
+ continue;
+ }
+ if( x==(-3) ){
+ j = pParse->iErr;
+ break;
+ }
+ }
+ pParse->iErr = j;
+ return -1;
}
- pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart);
+ pParse->iDepth--;
return j+1;
- }else if( c=='"' ){
+ }
+ case '\'': {
+ u8 opcode;
+ char cDelim;
+ pParse->hasNonstd = 1;
+ opcode = JSONB_TEXT;
+ goto parse_string;
+ case '"':
/* Parse string */
- u8 jnFlags = 0;
+ opcode = JSONB_TEXT;
+ parse_string:
+ cDelim = z[i];
j = i+1;
- for(;;){
- c = z[j];
- if( (c & ~0x1f)==0 ){
- /* Control characters are not allowed in strings */
- return -1;
+ while( 1 /*exit-by-break*/ ){
+ if( jsonIsOk[(u8)z[j]] ){
+ if( !jsonIsOk[(u8)z[j+1]] ){
+ j += 1;
+ }else if( !jsonIsOk[(u8)z[j+2]] ){
+ j += 2;
+ }else{
+ j += 3;
+ continue;
+ }
}
- if( c=='\\' ){
+ c = z[j];
+ if( c==cDelim ){
+ break;
+ }else if( c=='\\' ){
c = z[++j];
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|| c=='n' || c=='r' || c=='t'
- || (c=='u' && jsonIs4Hex(z+j+1)) ){
- jnFlags = JNODE_ESCAPE;
+ || (c=='u' && jsonIs4Hex(&z[j+1])) ){
+ if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ;
+ }else if( c=='\'' || c=='0' || c=='v' || c=='\n'
+ || (0xe2==(u8)c && 0x80==(u8)z[j+1]
+ && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]))
+ || (c=='x' && jsonIs2Hex(&z[j+1])) ){
+ opcode = JSONB_TEXT5;
+ pParse->hasNonstd = 1;
+ }else if( c=='\r' ){
+ if( z[j+1]=='\n' ) j++;
+ opcode = JSONB_TEXT5;
+ pParse->hasNonstd = 1;
}else{
+ pParse->iErr = j;
return -1;
}
+ }else if( c<=0x1f ){
+ if( c==0 ){
+ pParse->iErr = j;
+ return -1;
+ }
+ /* Control characters are not allowed in canonical JSON string
+ ** literals, but are allowed in JSON5 string literals. */
+ opcode = JSONB_TEXT5;
+ pParse->hasNonstd = 1;
}else if( c=='"' ){
- break;
+ opcode = JSONB_TEXT5;
}
j++;
}
- jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
- if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
+ jsonBlobAppendNode(pParse, opcode, j-1-i, &z[i+1]);
return j+1;
- }else if( c=='n'
- && strncmp(z+i,"null",4)==0
- && !wx_sqlite3Isalnum(z[i+4]) ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return i+4;
- }else if( c=='t'
- && strncmp(z+i,"true",4)==0
- && !wx_sqlite3Isalnum(z[i+4]) ){
- jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
- return i+4;
- }else if( c=='f'
- && strncmp(z+i,"false",5)==0
- && !wx_sqlite3Isalnum(z[i+5]) ){
- jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
- return i+5;
- }else if( c=='-' || (c>='0' && c<='9') ){
+ }
+ case 't': {
+ if( strncmp(z+i,"true",4)==0 && !wx_sqlite3Isalnum(z[i+4]) ){
+ jsonBlobAppendOneByte(pParse, JSONB_TRUE);
+ return i+4;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case 'f': {
+ if( strncmp(z+i,"false",5)==0 && !wx_sqlite3Isalnum(z[i+5]) ){
+ jsonBlobAppendOneByte(pParse, JSONB_FALSE);
+ return i+5;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case '+': {
+ u8 seenE;
+ pParse->hasNonstd = 1;
+ t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */
+ goto parse_number;
+ case '.':
+ if( wx_sqlite3Isdigit(z[i+1]) ){
+ pParse->hasNonstd = 1;
+ t = 0x03; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */
+ seenE = 0;
+ goto parse_number_2;
+ }
+ pParse->iErr = i;
+ return -1;
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
/* Parse number */
- u8 seenDP = 0;
- u8 seenE = 0;
+ t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */
+ parse_number:
+ seenE = 0;
assert( '-' < '0' );
+ assert( '+' < '0' );
+ assert( '.' < '0' );
+ c = z[i];
+
if( c<='0' ){
- j = c=='-' ? i+1 : i;
- if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
+ if( c=='0' ){
+ if( (z[i+1]=='x' || z[i+1]=='X') && wx_sqlite3Isxdigit(z[i+2]) ){
+ assert( t==0x00 );
+ pParse->hasNonstd = 1;
+ t = 0x01;
+ for(j=i+3; wx_sqlite3Isxdigit(z[j]); j++){}
+ goto parse_number_finish;
+ }else if( wx_sqlite3Isdigit(z[i+1]) ){
+ pParse->iErr = i+1;
+ return -1;
+ }
+ }else{
+ if( !wx_sqlite3Isdigit(z[i+1]) ){
+ /* JSON5 allows for "+Infinity" and "-Infinity" using exactly
+ ** that case. SQLite also allows these in any case and it allows
+ ** "+inf" and "-inf". */
+ if( (z[i+1]=='I' || z[i+1]=='i')
+ && wx_sqlite3StrNICmp(&z[i+1], "inf",3)==0
+ ){
+ pParse->hasNonstd = 1;
+ if( z[i]=='-' ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999");
+ }else{
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
+ }
+ return i + (wx_sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4);
+ }
+ if( z[i+1]=='.' ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ goto parse_number_2;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ if( z[i+1]=='0' ){
+ if( wx_sqlite3Isdigit(z[i+2]) ){
+ pParse->iErr = i+1;
+ return -1;
+ }else if( (z[i+2]=='x' || z[i+2]=='X') && wx_sqlite3Isxdigit(z[i+3]) ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ for(j=i+4; wx_sqlite3Isxdigit(z[j]); j++){}
+ goto parse_number_finish;
+ }
+ }
+ }
}
- j = i+1;
- for(;; j++){
+
+ parse_number_2:
+ for(j=i+1;; j++){
c = z[j];
- if( c>='0' && c<='9' ) continue;
+ if( wx_sqlite3Isdigit(c) ) continue;
if( c=='.' ){
- if( z[j-1]=='-' ) return -1;
- if( seenDP ) return -1;
- seenDP = 1;
+ if( (t & 0x02)!=0 ){
+ pParse->iErr = j;
+ return -1;
+ }
+ t |= 0x02;
continue;
}
if( c=='e' || c=='E' ){
- if( z[j-1]<'0' ) return -1;
- if( seenE ) return -1;
- seenDP = seenE = 1;
+ if( z[j-1]<'0' ){
+ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && wx_sqlite3Isdigit(z[j-2]) ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ }else{
+ pParse->iErr = j;
+ return -1;
+ }
+ }
+ if( seenE ){
+ pParse->iErr = j;
+ return -1;
+ }
+ t |= 0x02;
+ seenE = 1;
c = z[j+1];
if( c=='+' || c=='-' ){
j++;
c = z[j+1];
}
- if( c<'0' || c>'9' ) return -1;
+ if( c<'0' || c>'9' ){
+ pParse->iErr = j;
+ return -1;
+ }
continue;
}
break;
}
- if( z[j-1]<'0' ) return -1;
- jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
- j - i, &z[i]);
+ if( z[j-1]<'0' ){
+ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && wx_sqlite3Isdigit(z[j-2]) ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ }else{
+ pParse->iErr = j;
+ return -1;
+ }
+ }
+ parse_number_finish:
+ assert( JSONB_INT+0x01==JSONB_INT5 );
+ assert( JSONB_FLOAT+0x01==JSONB_FLOAT5 );
+ assert( JSONB_INT+0x02==JSONB_FLOAT );
+ if( z[i]=='+' ) i++;
+ jsonBlobAppendNode(pParse, JSONB_INT+t, j-i, &z[i]);
return j;
- }else if( c=='}' ){
+ }
+ case '}': {
+ pParse->iErr = i;
return -2; /* End of {...} */
- }else if( c==']' ){
+ }
+ case ']': {
+ pParse->iErr = i;
return -3; /* End of [...] */
- }else if( c==0 ){
+ }
+ case ',': {
+ pParse->iErr = i;
+ return -4; /* List separator */
+ }
+ case ':': {
+ pParse->iErr = i;
+ return -5; /* Object label/value separator */
+ }
+ case 0: {
return 0; /* End of file */
- }else{
+ }
+ case 0x09:
+ case 0x0a:
+ case 0x0d:
+ case 0x20: {
+ i += 1 + (u32)strspn(&z[i+1], jsonSpaces);
+ goto json_parse_restart;
+ }
+ case 0x0b:
+ case 0x0c:
+ case '/':
+ case 0xc2:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xef: {
+ j = json5Whitespace(&z[i]);
+ if( j>0 ){
+ i += j;
+ pParse->hasNonstd = 1;
+ goto json_parse_restart;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case 'n': {
+ if( strncmp(z+i,"null",4)==0 && !wx_sqlite3Isalnum(z[i+4]) ){
+ jsonBlobAppendOneByte(pParse, JSONB_NULL);
+ return i+4;
+ }
+ /* fall-through into the default case that checks for NaN */
+ /* no break */ deliberate_fall_through
+ }
+ default: {
+ u32 k;
+ int nn;
+ c = z[i];
+ for(k=0; k<sizeof(aNanInfName)/sizeof(aNanInfName[0]); k++){
+ if( c!=aNanInfName[k].c1 && c!=aNanInfName[k].c2 ) continue;
+ nn = aNanInfName[k].n;
+ if( wx_sqlite3StrNICmp(&z[i], aNanInfName[k].zMatch, nn)!=0 ){
+ continue;
+ }
+ if( wx_sqlite3Isalnum(z[i+nn]) ) continue;
+ if( aNanInfName[k].eType==JSONB_FLOAT ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
+ }else{
+ jsonBlobAppendOneByte(pParse, JSONB_NULL);
+ }
+ pParse->hasNonstd = 1;
+ return i + nn;
+ }
+ pParse->iErr = i;
return -1; /* Syntax error */
}
+ } /* End switch(z[i]) */
}
+
/*
** Parse a complete JSON string. Return 0 on success or non-zero if there
-** are any errors. If an error occurs, free all memory associated with
-** pParse.
+** are any errors. If an error occurs, free all memory held by pParse,
+** but not pParse itself.
**
-** pParse is uninitialized when this routine is called.
+** pParse must be initialized to an empty parse object prior to calling
+** this routine.
*/
-static int jsonParse(
+static int jsonConvertTextToBlob(
JsonParse *pParse, /* Initialize and fill this JsonParse object */
- wx_sqlite3_context *pCtx, /* Report errors here */
- const char *zJson /* Input JSON text to be parsed */
+ wx_sqlite3_context *pCtx /* Report errors here */
){
int i;
- memset(pParse, 0, sizeof(*pParse));
- if( zJson==0 ) return 1;
- pParse->zJson = zJson;
- i = jsonParseValue(pParse, 0);
+ const char *zJson = pParse->zJson;
+ i = jsonTranslateTextToBlob(pParse, 0);
if( pParse->oom ) i = -1;
if( i>0 ){
+#ifdef SQLITE_DEBUG
assert( pParse->iDepth==0 );
- while( fast_isspace(zJson[i]) ) i++;
- if( zJson[i] ) i = -1;
+ if( wx_sqlite3Config.bJsonSelfcheck ){
+ assert( jsonbValidityCheck(pParse, 0, pParse->nBlob, 0)==0 );
+ }
+#endif
+ while( jsonIsspace(zJson[i]) ) i++;
+ if( zJson[i] ){
+ i += json5Whitespace(&zJson[i]);
+ if( zJson[i] ){
+ if( pCtx ) wx_sqlite3_result_error(pCtx, "malformed JSON", -1);
+ jsonParseReset(pParse);
+ return 1;
+ }
+ pParse->hasNonstd = 1;
+ }
}
if( i<=0 ){
if( pCtx!=0 ){
@@ -199873,466 +208388,1687 @@ static int jsonParse(
return 0;
}
-/* Mark node i of pParse as being a child of iParent. Call recursively
-** to fill in all the descendants of node i.
+/*
+** The input string pStr is a well-formed JSON text string. Convert
+** this into the JSONB format and make it the return value of the
+** SQL function.
*/
-static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
- JsonNode *pNode = &pParse->aNode[i];
- u32 j;
- pParse->aUp[i] = iParent;
- switch( pNode->eType ){
- case JSON_ARRAY: {
- for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
- jsonParseFillInParentage(pParse, i+j, i);
+static void jsonReturnStringAsBlob(JsonString *pStr){
+ JsonParse px;
+ memset(&px, 0, sizeof(px));
+ jsonStringTerminate(pStr);
+ if( pStr->eErr ){
+ wx_sqlite3_result_error_nomem(pStr->pCtx);
+ return;
+ }
+ px.zJson = pStr->zBuf;
+ px.nJson = pStr->nUsed;
+ px.db = wx_sqlite3_context_db_handle(pStr->pCtx);
+ (void)jsonTranslateTextToBlob(&px, 0);
+ if( px.oom ){
+ wx_sqlite3DbFree(px.db, px.aBlob);
+ wx_sqlite3_result_error_nomem(pStr->pCtx);
+ }else{
+ assert( px.nBlobAlloc>0 );
+ assert( !px.bReadOnly );
+ wx_sqlite3_result_blob(pStr->pCtx, px.aBlob, px.nBlob, SQLITE_DYNAMIC);
+ }
+}
+
+/* The byte at index i is a node type-code. This routine
+** determines the payload size for that node and writes that
+** payload size in to *pSz. It returns the offset from i to the
+** beginning of the payload. Return 0 on error.
+*/
+static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
+ u8 x;
+ u32 sz;
+ u32 n;
+ if( NEVER(i>pParse->nBlob) ){
+ *pSz = 0;
+ return 0;
+ }
+ x = pParse->aBlob[i]>>4;
+ if( x<=11 ){
+ sz = x;
+ n = 1;
+ }else if( x==12 ){
+ if( i+1>=pParse->nBlob ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = pParse->aBlob[i+1];
+ n = 2;
+ }else if( x==13 ){
+ if( i+2>=pParse->nBlob ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = (pParse->aBlob[i+1]<<8) + pParse->aBlob[i+2];
+ n = 3;
+ }else if( x==14 ){
+ if( i+4>=pParse->nBlob ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = ((u32)pParse->aBlob[i+1]<<24) + (pParse->aBlob[i+2]<<16) +
+ (pParse->aBlob[i+3]<<8) + pParse->aBlob[i+4];
+ n = 5;
+ }else{
+ if( i+8>=pParse->nBlob
+ || pParse->aBlob[i+1]!=0
+ || pParse->aBlob[i+2]!=0
+ || pParse->aBlob[i+3]!=0
+ || pParse->aBlob[i+4]!=0
+ ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) +
+ (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8];
+ n = 9;
+ }
+ if( (i64)i+sz+n > pParse->nBlob
+ && (i64)i+sz+n > pParse->nBlob-pParse->delta
+ ){
+ sz = 0;
+ n = 0;
+ }
+ *pSz = sz;
+ return n;
+}
+
+
+/*
+** Translate the binary JSONB representation of JSON beginning at
+** pParse->aBlob[i] into a JSON text string. Append the JSON
+** text onto the end of pOut. Return the index in pParse->aBlob[]
+** of the first byte past the end of the element that is translated.
+**
+** If an error is detected in the BLOB input, the pOut->eErr flag
+** might get set to JSTRING_MALFORMED. But not all BLOB input errors
+** are detected. So a malformed JSONB input might either result
+** in an error, or in incorrect JSON.
+**
+** The pOut->eErr JSTRING_OOM flag is set on a OOM.
+*/
+static u32 jsonTranslateBlobToText(
+ const JsonParse *pParse, /* the complete parse of the JSON */
+ u32 i, /* Start rendering at this index */
+ JsonString *pOut /* Write JSON here */
+){
+ u32 sz, n, j, iEnd;
+
+ n = jsonbPayloadSize(pParse, i, &sz);
+ if( n==0 ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ return pParse->nBlob+1;
+ }
+ switch( pParse->aBlob[i] & 0x0f ){
+ case JSONB_NULL: {
+ jsonAppendRawNZ(pOut, "null", 4);
+ return i+1;
+ }
+ case JSONB_TRUE: {
+ jsonAppendRawNZ(pOut, "true", 4);
+ return i+1;
+ }
+ case JSONB_FALSE: {
+ jsonAppendRawNZ(pOut, "false", 5);
+ return i+1;
+ }
+ case JSONB_INT:
+ case JSONB_FLOAT: {
+ if( sz==0 ) goto malformed_jsonb;
+ jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz);
+ break;
+ }
+ case JSONB_INT5: { /* Integer literal in hexadecimal notation */
+ u32 k = 2;
+ wx_sqlite3_uint64 u = 0;
+ const char *zIn = (const char*)&pParse->aBlob[i+n];
+ int bOverflow = 0;
+ if( sz==0 ) goto malformed_jsonb;
+ if( zIn[0]=='-' ){
+ jsonAppendChar(pOut, '-');
+ k++;
+ }else if( zIn[0]=='+' ){
+ k++;
+ }
+ for(; k<sz; k++){
+ if( !wx_sqlite3Isxdigit(zIn[k]) ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ break;
+ }else if( (u>>60)!=0 ){
+ bOverflow = 1;
+ }else{
+ u = u*16 + wx_sqlite3HexToInt(zIn[k]);
+ }
+ }
+ jsonPrintf(100,pOut,bOverflow?"9.0e999":"%llu", u);
+ break;
+ }
+ case JSONB_FLOAT5: { /* Float literal missing digits beside "." */
+ u32 k = 0;
+ const char *zIn = (const char*)&pParse->aBlob[i+n];
+ if( sz==0 ) goto malformed_jsonb;
+ if( zIn[0]=='-' ){
+ jsonAppendChar(pOut, '-');
+ k++;
+ }
+ if( zIn[k]=='.' ){
+ jsonAppendChar(pOut, '0');
+ }
+ for(; k<sz; k++){
+ jsonAppendChar(pOut, zIn[k]);
+ if( zIn[k]=='.' && (k+1==sz || !wx_sqlite3Isdigit(zIn[k+1])) ){
+ jsonAppendChar(pOut, '0');
+ }
+ }
+ break;
+ }
+ case JSONB_TEXT:
+ case JSONB_TEXTJ: {
+ jsonAppendChar(pOut, '"');
+ jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz);
+ jsonAppendChar(pOut, '"');
+ break;
+ }
+ case JSONB_TEXT5: {
+ const char *zIn;
+ u32 k;
+ u32 sz2 = sz;
+ zIn = (const char*)&pParse->aBlob[i+n];
+ jsonAppendChar(pOut, '"');
+ while( sz2>0 ){
+ for(k=0; k<sz2 && (jsonIsOk[(u8)zIn[k]] || zIn[k]=='\''); k++){}
+ if( k>0 ){
+ jsonAppendRawNZ(pOut, zIn, k);
+ if( k>=sz2 ){
+ break;
+ }
+ zIn += k;
+ sz2 -= k;
+ }
+ if( zIn[0]=='"' ){
+ jsonAppendRawNZ(pOut, "\\\"", 2);
+ zIn++;
+ sz2--;
+ continue;
+ }
+ if( zIn[0]<=0x1f ){
+ if( pOut->nUsed+7>pOut->nAlloc && jsonStringGrow(pOut,7) ) break;
+ jsonAppendControlChar(pOut, zIn[0]);
+ zIn++;
+ sz2--;
+ continue;
+ }
+ assert( zIn[0]=='\\' );
+ assert( sz2>=1 );
+ if( sz2<2 ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ break;
+ }
+ switch( (u8)zIn[1] ){
+ case '\'':
+ jsonAppendChar(pOut, '\'');
+ break;
+ case 'v':
+ jsonAppendRawNZ(pOut, "\\u0009", 6);
+ break;
+ case 'x':
+ if( sz2<4 ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ sz2 = 2;
+ break;
+ }
+ jsonAppendRawNZ(pOut, "\\u00", 4);
+ jsonAppendRawNZ(pOut, &zIn[2], 2);
+ zIn += 2;
+ sz2 -= 2;
+ break;
+ case '0':
+ jsonAppendRawNZ(pOut, "\\u0000", 6);
+ break;
+ case '\r':
+ if( sz2>2 && zIn[2]=='\n' ){
+ zIn++;
+ sz2--;
+ }
+ break;
+ case '\n':
+ break;
+ case 0xe2:
+ /* '\' followed by either U+2028 or U+2029 is ignored as
+ ** whitespace. Not that in UTF8, U+2028 is 0xe2 0x80 0x29.
+ ** U+2029 is the same except for the last byte */
+ if( sz2<4
+ || 0x80!=(u8)zIn[2]
+ || (0xa8!=(u8)zIn[3] && 0xa9!=(u8)zIn[3])
+ ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ sz2 = 2;
+ break;
+ }
+ zIn += 2;
+ sz2 -= 2;
+ break;
+ default:
+ jsonAppendRawNZ(pOut, zIn, 2);
+ break;
+ }
+ assert( sz2>=2 );
+ zIn += 2;
+ sz2 -= 2;
+ }
+ jsonAppendChar(pOut, '"');
+ break;
+ }
+ case JSONB_TEXTRAW: {
+ jsonAppendString(pOut, (const char*)&pParse->aBlob[i+n], sz);
+ break;
+ }
+ case JSONB_ARRAY: {
+ jsonAppendChar(pOut, '[');
+ j = i+n;
+ iEnd = j+sz;
+ while( j<iEnd && pOut->eErr==0 ){
+ j = jsonTranslateBlobToText(pParse, j, pOut);
+ jsonAppendChar(pOut, ',');
+ }
+ if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
+ if( sz>0 ) jsonStringTrimOneChar(pOut);
+ jsonAppendChar(pOut, ']');
+ break;
+ }
+ case JSONB_OBJECT: {
+ int x = 0;
+ jsonAppendChar(pOut, '{');
+ j = i+n;
+ iEnd = j+sz;
+ while( j<iEnd && pOut->eErr==0 ){
+ j = jsonTranslateBlobToText(pParse, j, pOut);
+ jsonAppendChar(pOut, (x++ & 1) ? ',' : ':');
+ }
+ if( (x & 1)!=0 || j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
+ if( sz>0 ) jsonStringTrimOneChar(pOut);
+ jsonAppendChar(pOut, '}');
+ break;
+ }
+
+ default: {
+ malformed_jsonb:
+ pOut->eErr |= JSTRING_MALFORMED;
+ break;
+ }
+ }
+ return i+n+sz;
+}
+
+/* Context for recursion of json_pretty()
+*/
+typedef struct JsonPretty JsonPretty;
+struct JsonPretty {
+ JsonParse *pParse; /* The BLOB being rendered */
+ JsonString *pOut; /* Generate pretty output into this string */
+ const char *zIndent; /* Use this text for indentation */
+ u32 szIndent; /* Bytes in zIndent[] */
+ u32 nIndent; /* Current level of indentation */
+};
+
+/* Append indentation to the pretty JSON under construction */
+static void jsonPrettyIndent(JsonPretty *pPretty){
+ u32 jj;
+ for(jj=0; jj<pPretty->nIndent; jj++){
+ jsonAppendRaw(pPretty->pOut, pPretty->zIndent, pPretty->szIndent);
+ }
+}
+
+/*
+** Translate the binary JSONB representation of JSON beginning at
+** pParse->aBlob[i] into a JSON text string. Append the JSON
+** text onto the end of pOut. Return the index in pParse->aBlob[]
+** of the first byte past the end of the element that is translated.
+**
+** This is a variant of jsonTranslateBlobToText() that "pretty-prints"
+** the output. Extra whitespace is inserted to make the JSON easier
+** for humans to read.
+**
+** If an error is detected in the BLOB input, the pOut->eErr flag
+** might get set to JSTRING_MALFORMED. But not all BLOB input errors
+** are detected. So a malformed JSONB input might either result
+** in an error, or in incorrect JSON.
+**
+** The pOut->eErr JSTRING_OOM flag is set on a OOM.
+*/
+static u32 jsonTranslateBlobToPrettyText(
+ JsonPretty *pPretty, /* Pretty-printing context */
+ u32 i /* Start rendering at this index */
+){
+ u32 sz, n, j, iEnd;
+ const JsonParse *pParse = pPretty->pParse;
+ JsonString *pOut = pPretty->pOut;
+ n = jsonbPayloadSize(pParse, i, &sz);
+ if( n==0 ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ return pParse->nBlob+1;
+ }
+ switch( pParse->aBlob[i] & 0x0f ){
+ case JSONB_ARRAY: {
+ j = i+n;
+ iEnd = j+sz;
+ jsonAppendChar(pOut, '[');
+ if( j<iEnd ){
+ jsonAppendChar(pOut, '\n');
+ pPretty->nIndent++;
+ while( pOut->eErr==0 ){
+ jsonPrettyIndent(pPretty);
+ j = jsonTranslateBlobToPrettyText(pPretty, j);
+ if( j>=iEnd ) break;
+ jsonAppendRawNZ(pOut, ",\n", 2);
+ }
+ jsonAppendChar(pOut, '\n');
+ pPretty->nIndent--;
+ jsonPrettyIndent(pPretty);
}
+ jsonAppendChar(pOut, ']');
+ i = iEnd;
break;
}
- case JSON_OBJECT: {
- for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
- pParse->aUp[i+j] = i;
- jsonParseFillInParentage(pParse, i+j+1, i);
+ case JSONB_OBJECT: {
+ j = i+n;
+ iEnd = j+sz;
+ jsonAppendChar(pOut, '{');
+ if( j<iEnd ){
+ jsonAppendChar(pOut, '\n');
+ pPretty->nIndent++;
+ while( pOut->eErr==0 ){
+ jsonPrettyIndent(pPretty);
+ j = jsonTranslateBlobToText(pParse, j, pOut);
+ if( j>iEnd ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ break;
+ }
+ jsonAppendRawNZ(pOut, ": ", 2);
+ j = jsonTranslateBlobToPrettyText(pPretty, j);
+ if( j>=iEnd ) break;
+ jsonAppendRawNZ(pOut, ",\n", 2);
+ }
+ jsonAppendChar(pOut, '\n');
+ pPretty->nIndent--;
+ jsonPrettyIndent(pPretty);
}
+ jsonAppendChar(pOut, '}');
+ i = iEnd;
break;
}
default: {
+ i = jsonTranslateBlobToText(pParse, i, pOut);
break;
}
}
+ return i;
+}
+
+
+/* Return true if the input pJson
+**
+** For performance reasons, this routine does not do a detailed check of the
+** input BLOB to ensure that it is well-formed. Hence, false positives are
+** possible. False negatives should never occur, however.
+*/
+static int jsonFuncArgMightBeBinary(wx_sqlite3_value *pJson){
+ u32 sz, n;
+ const u8 *aBlob;
+ int nBlob;
+ JsonParse s;
+ if( wx_sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0;
+ aBlob = wx_sqlite3_value_blob(pJson);
+ nBlob = wx_sqlite3_value_bytes(pJson);
+ if( nBlob<1 ) return 0;
+ if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0;
+ memset(&s, 0, sizeof(s));
+ s.aBlob = (u8*)aBlob;
+ s.nBlob = nBlob;
+ n = jsonbPayloadSize(&s, 0, &sz);
+ if( n==0 ) return 0;
+ if( sz+n!=(u32)nBlob ) return 0;
+ if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0;
+ return sz+n==(u32)nBlob;
}
/*
-** Compute the parentage of all nodes in a completed parse.
+** Given that a JSONB_ARRAY object starts at offset i, return
+** the number of entries in that array.
*/
-static int jsonParseFindParents(JsonParse *pParse){
- u32 *aUp;
- assert( pParse->aUp==0 );
- aUp = pParse->aUp = wx_sqlite3_malloc64( sizeof(u32)*pParse->nNode );
- if( aUp==0 ){
- pParse->oom = 1;
- return SQLITE_NOMEM;
+static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){
+ u32 n, sz, i, iEnd;
+ u32 k = 0;
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ iEnd = iRoot+n+sz;
+ for(i=iRoot+n; n>0 && i<iEnd; i+=sz+n, k++){
+ n = jsonbPayloadSize(pParse, i, &sz);
}
- jsonParseFillInParentage(pParse, 0, 0);
- return SQLITE_OK;
+ return k;
}
/*
-** Magic number used for the JSON parse cache in wx_sqlite3_get_auxdata()
+** Edit the payload size of the element at iRoot by the amount in
+** pParse->delta.
*/
-#define JSON_CACHE_ID (-429938) /* First cache entry */
-#define JSON_CACHE_SZ 4 /* Max number of cache entries */
+static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){
+ u32 sz = 0;
+ u32 nBlob;
+ assert( pParse->delta!=0 );
+ assert( pParse->nBlobAlloc >= pParse->nBlob );
+ nBlob = pParse->nBlob;
+ pParse->nBlob = pParse->nBlobAlloc;
+ (void)jsonbPayloadSize(pParse, iRoot, &sz);
+ pParse->nBlob = nBlob;
+ sz += pParse->delta;
+ pParse->delta += jsonBlobChangePayloadSize(pParse, iRoot, sz);
+}
/*
-** Obtain a complete parse of the JSON found in the first argument
-** of the argv array. Use the wx_sqlite3_get_auxdata() cache for this
-** parse if it is available. If the cache is not available or if it
-** is no longer valid, parse the JSON again and return the new parse,
-** and also register the new parse so that it will be available for
-** future wx_sqlite3_get_auxdata() calls.
+** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of
+** content beginning at iDel, and replacing them with nIns bytes of
+** content given by aIns.
+**
+** nDel may be zero, in which case no bytes are removed. But iDel is
+** still important as new bytes will be insert beginning at iDel.
+**
+** aIns may be zero, in which case space is created to hold nIns bytes
+** beginning at iDel, but that space is uninitialized.
+**
+** Set pParse->oom if an OOM occurs.
*/
-static JsonParse *jsonParseCached(
- wx_sqlite3_context *pCtx,
- wx_sqlite3_value **argv,
- wx_sqlite3_context *pErrCtx
+static void jsonBlobEdit(
+ JsonParse *pParse, /* The JSONB to be modified is in pParse->aBlob */
+ u32 iDel, /* First byte to be removed */
+ u32 nDel, /* Number of bytes to remove */
+ const u8 *aIns, /* Content to insert */
+ u32 nIns /* Bytes of content to insert */
){
- const char *zJson = (const char*)wx_sqlite3_value_text(argv[0]);
- int nJson = wx_sqlite3_value_bytes(argv[0]);
- JsonParse *p;
- JsonParse *pMatch = 0;
- int iKey;
- int iMinKey = 0;
- u32 iMinHold = 0xffffffff;
- u32 iMaxHold = 0;
- if( zJson==0 ) return 0;
- for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){
- p = (JsonParse*)wx_sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey);
- if( p==0 ){
- iMinKey = iKey;
- break;
+ i64 d = (i64)nIns - (i64)nDel;
+ if( d!=0 ){
+ if( pParse->nBlob + d > pParse->nBlobAlloc ){
+ jsonBlobExpand(pParse, pParse->nBlob+d);
+ if( pParse->oom ) return;
}
- if( pMatch==0
- && p->nJson==nJson
- && memcmp(p->zJson,zJson,nJson)==0
- ){
- p->nErr = 0;
- pMatch = p;
- }else if( p->iHold<iMinHold ){
- iMinHold = p->iHold;
- iMinKey = iKey;
+ memmove(&pParse->aBlob[iDel+nIns],
+ &pParse->aBlob[iDel+nDel],
+ pParse->nBlob - (iDel+nDel));
+ pParse->nBlob += d;
+ pParse->delta += d;
+ }
+ if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns);
+}
+
+/*
+** Return the number of escaped newlines to be ignored.
+** An escaped newline is a one of the following byte sequences:
+**
+** 0x5c 0x0a
+** 0x5c 0x0d
+** 0x5c 0x0d 0x0a
+** 0x5c 0xe2 0x80 0xa8
+** 0x5c 0xe2 0x80 0xa9
+*/
+static u32 jsonBytesToBypass(const char *z, u32 n){
+ u32 i = 0;
+ while( i+1<n ){
+ if( z[i]!='\\' ) return i;
+ if( z[i+1]=='\n' ){
+ i += 2;
+ continue;
}
- if( p->iHold>iMaxHold ){
- iMaxHold = p->iHold;
+ if( z[i+1]=='\r' ){
+ if( i+2<n && z[i+2]=='\n' ){
+ i += 3;
+ }else{
+ i += 2;
+ }
+ continue;
}
+ if( 0xe2==(u8)z[i+1]
+ && i+3<n
+ && 0x80==(u8)z[i+2]
+ && (0xa8==(u8)z[i+3] || 0xa9==(u8)z[i+3])
+ ){
+ i += 4;
+ continue;
+ }
+ break;
}
- if( pMatch ){
- pMatch->nErr = 0;
- pMatch->iHold = iMaxHold+1;
- return pMatch;
+ return i;
+}
+
+/*
+** Input z[0..n] defines JSON escape sequence including the leading '\\'.
+** Decode that escape sequence into a single character. Write that
+** character into *piOut. Return the number of bytes in the escape sequence.
+**
+** If there is a syntax error of some kind (for example too few characters
+** after the '\\' to complete the encoding) then *piOut is set to
+** JSON_INVALID_CHAR.
+*/
+static u32 jsonUnescapeOneChar(const char *z, u32 n, u32 *piOut){
+ assert( n>0 );
+ assert( z[0]=='\\' );
+ if( n<2 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
}
- p = wx_sqlite3_malloc64( sizeof(*p) + nJson + 1 );
- if( p==0 ){
- wx_sqlite3_result_error_nomem(pCtx);
- return 0;
+ switch( (u8)z[1] ){
+ case 'u': {
+ u32 v, vlo;
+ if( n<6 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
+ }
+ v = jsonHexToInt4(&z[2]);
+ if( (v & 0xfc00)==0xd800
+ && n>=12
+ && z[6]=='\\'
+ && z[7]=='u'
+ && ((vlo = jsonHexToInt4(&z[8]))&0xfc00)==0xdc00
+ ){
+ *piOut = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
+ return 12;
+ }else{
+ *piOut = v;
+ return 6;
+ }
+ }
+ case 'b': { *piOut = '\b'; return 2; }
+ case 'f': { *piOut = '\f'; return 2; }
+ case 'n': { *piOut = '\n'; return 2; }
+ case 'r': { *piOut = '\r'; return 2; }
+ case 't': { *piOut = '\t'; return 2; }
+ case 'v': { *piOut = '\v'; return 2; }
+ case '0': { *piOut = 0; return 2; }
+ case '\'':
+ case '"':
+ case '/':
+ case '\\':{ *piOut = z[1]; return 2; }
+ case 'x': {
+ if( n<4 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
+ }
+ *piOut = (jsonHexToInt(z[2])<<4) | jsonHexToInt(z[3]);
+ return 4;
+ }
+ case 0xe2:
+ case '\r':
+ case '\n': {
+ u32 nSkip = jsonBytesToBypass(z, n);
+ if( nSkip==0 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
+ }else if( nSkip==n ){
+ *piOut = 0;
+ return n;
+ }else if( z[nSkip]=='\\' ){
+ return nSkip + jsonUnescapeOneChar(&z[nSkip], n-nSkip, piOut);
+ }else{
+ int sz = wx_sqlite3Utf8ReadLimited((u8*)&z[nSkip], n-nSkip, piOut);
+ return nSkip + sz;
+ }
+ }
+ default: {
+ *piOut = JSON_INVALID_CHAR;
+ return 2;
+ }
}
- memset(p, 0, sizeof(*p));
- p->zJson = (char*)&p[1];
- memcpy((char*)p->zJson, zJson, nJson+1);
- if( jsonParse(p, pErrCtx, p->zJson) ){
- wx_sqlite3_free(p);
- return 0;
+}
+
+
+/*
+** Compare two object labels. Return 1 if they are equal and
+** 0 if they differ.
+**
+** In this version, we know that one or the other or both of the
+** two comparands contains an escape sequence.
+*/
+static SQLITE_NOINLINE int jsonLabelCompareEscaped(
+ const char *zLeft, /* The left label */
+ u32 nLeft, /* Size of the left label in bytes */
+ int rawLeft, /* True if zLeft contains no escapes */
+ const char *zRight, /* The right label */
+ u32 nRight, /* Size of the right label in bytes */
+ int rawRight /* True if zRight is escape-free */
+){
+ u32 cLeft, cRight;
+ assert( rawLeft==0 || rawRight==0 );
+ while( 1 /*exit-by-return*/ ){
+ if( nLeft==0 ){
+ cLeft = 0;
+ }else if( rawLeft || zLeft[0]!='\\' ){
+ cLeft = ((u8*)zLeft)[0];
+ if( cLeft>=0xc0 ){
+ int sz = wx_sqlite3Utf8ReadLimited((u8*)zLeft, nLeft, &cLeft);
+ zLeft += sz;
+ nLeft -= sz;
+ }else{
+ zLeft++;
+ nLeft--;
+ }
+ }else{
+ u32 n = jsonUnescapeOneChar(zLeft, nLeft, &cLeft);
+ zLeft += n;
+ assert( n<=nLeft );
+ nLeft -= n;
+ }
+ if( nRight==0 ){
+ cRight = 0;
+ }else if( rawRight || zRight[0]!='\\' ){
+ cRight = ((u8*)zRight)[0];
+ if( cRight>=0xc0 ){
+ int sz = wx_sqlite3Utf8ReadLimited((u8*)zRight, nRight, &cRight);
+ zRight += sz;
+ nRight -= sz;
+ }else{
+ zRight++;
+ nRight--;
+ }
+ }else{
+ u32 n = jsonUnescapeOneChar(zRight, nRight, &cRight);
+ zRight += n;
+ assert( n<=nRight );
+ nRight -= n;
+ }
+ if( cLeft!=cRight ) return 0;
+ if( cLeft==0 ) return 1;
}
- p->nJson = nJson;
- p->iHold = iMaxHold+1;
- wx_sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
- (void(*)(void*))jsonParseFree);
- return (JsonParse*)wx_sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
}
/*
-** Compare the OBJECT label at pNode against zKey,nKey. Return true on
-** a match.
+** Compare two object labels. Return 1 if they are equal and
+** 0 if they differ. Return -1 if an OOM occurs.
*/
-static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
- assert( pNode->eU==1 );
- if( pNode->jnFlags & JNODE_RAW ){
- if( pNode->n!=nKey ) return 0;
- return strncmp(pNode->u.zJContent, zKey, nKey)==0;
+static int jsonLabelCompare(
+ const char *zLeft, /* The left label */
+ u32 nLeft, /* Size of the left label in bytes */
+ int rawLeft, /* True if zLeft contains no escapes */
+ const char *zRight, /* The right label */
+ u32 nRight, /* Size of the right label in bytes */
+ int rawRight /* True if zRight is escape-free */
+){
+ if( rawLeft && rawRight ){
+ /* Simpliest case: Neither label contains escapes. A simple
+ ** memcmp() is sufficient. */
+ if( nLeft!=nRight ) return 0;
+ return memcmp(zLeft, zRight, nLeft)==0;
}else{
- if( pNode->n!=nKey+2 ) return 0;
- return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
+ return jsonLabelCompareEscaped(zLeft, nLeft, rawLeft,
+ zRight, nRight, rawRight);
}
}
-/* forward declaration */
-static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
+/*
+** Error returns from jsonLookupStep()
+*/
+#define JSON_LOOKUP_ERROR 0xffffffff
+#define JSON_LOOKUP_NOTFOUND 0xfffffffe
+#define JSON_LOOKUP_PATHERROR 0xfffffffd
+#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR)
+
+/* Forward declaration */
+static u32 jsonLookupStep(JsonParse*,u32,const char*,u32);
+
+
+/* This helper routine for jsonLookupStep() populates pIns with
+** binary data that is to be inserted into pParse.
+**
+** In the common case, pIns just points to pParse->aIns and pParse->nIns.
+** But if the zPath of the original edit operation includes path elements
+** that go deeper, additional substructure must be created.
+**
+** For example:
+**
+** json_insert('{}', '$.a.b.c', 123);
+**
+** The search stops at '$.a' But additional substructure must be
+** created for the ".b.c" part of the patch so that the final result
+** is: {"a":{"b":{"c"::123}}}. This routine populates pIns with
+** the binary equivalent of {"b":{"c":123}} so that it can be inserted.
+**
+** The caller is responsible for resetting pIns when it has finished
+** using the substructure.
+*/
+static u32 jsonCreateEditSubstructure(
+ JsonParse *pParse, /* The original JSONB that is being edited */
+ JsonParse *pIns, /* Populate this with the blob data to insert */
+ const char *zTail /* Tail of the path that determins substructure */
+){
+ static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT };
+ int rc;
+ memset(pIns, 0, sizeof(*pIns));
+ pIns->db = pParse->db;
+ if( zTail[0]==0 ){
+ /* No substructure. Just insert what is given in pParse. */
+ pIns->aBlob = pParse->aIns;
+ pIns->nBlob = pParse->nIns;
+ rc = 0;
+ }else{
+ /* Construct the binary substructure */
+ pIns->nBlob = 1;
+ pIns->aBlob = (u8*)&emptyObject[zTail[0]=='.'];
+ pIns->eEdit = pParse->eEdit;
+ pIns->nIns = pParse->nIns;
+ pIns->aIns = pParse->aIns;
+ rc = jsonLookupStep(pIns, 0, zTail, 0);
+ pParse->oom |= pIns->oom;
+ }
+ return rc; /* Error code only */
+}
/*
-** Search along zPath to find the node specified. Return a pointer
-** to that node, or NULL if zPath is malformed or if there is no such
-** node.
+** Search along zPath to find the Json element specified. Return an
+** index into pParse->aBlob[] for the start of that element's value.
**
-** If pApnd!=0, then try to append new nodes to complete zPath if it is
-** possible to do so and if no existing node corresponds to zPath. If
-** new nodes are appended *pApnd is set to 1.
+** If the value found by this routine is the value half of label/value pair
+** within an object, then set pPath->iLabel to the start of the corresponding
+** label, before returning.
+**
+** Return one of the JSON_LOOKUP error codes if problems are seen.
+**
+** This routine will also modify the blob. If pParse->eEdit is one of
+** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be
+** made to the selected value. If an edit is performed, then the return
+** value does not necessarily point to the select element. If an edit
+** is performed, the return value is only useful for detecting error
+** conditions.
*/
-static JsonNode *jsonLookupStep(
+static u32 jsonLookupStep(
JsonParse *pParse, /* The JSON to search */
- u32 iRoot, /* Begin the search at this node */
+ u32 iRoot, /* Begin the search at this element of aBlob[] */
const char *zPath, /* The path to search */
- int *pApnd, /* Append nodes to complete path if not NULL */
- const char **pzErr /* Make *pzErr point to any syntax error in zPath */
+ u32 iLabel /* Label if iRoot is a value of in an object */
){
- u32 i, j, nKey;
+ u32 i, j, k, nKey, sz, n, iEnd, rc;
const char *zKey;
- JsonNode *pRoot = &pParse->aNode[iRoot];
- if( zPath[0]==0 ) return pRoot;
- if( pRoot->jnFlags & JNODE_REPLACE ) return 0;
+ u8 x;
+
+ if( zPath[0]==0 ){
+ if( pParse->eEdit && jsonBlobMakeEditable(pParse, pParse->nIns) ){
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ sz += n;
+ if( pParse->eEdit==JEDIT_DEL ){
+ if( iLabel>0 ){
+ sz += iRoot - iLabel;
+ iRoot = iLabel;
+ }
+ jsonBlobEdit(pParse, iRoot, sz, 0, 0);
+ }else if( pParse->eEdit==JEDIT_INS ){
+ /* Already exists, so json_insert() is a no-op */
+ }else{
+ /* json_set() or json_replace() */
+ jsonBlobEdit(pParse, iRoot, sz, pParse->aIns, pParse->nIns);
+ }
+ }
+ pParse->iLabel = iLabel;
+ return iRoot;
+ }
if( zPath[0]=='.' ){
- if( pRoot->eType!=JSON_OBJECT ) return 0;
+ int rawKey = 1;
+ x = pParse->aBlob[iRoot];
zPath++;
if( zPath[0]=='"' ){
zKey = zPath + 1;
- for(i=1; zPath[i] && zPath[i]!='"'; i++){}
+ for(i=1; zPath[i] && zPath[i]!='"'; i++){
+ if( zPath[i]=='\\' && zPath[i+1]!=0 ) i++;
+ }
nKey = i-1;
if( zPath[i] ){
i++;
}else{
- *pzErr = zPath;
- return 0;
+ return JSON_LOOKUP_PATHERROR;
}
testcase( nKey==0 );
+ rawKey = memchr(zKey, '\\', nKey)==0;
}else{
zKey = zPath;
for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
nKey = i;
if( nKey==0 ){
- *pzErr = zPath;
- return 0;
- }
- }
- j = 1;
- for(;;){
- while( j<=pRoot->n ){
- if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
- return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
- }
- j++;
- j += jsonNodeSize(&pRoot[j]);
+ return JSON_LOOKUP_PATHERROR;
+ }
+ }
+ if( (x & 0x0f)!=JSONB_OBJECT ) return JSON_LOOKUP_NOTFOUND;
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ j = iRoot + n; /* j is the index of a label */
+ iEnd = j+sz;
+ while( j<iEnd ){
+ int rawLabel;
+ const char *zLabel;
+ x = pParse->aBlob[j] & 0x0f;
+ if( x<JSONB_TEXT || x>JSONB_TEXTRAW ) return JSON_LOOKUP_ERROR;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return JSON_LOOKUP_ERROR;
+ k = j+n; /* k is the index of the label text */
+ if( k+sz>=iEnd ) return JSON_LOOKUP_ERROR;
+ zLabel = (const char*)&pParse->aBlob[k];
+ rawLabel = x==JSONB_TEXT || x==JSONB_TEXTRAW;
+ if( jsonLabelCompare(zKey, nKey, rawKey, zLabel, sz, rawLabel) ){
+ u32 v = k+sz; /* v is the index of the value */
+ if( ((pParse->aBlob[v])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR;
+ n = jsonbPayloadSize(pParse, v, &sz);
+ if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR;
+ assert( j>0 );
+ rc = jsonLookupStep(pParse, v, &zPath[i], j);
+ if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ return rc;
}
- if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pRoot->eU==2 );
- iRoot += pRoot->u.iAppend;
- pRoot = &pParse->aNode[iRoot];
- j = 1;
- }
- if( pApnd ){
- u32 iStart, iLabel;
- JsonNode *pNode;
- iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
- iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
- zPath += i;
- pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
- if( pParse->oom ) return 0;
- if( pNode ){
- pRoot = &pParse->aNode[iRoot];
- assert( pRoot->eU==0 );
- pRoot->u.iAppend = iStart - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
- VVA( pRoot->eU = 2 );
- pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
- }
- return pNode;
+ j = k+sz;
+ if( ((pParse->aBlob[j])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return JSON_LOOKUP_ERROR;
+ j += n+sz;
+ }
+ if( j>iEnd ) return JSON_LOOKUP_ERROR;
+ if( pParse->eEdit>=JEDIT_INS ){
+ u32 nIns; /* Total bytes to insert (label+value) */
+ JsonParse v; /* BLOB encoding of the value to be inserted */
+ JsonParse ix; /* Header of the label to be inserted */
+ testcase( pParse->eEdit==JEDIT_INS );
+ testcase( pParse->eEdit==JEDIT_SET );
+ memset(&ix, 0, sizeof(ix));
+ ix.db = pParse->db;
+ jsonBlobAppendNode(&ix, rawKey?JSONB_TEXTRAW:JSONB_TEXT5, nKey, 0);
+ pParse->oom |= ix.oom;
+ rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i]);
+ if( !JSON_LOOKUP_ISERROR(rc)
+ && jsonBlobMakeEditable(pParse, ix.nBlob+nKey+v.nBlob)
+ ){
+ assert( !pParse->oom );
+ nIns = ix.nBlob + nKey + v.nBlob;
+ jsonBlobEdit(pParse, j, 0, 0, nIns);
+ if( !pParse->oom ){
+ assert( pParse->aBlob!=0 ); /* Because pParse->oom!=0 */
+ assert( ix.aBlob!=0 ); /* Because pPasre->oom!=0 */
+ memcpy(&pParse->aBlob[j], ix.aBlob, ix.nBlob);
+ k = j + ix.nBlob;
+ memcpy(&pParse->aBlob[k], zKey, nKey);
+ k += nKey;
+ memcpy(&pParse->aBlob[k], v.aBlob, v.nBlob);
+ if( ALWAYS(pParse->delta) ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ }
+ }
+ jsonParseReset(&v);
+ jsonParseReset(&ix);
+ return rc;
}
}else if( zPath[0]=='[' ){
- i = 0;
- j = 1;
- while( wx_sqlite3Isdigit(zPath[j]) ){
- i = i*10 + zPath[j] - '0';
- j++;
+ x = pParse->aBlob[iRoot] & 0x0f;
+ if( x!=JSONB_ARRAY ) return JSON_LOOKUP_NOTFOUND;
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ k = 0;
+ i = 1;
+ while( wx_sqlite3Isdigit(zPath[i]) ){
+ k = k*10 + zPath[i] - '0';
+ i++;
}
- if( j<2 || zPath[j]!=']' ){
+ if( i<2 || zPath[i]!=']' ){
if( zPath[1]=='#' ){
- JsonNode *pBase = pRoot;
- int iBase = iRoot;
- if( pRoot->eType!=JSON_ARRAY ) return 0;
- for(;;){
- while( j<=pBase->n ){
- if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++;
- j += jsonNodeSize(&pBase[j]);
- }
- if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pBase->eU==2 );
- iBase += pBase->u.iAppend;
- pBase = &pParse->aNode[iBase];
- j = 1;
- }
- j = 2;
+ k = jsonbArrayCount(pParse, iRoot);
+ i = 2;
if( zPath[2]=='-' && wx_sqlite3Isdigit(zPath[3]) ){
- unsigned int x = 0;
- j = 3;
+ unsigned int nn = 0;
+ i = 3;
do{
- x = x*10 + zPath[j] - '0';
- j++;
- }while( wx_sqlite3Isdigit(zPath[j]) );
- if( x>i ) return 0;
- i -= x;
+ nn = nn*10 + zPath[i] - '0';
+ i++;
+ }while( wx_sqlite3Isdigit(zPath[i]) );
+ if( nn>k ) return JSON_LOOKUP_NOTFOUND;
+ k -= nn;
}
- if( zPath[j]!=']' ){
- *pzErr = zPath;
- return 0;
+ if( zPath[i]!=']' ){
+ return JSON_LOOKUP_PATHERROR;
}
}else{
- *pzErr = zPath;
- return 0;
+ return JSON_LOOKUP_PATHERROR;
}
}
- if( pRoot->eType!=JSON_ARRAY ) return 0;
- zPath += j + 1;
- j = 1;
- for(;;){
- while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
- if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
- j += jsonNodeSize(&pRoot[j]);
- }
- if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pRoot->eU==2 );
- iRoot += pRoot->u.iAppend;
- pRoot = &pParse->aNode[iRoot];
- j = 1;
- }
- if( j<=pRoot->n ){
- return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
- }
- if( i==0 && pApnd ){
- u32 iStart;
- JsonNode *pNode;
- iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
- pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
- if( pParse->oom ) return 0;
- if( pNode ){
- pRoot = &pParse->aNode[iRoot];
- assert( pRoot->eU==0 );
- pRoot->u.iAppend = iStart - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
- VVA( pRoot->eU = 2 );
+ j = iRoot+n;
+ iEnd = j+sz;
+ while( j<iEnd ){
+ if( k==0 ){
+ rc = jsonLookupStep(pParse, j, &zPath[i+1], 0);
+ if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ return rc;
+ }
+ k--;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return JSON_LOOKUP_ERROR;
+ j += n+sz;
+ }
+ if( j>iEnd ) return JSON_LOOKUP_ERROR;
+ if( k>0 ) return JSON_LOOKUP_NOTFOUND;
+ if( pParse->eEdit>=JEDIT_INS ){
+ JsonParse v;
+ testcase( pParse->eEdit==JEDIT_INS );
+ testcase( pParse->eEdit==JEDIT_SET );
+ rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]);
+ if( !JSON_LOOKUP_ISERROR(rc)
+ && jsonBlobMakeEditable(pParse, v.nBlob)
+ ){
+ assert( !pParse->oom );
+ jsonBlobEdit(pParse, j, 0, v.aBlob, v.nBlob);
}
- return pNode;
+ jsonParseReset(&v);
+ if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ return rc;
}
}else{
- *pzErr = zPath;
+ return JSON_LOOKUP_PATHERROR;
}
- return 0;
+ return JSON_LOOKUP_NOTFOUND;
}
/*
-** Append content to pParse that will complete zPath. Return a pointer
-** to the inserted node, or return NULL if the append fails.
+** Convert a JSON BLOB into text and make that text the return value
+** of an SQL function.
*/
-static JsonNode *jsonLookupAppend(
- JsonParse *pParse, /* Append content to the JSON parse */
- const char *zPath, /* Description of content to append */
- int *pApnd, /* Set this flag to 1 */
- const char **pzErr /* Make this point to any syntax error */
+static void jsonReturnTextJsonFromBlob(
+ wx_sqlite3_context *ctx,
+ const u8 *aBlob,
+ u32 nBlob
){
- *pApnd = 1;
- if( zPath[0]==0 ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
- }
- if( zPath[0]=='.' ){
- jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
- }else if( strncmp(zPath,"[0]",3)==0 ){
- jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
- }else{
- return 0;
- }
- if( pParse->oom ) return 0;
- return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
+ JsonParse x;
+ JsonString s;
+
+ if( NEVER(aBlob==0) ) return;
+ memset(&x, 0, sizeof(x));
+ x.aBlob = (u8*)aBlob;
+ x.nBlob = nBlob;
+ jsonStringInit(&s, ctx);
+ jsonTranslateBlobToText(&x, 0, &s);
+ jsonReturnString(&s, 0, 0);
}
+
/*
-** Return the text of a syntax error message on a JSON path. Space is
-** obtained from wx_sqlite3_malloc().
+** Return the value of the BLOB node at index i.
+**
+** If the value is a primitive, return it as an SQL value.
+** If the value is an array or object, return it as either
+** JSON text or the BLOB encoding, depending on the JSON_B flag
+** on the userdata.
*/
-static char *jsonPathSyntaxError(const char *zErr){
- return wx_sqlite3_mprintf("JSON path error near '%q'", zErr);
+static void jsonReturnFromBlob(
+ JsonParse *pParse, /* Complete JSON parse tree */
+ u32 i, /* Index of the node */
+ wx_sqlite3_context *pCtx, /* Return value for this function */
+ int textOnly /* return text JSON. Disregard user-data */
+){
+ u32 n, sz;
+ int rc;
+ wx_sqlite3 *db = wx_sqlite3_context_db_handle(pCtx);
+
+ n = jsonbPayloadSize(pParse, i, &sz);
+ if( n==0 ){
+ wx_sqlite3_result_error(pCtx, "malformed JSON", -1);
+ return;
+ }
+ switch( pParse->aBlob[i] & 0x0f ){
+ case JSONB_NULL: {
+ if( sz ) goto returnfromblob_malformed;
+ wx_sqlite3_result_null(pCtx);
+ break;
+ }
+ case JSONB_TRUE: {
+ if( sz ) goto returnfromblob_malformed;
+ wx_sqlite3_result_int(pCtx, 1);
+ break;
+ }
+ case JSONB_FALSE: {
+ if( sz ) goto returnfromblob_malformed;
+ wx_sqlite3_result_int(pCtx, 0);
+ break;
+ }
+ case JSONB_INT5:
+ case JSONB_INT: {
+ wx_sqlite3_int64 iRes = 0;
+ char *z;
+ int bNeg = 0;
+ char x;
+ if( sz==0 ) goto returnfromblob_malformed;
+ x = (char)pParse->aBlob[i+n];
+ if( x=='-' ){
+ if( sz<2 ) goto returnfromblob_malformed;
+ n++;
+ sz--;
+ bNeg = 1;
+ }
+ z = wx_sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz);
+ if( z==0 ) goto returnfromblob_oom;
+ rc = wx_sqlite3DecOrHexToI64(z, &iRes);
+ wx_sqlite3DbFree(db, z);
+ if( rc==0 ){
+ wx_sqlite3_result_int64(pCtx, bNeg ? -iRes : iRes);
+ }else if( rc==3 && bNeg ){
+ wx_sqlite3_result_int64(pCtx, SMALLEST_INT64);
+ }else if( rc==1 ){
+ goto returnfromblob_malformed;
+ }else{
+ if( bNeg ){ n--; sz++; }
+ goto to_double;
+ }
+ break;
+ }
+ case JSONB_FLOAT5:
+ case JSONB_FLOAT: {
+ double r;
+ char *z;
+ if( sz==0 ) goto returnfromblob_malformed;
+ to_double:
+ z = wx_sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz);
+ if( z==0 ) goto returnfromblob_oom;
+ rc = wx_sqlite3AtoF(z, &r, wx_sqlite3Strlen30(z), SQLITE_UTF8);
+ wx_sqlite3DbFree(db, z);
+ if( rc<=0 ) goto returnfromblob_malformed;
+ wx_sqlite3_result_double(pCtx, r);
+ break;
+ }
+ case JSONB_TEXTRAW:
+ case JSONB_TEXT: {
+ wx_sqlite3_result_text(pCtx, (char*)&pParse->aBlob[i+n], sz,
+ SQLITE_TRANSIENT);
+ break;
+ }
+ case JSONB_TEXT5:
+ case JSONB_TEXTJ: {
+ /* Translate JSON formatted string into raw text */
+ u32 iIn, iOut;
+ const char *z;
+ char *zOut;
+ u32 nOut = sz;
+ z = (const char*)&pParse->aBlob[i+n];
+ zOut = wx_sqlite3DbMallocRaw(db, nOut+1);
+ if( zOut==0 ) goto returnfromblob_oom;
+ for(iIn=iOut=0; iIn<sz; iIn++){
+ char c = z[iIn];
+ if( c=='\\' ){
+ u32 v;
+ u32 szEscape = jsonUnescapeOneChar(&z[iIn], sz-iIn, &v);
+ if( v<=0x7f ){
+ zOut[iOut++] = (char)v;
+ }else if( v<=0x7ff ){
+ assert( szEscape>=2 );
+ zOut[iOut++] = (char)(0xc0 | (v>>6));
+ zOut[iOut++] = 0x80 | (v&0x3f);
+ }else if( v<0x10000 ){
+ assert( szEscape>=3 );
+ zOut[iOut++] = 0xe0 | (v>>12);
+ zOut[iOut++] = 0x80 | ((v>>6)&0x3f);
+ zOut[iOut++] = 0x80 | (v&0x3f);
+ }else if( v==JSON_INVALID_CHAR ){
+ /* Silently ignore illegal unicode */
+ }else{
+ assert( szEscape>=4 );
+ zOut[iOut++] = 0xf0 | (v>>18);
+ zOut[iOut++] = 0x80 | ((v>>12)&0x3f);
+ zOut[iOut++] = 0x80 | ((v>>6)&0x3f);
+ zOut[iOut++] = 0x80 | (v&0x3f);
+ }
+ iIn += szEscape - 1;
+ }else{
+ zOut[iOut++] = c;
+ }
+ } /* end for() */
+ assert( iOut<=nOut );
+ zOut[iOut] = 0;
+ wx_sqlite3_result_text(pCtx, zOut, iOut, SQLITE_DYNAMIC);
+ break;
+ }
+ case JSONB_ARRAY:
+ case JSONB_OBJECT: {
+ int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(wx_sqlite3_user_data(pCtx));
+ if( flags & JSON_BLOB ){
+ wx_sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT);
+ }else{
+ jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n);
+ }
+ break;
+ }
+ default: {
+ goto returnfromblob_malformed;
+ }
+ }
+ return;
+
+returnfromblob_oom:
+ wx_sqlite3_result_error_nomem(pCtx);
+ return;
+
+returnfromblob_malformed:
+ wx_sqlite3_result_error(pCtx, "malformed JSON", -1);
+ return;
}
/*
-** Do a node lookup using zPath. Return a pointer to the node on success.
-** Return NULL if not found or if there is an error.
+** pArg is a function argument that might be an SQL value or a JSON
+** value. Figure out what it is and encode it as a JSONB blob.
+** Return the results in pParse.
**
-** On an error, write an error message into pCtx and increment the
-** pParse->nErr counter.
+** pParse is uninitialized upon entry. This routine will handle the
+** initialization of pParse. The result will be contained in
+** pParse->aBlob and pParse->nBlob. pParse->aBlob might be dynamically
+** allocated (if pParse->nBlobAlloc is greater than zero) in which case
+** the caller is responsible for freeing the space allocated to pParse->aBlob
+** when it has finished with it. Or pParse->aBlob might be a static string
+** or a value obtained from wx_sqlite3_value_blob(pArg).
**
-** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
-** nodes are appended.
+** If the argument is a BLOB that is clearly not a JSONB, then this
+** function might set an error message in ctx and return non-zero.
+** It might also set an error message and return non-zero on an OOM error.
*/
-static JsonNode *jsonLookup(
- JsonParse *pParse, /* The JSON to search */
- const char *zPath, /* The path to search */
- int *pApnd, /* Append nodes to complete path if not NULL */
- wx_sqlite3_context *pCtx /* Report errors here, if not NULL */
-){
- const char *zErr = 0;
- JsonNode *pNode = 0;
- char *zMsg;
-
- if( zPath==0 ) return 0;
- if( zPath[0]!='$' ){
- zErr = zPath;
- goto lookup_err;
+static int jsonFunctionArgToBlob(
+ wx_sqlite3_context *ctx,
+ wx_sqlite3_value *pArg,
+ JsonParse *pParse
+){
+ int eType = wx_sqlite3_value_type(pArg);
+ static u8 aNull[] = { 0x00 };
+ memset(pParse, 0, sizeof(pParse[0]));
+ pParse->db = wx_sqlite3_context_db_handle(ctx);
+ switch( eType ){
+ default: {
+ pParse->aBlob = aNull;
+ pParse->nBlob = 1;
+ return 0;
+ }
+ case SQLITE_BLOB: {
+ if( jsonFuncArgMightBeBinary(pArg) ){
+ pParse->aBlob = (u8*)wx_sqlite3_value_blob(pArg);
+ pParse->nBlob = wx_sqlite3_value_bytes(pArg);
+ }else{
+ wx_sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1);
+ return 1;
+ }
+ break;
+ }
+ case SQLITE_TEXT: {
+ const char *zJson = (const char*)wx_sqlite3_value_text(pArg);
+ int nJson = wx_sqlite3_value_bytes(pArg);
+ if( zJson==0 ) return 1;
+ if( wx_sqlite3_value_subtype(pArg)==JSON_SUBTYPE ){
+ pParse->zJson = (char*)zJson;
+ pParse->nJson = nJson;
+ if( jsonConvertTextToBlob(pParse, ctx) ){
+ wx_sqlite3_result_error(ctx, "malformed JSON", -1);
+ wx_sqlite3DbFree(pParse->db, pParse->aBlob);
+ memset(pParse, 0, sizeof(pParse[0]));
+ return 1;
+ }
+ }else{
+ jsonBlobAppendNode(pParse, JSONB_TEXTRAW, nJson, zJson);
+ }
+ break;
+ }
+ case SQLITE_FLOAT: {
+ double r = wx_sqlite3_value_double(pArg);
+ if( NEVER(wx_sqlite3IsNaN(r)) ){
+ jsonBlobAppendNode(pParse, JSONB_NULL, 0, 0);
+ }else{
+ int n = wx_sqlite3_value_bytes(pArg);
+ const char *z = (const char*)wx_sqlite3_value_text(pArg);
+ if( z==0 ) return 1;
+ if( z[0]=='I' ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
+ }else if( z[0]=='-' && z[1]=='I' ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999");
+ }else{
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, n, z);
+ }
+ }
+ break;
+ }
+ case SQLITE_INTEGER: {
+ int n = wx_sqlite3_value_bytes(pArg);
+ const char *z = (const char*)wx_sqlite3_value_text(pArg);
+ if( z==0 ) return 1;
+ jsonBlobAppendNode(pParse, JSONB_INT, n, z);
+ break;
+ }
+ }
+ if( pParse->oom ){
+ wx_sqlite3_result_error_nomem(ctx);
+ return 1;
+ }else{
+ return 0;
}
- zPath++;
- pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
- if( zErr==0 ) return pNode;
+}
-lookup_err:
- pParse->nErr++;
- assert( zErr!=0 && pCtx!=0 );
- zMsg = jsonPathSyntaxError(zErr);
+/*
+** Generate a bad path error.
+**
+** If ctx is not NULL then push the error message into ctx and return NULL.
+** If ctx is NULL, then return the text of the error message.
+*/
+static char *jsonBadPathError(
+ wx_sqlite3_context *ctx, /* The function call containing the error */
+ const char *zPath /* The path with the problem */
+){
+ char *zMsg = wx_sqlite3_mprintf("bad JSON path: %Q", zPath);
+ if( ctx==0 ) return zMsg;
if( zMsg ){
- wx_sqlite3_result_error(pCtx, zMsg, -1);
+ wx_sqlite3_result_error(ctx, zMsg, -1);
wx_sqlite3_free(zMsg);
}else{
- wx_sqlite3_result_error_nomem(pCtx);
+ wx_sqlite3_result_error_nomem(ctx);
}
return 0;
}
+/* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent
+** arguments come in parse where each pair contains a JSON path and
+** content to insert or set at that patch. Do the updates
+** and return the result.
+**
+** The specific operation is determined by eEdit, which can be one
+** of JEDIT_INS, JEDIT_REPL, or JEDIT_SET.
+*/
+static void jsonInsertIntoBlob(
+ wx_sqlite3_context *ctx,
+ int argc,
+ wx_sqlite3_value **argv,
+ int eEdit /* JEDIT_INS, JEDIT_REPL, or JEDIT_SET */
+){
+ int i;
+ u32 rc = 0;
+ const char *zPath = 0;
+ int flgs;
+ JsonParse *p;
+ JsonParse ax;
+
+ assert( (argc&1)==1 );
+ flgs = argc==1 ? 0 : JSON_EDITABLE;
+ p = jsonParseFuncArg(ctx, argv[0], flgs);
+ if( p==0 ) return;
+ for(i=1; i<argc-1; i+=2){
+ if( wx_sqlite3_value_type(argv[i])==SQLITE_NULL ) continue;
+ zPath = (const char*)wx_sqlite3_value_text(argv[i]);
+ if( zPath==0 ){
+ wx_sqlite3_result_error_nomem(ctx);
+ jsonParseFree(p);
+ return;
+ }
+ if( zPath[0]!='$' ) goto jsonInsertIntoBlob_patherror;
+ if( jsonFunctionArgToBlob(ctx, argv[i+1], &ax) ){
+ jsonParseReset(&ax);
+ jsonParseFree(p);
+ return;
+ }
+ if( zPath[1]==0 ){
+ if( eEdit==JEDIT_REPL || eEdit==JEDIT_SET ){
+ jsonBlobEdit(p, 0, p->nBlob, ax.aBlob, ax.nBlob);
+ }
+ rc = 0;
+ }else{
+ p->eEdit = eEdit;
+ p->nIns = ax.nBlob;
+ p->aIns = ax.aBlob;
+ p->delta = 0;
+ rc = jsonLookupStep(p, 0, zPath+1, 0);
+ }
+ jsonParseReset(&ax);
+ if( rc==JSON_LOOKUP_NOTFOUND ) continue;
+ if( JSON_LOOKUP_ISERROR(rc) ) goto jsonInsertIntoBlob_patherror;
+ }
+ jsonReturnParse(ctx, p);
+ jsonParseFree(p);
+ return;
+
+jsonInsertIntoBlob_patherror:
+ jsonParseFree(p);
+ if( rc==JSON_LOOKUP_ERROR ){
+ wx_sqlite3_result_error(ctx, "malformed JSON", -1);
+ }else{
+ jsonBadPathError(ctx, zPath);
+ }
+ return;
+}
/*
-** Report the wrong number of arguments for json_insert(), json_replace()
-** or json_set().
+** If pArg is a blob that seems like a JSONB blob, then initialize
+** p to point to that JSONB and return TRUE. If pArg does not seem like
+** a JSONB blob, then return FALSE;
+**
+** This routine is only called if it is already known that pArg is a
+** blob. The only open question is whether or not the blob appears
+** to be a JSONB blob.
*/
-static void jsonWrongNumArgs(
- wx_sqlite3_context *pCtx,
- const char *zFuncName
-){
- char *zMsg = wx_sqlite3_mprintf("json_%s() needs an odd number of arguments",
- zFuncName);
- wx_sqlite3_result_error(pCtx, zMsg, -1);
- wx_sqlite3_free(zMsg);
+static int jsonArgIsJsonb(wx_sqlite3_value *pArg, JsonParse *p){
+ u32 n, sz = 0;
+ p->aBlob = (u8*)wx_sqlite3_value_blob(pArg);
+ p->nBlob = (u32)wx_sqlite3_value_bytes(pArg);
+ if( p->nBlob==0 ){
+ p->aBlob = 0;
+ return 0;
+ }
+ if( NEVER(p->aBlob==0) ){
+ return 0;
+ }
+ if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT
+ && (n = jsonbPayloadSize(p, 0, &sz))>0
+ && sz+n==p->nBlob
+ && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0)
+ ){
+ return 1;
+ }
+ p->aBlob = 0;
+ p->nBlob = 0;
+ return 0;
}
/*
-** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
+** Generate a JsonParse object, containing valid JSONB in aBlob and nBlob,
+** from the SQL function argument pArg. Return a pointer to the new
+** JsonParse object.
+**
+** Ownership of the new JsonParse object is passed to the caller. The
+** caller should invoke jsonParseFree() on the return value when it
+** has finished using it.
+**
+** If any errors are detected, an appropriate error messages is set
+** using wx_sqlite3_result_error() or the equivalent and this routine
+** returns NULL. This routine also returns NULL if the pArg argument
+** is an SQL NULL value, but no error message is set in that case. This
+** is so that SQL functions that are given NULL arguments will return
+** a NULL value.
*/
-static void jsonRemoveAllNulls(JsonNode *pNode){
- int i, n;
- assert( pNode->eType==JSON_OBJECT );
- n = pNode->n;
- for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
- switch( pNode[i].eType ){
- case JSON_NULL:
- pNode[i].jnFlags |= JNODE_REMOVE;
- break;
- case JSON_OBJECT:
- jsonRemoveAllNulls(&pNode[i]);
- break;
+static JsonParse *jsonParseFuncArg(
+ wx_sqlite3_context *ctx,
+ wx_sqlite3_value *pArg,
+ u32 flgs
+){
+ int eType; /* Datatype of pArg */
+ JsonParse *p = 0; /* Value to be returned */
+ JsonParse *pFromCache = 0; /* Value taken from cache */
+ wx_sqlite3 *db; /* The database connection */
+
+ assert( ctx!=0 );
+ eType = wx_sqlite3_value_type(pArg);
+ if( eType==SQLITE_NULL ){
+ return 0;
+ }
+ pFromCache = jsonCacheSearch(ctx, pArg);
+ if( pFromCache ){
+ pFromCache->nJPRef++;
+ if( (flgs & JSON_EDITABLE)==0 ){
+ return pFromCache;
}
}
-}
+ db = wx_sqlite3_context_db_handle(ctx);
+rebuild_from_cache:
+ p = wx_sqlite3DbMallocZero(db, sizeof(*p));
+ if( p==0 ) goto json_pfa_oom;
+ memset(p, 0, sizeof(*p));
+ p->db = db;
+ p->nJPRef = 1;
+ if( pFromCache!=0 ){
+ u32 nBlob = pFromCache->nBlob;
+ p->aBlob = wx_sqlite3DbMallocRaw(db, nBlob);
+ if( p->aBlob==0 ) goto json_pfa_oom;
+ memcpy(p->aBlob, pFromCache->aBlob, nBlob);
+ p->nBlobAlloc = p->nBlob = nBlob;
+ p->hasNonstd = pFromCache->hasNonstd;
+ jsonParseFree(pFromCache);
+ return p;
+ }
+ if( eType==SQLITE_BLOB ){
+ if( jsonArgIsJsonb(pArg,p) ){
+ if( (flgs & JSON_EDITABLE)!=0 && jsonBlobMakeEditable(p, 0)==0 ){
+ goto json_pfa_oom;
+ }
+ return p;
+ }
+ /* If the blob is not valid JSONB, fall through into trying to cast
+ ** the blob into text which is then interpreted as JSON. (tag-20240123-a)
+ **
+ ** This goes against all historical documentation about how the SQLite
+ ** JSON functions were suppose to work. From the beginning, blob was
+ ** reserved for expansion and a blob value should have raised an error.
+ ** But it did not, due to a bug. And many applications came to depend
+ ** upon this buggy behavior, espeically when using the CLI and reading
+ ** JSON text using readfile(), which returns a blob. For this reason
+ ** we will continue to support the bug moving forward.
+ ** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d
+ */
+ }
+ p->zJson = (char*)wx_sqlite3_value_text(pArg);
+ p->nJson = wx_sqlite3_value_bytes(pArg);
+ if( db->mallocFailed ) goto json_pfa_oom;
+ if( p->nJson==0 ) goto json_pfa_malformed;
+ assert( p->zJson!=0 );
+ if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){
+ if( flgs & JSON_KEEPERROR ){
+ p->nErr = 1;
+ return p;
+ }else{
+ jsonParseFree(p);
+ return 0;
+ }
+ }else{
+ int isRCStr = wx_sqlite3ValueIsOfClass(pArg, wx_sqlite3RCStrUnref);
+ int rc;
+ if( !isRCStr ){
+ char *zNew = wx_sqlite3RCStrNew( p->nJson );
+ if( zNew==0 ) goto json_pfa_oom;
+ memcpy(zNew, p->zJson, p->nJson);
+ p->zJson = zNew;
+ p->zJson[p->nJson] = 0;
+ }else{
+ wx_sqlite3RCStrRef(p->zJson);
+ }
+ p->bJsonIsRCStr = 1;
+ rc = jsonCacheInsert(ctx, p);
+ if( rc==SQLITE_NOMEM ) goto json_pfa_oom;
+ if( flgs & JSON_EDITABLE ){
+ pFromCache = p;
+ p = 0;
+ goto rebuild_from_cache;
+ }
+ }
+ return p;
+json_pfa_malformed:
+ if( flgs & JSON_KEEPERROR ){
+ p->nErr = 1;
+ return p;
+ }else{
+ jsonParseFree(p);
+ wx_sqlite3_result_error(ctx, "malformed JSON", -1);
+ return 0;
+ }
-/****************************************************************************
-** SQL functions used for testing and debugging
-****************************************************************************/
+json_pfa_oom:
+ jsonParseFree(pFromCache);
+ jsonParseFree(p);
+ wx_sqlite3_result_error_nomem(ctx);
+ return 0;
+}
-#ifdef SQLITE_DEBUG
/*
-** The json_parse(JSON) function returns a string which describes
-** a parse of the JSON provided. Or it returns NULL if JSON is not
-** well-formed.
+** Make the return value of a JSON function either the raw JSONB blob
+** or make it JSON text, depending on whether the JSON_BLOB flag is
+** set on the function.
*/
-static void jsonParseFunc(
+static void jsonReturnParse(
wx_sqlite3_context *ctx,
- int argc,
- wx_sqlite3_value **argv
+ JsonParse *p
){
- JsonString s; /* Output string - not real JSON */
- JsonParse x; /* The parse */
- u32 i;
-
- assert( argc==1 );
- if( jsonParse(&x, ctx, (const char*)wx_sqlite3_value_text(argv[0])) ) return;
- jsonParseFindParents(&x);
- jsonInit(&s, ctx);
- for(i=0; i<x.nNode; i++){
- const char *zType;
- if( x.aNode[i].jnFlags & JNODE_LABEL ){
- assert( x.aNode[i].eType==JSON_STRING );
- zType = "label";
- }else{
- zType = jsonType[x.aNode[i].eType];
- }
- jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d",
- i, zType, x.aNode[i].n, x.aUp[i]);
- assert( x.aNode[i].eU==0 || x.aNode[i].eU==1 );
- if( x.aNode[i].u.zJContent!=0 ){
- assert( x.aNode[i].eU==1 );
- jsonAppendRaw(&s, " ", 1);
- jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
+ int flgs;
+ if( p->oom ){
+ wx_sqlite3_result_error_nomem(ctx);
+ return;
+ }
+ flgs = SQLITE_PTR_TO_INT(wx_sqlite3_user_data(ctx));
+ if( flgs & JSON_BLOB ){
+ if( p->nBlobAlloc>0 && !p->bReadOnly ){
+ wx_sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_DYNAMIC);
+ p->nBlobAlloc = 0;
}else{
- assert( x.aNode[i].eU==0 );
+ wx_sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_TRANSIENT);
}
- jsonAppendRaw(&s, "\n", 1);
+ }else{
+ JsonString s;
+ jsonStringInit(&s, ctx);
+ p->delta = 0;
+ jsonTranslateBlobToText(p, 0, &s);
+ jsonReturnString(&s, p, ctx);
+ wx_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
+}
+
+/****************************************************************************
+** SQL functions used for testing and debugging
+****************************************************************************/
+
+#if SQLITE_DEBUG
+/*
+** Decode JSONB bytes in aBlob[] starting at iStart through but not
+** including iEnd. Indent the
+** content by nIndent spaces.
+*/
+static void jsonDebugPrintBlob(
+ JsonParse *pParse, /* JSON content */
+ u32 iStart, /* Start rendering here */
+ u32 iEnd, /* Do not render this byte or any byte after this one */
+ int nIndent, /* Indent by this many spaces */
+ wx_sqlite3_str *pOut /* Generate output into this wx_sqlite3_str object */
+){
+ while( iStart<iEnd ){
+ u32 i, n, nn, sz = 0;
+ int showContent = 1;
+ u8 x = pParse->aBlob[iStart] & 0x0f;
+ u32 savedNBlob = pParse->nBlob;
+ wx_sqlite3_str_appendf(pOut, "%5d:%*s", iStart, nIndent, "");
+ if( pParse->nBlobAlloc>pParse->nBlob ){
+ pParse->nBlob = pParse->nBlobAlloc;
+ }
+ nn = n = jsonbPayloadSize(pParse, iStart, &sz);
+ if( nn==0 ) nn = 1;
+ if( sz>0 && x<JSONB_ARRAY ){
+ nn += sz;
+ }
+ for(i=0; i<nn; i++){
+ wx_sqlite3_str_appendf(pOut, " %02x", pParse->aBlob[iStart+i]);
+ }
+ if( n==0 ){
+ wx_sqlite3_str_appendf(pOut, " ERROR invalid node size\n");
+ iStart = n==0 ? iStart+1 : iEnd;
+ continue;
+ }
+ pParse->nBlob = savedNBlob;
+ if( iStart+n+sz>iEnd ){
+ iEnd = iStart+n+sz;
+ if( iEnd>pParse->nBlob ){
+ if( pParse->nBlobAlloc>0 && iEnd>pParse->nBlobAlloc ){
+ iEnd = pParse->nBlobAlloc;
+ }else{
+ iEnd = pParse->nBlob;
+ }
+ }
+ }
+ wx_sqlite3_str_appendall(pOut," <-- ");
+ switch( x ){
+ case JSONB_NULL: wx_sqlite3_str_appendall(pOut,"null"); break;
+ case JSONB_TRUE: wx_sqlite3_str_appendall(pOut,"true"); break;
+ case JSONB_FALSE: wx_sqlite3_str_appendall(pOut,"false"); break;
+ case JSONB_INT: wx_sqlite3_str_appendall(pOut,"int"); break;
+ case JSONB_INT5: wx_sqlite3_str_appendall(pOut,"int5"); break;
+ case JSONB_FLOAT: wx_sqlite3_str_appendall(pOut,"float"); break;
+ case JSONB_FLOAT5: wx_sqlite3_str_appendall(pOut,"float5"); break;
+ case JSONB_TEXT: wx_sqlite3_str_appendall(pOut,"text"); break;
+ case JSONB_TEXTJ: wx_sqlite3_str_appendall(pOut,"textj"); break;
+ case JSONB_TEXT5: wx_sqlite3_str_appendall(pOut,"text5"); break;
+ case JSONB_TEXTRAW: wx_sqlite3_str_appendall(pOut,"textraw"); break;
+ case JSONB_ARRAY: {
+ wx_sqlite3_str_appendf(pOut,"array, %u bytes\n", sz);
+ jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut);
+ showContent = 0;
+ break;
+ }
+ case JSONB_OBJECT: {
+ wx_sqlite3_str_appendf(pOut, "object, %u bytes\n", sz);
+ jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut);
+ showContent = 0;
+ break;
+ }
+ default: {
+ wx_sqlite3_str_appendall(pOut, "ERROR: unknown node type\n");
+ showContent = 0;
+ break;
+ }
+ }
+ if( showContent ){
+ if( sz==0 && x<=JSONB_FALSE ){
+ wx_sqlite3_str_append(pOut, "\n", 1);
+ }else{
+ u32 j;
+ wx_sqlite3_str_appendall(pOut, ": \"");
+ for(j=iStart+n; j<iStart+n+sz; j++){
+ u8 c = pParse->aBlob[j];
+ if( c<0x20 || c>=0x7f ) c = '.';
+ wx_sqlite3_str_append(pOut, (char*)&c, 1);
+ }
+ wx_sqlite3_str_append(pOut, "\"\n", 2);
+ }
+ }
+ iStart += n + sz;
+ }
+}
+static void jsonShowParse(JsonParse *pParse){
+ wx_sqlite3_str out;
+ char zBuf[1000];
+ if( pParse==0 ){
+ printf("NULL pointer\n");
+ return;
+ }else{
+ printf("nBlobAlloc = %u\n", pParse->nBlobAlloc);
+ printf("nBlob = %u\n", pParse->nBlob);
+ printf("delta = %d\n", pParse->delta);
+ if( pParse->nBlob==0 ) return;
+ printf("content (bytes 0..%u):\n", pParse->nBlob-1);
}
- jsonParseReset(&x);
- jsonResult(&s);
+ wx_sqlite3StrAccumInit(&out, 0, zBuf, sizeof(zBuf), 1000000);
+ jsonDebugPrintBlob(pParse, 0, pParse->nBlob, 0, &out);
+ printf("%s", wx_sqlite3_str_value(&out));
+ wx_sqlite3_str_reset(&out);
}
+#endif /* SQLITE_DEBUG */
+#ifdef SQLITE_DEBUG
/*
-** The json_test1(JSON) function return true (1) if the input is JSON
-** text generated by another json function. It returns (0) if the input
-** is not known to be JSON.
+** SQL function: json_parse(JSON)
+**
+** Parse JSON using jsonParseFuncArg(). Return text that is a
+** human-readable dump of the binary JSONB for the input parameter.
*/
-static void jsonTest1Func(
+static void jsonParseFunc(
wx_sqlite3_context *ctx,
int argc,
wx_sqlite3_value **argv
){
- UNUSED_PARAMETER(argc);
- wx_sqlite3_result_int(ctx, wx_sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
+ JsonParse *p; /* The parse */
+ wx_sqlite3_str out;
+
+ assert( argc>=1 );
+ wx_sqlite3StrAccumInit(&out, 0, 0, 0, 1000000);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
+ if( p==0 ) return;
+ if( argc==1 ){
+ jsonDebugPrintBlob(p, 0, p->nBlob, 0, &out);
+ wx_sqlite3_result_text64(ctx,out.zText,out.nChar,SQLITE_TRANSIENT,SQLITE_UTF8);
+ }else{
+ jsonShowParse(p);
+ }
+ jsonParseFree(p);
+ wx_sqlite3_str_reset(&out);
}
#endif /* SQLITE_DEBUG */
@@ -200341,7 +210077,7 @@ static void jsonTest1Func(
****************************************************************************/
/*
-** Implementation of the json_QUOTE(VALUE) function. Return a JSON value
+** Implementation of the json_quote(VALUE) function. Return a JSON value
** corresponding to the SQL value input. Mostly this means putting
** double-quotes around strings and returning the unquoted string "null"
** when given a NULL input.
@@ -200354,9 +210090,9 @@ static void jsonQuoteFunc(
JsonString jx;
UNUSED_PARAMETER(argc);
- jsonInit(&jx, ctx);
- jsonAppendValue(&jx, argv[0]);
- jsonResult(&jx);
+ jsonStringInit(&jx, ctx);
+ jsonAppendSqlValue(&jx, argv[0]);
+ jsonReturnString(&jx, 0, 0);
wx_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
@@ -200373,18 +210109,17 @@ static void jsonArrayFunc(
int i;
JsonString jx;
- jsonInit(&jx, ctx);
+ jsonStringInit(&jx, ctx);
jsonAppendChar(&jx, '[');
for(i=0; i<argc; i++){
jsonAppendSeparator(&jx);
- jsonAppendValue(&jx, argv[i]);
+ jsonAppendSqlValue(&jx, argv[i]);
}
jsonAppendChar(&jx, ']');
- jsonResult(&jx);
+ jsonReturnString(&jx, 0, 0);
wx_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
-
/*
** json_array_length(JSON)
** json_array_length(JSON, PATH)
@@ -200398,39 +210133,46 @@ static void jsonArrayLengthFunc(
wx_sqlite3_value **argv
){
JsonParse *p; /* The parse */
- wx_sqlite3_int64 n = 0;
+ wx_sqlite3_int64 cnt = 0;
u32 i;
- JsonNode *pNode;
+ u8 eErr = 0;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
if( p==0 ) return;
- assert( p->nNode );
if( argc==2 ){
const char *zPath = (const char*)wx_sqlite3_value_text(argv[1]);
- pNode = jsonLookup(p, zPath, 0, ctx);
+ if( zPath==0 ){
+ jsonParseFree(p);
+ return;
+ }
+ i = jsonLookupStep(p, 0, zPath[0]=='$' ? zPath+1 : "@", 0);
+ if( JSON_LOOKUP_ISERROR(i) ){
+ if( i==JSON_LOOKUP_NOTFOUND ){
+ /* no-op */
+ }else if( i==JSON_LOOKUP_PATHERROR ){
+ jsonBadPathError(ctx, zPath);
+ }else{
+ wx_sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ eErr = 1;
+ i = 0;
+ }
}else{
- pNode = p->aNode;
- }
- if( pNode==0 ){
- return;
+ i = 0;
}
- if( pNode->eType==JSON_ARRAY ){
- assert( (pNode->jnFlags & JNODE_APPEND)==0 );
- for(i=1; i<=pNode->n; n++){
- i += jsonNodeSize(&pNode[i]);
- }
+ if( (p->aBlob[i] & 0x0f)==JSONB_ARRAY ){
+ cnt = jsonbArrayCount(p, i);
}
- wx_sqlite3_result_int64(ctx, n);
+ if( !eErr ) wx_sqlite3_result_int64(ctx, cnt);
+ jsonParseFree(p);
}
-/*
-** Bit values for the flags passed into jsonExtractFunc() or
-** jsonSetFunc() via the user-data value.
-*/
-#define JSON_JSON 0x01 /* Result is always JSON */
-#define JSON_SQL 0x02 /* Result is always SQL */
-#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */
-#define JSON_ISSET 0x04 /* json_set(), not json_insert() */
+/* True if the string is all alphanumerics and underscores */
+static int jsonAllAlphanum(const char *z, int n){
+ int i;
+ for(i=0; i<n && (wx_sqlite3Isalnum(z[i]) || z[i]=='_'); i++){}
+ return i==n;
+}
/*
** json_extract(JSON, PATH, ...)
@@ -200457,161 +210199,313 @@ static void jsonExtractFunc(
int argc,
wx_sqlite3_value **argv
){
- JsonParse *p; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- int flags = SQLITE_PTR_TO_INT(wx_sqlite3_user_data(ctx));
- JsonString jx;
+ JsonParse *p = 0; /* The parse */
+ int flags; /* Flags associated with the function */
+ int i; /* Loop counter */
+ JsonString jx; /* String for array result */
if( argc<2 ) return;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
if( p==0 ) return;
- if( argc==2 ){
+ flags = SQLITE_PTR_TO_INT(wx_sqlite3_user_data(ctx));
+ jsonStringInit(&jx, ctx);
+ if( argc>2 ){
+ jsonAppendChar(&jx, '[');
+ }
+ for(i=1; i<argc; i++){
/* With a single PATH argument */
- zPath = (const char*)wx_sqlite3_value_text(argv[1]);
- if( zPath==0 ) return;
- if( flags & JSON_ABPATH ){
- if( zPath[0]!='$' ){
- /* The -> and ->> operators accept abbreviated PATH arguments. This
- ** is mostly for compatibility with PostgreSQL, but also for
- ** convenience.
- **
- ** NUMBER ==> $[NUMBER] // PG compatible
- ** LABEL ==> $.LABEL // PG compatible
- ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience
- */
- jsonInit(&jx, ctx);
- if( wx_sqlite3Isdigit(zPath[0]) ){
- jsonAppendRaw(&jx, "$[", 2);
- jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
- jsonAppendRaw(&jx, "]", 2);
- }else{
- jsonAppendRaw(&jx, "$.", 1 + (zPath[0]!='['));
- jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
- jsonAppendChar(&jx, 0);
- }
- pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx);
- jsonReset(&jx);
+ const char *zPath = (const char*)wx_sqlite3_value_text(argv[i]);
+ int nPath;
+ u32 j;
+ if( zPath==0 ) goto json_extract_error;
+ nPath = wx_sqlite3Strlen30(zPath);
+ if( zPath[0]=='$' ){
+ j = jsonLookupStep(p, 0, zPath+1, 0);
+ }else if( (flags & JSON_ABPATH) ){
+ /* The -> and ->> operators accept abbreviated PATH arguments. This
+ ** is mostly for compatibility with PostgreSQL, but also for
+ ** convenience.
+ **
+ ** NUMBER ==> $[NUMBER] // PG compatible
+ ** LABEL ==> $.LABEL // PG compatible
+ ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience
+ **
+ ** Updated 2024-05-27: If the NUMBER is negative, then PG counts from
+ ** the right of the array. Hence for negative NUMBER:
+ **
+ ** NUMBER ==> $[#NUMBER] // PG compatible
+ */
+ jsonStringInit(&jx, ctx);
+ if( wx_sqlite3_value_type(argv[i])==SQLITE_INTEGER ){
+ jsonAppendRawNZ(&jx, "[", 1);
+ if( zPath[0]=='-' ) jsonAppendRawNZ(&jx,"#",1);
+ jsonAppendRaw(&jx, zPath, nPath);
+ jsonAppendRawNZ(&jx, "]", 2);
+ }else if( jsonAllAlphanum(zPath, nPath) ){
+ jsonAppendRawNZ(&jx, ".", 1);
+ jsonAppendRaw(&jx, zPath, nPath);
+ }else if( zPath[0]=='[' && nPath>=3 && zPath[nPath-1]==']' ){
+ jsonAppendRaw(&jx, zPath, nPath);
}else{
- pNode = jsonLookup(p, zPath, 0, ctx);
+ jsonAppendRawNZ(&jx, ".\"", 2);
+ jsonAppendRaw(&jx, zPath, nPath);
+ jsonAppendRawNZ(&jx, "\"", 1);
}
- if( pNode ){
+ jsonStringTerminate(&jx);
+ j = jsonLookupStep(p, 0, jx.zBuf, 0);
+ jsonStringReset(&jx);
+ }else{
+ jsonBadPathError(ctx, zPath);
+ goto json_extract_error;
+ }
+ if( j<p->nBlob ){
+ if( argc==2 ){
if( flags & JSON_JSON ){
- jsonReturnJson(pNode, ctx, 0);
+ jsonStringInit(&jx, ctx);
+ jsonTranslateBlobToText(p, j, &jx);
+ jsonReturnString(&jx, 0, 0);
+ jsonStringReset(&jx);
+ assert( (flags & JSON_BLOB)==0 );
+ wx_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}else{
- jsonReturn(pNode, ctx, 0);
- wx_sqlite3_result_subtype(ctx, 0);
+ jsonReturnFromBlob(p, j, ctx, 0);
+ if( (flags & (JSON_SQL|JSON_BLOB))==0
+ && (p->aBlob[j]&0x0f)>=JSONB_ARRAY
+ ){
+ wx_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
}
+ }else{
+ jsonAppendSeparator(&jx);
+ jsonTranslateBlobToText(p, j, &jx);
}
- }else{
- pNode = jsonLookup(p, zPath, 0, ctx);
- if( p->nErr==0 && pNode ) jsonReturn(pNode, ctx, 0);
- }
- }else{
- /* Two or more PATH arguments results in a JSON array with each
- ** element of the array being the value selected by one of the PATHs */
- int i;
- jsonInit(&jx, ctx);
- jsonAppendChar(&jx, '[');
- for(i=1; i<argc; i++){
- zPath = (const char*)wx_sqlite3_value_text(argv[i]);
- pNode = jsonLookup(p, zPath, 0, ctx);
- if( p->nErr ) break;
- jsonAppendSeparator(&jx);
- if( pNode ){
- jsonRenderNode(pNode, &jx, 0);
+ }else if( j==JSON_LOOKUP_NOTFOUND ){
+ if( argc==2 ){
+ goto json_extract_error; /* Return NULL if not found */
}else{
- jsonAppendRaw(&jx, "null", 4);
+ jsonAppendSeparator(&jx);
+ jsonAppendRawNZ(&jx, "null", 4);
}
+ }else if( j==JSON_LOOKUP_ERROR ){
+ wx_sqlite3_result_error(ctx, "malformed JSON", -1);
+ goto json_extract_error;
+ }else{
+ jsonBadPathError(ctx, zPath);
+ goto json_extract_error;
}
- if( i==argc ){
- jsonAppendChar(&jx, ']');
- jsonResult(&jx);
+ }
+ if( argc>2 ){
+ jsonAppendChar(&jx, ']');
+ jsonReturnString(&jx, 0, 0);
+ if( (flags & JSON_BLOB)==0 ){
wx_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
- jsonReset(&jx);
}
+json_extract_error:
+ jsonStringReset(&jx);
+ jsonParseFree(p);
+ return;
}
-/* This is the RFC 7396 MergePatch algorithm.
-*/
-static JsonNode *jsonMergePatch(
- JsonParse *pParse, /* The JSON parser that contains the TARGET */
- u32 iTarget, /* Node of the TARGET in pParse */
- JsonNode *pPatch /* The PATCH */
-){
- u32 i, j;
- u32 iRoot;
- JsonNode *pTarget;
- if( pPatch->eType!=JSON_OBJECT ){
- return pPatch;
- }
- assert( iTarget<pParse->nNode );
- pTarget = &pParse->aNode[iTarget];
- assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
- if( pTarget->eType!=JSON_OBJECT ){
- jsonRemoveAllNulls(pPatch);
- return pPatch;
- }
- iRoot = iTarget;
- for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
- u32 nKey;
- const char *zKey;
- assert( pPatch[i].eType==JSON_STRING );
- assert( pPatch[i].jnFlags & JNODE_LABEL );
- assert( pPatch[i].eU==1 );
- nKey = pPatch[i].n;
- zKey = pPatch[i].u.zJContent;
- assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
- for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
- assert( pTarget[j].eType==JSON_STRING );
- assert( pTarget[j].jnFlags & JNODE_LABEL );
- assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
- if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
- if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
- if( pPatch[i+1].eType==JSON_NULL ){
- pTarget[j+1].jnFlags |= JNODE_REMOVE;
- }else{
- JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
- if( pNew==0 ) return 0;
- pTarget = &pParse->aNode[iTarget];
- if( pNew!=&pTarget[j+1] ){
- assert( pTarget[j+1].eU==0
- || pTarget[j+1].eU==1
- || pTarget[j+1].eU==2 );
- testcase( pTarget[j+1].eU==1 );
- testcase( pTarget[j+1].eU==2 );
- VVA( pTarget[j+1].eU = 5 );
- pTarget[j+1].u.pPatch = pNew;
- pTarget[j+1].jnFlags |= JNODE_PATCH;
- }
- }
- break;
+/*
+** Return codes for jsonMergePatch()
+*/
+#define JSON_MERGE_OK 0 /* Success */
+#define JSON_MERGE_BADTARGET 1 /* Malformed TARGET blob */
+#define JSON_MERGE_BADPATCH 2 /* Malformed PATCH blob */
+#define JSON_MERGE_OOM 3 /* Out-of-memory condition */
+
+/*
+** RFC-7396 MergePatch for two JSONB blobs.
+**
+** pTarget is the target. pPatch is the patch. The target is updated
+** in place. The patch is read-only.
+**
+** The original RFC-7396 algorithm is this:
+**
+** define MergePatch(Target, Patch):
+** if Patch is an Object:
+** if Target is not an Object:
+** Target = {} # Ignore the contents and set it to an empty Object
+** for each Name/Value pair in Patch:
+** if Value is null:
+** if Name exists in Target:
+** remove the Name/Value pair from Target
+** else:
+** Target[Name] = MergePatch(Target[Name], Value)
+** return Target
+** else:
+** return Patch
+**
+** Here is an equivalent algorithm restructured to show the actual
+** implementation:
+**
+** 01 define MergePatch(Target, Patch):
+** 02 if Patch is not an Object:
+** 03 return Patch
+** 04 else: // if Patch is an Object
+** 05 if Target is not an Object:
+** 06 Target = {}
+** 07 for each Name/Value pair in Patch:
+** 08 if Name exists in Target:
+** 09 if Value is null:
+** 10 remove the Name/Value pair from Target
+** 11 else
+** 12 Target[name] = MergePatch(Target[Name], Value)
+** 13 else if Value is not NULL:
+** 14 if Value is not an Object:
+** 15 Target[name] = Value
+** 16 else:
+** 17 Target[name] = MergePatch('{}',value)
+** 18 return Target
+** |
+** ^---- Line numbers referenced in comments in the implementation
+*/
+static int jsonMergePatch(
+ JsonParse *pTarget, /* The JSON parser that contains the TARGET */
+ u32 iTarget, /* Index of TARGET in pTarget->aBlob[] */
+ const JsonParse *pPatch, /* The PATCH */
+ u32 iPatch /* Index of PATCH in pPatch->aBlob[] */
+){
+ u8 x; /* Type of a single node */
+ u32 n, sz=0; /* Return values from jsonbPayloadSize() */
+ u32 iTCursor; /* Cursor position while scanning the target object */
+ u32 iTStart; /* First label in the target object */
+ u32 iTEndBE; /* Original first byte past end of target, before edit */
+ u32 iTEnd; /* Current first byte past end of target */
+ u8 eTLabel; /* Node type of the target label */
+ u32 iTLabel = 0; /* Index of the label */
+ u32 nTLabel = 0; /* Header size in bytes for the target label */
+ u32 szTLabel = 0; /* Size of the target label payload */
+ u32 iTValue = 0; /* Index of the target value */
+ u32 nTValue = 0; /* Header size of the target value */
+ u32 szTValue = 0; /* Payload size for the target value */
+
+ u32 iPCursor; /* Cursor position while scanning the patch */
+ u32 iPEnd; /* First byte past the end of the patch */
+ u8 ePLabel; /* Node type of the patch label */
+ u32 iPLabel; /* Start of patch label */
+ u32 nPLabel; /* Size of header on the patch label */
+ u32 szPLabel; /* Payload size of the patch label */
+ u32 iPValue; /* Start of patch value */
+ u32 nPValue; /* Header size for the patch value */
+ u32 szPValue; /* Payload size of the patch value */
+
+ assert( iTarget>=0 && iTarget<pTarget->nBlob );
+ assert( iPatch>=0 && iPatch<pPatch->nBlob );
+ x = pPatch->aBlob[iPatch] & 0x0f;
+ if( x!=JSONB_OBJECT ){ /* Algorithm line 02 */
+ u32 szPatch; /* Total size of the patch, header+payload */
+ u32 szTarget; /* Total size of the target, header+payload */
+ n = jsonbPayloadSize(pPatch, iPatch, &sz);
+ szPatch = n+sz;
+ sz = 0;
+ n = jsonbPayloadSize(pTarget, iTarget, &sz);
+ szTarget = n+sz;
+ jsonBlobEdit(pTarget, iTarget, szTarget, pPatch->aBlob+iPatch, szPatch);
+ return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK; /* Line 03 */
+ }
+ x = pTarget->aBlob[iTarget] & 0x0f;
+ if( x!=JSONB_OBJECT ){ /* Algorithm line 05 */
+ n = jsonbPayloadSize(pTarget, iTarget, &sz);
+ jsonBlobEdit(pTarget, iTarget+n, sz, 0, 0);
+ x = pTarget->aBlob[iTarget];
+ pTarget->aBlob[iTarget] = (x & 0xf0) | JSONB_OBJECT;
+ }
+ n = jsonbPayloadSize(pPatch, iPatch, &sz);
+ if( NEVER(n==0) ) return JSON_MERGE_BADPATCH;
+ iPCursor = iPatch+n;
+ iPEnd = iPCursor+sz;
+ n = jsonbPayloadSize(pTarget, iTarget, &sz);
+ if( NEVER(n==0) ) return JSON_MERGE_BADTARGET;
+ iTStart = iTarget+n;
+ iTEndBE = iTStart+sz;
+
+ while( iPCursor<iPEnd ){ /* Algorithm line 07 */
+ iPLabel = iPCursor;
+ ePLabel = pPatch->aBlob[iPCursor] & 0x0f;
+ if( ePLabel<JSONB_TEXT || ePLabel>JSONB_TEXTRAW ){
+ return JSON_MERGE_BADPATCH;
+ }
+ nPLabel = jsonbPayloadSize(pPatch, iPCursor, &szPLabel);
+ if( nPLabel==0 ) return JSON_MERGE_BADPATCH;
+ iPValue = iPCursor + nPLabel + szPLabel;
+ if( iPValue>=iPEnd ) return JSON_MERGE_BADPATCH;
+ nPValue = jsonbPayloadSize(pPatch, iPValue, &szPValue);
+ if( nPValue==0 ) return JSON_MERGE_BADPATCH;
+ iPCursor = iPValue + nPValue + szPValue;
+ if( iPCursor>iPEnd ) return JSON_MERGE_BADPATCH;
+
+ iTCursor = iTStart;
+ iTEnd = iTEndBE + pTarget->delta;
+ while( iTCursor<iTEnd ){
+ int isEqual; /* true if the patch and target labels match */
+ iTLabel = iTCursor;
+ eTLabel = pTarget->aBlob[iTCursor] & 0x0f;
+ if( eTLabel<JSONB_TEXT || eTLabel>JSONB_TEXTRAW ){
+ return JSON_MERGE_BADTARGET;
+ }
+ nTLabel = jsonbPayloadSize(pTarget, iTCursor, &szTLabel);
+ if( nTLabel==0 ) return JSON_MERGE_BADTARGET;
+ iTValue = iTLabel + nTLabel + szTLabel;
+ if( iTValue>=iTEnd ) return JSON_MERGE_BADTARGET;
+ nTValue = jsonbPayloadSize(pTarget, iTValue, &szTValue);
+ if( nTValue==0 ) return JSON_MERGE_BADTARGET;
+ if( iTValue + nTValue + szTValue > iTEnd ) return JSON_MERGE_BADTARGET;
+ isEqual = jsonLabelCompare(
+ (const char*)&pPatch->aBlob[iPLabel+nPLabel],
+ szPLabel,
+ (ePLabel==JSONB_TEXT || ePLabel==JSONB_TEXTRAW),
+ (const char*)&pTarget->aBlob[iTLabel+nTLabel],
+ szTLabel,
+ (eTLabel==JSONB_TEXT || eTLabel==JSONB_TEXTRAW));
+ if( isEqual ) break;
+ iTCursor = iTValue + nTValue + szTValue;
+ }
+ x = pPatch->aBlob[iPValue] & 0x0f;
+ if( iTCursor<iTEnd ){
+ /* A match was found. Algorithm line 08 */
+ if( x==0 ){
+ /* Patch value is NULL. Algorithm line 09 */
+ jsonBlobEdit(pTarget, iTLabel, nTLabel+szTLabel+nTValue+szTValue, 0,0);
+ /* vvvvvv----- No OOM on a delete-only edit */
+ if( NEVER(pTarget->oom) ) return JSON_MERGE_OOM;
+ }else{
+ /* Algorithm line 12 */
+ int rc, savedDelta = pTarget->delta;
+ pTarget->delta = 0;
+ rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue);
+ if( rc ) return rc;
+ pTarget->delta += savedDelta;
+ }
+ }else if( x>0 ){ /* Algorithm line 13 */
+ /* No match and patch value is not NULL */
+ u32 szNew = szPLabel+nPLabel;
+ if( (pPatch->aBlob[iPValue] & 0x0f)!=JSONB_OBJECT ){ /* Line 14 */
+ jsonBlobEdit(pTarget, iTEnd, 0, 0, szPValue+nPValue+szNew);
+ if( pTarget->oom ) return JSON_MERGE_OOM;
+ memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew);
+ memcpy(&pTarget->aBlob[iTEnd+szNew],
+ &pPatch->aBlob[iPValue], szPValue+nPValue);
+ }else{
+ int rc, savedDelta;
+ jsonBlobEdit(pTarget, iTEnd, 0, 0, szNew+1);
+ if( pTarget->oom ) return JSON_MERGE_OOM;
+ memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew);
+ pTarget->aBlob[iTEnd+szNew] = 0x00;
+ savedDelta = pTarget->delta;
+ pTarget->delta = 0;
+ rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue);
+ if( rc ) return rc;
+ pTarget->delta += savedDelta;
}
}
- if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
- int iStart, iPatch;
- iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
- jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
- iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
- if( pParse->oom ) return 0;
- jsonRemoveAllNulls(pPatch);
- pTarget = &pParse->aNode[iTarget];
- assert( pParse->aNode[iRoot].eU==0 || pParse->aNode[iRoot].eU==2 );
- testcase( pParse->aNode[iRoot].eU==2 );
- pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
- VVA( pParse->aNode[iRoot].eU = 2 );
- pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
- iRoot = iStart;
- assert( pParse->aNode[iPatch].eU==0 );
- VVA( pParse->aNode[iPatch].eU = 5 );
- pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
- pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
- }
}
- return pTarget;
+ if( pTarget->delta ) jsonAfterEditSizeAdjust(pTarget, iTarget);
+ return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK;
}
+
/*
** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON
** object that is the result of running the RFC 7396 MergePatch() algorithm
@@ -200622,25 +210516,27 @@ static void jsonPatchFunc(
int argc,
wx_sqlite3_value **argv
){
- JsonParse x; /* The JSON that is being patched */
- JsonParse y; /* The patch */
- JsonNode *pResult; /* The result of the merge */
+ JsonParse *pTarget; /* The TARGET */
+ JsonParse *pPatch; /* The PATCH */
+ int rc; /* Result code */
UNUSED_PARAMETER(argc);
- if( jsonParse(&x, ctx, (const char*)wx_sqlite3_value_text(argv[0])) ) return;
- if( jsonParse(&y, ctx, (const char*)wx_sqlite3_value_text(argv[1])) ){
- jsonParseReset(&x);
- return;
- }
- pResult = jsonMergePatch(&x, 0, y.aNode);
- assert( pResult!=0 || x.oom );
- if( pResult ){
- jsonReturnJson(pResult, ctx, 0);
- }else{
- wx_sqlite3_result_error_nomem(ctx);
+ assert( argc==2 );
+ pTarget = jsonParseFuncArg(ctx, argv[0], JSON_EDITABLE);
+ if( pTarget==0 ) return;
+ pPatch = jsonParseFuncArg(ctx, argv[1], 0);
+ if( pPatch ){
+ rc = jsonMergePatch(pTarget, 0, pPatch, 0);
+ if( rc==JSON_MERGE_OK ){
+ jsonReturnParse(ctx, pTarget);
+ }else if( rc==JSON_MERGE_OOM ){
+ wx_sqlite3_result_error_nomem(ctx);
+ }else{
+ wx_sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ jsonParseFree(pPatch);
}
- jsonParseReset(&x);
- jsonParseReset(&y);
+ jsonParseFree(pTarget);
}
@@ -200664,23 +210560,23 @@ static void jsonObjectFunc(
"of arguments", -1);
return;
}
- jsonInit(&jx, ctx);
+ jsonStringInit(&jx, ctx);
jsonAppendChar(&jx, '{');
for(i=0; i<argc; i+=2){
if( wx_sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
wx_sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
- jsonReset(&jx);
+ jsonStringReset(&jx);
return;
}
jsonAppendSeparator(&jx);
z = (const char*)wx_sqlite3_value_text(argv[i]);
- n = (u32)wx_sqlite3_value_bytes(argv[i]);
+ n = wx_sqlite3_value_bytes(argv[i]);
jsonAppendString(&jx, z, n);
jsonAppendChar(&jx, ':');
- jsonAppendValue(&jx, argv[i+1]);
+ jsonAppendSqlValue(&jx, argv[i+1]);
}
jsonAppendChar(&jx, '}');
- jsonResult(&jx);
+ jsonReturnString(&jx, 0, 0);
wx_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
@@ -200696,26 +210592,50 @@ static void jsonRemoveFunc(
int argc,
wx_sqlite3_value **argv
){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
+ JsonParse *p; /* The parse */
+ const char *zPath = 0; /* Path of element to be removed */
+ int i; /* Loop counter */
+ u32 rc; /* Subroutine return code */
if( argc<1 ) return;
- if( jsonParse(&x, ctx, (const char*)wx_sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i++){
+ p = jsonParseFuncArg(ctx, argv[0], argc>1 ? JSON_EDITABLE : 0);
+ if( p==0 ) return;
+ for(i=1; i<argc; i++){
zPath = (const char*)wx_sqlite3_value_text(argv[i]);
- if( zPath==0 ) goto remove_done;
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto remove_done;
- if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
- }
- if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
- jsonReturnJson(x.aNode, ctx, 0);
+ if( zPath==0 ){
+ goto json_remove_done;
+ }
+ if( zPath[0]!='$' ){
+ goto json_remove_patherror;
+ }
+ if( zPath[1]==0 ){
+ /* json_remove(j,'$') returns NULL */
+ goto json_remove_done;
+ }
+ p->eEdit = JEDIT_DEL;
+ p->delta = 0;
+ rc = jsonLookupStep(p, 0, zPath+1, 0);
+ if( JSON_LOOKUP_ISERROR(rc) ){
+ if( rc==JSON_LOOKUP_NOTFOUND ){
+ continue; /* No-op */
+ }else if( rc==JSON_LOOKUP_PATHERROR ){
+ jsonBadPathError(ctx, zPath);
+ }else{
+ wx_sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ goto json_remove_done;
+ }
}
-remove_done:
- jsonParseReset(&x);
+ jsonReturnParse(ctx, p);
+ jsonParseFree(p);
+ return;
+
+json_remove_patherror:
+ jsonBadPathError(ctx, zPath);
+
+json_remove_done:
+ jsonParseFree(p);
+ return;
}
/*
@@ -200729,38 +210649,12 @@ static void jsonReplaceFunc(
int argc,
wx_sqlite3_value **argv
){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
-
if( argc<1 ) return;
if( (argc&1)==0 ) {
jsonWrongNumArgs(ctx, "replace");
return;
}
- if( jsonParse(&x, ctx, (const char*)wx_sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i+=2){
- zPath = (const char*)wx_sqlite3_value_text(argv[i]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto replace_err;
- if( pNode ){
- assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 );
- testcase( pNode->eU!=0 && pNode->eU!=1 );
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- VVA( pNode->eU = 4 );
- pNode->u.iReplace = i + 1;
- }
- }
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- assert( x.aNode[0].eU==4 );
- wx_sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
- }else{
- jsonReturnJson(x.aNode, ctx, argv);
- }
-replace_err:
- jsonParseReset(&x);
+ jsonInsertIntoBlob(ctx, argc, argv, JEDIT_REPL);
}
@@ -200781,45 +210675,16 @@ static void jsonSetFunc(
int argc,
wx_sqlite3_value **argv
){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
- int bApnd;
- int bIsSet = wx_sqlite3_user_data(ctx)!=0;
+
+ int flags = SQLITE_PTR_TO_INT(wx_sqlite3_user_data(ctx));
+ int bIsSet = (flags&JSON_ISSET)!=0;
if( argc<1 ) return;
if( (argc&1)==0 ) {
jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
return;
}
- if( jsonParse(&x, ctx, (const char*)wx_sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i+=2){
- zPath = (const char*)wx_sqlite3_value_text(argv[i]);
- bApnd = 0;
- pNode = jsonLookup(&x, zPath, &bApnd, ctx);
- if( x.oom ){
- wx_sqlite3_result_error_nomem(ctx);
- goto jsonSetDone;
- }else if( x.nErr ){
- goto jsonSetDone;
- }else if( pNode && (bApnd || bIsSet) ){
- testcase( pNode->eU!=0 && pNode->eU!=1 );
- assert( pNode->eU!=3 && pNode->eU!=5 );
- VVA( pNode->eU = 4 );
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- pNode->u.iReplace = i + 1;
- }
- }
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- assert( x.aNode[0].eU==4 );
- wx_sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
- }else{
- jsonReturnJson(x.aNode, ctx, argv);
- }
-jsonSetDone:
- jsonParseReset(&x);
+ jsonInsertIntoBlob(ctx, argc, argv, bIsSet ? JEDIT_SET : JEDIT_INS);
}
/*
@@ -200835,27 +210700,127 @@ static void jsonTypeFunc(
wx_sqlite3_value **argv
){
JsonParse *p; /* The parse */
- const char *zPath;
- JsonNode *pNode;
+ const char *zPath = 0;
+ u32 i;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
if( p==0 ) return;
if( argc==2 ){
zPath = (const char*)wx_sqlite3_value_text(argv[1]);
- pNode = jsonLookup(p, zPath, 0, ctx);
+ if( zPath==0 ) goto json_type_done;
+ if( zPath[0]!='$' ){
+ jsonBadPathError(ctx, zPath);
+ goto json_type_done;
+ }
+ i = jsonLookupStep(p, 0, zPath+1, 0);
+ if( JSON_LOOKUP_ISERROR(i) ){
+ if( i==JSON_LOOKUP_NOTFOUND ){
+ /* no-op */
+ }else if( i==JSON_LOOKUP_PATHERROR ){
+ jsonBadPathError(ctx, zPath);
+ }else{
+ wx_sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ goto json_type_done;
+ }
}else{
- pNode = p->aNode;
+ i = 0;
}
- if( pNode ){
- wx_sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
+ wx_sqlite3_result_text(ctx, jsonbType[p->aBlob[i]&0x0f], -1, SQLITE_STATIC);
+json_type_done:
+ jsonParseFree(p);
+}
+
+/*
+** json_pretty(JSON)
+** json_pretty(JSON, INDENT)
+**
+** Return text that is a pretty-printed rendering of the input JSON.
+** If the argument is not valid JSON, return NULL.
+**
+** The INDENT argument is text that is used for indentation. If omitted,
+** it defaults to four spaces (the same as PostgreSQL).
+*/
+static void jsonPrettyFunc(
+ wx_sqlite3_context *ctx,
+ int argc,
+ wx_sqlite3_value **argv
+){
+ JsonString s; /* The output string */
+ JsonPretty x; /* Pretty printing context */
+
+ memset(&x, 0, sizeof(x));
+ x.pParse = jsonParseFuncArg(ctx, argv[0], 0);
+ if( x.pParse==0 ) return;
+ x.pOut = &s;
+ jsonStringInit(&s, ctx);
+ if( argc==1 || (x.zIndent = (const char*)wx_sqlite3_value_text(argv[1]))==0 ){
+ x.zIndent = " ";
+ x.szIndent = 4;
+ }else{
+ x.szIndent = (u32)strlen(x.zIndent);
}
+ jsonTranslateBlobToPrettyText(&x, 0);
+ jsonReturnString(&s, 0, 0);
+ jsonParseFree(x.pParse);
}
/*
** json_valid(JSON)
-**
-** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
-** Return 0 otherwise.
+** json_valid(JSON, FLAGS)
+**
+** Check the JSON argument to see if it is well-formed. The FLAGS argument
+** encodes the various constraints on what is meant by "well-formed":
+**
+** 0x01 Canonical RFC-8259 JSON text
+** 0x02 JSON text with optional JSON-5 extensions
+** 0x04 Superficially appears to be JSONB
+** 0x08 Strictly well-formed JSONB
+**
+** If the FLAGS argument is omitted, it defaults to 1. Useful values for
+** FLAGS include:
+**
+** 1 Strict canonical JSON text
+** 2 JSON text perhaps with JSON-5 extensions
+** 4 Superficially appears to be JSONB
+** 5 Canonical JSON text or superficial JSONB
+** 6 JSON-5 text or superficial JSONB
+** 8 Strict JSONB
+** 9 Canonical JSON text or strict JSONB
+** 10 JSON-5 text or strict JSONB
+**
+** Other flag combinations are redundant. For example, every canonical
+** JSON text is also well-formed JSON-5 text, so FLAG values 2 and 3
+** are the same. Similarly, any input that passes a strict JSONB validation
+** will also pass the superficial validation so 12 through 15 are the same
+** as 8 through 11 respectively.
+**
+** This routine runs in linear time to validate text and when doing strict
+** JSONB validation. Superficial JSONB validation is constant time,
+** assuming the BLOB is already in memory. The performance advantage
+** of superficial JSONB validation is why that option is provided.
+** Application developers can choose to do fast superficial validation or
+** slower strict validation, according to their specific needs.
+**
+** Only the lower four bits of the FLAGS argument are currently used.
+** Higher bits are reserved for future expansion. To facilitate
+** compatibility, the current implementation raises an error if any bit
+** in FLAGS is set other than the lower four bits.
+**
+** The original circa 2015 implementation of the JSON routines in
+** SQLite only supported canonical RFC-8259 JSON text and the json_valid()
+** function only accepted one argument. That is why the default value
+** for the FLAGS argument is 1, since FLAGS=1 causes this routine to only
+** recognize canonical RFC-8259 JSON text as valid. The extra FLAGS
+** argument was added when the JSON routines were extended to support
+** JSON5-like extensions and binary JSONB stored in BLOBs.
+**
+** Return Values:
+**
+** * Raise an error if FLAGS is outside the range of 1 to 15.
+** * Return NULL if the input is NULL
+** * Return 1 if the input is well-formed.
+** * Return 0 if the input is not well-formed.
*/
static void jsonValidFunc(
wx_sqlite3_context *ctx,
@@ -200863,11 +210828,127 @@ static void jsonValidFunc(
wx_sqlite3_value **argv
){
JsonParse *p; /* The parse */
- UNUSED_PARAMETER(argc);
- p = jsonParseCached(ctx, argv, 0);
- wx_sqlite3_result_int(ctx, p!=0);
+ u8 flags = 1;
+ u8 res = 0;
+ if( argc==2 ){
+ i64 f = wx_sqlite3_value_int64(argv[1]);
+ if( f<1 || f>15 ){
+ wx_sqlite3_result_error(ctx, "FLAGS parameter to json_valid() must be"
+ " between 1 and 15", -1);
+ return;
+ }
+ flags = f & 0x0f;
+ }
+ switch( wx_sqlite3_value_type(argv[0]) ){
+ case SQLITE_NULL: {
+#ifdef SQLITE_LEGACY_JSON_VALID
+ /* Incorrect legacy behavior was to return FALSE for a NULL input */
+ wx_sqlite3_result_int(ctx, 0);
+#endif
+ return;
+ }
+ case SQLITE_BLOB: {
+ if( jsonFuncArgMightBeBinary(argv[0]) ){
+ if( flags & 0x04 ){
+ /* Superficial checking only - accomplished by the
+ ** jsonFuncArgMightBeBinary() call above. */
+ res = 1;
+ }else if( flags & 0x08 ){
+ /* Strict checking. Check by translating BLOB->TEXT->BLOB. If
+ ** no errors occur, call that a "strict check". */
+ JsonParse px;
+ u32 iErr;
+ memset(&px, 0, sizeof(px));
+ px.aBlob = (u8*)wx_sqlite3_value_blob(argv[0]);
+ px.nBlob = wx_sqlite3_value_bytes(argv[0]);
+ iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1);
+ res = iErr==0;
+ }
+ break;
+ }
+ /* Fall through into interpreting the input as text. See note
+ ** above at tag-20240123-a. */
+ /* no break */ deliberate_fall_through
+ }
+ default: {
+ JsonParse px;
+ if( (flags & 0x3)==0 ) break;
+ memset(&px, 0, sizeof(px));
+
+ p = jsonParseFuncArg(ctx, argv[0], JSON_KEEPERROR);
+ if( p ){
+ if( p->oom ){
+ wx_sqlite3_result_error_nomem(ctx);
+ }else if( p->nErr ){
+ /* no-op */
+ }else if( (flags & 0x02)!=0 || p->hasNonstd==0 ){
+ res = 1;
+ }
+ jsonParseFree(p);
+ }else{
+ wx_sqlite3_result_error_nomem(ctx);
+ }
+ break;
+ }
+ }
+ wx_sqlite3_result_int(ctx, res);
}
+/*
+** json_error_position(JSON)
+**
+** If the argument is NULL, return NULL
+**
+** If the argument is BLOB, do a full validity check and return non-zero
+** if the check fails. The return value is the approximate 1-based offset
+** to the byte of the element that contains the first error.
+**
+** Otherwise interpret the argument is TEXT (even if it is numeric) and
+** return the 1-based character position for where the parser first recognized
+** that the input was not valid JSON, or return 0 if the input text looks
+** ok. JSON-5 extensions are accepted.
+*/
+static void jsonErrorFunc(
+ wx_sqlite3_context *ctx,
+ int argc,
+ wx_sqlite3_value **argv
+){
+ i64 iErrPos = 0; /* Error position to be returned */
+ JsonParse s;
+
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ memset(&s, 0, sizeof(s));
+ s.db = wx_sqlite3_context_db_handle(ctx);
+ if( jsonFuncArgMightBeBinary(argv[0]) ){
+ s.aBlob = (u8*)wx_sqlite3_value_blob(argv[0]);
+ s.nBlob = wx_sqlite3_value_bytes(argv[0]);
+ iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1);
+ }else{
+ s.zJson = (char*)wx_sqlite3_value_text(argv[0]);
+ if( s.zJson==0 ) return; /* NULL input or OOM */
+ s.nJson = wx_sqlite3_value_bytes(argv[0]);
+ if( jsonConvertTextToBlob(&s,0) ){
+ if( s.oom ){
+ iErrPos = -1;
+ }else{
+ /* Convert byte-offset s.iErr into a character offset */
+ u32 k;
+ assert( s.zJson!=0 ); /* Because s.oom is false */
+ for(k=0; k<s.iErr && ALWAYS(s.zJson[k]); k++){
+ if( (s.zJson[k] & 0xc0)!=0x80 ) iErrPos++;
+ }
+ iErrPos++;
+ }
+ }
+ }
+ jsonParseReset(&s);
+ if( iErrPos<0 ){
+ wx_sqlite3_result_error_nomem(ctx);
+ }else{
+ wx_sqlite3_result_int64(ctx, iErrPos);
+ }
+}
/****************************************************************************
** Aggregate SQL function implementations
@@ -200887,31 +210968,42 @@ static void jsonArrayStep(
pStr = (JsonString*)wx_sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
- jsonInit(pStr, ctx);
+ jsonStringInit(pStr, ctx);
jsonAppendChar(pStr, '[');
}else if( pStr->nUsed>1 ){
jsonAppendChar(pStr, ',');
}
pStr->pCtx = ctx;
- jsonAppendValue(pStr, argv[0]);
+ jsonAppendSqlValue(pStr, argv[0]);
}
}
static void jsonArrayCompute(wx_sqlite3_context *ctx, int isFinal){
JsonString *pStr;
pStr = (JsonString*)wx_sqlite3_aggregate_context(ctx, 0);
if( pStr ){
+ int flags;
pStr->pCtx = ctx;
jsonAppendChar(pStr, ']');
- if( pStr->bErr ){
- if( pStr->bErr==1 ) wx_sqlite3_result_error_nomem(ctx);
- assert( pStr->bStatic );
+ flags = SQLITE_PTR_TO_INT(wx_sqlite3_user_data(ctx));
+ if( pStr->eErr ){
+ jsonReturnString(pStr, 0, 0);
+ return;
+ }else if( flags & JSON_BLOB ){
+ jsonReturnStringAsBlob(pStr);
+ if( isFinal ){
+ if( !pStr->bStatic ) wx_sqlite3RCStrUnref(pStr->zBuf);
+ }else{
+ jsonStringTrimOneChar(pStr);
+ }
+ return;
}else if( isFinal ){
wx_sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : wx_sqlite3_free);
+ pStr->bStatic ? SQLITE_TRANSIENT :
+ wx_sqlite3RCStrUnref);
pStr->bStatic = 1;
}else{
wx_sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
- pStr->nUsed--;
+ jsonStringTrimOneChar(pStr);
}
}else{
wx_sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
@@ -200948,7 +211040,7 @@ static void jsonGroupInverse(
pStr = (JsonString*)wx_sqlite3_aggregate_context(ctx, 0);
#ifdef NEVER
/* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
- ** always have been called to initalize it */
+ ** always have been called to initialize it */
if( NEVER(!pStr) ) return;
#endif
z = pStr->zBuf;
@@ -200992,34 +211084,46 @@ static void jsonObjectStep(
pStr = (JsonString*)wx_sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
- jsonInit(pStr, ctx);
+ jsonStringInit(pStr, ctx);
jsonAppendChar(pStr, '{');
}else if( pStr->nUsed>1 ){
jsonAppendChar(pStr, ',');
}
pStr->pCtx = ctx;
z = (const char*)wx_sqlite3_value_text(argv[0]);
- n = (u32)wx_sqlite3_value_bytes(argv[0]);
+ n = wx_sqlite3Strlen30(z);
jsonAppendString(pStr, z, n);
jsonAppendChar(pStr, ':');
- jsonAppendValue(pStr, argv[1]);
+ jsonAppendSqlValue(pStr, argv[1]);
}
}
static void jsonObjectCompute(wx_sqlite3_context *ctx, int isFinal){
JsonString *pStr;
pStr = (JsonString*)wx_sqlite3_aggregate_context(ctx, 0);
if( pStr ){
+ int flags;
jsonAppendChar(pStr, '}');
- if( pStr->bErr ){
- if( pStr->bErr==1 ) wx_sqlite3_result_error_nomem(ctx);
- assert( pStr->bStatic );
+ pStr->pCtx = ctx;
+ flags = SQLITE_PTR_TO_INT(wx_sqlite3_user_data(ctx));
+ if( pStr->eErr ){
+ jsonReturnString(pStr, 0, 0);
+ return;
+ }else if( flags & JSON_BLOB ){
+ jsonReturnStringAsBlob(pStr);
+ if( isFinal ){
+ if( !pStr->bStatic ) wx_sqlite3RCStrUnref(pStr->zBuf);
+ }else{
+ jsonStringTrimOneChar(pStr);
+ }
+ return;
}else if( isFinal ){
wx_sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : wx_sqlite3_free);
+ pStr->bStatic ? SQLITE_TRANSIENT :
+ wx_sqlite3RCStrUnref);
pStr->bStatic = 1;
}else{
wx_sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
- pStr->nUsed--;
+ jsonStringTrimOneChar(pStr);
}
}else{
wx_sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
@@ -201039,19 +211143,37 @@ static void jsonObjectFinal(wx_sqlite3_context *ctx){
/****************************************************************************
** The json_each virtual table
****************************************************************************/
+typedef struct JsonParent JsonParent;
+struct JsonParent {
+ u32 iHead; /* Start of object or array */
+ u32 iValue; /* Start of the value */
+ u32 iEnd; /* First byte past the end */
+ u32 nPath; /* Length of path */
+ i64 iKey; /* Key for JSONB_ARRAY */
+};
+
typedef struct JsonEachCursor JsonEachCursor;
struct JsonEachCursor {
wx_sqlite3_vtab_cursor base; /* Base class - must be first */
u32 iRowid; /* The rowid */
- u32 iBegin; /* The first node of the scan */
- u32 i; /* Index in sParse.aNode[] of current row */
+ u32 i; /* Index in sParse.aBlob[] of current row */
u32 iEnd; /* EOF when i equals or exceeds this value */
- u8 eType; /* Type of top-level element */
+ u32 nRoot; /* Size of the root path in bytes */
+ u8 eType; /* Type of the container for element i */
u8 bRecursive; /* True for json_tree(). False for json_each() */
- char *zJson; /* Input JSON */
- char *zRoot; /* Path by which to filter zJson */
+ u32 nParent; /* Current nesting depth */
+ u32 nParentAlloc; /* Space allocated for aParent[] */
+ JsonParent *aParent; /* Parent elements of i */
+ wx_sqlite3 *db; /* Database connection */
+ JsonString path; /* Current path */
JsonParse sParse; /* Parse of the input JSON */
};
+typedef struct JsonEachConnection JsonEachConnection;
+struct JsonEachConnection {
+ wx_sqlite3_vtab base; /* Base class - must be first */
+ wx_sqlite3 *db; /* Database connection */
+};
+
/* Constructor for the json_each virtual table */
static int jsonEachConnect(
@@ -201061,7 +211183,7 @@ static int jsonEachConnect(
wx_sqlite3_vtab **ppVtab,
char **pzErr
){
- wx_sqlite3_vtab *pNew;
+ JsonEachConnection *pNew;
int rc;
/* Column numbers */
@@ -201087,28 +211209,32 @@ static int jsonEachConnect(
"CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
"json HIDDEN,root HIDDEN)");
if( rc==SQLITE_OK ){
- pNew = *ppVtab = wx_sqlite3_malloc( sizeof(*pNew) );
+ pNew = (JsonEachConnection*)wx_sqlite3DbMallocZero(db, sizeof(*pNew));
+ *ppVtab = (wx_sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
- memset(pNew, 0, sizeof(*pNew));
wx_sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
+ pNew->db = db;
}
return rc;
}
/* destructor for json_each virtual table */
static int jsonEachDisconnect(wx_sqlite3_vtab *pVtab){
- wx_sqlite3_free(pVtab);
+ JsonEachConnection *p = (JsonEachConnection*)pVtab;
+ wx_sqlite3DbFree(p->db, pVtab);
return SQLITE_OK;
}
/* constructor for a JsonEachCursor object for json_each(). */
static int jsonEachOpenEach(wx_sqlite3_vtab *p, wx_sqlite3_vtab_cursor **ppCursor){
+ JsonEachConnection *pVtab = (JsonEachConnection*)p;
JsonEachCursor *pCur;
UNUSED_PARAMETER(p);
- pCur = wx_sqlite3_malloc( sizeof(*pCur) );
+ pCur = wx_sqlite3DbMallocZero(pVtab->db, sizeof(*pCur));
if( pCur==0 ) return SQLITE_NOMEM;
- memset(pCur, 0, sizeof(*pCur));
+ pCur->db = pVtab->db;
+ jsonStringZero(&pCur->path);
*ppCursor = &pCur->base;
return SQLITE_OK;
}
@@ -201126,22 +211252,24 @@ static int jsonEachOpenTree(wx_sqlite3_vtab *p, wx_sqlite3_vtab_cursor **ppCurso
/* Reset a JsonEachCursor back to its original state. Free any memory
** held. */
static void jsonEachCursorReset(JsonEachCursor *p){
- wx_sqlite3_free(p->zJson);
- wx_sqlite3_free(p->zRoot);
jsonParseReset(&p->sParse);
+ jsonStringReset(&p->path);
+ wx_sqlite3DbFree(p->db, p->aParent);
p->iRowid = 0;
p->i = 0;
+ p->aParent = 0;
+ p->nParent = 0;
+ p->nParentAlloc = 0;
p->iEnd = 0;
p->eType = 0;
- p->zJson = 0;
- p->zRoot = 0;
}
/* Destructor for a jsonEachCursor object */
static int jsonEachClose(wx_sqlite3_vtab_cursor *cur){
JsonEachCursor *p = (JsonEachCursor*)cur;
jsonEachCursorReset(p);
- wx_sqlite3_free(cur);
+
+ wx_sqlite3DbFree(p->db, cur);
return SQLITE_OK;
}
@@ -201152,198 +211280,233 @@ static int jsonEachEof(wx_sqlite3_vtab_cursor *cur){
return p->i >= p->iEnd;
}
-/* Advance the cursor to the next element for json_tree() */
-static int jsonEachNext(wx_sqlite3_vtab_cursor *cur){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- if( p->bRecursive ){
- if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
- p->i++;
- p->iRowid++;
- if( p->i<p->iEnd ){
- u32 iUp = p->sParse.aUp[p->i];
- JsonNode *pUp = &p->sParse.aNode[iUp];
- p->eType = pUp->eType;
- if( pUp->eType==JSON_ARRAY ){
- assert( pUp->eU==0 || pUp->eU==3 );
- testcase( pUp->eU==3 );
- VVA( pUp->eU = 3 );
- if( iUp==p->i-1 ){
- pUp->u.iKey = 0;
- }else{
- pUp->u.iKey++;
+/*
+** If the cursor is currently pointing at the label of a object entry,
+** then return the index of the value. For all other cases, return the
+** current pointer position, which is the value.
+*/
+static int jsonSkipLabel(JsonEachCursor *p){
+ if( p->eType==JSONB_OBJECT ){
+ u32 sz = 0;
+ u32 n = jsonbPayloadSize(&p->sParse, p->i, &sz);
+ return p->i + n + sz;
+ }else{
+ return p->i;
+ }
+}
+
+/*
+** Append the path name for the current element.
+*/
+static void jsonAppendPathName(JsonEachCursor *p){
+ assert( p->nParent>0 );
+ assert( p->eType==JSONB_ARRAY || p->eType==JSONB_OBJECT );
+ if( p->eType==JSONB_ARRAY ){
+ jsonPrintf(30, &p->path, "[%lld]", p->aParent[p->nParent-1].iKey);
+ }else{
+ u32 n, sz = 0, k, i;
+ const char *z;
+ int needQuote = 0;
+ n = jsonbPayloadSize(&p->sParse, p->i, &sz);
+ k = p->i + n;
+ z = (const char*)&p->sParse.aBlob[k];
+ if( sz==0 || !wx_sqlite3Isalpha(z[0]) ){
+ needQuote = 1;
+ }else{
+ for(i=0; i<sz; i++){
+ if( !wx_sqlite3Isalnum(z[i]) ){
+ needQuote = 1;
+ break;
}
}
}
- }else{
- switch( p->eType ){
- case JSON_ARRAY: {
- p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
- p->iRowid++;
- break;
- }
- case JSON_OBJECT: {
- p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
- p->iRowid++;
- break;
- }
- default: {
- p->i = p->iEnd;
- break;
- }
+ if( needQuote ){
+ jsonPrintf(sz+4,&p->path,".\"%.*s\"", sz, z);
+ }else{
+ jsonPrintf(sz+2,&p->path,".%.*s", sz, z);
}
}
- return SQLITE_OK;
}
-/* Append an object label to the JSON Path being constructed
-** in pStr.
-*/
-static void jsonAppendObjectPathElement(
- JsonString *pStr,
- JsonNode *pNode
-){
- int jj, nn;
- const char *z;
- assert( pNode->eType==JSON_STRING );
- assert( pNode->jnFlags & JNODE_LABEL );
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- nn = pNode->n;
- assert( nn>=2 );
- assert( z[0]=='"' );
- assert( z[nn-1]=='"' );
- if( nn>2 && wx_sqlite3Isalpha(z[1]) ){
- for(jj=2; jj<nn-1 && wx_sqlite3Isalnum(z[jj]); jj++){}
- if( jj==nn-1 ){
- z++;
- nn -= 2;
+/* Advance the cursor to the next element for json_tree() */
+static int jsonEachNext(wx_sqlite3_vtab_cursor *cur){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ int rc = SQLITE_OK;
+ if( p->bRecursive ){
+ u8 x;
+ u8 levelChange = 0;
+ u32 n, sz = 0;
+ u32 i = jsonSkipLabel(p);
+ x = p->sParse.aBlob[i] & 0x0f;
+ n = jsonbPayloadSize(&p->sParse, i, &sz);
+ if( x==JSONB_OBJECT || x==JSONB_ARRAY ){
+ JsonParent *pParent;
+ if( p->nParent>=p->nParentAlloc ){
+ JsonParent *pNew;
+ u64 nNew;
+ nNew = p->nParentAlloc*2 + 3;
+ pNew = wx_sqlite3DbRealloc(p->db, p->aParent, sizeof(JsonParent)*nNew);
+ if( pNew==0 ) return SQLITE_NOMEM;
+ p->nParentAlloc = (u32)nNew;
+ p->aParent = pNew;
+ }
+ levelChange = 1;
+ pParent = &p->aParent[p->nParent];
+ pParent->iHead = p->i;
+ pParent->iValue = i;
+ pParent->iEnd = i + n + sz;
+ pParent->iKey = -1;
+ pParent->nPath = (u32)p->path.nUsed;
+ if( p->eType && p->nParent ){
+ jsonAppendPathName(p);
+ if( p->path.eErr ) rc = SQLITE_NOMEM;
+ }
+ p->nParent++;
+ p->i = i + n;
+ }else{
+ p->i = i + n + sz;
+ }
+ while( p->nParent>0 && p->i >= p->aParent[p->nParent-1].iEnd ){
+ p->nParent--;
+ p->path.nUsed = p->aParent[p->nParent].nPath;
+ levelChange = 1;
+ }
+ if( levelChange ){
+ if( p->nParent>0 ){
+ JsonParent *pParent = &p->aParent[p->nParent-1];
+ u32 iVal = pParent->iValue;
+ p->eType = p->sParse.aBlob[iVal] & 0x0f;
+ }else{
+ p->eType = 0;
+ }
}
+ }else{
+ u32 n, sz = 0;
+ u32 i = jsonSkipLabel(p);
+ n = jsonbPayloadSize(&p->sParse, i, &sz);
+ p->i = i + n + sz;
+ }
+ if( p->eType==JSONB_ARRAY && p->nParent ){
+ p->aParent[p->nParent-1].iKey++;
}
- jsonPrintf(nn+2, pStr, ".%.*s", nn, z);
+ p->iRowid++;
+ return rc;
}
-/* Append the name of the path for element i to pStr
+/* Length of the path for rowid==0 in bRecursive mode.
*/
-static void jsonEachComputePath(
- JsonEachCursor *p, /* The cursor */
- JsonString *pStr, /* Write the path here */
- u32 i /* Path to this element */
-){
- JsonNode *pNode, *pUp;
- u32 iUp;
- if( i==0 ){
- jsonAppendChar(pStr, '$');
- return;
- }
- iUp = p->sParse.aUp[i];
- jsonEachComputePath(p, pStr, iUp);
- pNode = &p->sParse.aNode[i];
- pUp = &p->sParse.aNode[iUp];
- if( pUp->eType==JSON_ARRAY ){
- assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) );
- testcase( pUp->eU==0 );
- jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
- }else{
- assert( pUp->eType==JSON_OBJECT );
- if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
- jsonAppendObjectPathElement(pStr, pNode);
+static int jsonEachPathLength(JsonEachCursor *p){
+ u32 n = p->path.nUsed;
+ char *z = p->path.zBuf;
+ if( p->iRowid==0 && p->bRecursive && n>=2 ){
+ while( n>1 ){
+ n--;
+ if( z[n]=='[' || z[n]=='.' ){
+ u32 x, sz = 0;
+ char cSaved = z[n];
+ z[n] = 0;
+ assert( p->sParse.eEdit==0 );
+ x = jsonLookupStep(&p->sParse, 0, z+1, 0);
+ z[n] = cSaved;
+ if( JSON_LOOKUP_ISERROR(x) ) continue;
+ if( x + jsonbPayloadSize(&p->sParse, x, &sz) == p->i ) break;
+ }
+ }
}
+ return n;
}
/* Return the value of a column */
static int jsonEachColumn(
wx_sqlite3_vtab_cursor *cur, /* The cursor */
wx_sqlite3_context *ctx, /* First argument to wx_sqlite3_result_...() */
- int i /* Which column to return */
+ int iColumn /* Which column to return */
){
JsonEachCursor *p = (JsonEachCursor*)cur;
- JsonNode *pThis = &p->sParse.aNode[p->i];
- switch( i ){
+ switch( iColumn ){
case JEACH_KEY: {
- if( p->i==0 ) break;
- if( p->eType==JSON_OBJECT ){
- jsonReturn(pThis, ctx, 0);
- }else if( p->eType==JSON_ARRAY ){
- u32 iKey;
- if( p->bRecursive ){
- if( p->iRowid==0 ) break;
- assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 );
- iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
+ if( p->nParent==0 ){
+ u32 n, j;
+ if( p->nRoot==1 ) break;
+ j = jsonEachPathLength(p);
+ n = p->nRoot - j;
+ if( n==0 ){
+ break;
+ }else if( p->path.zBuf[j]=='[' ){
+ i64 x;
+ wx_sqlite3Atoi64(&p->path.zBuf[j+1], &x, n-1, SQLITE_UTF8);
+ wx_sqlite3_result_int64(ctx, x);
+ }else if( p->path.zBuf[j+1]=='"' ){
+ wx_sqlite3_result_text(ctx, &p->path.zBuf[j+2], n-3, SQLITE_TRANSIENT);
}else{
- iKey = p->iRowid;
+ wx_sqlite3_result_text(ctx, &p->path.zBuf[j+1], n-1, SQLITE_TRANSIENT);
}
- wx_sqlite3_result_int64(ctx, (wx_sqlite3_int64)iKey);
+ break;
+ }
+ if( p->eType==JSONB_OBJECT ){
+ jsonReturnFromBlob(&p->sParse, p->i, ctx, 1);
+ }else{
+ assert( p->eType==JSONB_ARRAY );
+ wx_sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iKey);
}
break;
}
case JEACH_VALUE: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- jsonReturn(pThis, ctx, 0);
+ u32 i = jsonSkipLabel(p);
+ jsonReturnFromBlob(&p->sParse, i, ctx, 1);
+ if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){
+ wx_sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
break;
}
case JEACH_TYPE: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- wx_sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
+ u32 i = jsonSkipLabel(p);
+ u8 eType = p->sParse.aBlob[i] & 0x0f;
+ wx_sqlite3_result_text(ctx, jsonbType[eType], -1, SQLITE_STATIC);
break;
}
case JEACH_ATOM: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- if( pThis->eType>=JSON_ARRAY ) break;
- jsonReturn(pThis, ctx, 0);
+ u32 i = jsonSkipLabel(p);
+ if( (p->sParse.aBlob[i] & 0x0f)<JSONB_ARRAY ){
+ jsonReturnFromBlob(&p->sParse, i, ctx, 1);
+ }
break;
}
case JEACH_ID: {
- wx_sqlite3_result_int64(ctx,
- (wx_sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
+ wx_sqlite3_result_int64(ctx, (wx_sqlite3_int64)p->i);
break;
}
case JEACH_PARENT: {
- if( p->i>p->iBegin && p->bRecursive ){
- wx_sqlite3_result_int64(ctx, (wx_sqlite3_int64)p->sParse.aUp[p->i]);
+ if( p->nParent>0 && p->bRecursive ){
+ wx_sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iHead);
}
break;
}
case JEACH_FULLKEY: {
- JsonString x;
- jsonInit(&x, ctx);
- if( p->bRecursive ){
- jsonEachComputePath(p, &x, p->i);
- }else{
- if( p->zRoot ){
- jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
- }else{
- jsonAppendChar(&x, '$');
- }
- if( p->eType==JSON_ARRAY ){
- jsonPrintf(30, &x, "[%d]", p->iRowid);
- }else if( p->eType==JSON_OBJECT ){
- jsonAppendObjectPathElement(&x, pThis);
- }
- }
- jsonResult(&x);
+ u64 nBase = p->path.nUsed;
+ if( p->nParent ) jsonAppendPathName(p);
+ wx_sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed,
+ SQLITE_TRANSIENT, SQLITE_UTF8);
+ p->path.nUsed = nBase;
break;
}
case JEACH_PATH: {
- if( p->bRecursive ){
- JsonString x;
- jsonInit(&x, ctx);
- jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
- jsonResult(&x);
- break;
- }
- /* For json_each() path and root are the same so fall through
- ** into the root case */
- /* no break */ deliberate_fall_through
+ u32 n = jsonEachPathLength(p);
+ wx_sqlite3_result_text64(ctx, p->path.zBuf, n,
+ SQLITE_TRANSIENT, SQLITE_UTF8);
+ break;
}
default: {
- const char *zRoot = p->zRoot;
- if( zRoot==0 ) zRoot = "$";
- wx_sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
+ wx_sqlite3_result_text(ctx, p->path.zBuf, p->nRoot, SQLITE_STATIC);
break;
}
case JEACH_JSON: {
- assert( i==JEACH_JSON );
- wx_sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
+ if( p->sParse.zJson==0 ){
+ wx_sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
+ SQLITE_TRANSIENT);
+ }else{
+ wx_sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_TRANSIENT);
+ }
break;
}
}
@@ -201434,78 +211597,97 @@ static int jsonEachFilter(
int argc, wx_sqlite3_value **argv
){
JsonEachCursor *p = (JsonEachCursor*)cur;
- const char *z;
const char *zRoot = 0;
- wx_sqlite3_int64 n;
+ u32 i, n, sz;
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(argc);
jsonEachCursorReset(p);
if( idxNum==0 ) return SQLITE_OK;
- z = (const char*)wx_sqlite3_value_text(argv[0]);
- if( z==0 ) return SQLITE_OK;
- n = wx_sqlite3_value_bytes(argv[0]);
- p->zJson = wx_sqlite3_malloc64( n+1 );
- if( p->zJson==0 ) return SQLITE_NOMEM;
- memcpy(p->zJson, z, (size_t)n+1);
- if( jsonParse(&p->sParse, 0, p->zJson) ){
- int rc = SQLITE_NOMEM;
- if( p->sParse.oom==0 ){
- wx_sqlite3_free(cur->pVtab->zErrMsg);
- cur->pVtab->zErrMsg = wx_sqlite3_mprintf("malformed JSON");
- if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
+ memset(&p->sParse, 0, sizeof(p->sParse));
+ p->sParse.nJPRef = 1;
+ p->sParse.db = p->db;
+ if( jsonFuncArgMightBeBinary(argv[0]) ){
+ p->sParse.nBlob = wx_sqlite3_value_bytes(argv[0]);
+ p->sParse.aBlob = (u8*)wx_sqlite3_value_blob(argv[0]);
+ }else{
+ p->sParse.zJson = (char*)wx_sqlite3_value_text(argv[0]);
+ p->sParse.nJson = wx_sqlite3_value_bytes(argv[0]);
+ if( p->sParse.zJson==0 ){
+ p->i = p->iEnd = 0;
+ return SQLITE_OK;
}
- jsonEachCursorReset(p);
- return rc;
- }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
- jsonEachCursorReset(p);
- return SQLITE_NOMEM;
- }else{
- JsonNode *pNode = 0;
- if( idxNum==3 ){
- const char *zErr = 0;
- zRoot = (const char*)wx_sqlite3_value_text(argv[1]);
- if( zRoot==0 ) return SQLITE_OK;
- n = wx_sqlite3_value_bytes(argv[1]);
- p->zRoot = wx_sqlite3_malloc64( n+1 );
- if( p->zRoot==0 ) return SQLITE_NOMEM;
- memcpy(p->zRoot, zRoot, (size_t)n+1);
- if( zRoot[0]!='$' ){
- zErr = zRoot;
- }else{
- pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
+ if( jsonConvertTextToBlob(&p->sParse, 0) ){
+ if( p->sParse.oom ){
+ return SQLITE_NOMEM;
}
- if( zErr ){
+ goto json_each_malformed_input;
+ }
+ }
+ if( idxNum==3 ){
+ zRoot = (const char*)wx_sqlite3_value_text(argv[1]);
+ if( zRoot==0 ) return SQLITE_OK;
+ if( zRoot[0]!='$' ){
+ wx_sqlite3_free(cur->pVtab->zErrMsg);
+ cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
+ jsonEachCursorReset(p);
+ return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
+ }
+ p->nRoot = wx_sqlite3Strlen30(zRoot);
+ if( zRoot[1]==0 ){
+ i = p->i = 0;
+ p->eType = 0;
+ }else{
+ i = jsonLookupStep(&p->sParse, 0, zRoot+1, 0);
+ if( JSON_LOOKUP_ISERROR(i) ){
+ if( i==JSON_LOOKUP_NOTFOUND ){
+ p->i = 0;
+ p->eType = 0;
+ p->iEnd = 0;
+ return SQLITE_OK;
+ }
wx_sqlite3_free(cur->pVtab->zErrMsg);
- cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
+ cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
jsonEachCursorReset(p);
return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
- }else if( pNode==0 ){
- return SQLITE_OK;
}
- }else{
- pNode = p->sParse.aNode;
- }
- p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
- p->eType = pNode->eType;
- if( p->eType>=JSON_ARRAY ){
- assert( pNode->eU==0 );
- VVA( pNode->eU = 3 );
- pNode->u.iKey = 0;
- p->iEnd = p->i + pNode->n + 1;
- if( p->bRecursive ){
- p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
- if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
- p->i--;
- }
+ if( p->sParse.iLabel ){
+ p->i = p->sParse.iLabel;
+ p->eType = JSONB_OBJECT;
}else{
- p->i++;
- }
- }else{
- p->iEnd = p->i+1;
- }
+ p->i = i;
+ p->eType = JSONB_ARRAY;
+ }
+ }
+ jsonAppendRaw(&p->path, zRoot, p->nRoot);
+ }else{
+ i = p->i = 0;
+ p->eType = 0;
+ p->nRoot = 1;
+ jsonAppendRaw(&p->path, "$", 1);
+ }
+ p->nParent = 0;
+ n = jsonbPayloadSize(&p->sParse, i, &sz);
+ p->iEnd = i+n+sz;
+ if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY && !p->bRecursive ){
+ p->i = i + n;
+ p->eType = p->sParse.aBlob[i] & 0x0f;
+ p->aParent = wx_sqlite3DbMallocZero(p->db, sizeof(JsonParent));
+ if( p->aParent==0 ) return SQLITE_NOMEM;
+ p->nParent = 1;
+ p->nParentAlloc = 1;
+ p->aParent[0].iKey = 0;
+ p->aParent[0].iEnd = p->iEnd;
+ p->aParent[0].iHead = p->i;
+ p->aParent[0].iValue = i;
}
return SQLITE_OK;
+
+json_each_malformed_input:
+ wx_sqlite3_free(cur->pVtab->zErrMsg);
+ cur->pVtab->zErrMsg = wx_sqlite3_mprintf("malformed JSON");
+ jsonEachCursorReset(p);
+ return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
}
/* The methods of the json_each virtual table */
@@ -201533,7 +211715,8 @@ static wx_sqlite3_module jsonEachModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
/* The methods of the json_tree virtual table. */
@@ -201561,7 +211744,8 @@ static wx_sqlite3_module jsonTreeModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#endif /* !defined(SQLITE_OMIT_JSON) */
@@ -201572,33 +211756,59 @@ static wx_sqlite3_module jsonTreeModule = {
SQLITE_PRIVATE void wx_sqlite3RegisterJsonFunctions(void){
#ifndef SQLITE_OMIT_JSON
static FuncDef aJsonFunc[] = {
- JFUNCTION(json, 1, 0, jsonRemoveFunc),
- JFUNCTION(json_array, -1, 0, jsonArrayFunc),
- JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc),
- JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc),
- JFUNCTION(json_extract, -1, 0, jsonExtractFunc),
- JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc),
- JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc),
- JFUNCTION(json_insert, -1, 0, jsonSetFunc),
- JFUNCTION(json_object, -1, 0, jsonObjectFunc),
- JFUNCTION(json_patch, 2, 0, jsonPatchFunc),
- JFUNCTION(json_quote, 1, 0, jsonQuoteFunc),
- JFUNCTION(json_remove, -1, 0, jsonRemoveFunc),
- JFUNCTION(json_replace, -1, 0, jsonReplaceFunc),
- JFUNCTION(json_set, -1, JSON_ISSET, jsonSetFunc),
- JFUNCTION(json_type, 1, 0, jsonTypeFunc),
- JFUNCTION(json_type, 2, 0, jsonTypeFunc),
- JFUNCTION(json_valid, 1, 0, jsonValidFunc),
+ /* wx_sqlite3_result_subtype() ----, ,--- wx_sqlite3_value_subtype() */
+ /* | | */
+ /* Uses cache ------, | | ,---- Returns JSONB */
+ /* | | | | */
+ /* Number of arguments ---, | | | | ,--- Flags */
+ /* | | | | | | */
+ JFUNCTION(json, 1,1,1, 0,0,0, jsonRemoveFunc),
+ JFUNCTION(jsonb, 1,1,0, 0,1,0, jsonRemoveFunc),
+ JFUNCTION(json_array, -1,0,1, 1,0,0, jsonArrayFunc),
+ JFUNCTION(jsonb_array, -1,0,1, 1,1,0, jsonArrayFunc),
+ JFUNCTION(json_array_length, 1,1,0, 0,0,0, jsonArrayLengthFunc),
+ JFUNCTION(json_array_length, 2,1,0, 0,0,0, jsonArrayLengthFunc),
+ JFUNCTION(json_error_position,1,1,0, 0,0,0, jsonErrorFunc),
+ JFUNCTION(json_extract, -1,1,1, 0,0,0, jsonExtractFunc),
+ JFUNCTION(jsonb_extract, -1,1,0, 0,1,0, jsonExtractFunc),
+ JFUNCTION(->, 2,1,1, 0,0,JSON_JSON, jsonExtractFunc),
+ JFUNCTION(->>, 2,1,0, 0,0,JSON_SQL, jsonExtractFunc),
+ JFUNCTION(json_insert, -1,1,1, 1,0,0, jsonSetFunc),
+ JFUNCTION(jsonb_insert, -1,1,0, 1,1,0, jsonSetFunc),
+ JFUNCTION(json_object, -1,0,1, 1,0,0, jsonObjectFunc),
+ JFUNCTION(jsonb_object, -1,0,1, 1,1,0, jsonObjectFunc),
+ JFUNCTION(json_patch, 2,1,1, 0,0,0, jsonPatchFunc),
+ JFUNCTION(jsonb_patch, 2,1,0, 0,1,0, jsonPatchFunc),
+ JFUNCTION(json_pretty, 1,1,0, 0,0,0, jsonPrettyFunc),
+ JFUNCTION(json_pretty, 2,1,0, 0,0,0, jsonPrettyFunc),
+ JFUNCTION(json_quote, 1,0,1, 1,0,0, jsonQuoteFunc),
+ JFUNCTION(json_remove, -1,1,1, 0,0,0, jsonRemoveFunc),
+ JFUNCTION(jsonb_remove, -1,1,0, 0,1,0, jsonRemoveFunc),
+ JFUNCTION(json_replace, -1,1,1, 1,0,0, jsonReplaceFunc),
+ JFUNCTION(jsonb_replace, -1,1,0, 1,1,0, jsonReplaceFunc),
+ JFUNCTION(json_set, -1,1,1, 1,0,JSON_ISSET, jsonSetFunc),
+ JFUNCTION(jsonb_set, -1,1,0, 1,1,JSON_ISSET, jsonSetFunc),
+ JFUNCTION(json_type, 1,1,0, 0,0,0, jsonTypeFunc),
+ JFUNCTION(json_type, 2,1,0, 0,0,0, jsonTypeFunc),
+ JFUNCTION(json_valid, 1,1,0, 0,0,0, jsonValidFunc),
+ JFUNCTION(json_valid, 2,1,0, 0,0,0, jsonValidFunc),
#if SQLITE_DEBUG
- JFUNCTION(json_parse, 1, 0, jsonParseFunc),
- JFUNCTION(json_test1, 1, 0, jsonTest1Func),
+ JFUNCTION(json_parse, 1,1,0, 0,0,0, jsonParseFunc),
#endif
WAGGREGATE(json_group_array, 1, 0, 0,
jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
- SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|
+ SQLITE_DETERMINISTIC),
+ WAGGREGATE(jsonb_group_array, 1, JSON_BLOB, 0,
+ jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
WAGGREGATE(json_group_object, 2, 0, 0,
jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
- SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC)
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
+ WAGGREGATE(jsonb_group_object,2, JSON_BLOB, 0,
+ jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|
+ SQLITE_DETERMINISTIC)
};
wx_sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc));
#endif
@@ -201725,6 +211935,11 @@ typedef unsigned int u32;
#endif
#endif /* !defined(SQLITE_AMALGAMATION) */
+/* Macro to check for 4-byte alignment. Only used inside of assert() */
+#ifdef SQLITE_DEBUG
+# define FOUR_BYTE_ALIGNED(X) ((((char*)(X) - (char*)0) & 3)==0)
+#endif
+
/* #include <string.h> */
/* #include <stdio.h> */
/* #include <assert.h> */
@@ -201790,6 +212005,7 @@ struct Rtree {
int iDepth; /* Current depth of the r-tree structure */
char *zDb; /* Name of database containing r-tree table */
char *zName; /* Name of r-tree table */
+ char *zNodeName; /* Name of the %_node table */
u32 nBusy; /* Current number of users of this structure */
i64 nRowEst; /* Estimated number of rows in this table */
u32 nCursor; /* Number of open cursors */
@@ -201802,7 +212018,6 @@ struct Rtree {
** headed by the node (leaf nodes have RtreeNode.iNode==0).
*/
RtreeNode *pDeleted;
- int iReinsertHeight; /* Height of sub-trees Reinsert() has run on */
/* Blob I/O on xxx_node */
wx_sqlite3_blob *pNodeBlob;
@@ -202099,17 +212314,23 @@ struct RtreeMatchArg {
** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
** at run-time.
*/
-#ifndef SQLITE_BYTEORDER
-#if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
- defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
- defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
- defined(__arm__)
-# define SQLITE_BYTEORDER 1234
-#elif defined(sparc) || defined(__ppc__)
-# define SQLITE_BYTEORDER 4321
-#else
-# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
-#endif
+#ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */
+# if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
+# define SQLITE_BYTEORDER 4321
+# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
+# define SQLITE_BYTEORDER 1234
+# elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1
+# define SQLITE_BYTEORDER 4321
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
+ defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64)
+# define SQLITE_BYTEORDER 1234
+# elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__)
+# define SQLITE_BYTEORDER 4321
+# else
+# define SQLITE_BYTEORDER 0
+# endif
#endif
@@ -202130,7 +212351,7 @@ static int readInt16(u8 *p){
return (p[0]<<8) + p[1];
}
static void readCoord(u8 *p, RtreeCoord *pCoord){
- assert( (((wx_sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(p) );
#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
pCoord->u = _byteswap_ulong(*(u32*)p);
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
@@ -202184,7 +212405,7 @@ static void writeInt16(u8 *p, int i){
}
static int writeCoord(u8 *p, RtreeCoord *pCoord){
u32 i;
- assert( (((wx_sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(p) );
assert( sizeof(RtreeCoord)==4 );
assert( sizeof(u32)==4 );
#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
@@ -202312,11 +212533,9 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
** Clear the Rtree.pNodeBlob object
*/
static void nodeBlobReset(Rtree *pRtree){
- if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
- wx_sqlite3_blob *pBlob = pRtree->pNodeBlob;
- pRtree->pNodeBlob = 0;
- wx_sqlite3_blob_close(pBlob);
- }
+ wx_sqlite3_blob *pBlob = pRtree->pNodeBlob;
+ pRtree->pNodeBlob = 0;
+ wx_sqlite3_blob_close(pBlob);
}
/*
@@ -202335,7 +212554,7 @@ static int nodeAcquire(
** increase its reference count and return it.
*/
if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
- if( pParent && pParent!=pNode->pParent ){
+ if( pParent && ALWAYS(pParent!=pNode->pParent) ){
RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
@@ -202355,14 +212574,11 @@ static int nodeAcquire(
}
}
if( pRtree->pNodeBlob==0 ){
- char *zTab = wx_sqlite3_mprintf("%s_node", pRtree->zName);
- if( zTab==0 ) return SQLITE_NOMEM;
- rc = wx_sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0,
+ rc = wx_sqlite3_blob_open(pRtree->db, pRtree->zDb, pRtree->zNodeName,
+ "data", iNode, 0,
&pRtree->pNodeBlob);
- wx_sqlite3_free(zTab);
}
if( rc ){
- nodeBlobReset(pRtree);
*ppNode = 0;
/* If unable to open an wx_sqlite3_blob on the desired row, that can only
** be because the shadow tables hold erroneous data. */
@@ -202422,6 +212638,7 @@ static int nodeAcquire(
}
*ppNode = pNode;
}else{
+ nodeBlobReset(pRtree);
if( pNode ){
pRtree->nNodeRef--;
wx_sqlite3_free(pNode);
@@ -202566,6 +212783,7 @@ static void nodeGetCoord(
int iCoord, /* Which coordinate to extract */
RtreeCoord *pCoord /* OUT: Space to write result to */
){
+ assert( iCell<NCELL(pNode) );
readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord);
}
@@ -202755,7 +212973,9 @@ static int rtreeClose(wx_sqlite3_vtab_cursor *cur){
wx_sqlite3_finalize(pCsr->pReadAux);
wx_sqlite3_free(pCsr);
pRtree->nCursor--;
- nodeBlobReset(pRtree);
+ if( pRtree->nCursor==0 && pRtree->inWrTrans==0 ){
+ nodeBlobReset(pRtree);
+ }
return SQLITE_OK;
}
@@ -202912,7 +213132,7 @@ static void rtreeNonleafConstraint(
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|| p->op==RTREE_FALSE );
- assert( (((wx_sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(pCellData) );
switch( p->op ){
case RTREE_TRUE: return; /* Always satisfied */
case RTREE_FALSE: break; /* Never satisfied */
@@ -202965,7 +213185,7 @@ static void rtreeLeafConstraint(
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|| p->op==RTREE_FALSE );
pCellData += 8 + p->iCoord*4;
- assert( (((wx_sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(pCellData) );
RTREE_DECODE_COORD(eInt, pCellData, xN);
switch( p->op ){
case RTREE_TRUE: return; /* Always satisfied */
@@ -203340,7 +213560,11 @@ static int rtreeRowid(wx_sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid)
int rc = SQLITE_OK;
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
if( rc==SQLITE_OK && ALWAYS(p) ){
- *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
+ if( p->iCell>=NCELL(pNode) ){
+ rc = SQLITE_ABORT;
+ }else{
+ *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
+ }
}
return rc;
}
@@ -203358,6 +213582,7 @@ static int rtreeColumn(wx_sqlite3_vtab_cursor *cur, wx_sqlite3_context *ctx, int
if( rc ) return rc;
if( NEVER(p==0) ) return SQLITE_OK;
+ if( p->iCell>=NCELL(pNode) ) return SQLITE_ABORT;
if( i==0 ){
wx_sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
}else if( i<=pRtree->nDim2 ){
@@ -203455,6 +213680,8 @@ static int deserializeGeometry(wx_sqlite3_value *pValue, RtreeConstraint *pCons)
return SQLITE_OK;
}
+SQLITE_PRIVATE int wx_sqlite3IntFloatCompare(i64,double);
+
/*
** Rtree virtual table module xFilter method.
*/
@@ -203484,7 +213711,8 @@ static int rtreeFilter(
i64 iNode = 0;
int eType = wx_sqlite3_value_numeric_type(argv[0]);
if( eType==SQLITE_INTEGER
- || (eType==SQLITE_FLOAT && wx_sqlite3_value_double(argv[0])==iRowid)
+ || (eType==SQLITE_FLOAT
+ && 0==wx_sqlite3IntFloatCompare(iRowid,wx_sqlite3_value_double(argv[0])))
){
rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
}else{
@@ -203535,7 +213763,20 @@ static int rtreeFilter(
p->pInfo->nCoord = pRtree->nDim2;
p->pInfo->anQueue = pCsr->anQueue;
p->pInfo->mxLevel = pRtree->iDepth + 1;
- }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ }else if( eType==SQLITE_INTEGER ){
+ wx_sqlite3_int64 iVal = wx_sqlite3_value_int64(argv[ii]);
+#ifdef SQLITE_RTREE_INT_ONLY
+ p->u.rValue = iVal;
+#else
+ p->u.rValue = (double)iVal;
+ if( iVal>=((wx_sqlite3_int64)1)<<48
+ || iVal<=-(((wx_sqlite3_int64)1)<<48)
+ ){
+ if( p->op==RTREE_LT ) p->op = RTREE_LE;
+ if( p->op==RTREE_GT ) p->op = RTREE_GE;
+ }
+#endif
+ }else if( eType==SQLITE_FLOAT ){
#ifdef SQLITE_RTREE_INT_ONLY
p->u.rValue = wx_sqlite3_value_int64(argv[ii]);
#else
@@ -203666,11 +213907,12 @@ static int rtreeBestIndex(wx_sqlite3_vtab *tab, wx_sqlite3_index_info *pIdxInfo)
|| p->op==SQLITE_INDEX_CONSTRAINT_MATCH)
){
u8 op;
+ u8 doOmit = 1;
switch( p->op ){
- case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
- case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break;
+ case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; doOmit = 0; break;
+ case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; doOmit = 0; break;
case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
- case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
+ case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; doOmit = 0; break;
case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break;
case SQLITE_INDEX_CONSTRAINT_MATCH: op = RTREE_MATCH; break;
default: op = 0; break;
@@ -203679,15 +213921,19 @@ static int rtreeBestIndex(wx_sqlite3_vtab *tab, wx_sqlite3_index_info *pIdxInfo)
zIdxStr[iIdx++] = op;
zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0');
pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
- pIdxInfo->aConstraintUsage[ii].omit = 1;
+ pIdxInfo->aConstraintUsage[ii].omit = doOmit;
}
}
}
pIdxInfo->idxNum = 2;
pIdxInfo->needToFreeIdxStr = 1;
- if( iIdx>0 && 0==(pIdxInfo->idxStr = wx_sqlite3_mprintf("%s", zIdxStr)) ){
- return SQLITE_NOMEM;
+ if( iIdx>0 ){
+ pIdxInfo->idxStr = wx_sqlite3_malloc( iIdx+1 );
+ if( pIdxInfo->idxStr==0 ){
+ return SQLITE_NOMEM;
+ }
+ memcpy(pIdxInfo->idxStr, zIdxStr, iIdx+1);
}
nRow = pRtree->nRowEst >> (iIdx/2);
@@ -203766,31 +214012,22 @@ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
*/
static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
int ii;
- int isInt = (pRtree->eCoordType==RTREE_COORD_INT32);
- for(ii=0; ii<pRtree->nDim2; ii+=2){
- RtreeCoord *a1 = &p1->aCoord[ii];
- RtreeCoord *a2 = &p2->aCoord[ii];
- if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f))
- || ( isInt && (a2[0].i<a1[0].i || a2[1].i>a1[1].i))
- ){
- return 0;
+ if( pRtree->eCoordType==RTREE_COORD_INT32 ){
+ for(ii=0; ii<pRtree->nDim2; ii+=2){
+ RtreeCoord *a1 = &p1->aCoord[ii];
+ RtreeCoord *a2 = &p2->aCoord[ii];
+ if( a2[0].i<a1[0].i || a2[1].i>a1[1].i ) return 0;
+ }
+ }else{
+ for(ii=0; ii<pRtree->nDim2; ii+=2){
+ RtreeCoord *a1 = &p1->aCoord[ii];
+ RtreeCoord *a2 = &p2->aCoord[ii];
+ if( a2[0].f<a1[0].f || a2[1].f>a1[1].f ) return 0;
}
}
return 1;
}
-/*
-** Return the amount cell p would grow by if it were unioned with pCell.
-*/
-static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
- RtreeDValue area;
- RtreeCell cell;
- memcpy(&cell, p, sizeof(RtreeCell));
- area = cellArea(pRtree, &cell);
- cellUnion(pRtree, &cell, pCell);
- return (cellArea(pRtree, &cell)-area);
-}
-
static RtreeDValue cellOverlap(
Rtree *pRtree,
RtreeCell *p,
@@ -203837,38 +214074,52 @@ static int ChooseLeaf(
for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){
int iCell;
wx_sqlite3_int64 iBest = 0;
-
+ int bFound = 0;
RtreeDValue fMinGrowth = RTREE_ZERO;
RtreeDValue fMinArea = RTREE_ZERO;
-
int nCell = NCELL(pNode);
- RtreeCell cell;
RtreeNode *pChild = 0;
- RtreeCell *aCell = 0;
-
- /* Select the child node which will be enlarged the least if pCell
- ** is inserted into it. Resolve ties by choosing the entry with
- ** the smallest area.
+ /* First check to see if there is are any cells in pNode that completely
+ ** contains pCell. If two or more cells in pNode completely contain pCell
+ ** then pick the smallest.
*/
for(iCell=0; iCell<nCell; iCell++){
- int bBest = 0;
- RtreeDValue growth;
- RtreeDValue area;
+ RtreeCell cell;
nodeGetCell(pRtree, pNode, iCell, &cell);
- growth = cellGrowth(pRtree, &cell, pCell);
- area = cellArea(pRtree, &cell);
- if( iCell==0||growth<fMinGrowth||(growth==fMinGrowth && area<fMinArea) ){
- bBest = 1;
+ if( cellContains(pRtree, &cell, pCell) ){
+ RtreeDValue area = cellArea(pRtree, &cell);
+ if( bFound==0 || area<fMinArea ){
+ iBest = cell.iRowid;
+ fMinArea = area;
+ bFound = 1;
+ }
}
- if( bBest ){
- fMinGrowth = growth;
- fMinArea = area;
- iBest = cell.iRowid;
+ }
+ if( !bFound ){
+ /* No cells of pNode will completely contain pCell. So pick the
+ ** cell of pNode that grows by the least amount when pCell is added.
+ ** Break ties by selecting the smaller cell.
+ */
+ for(iCell=0; iCell<nCell; iCell++){
+ RtreeCell cell;
+ RtreeDValue growth;
+ RtreeDValue area;
+ nodeGetCell(pRtree, pNode, iCell, &cell);
+ area = cellArea(pRtree, &cell);
+ cellUnion(pRtree, &cell, pCell);
+ growth = cellArea(pRtree, &cell)-area;
+ if( iCell==0
+ || growth<fMinGrowth
+ || (growth==fMinGrowth && area<fMinArea)
+ ){
+ fMinGrowth = growth;
+ fMinArea = area;
+ iBest = cell.iRowid;
+ }
}
}
- wx_sqlite3_free(aCell);
rc = nodeAcquire(pRtree, iBest, pNode, &pChild);
nodeRelease(pRtree, pNode);
pNode = pChild;
@@ -203941,77 +214192,6 @@ static int parentWrite(Rtree *pRtree, wx_sqlite3_int64 iNode, wx_sqlite3_int64 i
static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int);
-/*
-** Arguments aIdx, aDistance and aSpare all point to arrays of size
-** nIdx. The aIdx array contains the set of integers from 0 to
-** (nIdx-1) in no particular order. This function sorts the values
-** in aIdx according to the indexed values in aDistance. For
-** example, assuming the inputs:
-**
-** aIdx = { 0, 1, 2, 3 }
-** aDistance = { 5.0, 2.0, 7.0, 6.0 }
-**
-** this function sets the aIdx array to contain:
-**
-** aIdx = { 0, 1, 2, 3 }
-**
-** The aSpare array is used as temporary working space by the
-** sorting algorithm.
-*/
-static void SortByDistance(
- int *aIdx,
- int nIdx,
- RtreeDValue *aDistance,
- int *aSpare
-){
- if( nIdx>1 ){
- int iLeft = 0;
- int iRight = 0;
-
- int nLeft = nIdx/2;
- int nRight = nIdx-nLeft;
- int *aLeft = aIdx;
- int *aRight = &aIdx[nLeft];
-
- SortByDistance(aLeft, nLeft, aDistance, aSpare);
- SortByDistance(aRight, nRight, aDistance, aSpare);
-
- memcpy(aSpare, aLeft, sizeof(int)*nLeft);
- aLeft = aSpare;
-
- while( iLeft<nLeft || iRight<nRight ){
- if( iLeft==nLeft ){
- aIdx[iLeft+iRight] = aRight[iRight];
- iRight++;
- }else if( iRight==nRight ){
- aIdx[iLeft+iRight] = aLeft[iLeft];
- iLeft++;
- }else{
- RtreeDValue fLeft = aDistance[aLeft[iLeft]];
- RtreeDValue fRight = aDistance[aRight[iRight]];
- if( fLeft<fRight ){
- aIdx[iLeft+iRight] = aLeft[iLeft];
- iLeft++;
- }else{
- aIdx[iLeft+iRight] = aRight[iRight];
- iRight++;
- }
- }
- }
-
-#if 0
- /* Check that the sort worked */
- {
- int jj;
- for(jj=1; jj<nIdx; jj++){
- RtreeDValue left = aDistance[aIdx[jj-1]];
- RtreeDValue right = aDistance[aIdx[jj]];
- assert( left<=right );
- }
- }
-#endif
- }
-}
/*
** Arguments aIdx, aCell and aSpare all point to arrays of size
@@ -204496,107 +214676,6 @@ static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){
return rc;
}
-static int Reinsert(
- Rtree *pRtree,
- RtreeNode *pNode,
- RtreeCell *pCell,
- int iHeight
-){
- int *aOrder;
- int *aSpare;
- RtreeCell *aCell;
- RtreeDValue *aDistance;
- int nCell;
- RtreeDValue aCenterCoord[RTREE_MAX_DIMENSIONS];
- int iDim;
- int ii;
- int rc = SQLITE_OK;
- int n;
-
- 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 *)wx_sqlite3_malloc64(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[n];
- aSpare = (int *)&aOrder[n];
- aDistance = (RtreeDValue *)&aSpare[n];
-
- for(ii=0; ii<nCell; ii++){
- if( ii==(nCell-1) ){
- memcpy(&aCell[ii], pCell, sizeof(RtreeCell));
- }else{
- nodeGetCell(pRtree, pNode, ii, &aCell[ii]);
- }
- aOrder[ii] = ii;
- for(iDim=0; iDim<pRtree->nDim; iDim++){
- 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] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2));
- }
-
- for(ii=0; ii<nCell; ii++){
- aDistance[ii] = RTREE_ZERO;
- for(iDim=0; iDim<pRtree->nDim; iDim++){
- RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) -
- DCOORD(aCell[ii].aCoord[iDim*2]));
- aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
- }
- }
-
- SortByDistance(aOrder, nCell, aDistance, aSpare);
- nodeZero(pRtree, pNode);
-
- for(ii=0; rc==SQLITE_OK && ii<(nCell-(RTREE_MINCELLS(pRtree)+1)); ii++){
- RtreeCell *p = &aCell[aOrder[ii]];
- nodeInsertCell(pRtree, pNode, p);
- if( p->iRowid==pCell->iRowid ){
- if( iHeight==0 ){
- rc = rowidWrite(pRtree, p->iRowid, pNode->iNode);
- }else{
- rc = parentWrite(pRtree, p->iRowid, pNode->iNode);
- }
- }
- }
- if( rc==SQLITE_OK ){
- rc = fixBoundingBox(pRtree, pNode);
- }
- for(; rc==SQLITE_OK && ii<nCell; ii++){
- /* Find a node to store this cell in. pNode->iNode currently contains
- ** the height of the sub-tree headed by the cell.
- */
- RtreeNode *pInsert;
- RtreeCell *p = &aCell[aOrder[ii]];
- rc = ChooseLeaf(pRtree, p, iHeight, &pInsert);
- if( rc==SQLITE_OK ){
- int rc2;
- rc = rtreeInsertCell(pRtree, pInsert, p, iHeight);
- rc2 = nodeRelease(pRtree, pInsert);
- if( rc==SQLITE_OK ){
- rc = rc2;
- }
- }
- }
-
- wx_sqlite3_free(aCell);
- return rc;
-}
-
/*
** Insert cell pCell into node pNode. Node pNode is the head of a
** subtree iHeight high (leaf nodes have iHeight==0).
@@ -204617,12 +214696,7 @@ static int rtreeInsertCell(
}
}
if( nodeInsertCell(pRtree, pNode, pCell) ){
- if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){
- rc = SplitNode(pRtree, pNode, pCell, iHeight);
- }else{
- pRtree->iReinsertHeight = iHeight;
- rc = Reinsert(pRtree, pNode, pCell, iHeight);
- }
+ rc = SplitNode(pRtree, pNode, pCell, iHeight);
}else{
rc = AdjustTree(pRtree, pNode, pCell);
if( ALWAYS(rc==SQLITE_OK) ){
@@ -204965,7 +215039,6 @@ static int rtreeUpdate(
}
if( rc==SQLITE_OK ){
int rc2;
- pRtree->iReinsertHeight = -1;
rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0);
rc2 = nodeRelease(pRtree, pLeaf);
if( rc==SQLITE_OK ){
@@ -204995,7 +215068,7 @@ constraint:
static int rtreeBeginTransaction(wx_sqlite3_vtab *pVtab){
Rtree *pRtree = (Rtree *)pVtab;
assert( pRtree->inWrTrans==0 );
- pRtree->inWrTrans++;
+ pRtree->inWrTrans = 1;
return SQLITE_OK;
}
@@ -205009,6 +215082,9 @@ static int rtreeEndTransaction(wx_sqlite3_vtab *pVtab){
nodeBlobReset(pRtree);
return SQLITE_OK;
}
+static int rtreeRollback(wx_sqlite3_vtab *pVtab){
+ return rtreeEndTransaction(pVtab);
+}
/*
** The xRename method for rtree module virtual tables.
@@ -205106,8 +215182,11 @@ static int rtreeShadowName(const char *zName){
return 0;
}
+/* Forward declaration */
+static int rtreeIntegrity(wx_sqlite3_vtab*, const char*, const char*, int, char**);
+
static wx_sqlite3_module rtreeModule = {
- 3, /* iVersion */
+ 4, /* iVersion */
rtreeCreate, /* xCreate - create a table */
rtreeConnect, /* xConnect - connect to an existing table */
rtreeBestIndex, /* xBestIndex - Determine search strategy */
@@ -205124,13 +215203,14 @@ static wx_sqlite3_module rtreeModule = {
rtreeBeginTransaction, /* xBegin - begin transaction */
rtreeEndTransaction, /* xSync - sync transaction */
rtreeEndTransaction, /* xCommit - commit transaction */
- rtreeEndTransaction, /* xRollback - rollback transaction */
+ rtreeRollback, /* xRollback - rollback transaction */
0, /* xFindFunction - function overloading */
rtreeRename, /* xRename - rename the table */
rtreeSavepoint, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- rtreeShadowName /* xShadowName */
+ rtreeShadowName, /* xShadowName */
+ rtreeIntegrity /* xIntegrity */
};
static int rtreeSqlInit(
@@ -205223,7 +215303,7 @@ static int rtreeSqlInit(
}
wx_sqlite3_free(zSql);
}
- if( pRtree->nAux ){
+ if( pRtree->nAux && rc!=SQLITE_NOMEM ){
pRtree->zReadAuxSql = wx_sqlite3_mprintf(
"SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1",
zDb, zPrefix);
@@ -205386,22 +215466,27 @@ static int rtreeInit(
}
wx_sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ wx_sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
+
/* Allocate the wx_sqlite3_vtab structure */
nDb = (int)strlen(argv[1]);
nName = (int)strlen(argv[2]);
- pRtree = (Rtree *)wx_sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
+ pRtree = (Rtree *)wx_sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8);
if( !pRtree ){
return SQLITE_NOMEM;
}
- memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
+ memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8);
pRtree->nBusy = 1;
pRtree->base.pModule = &rtreeModule;
pRtree->zDb = (char *)&pRtree[1];
pRtree->zName = &pRtree->zDb[nDb+1];
+ pRtree->zNodeName = &pRtree->zName[nName+1];
pRtree->eCoordType = (u8)eCoordType;
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
+ memcpy(pRtree->zNodeName, argv[2], nName);
+ memcpy(&pRtree->zNodeName[nName], "_node", 6);
/* Create/Connect to the underlying relational database schema. If
@@ -205898,7 +215983,6 @@ static int rtreeCheckTable(
){
RtreeCheck check; /* Common context for various routines */
wx_sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */
- int bEnd = 0; /* True if transaction should be closed */
int nAux = 0; /* Number of extra columns. */
/* Initialize the context object */
@@ -205907,24 +215991,14 @@ static int rtreeCheckTable(
check.zDb = zDb;
check.zTab = zTab;
- /* If there is not already an open transaction, open one now. This is
- ** to ensure that the queries run as part of this integrity-check operate
- ** on a consistent snapshot. */
- if( wx_sqlite3_get_autocommit(db) ){
- check.rc = wx_sqlite3_exec(db, "BEGIN", 0, 0, 0);
- bEnd = 1;
- }
-
/* Find the number of auxiliary columns */
- if( check.rc==SQLITE_OK ){
- pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
- if( pStmt ){
- nAux = wx_sqlite3_column_count(pStmt) - 2;
- wx_sqlite3_finalize(pStmt);
- }else
- if( check.rc!=SQLITE_NOMEM ){
- check.rc = SQLITE_OK;
- }
+ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
+ if( pStmt ){
+ nAux = wx_sqlite3_column_count(pStmt) - 2;
+ wx_sqlite3_finalize(pStmt);
+ }else
+ if( check.rc!=SQLITE_NOMEM ){
+ check.rc = SQLITE_OK;
}
/* Find number of dimensions in the rtree table. */
@@ -205955,16 +216029,36 @@ static int rtreeCheckTable(
wx_sqlite3_finalize(check.aCheckMapping[0]);
wx_sqlite3_finalize(check.aCheckMapping[1]);
- /* If one was opened, close the transaction */
- if( bEnd ){
- int rc = wx_sqlite3_exec(db, "END", 0, 0, 0);
- if( check.rc==SQLITE_OK ) check.rc = rc;
- }
*pzReport = check.zReport;
return check.rc;
}
/*
+** Implementation of the xIntegrity method for Rtree.
+*/
+static int rtreeIntegrity(
+ wx_sqlite3_vtab *pVtab, /* The virtual table to check */
+ const char *zSchema, /* Schema in which the virtual table lives */
+ const char *zName, /* Name of the virtual table */
+ int isQuick, /* True for a quick_check */
+ char **pzErr /* Write results here */
+){
+ Rtree *pRtree = (Rtree*)pVtab;
+ int rc;
+ assert( pzErr!=0 && *pzErr==0 );
+ UNUSED_PARAMETER(zSchema);
+ UNUSED_PARAMETER(zName);
+ UNUSED_PARAMETER(isQuick);
+ rc = rtreeCheckTable(pRtree->db, pRtree->zDb, pRtree->zName, pzErr);
+ if( rc==SQLITE_OK && *pzErr ){
+ *pzErr = wx_sqlite3_mprintf("In RTree %s.%s:\n%z",
+ pRtree->zDb, pRtree->zName, *pzErr);
+ if( (*pzErr)==0 ) rc = SQLITE_NOMEM;
+ }
+ return rc;
+}
+
+/*
** Usage:
**
** rtreecheck(<rtree-table>);
@@ -207285,24 +217379,28 @@ static int geopolyInit(
(void)pAux;
wx_sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ wx_sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
/* Allocate the wx_sqlite3_vtab structure */
nDb = strlen(argv[1]);
nName = strlen(argv[2]);
- pRtree = (Rtree *)wx_sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
+ pRtree = (Rtree *)wx_sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8);
if( !pRtree ){
return SQLITE_NOMEM;
}
- memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
+ memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8);
pRtree->nBusy = 1;
pRtree->base.pModule = &rtreeModule;
pRtree->zDb = (char *)&pRtree[1];
pRtree->zName = &pRtree->zDb[nDb+1];
+ pRtree->zNodeName = &pRtree->zName[nName+1];
pRtree->eCoordType = RTREE_COORD_REAL32;
pRtree->nDim = 2;
pRtree->nDim2 = 4;
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
+ memcpy(pRtree->zNodeName, argv[2], nName);
+ memcpy(&pRtree->zNodeName[nName], "_node", 6);
/* Create/Connect to the underlying relational database schema. If
@@ -207716,7 +217814,6 @@ static int geopolyUpdate(
}
if( rc==SQLITE_OK ){
int rc2;
- pRtree->iReinsertHeight = -1;
rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0);
rc2 = nodeRelease(pRtree, pLeaf);
if( rc==SQLITE_OK ){
@@ -207813,7 +217910,8 @@ static wx_sqlite3_module geopolyModule = {
rtreeSavepoint, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- rtreeShadowName /* xShadowName */
+ rtreeShadowName, /* xShadowName */
+ rtreeIntegrity /* xIntegrity */
};
static int wx_sqlite3_geopoly_init(wx_sqlite3 *db){
@@ -208524,7 +218622,7 @@ static void icuLoadCollation(
UCollator *pUCollator; /* ICU library collation object */
int rc; /* Return code from wx_sqlite3_create_collation_x() */
- assert(nArg==2);
+ assert(nArg==2 || nArg==3);
(void)nArg; /* Unused parameter */
zLocale = (const char *)wx_sqlite3_value_text(apArg[0]);
zName = (const char *)wx_sqlite3_value_text(apArg[1]);
@@ -208539,7 +218637,39 @@ static void icuLoadCollation(
return;
}
assert(p);
-
+ if(nArg==3){
+ const char *zOption = (const char*)wx_sqlite3_value_text(apArg[2]);
+ static const struct {
+ const char *zName;
+ UColAttributeValue val;
+ } aStrength[] = {
+ { "PRIMARY", UCOL_PRIMARY },
+ { "SECONDARY", UCOL_SECONDARY },
+ { "TERTIARY", UCOL_TERTIARY },
+ { "DEFAULT", UCOL_DEFAULT_STRENGTH },
+ { "QUARTERNARY", UCOL_QUATERNARY },
+ { "IDENTICAL", UCOL_IDENTICAL },
+ };
+ unsigned int i;
+ for(i=0; i<sizeof(aStrength)/sizeof(aStrength[0]); i++){
+ if( wx_sqlite3_stricmp(zOption,aStrength[i].zName)==0 ){
+ ucol_setStrength(pUCollator, aStrength[i].val);
+ break;
+ }
+ }
+ if( i>=sizeof(aStrength)/sizeof(aStrength[0]) ){
+ wx_sqlite3_str *pStr = wx_sqlite3_str_new(wx_sqlite3_context_db_handle(p));
+ wx_sqlite3_str_appendf(pStr,
+ "unknown collation strength \"%s\" - should be one of:",
+ zOption);
+ for(i=0; i<sizeof(aStrength)/sizeof(aStrength[0]); i++){
+ wx_sqlite3_str_appendf(pStr, " %s", aStrength[i].zName);
+ }
+ wx_sqlite3_result_error(p, wx_sqlite3_str_value(pStr), -1);
+ wx_sqlite3_free(wx_sqlite3_str_finish(pStr));
+ return;
+ }
+ }
rc = wx_sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
icuCollationColl, icuCollationDel
);
@@ -208562,6 +218692,7 @@ SQLITE_PRIVATE int wx_sqlite3IcuInit(wx_sqlite3 *db){
void (*xFunc)(wx_sqlite3_context*,int,wx_sqlite3_value**);
} scalars[] = {
{"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
+ {"icu_load_collation",3,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
{"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc},
{"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
@@ -209712,6 +219843,7 @@ typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef wx_sqlite3_int64 i64;
+typedef wx_sqlite3_uint64 u64;
#endif
/*
@@ -209848,6 +219980,27 @@ struct RbuFrame {
u32 iWalFrame;
};
+#ifndef UNUSED_PARAMETER
+/*
+** The following macros are used to suppress compiler warnings and to
+** make it clear to human readers when a function parameter is deliberately
+** left unused within the body of a function. This usually happens when
+** a function is called via a function pointer. For example the
+** implementation of an SQL aggregate step callback may not use the
+** parameter indicating the number of arguments passed to the aggregate,
+** if it knows that this is enforced elsewhere.
+**
+** When a function parameter is not used at all within the body of a function,
+** it is generally named "NotUsed" or "NotUsed2" to make things even clearer.
+** However, these macros may also be used to suppress warnings related to
+** parameters that may or may not be used depending on compilation options.
+** For example those parameters only used in assert() statements. In these
+** cases the parameters are named as per the usual conventions.
+*/
+#define UNUSED_PARAMETER(x) (void)(x)
+#define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y)
+#endif
+
/*
** RBU handle.
**
@@ -209899,7 +220052,7 @@ struct wx_sqlite3rbu {
int rc; /* Value returned by last rbu_step() call */
char *zErrmsg; /* Error message if rc!=SQLITE_OK */
int nStep; /* Rows processed for current object */
- int nProgress; /* Rows processed for all objects */
+ wx_sqlite3_int64 nProgress; /* Rows processed for all objects */
RbuObjIter objiter; /* Iterator for skipping through tbl/idx */
const char *zVfsName; /* Name of automatically created rbu vfs */
rbu_file *pTargetFd; /* File handle open on target db */
@@ -210016,7 +220169,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
v = (v<<6) + c;
}
z--;
- *pLen -= z - zStart;
+ *pLen -= (int)(z - zStart);
*pz = (char*)z;
return v;
}
@@ -210201,6 +220354,7 @@ static void rbuFossilDeltaFunc(
char *aOut;
assert( argc==2 );
+ UNUSED_PARAMETER(argc);
nOrig = wx_sqlite3_value_bytes(argv[0]);
aOrig = (const char*)wx_sqlite3_value_blob(argv[0]);
@@ -210398,6 +220552,7 @@ static int rbuObjIterNext(wx_sqlite3rbu *p, RbuObjIter *pIter){
if( rc!=SQLITE_ROW ){
rc = resetAndCollectError(pIter->pTblIter, &p->zErrmsg);
pIter->zTbl = 0;
+ pIter->zDataTbl = 0;
}else{
pIter->zTbl = (const char*)wx_sqlite3_column_text(pIter->pTblIter, 0);
pIter->zDataTbl = (const char*)wx_sqlite3_column_text(pIter->pTblIter,1);
@@ -211779,13 +221934,13 @@ static char *rbuObjIterGetIndexWhere(wx_sqlite3rbu *p, RbuObjIter *pIter){
else if( c==')' ){
nParen--;
if( nParen==0 ){
- int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan;
+ int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan);
pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
i++;
break;
}
}else if( c==',' && nParen==1 ){
- int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan;
+ int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan);
pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1];
}else if( c=='"' || c=='\'' || c=='`' ){
@@ -212475,6 +222630,8 @@ static void rbuFileSuffix3(const char *zBase, char *z){
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
}
+#else
+ UNUSED_PARAMETER2(zBase,z);
#endif
}
@@ -212492,7 +222649,7 @@ static i64 rbuShmChecksum(wx_sqlite3rbu *p){
u32 volatile *ptr;
p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, (void volatile**)&ptr);
if( p->rc==SQLITE_OK ){
- iRet = ((i64)ptr[10] << 32) + ptr[11];
+ iRet = (i64)(((u64)ptr[10] << 32) + ptr[11]);
}
}
return iRet;
@@ -212654,6 +222811,11 @@ static void rbuCheckpointFrame(wx_sqlite3rbu *p, RbuFrame *pFrame){
p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
}
+/*
+** This value is copied from the definition of ZIPVFS_CTRL_FILE_POINTER
+** in zipvfs.h.
+*/
+#define RBU_ZIPVFS_CTRL_FILE_POINTER 230439
/*
** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if
@@ -212662,9 +222824,20 @@ static void rbuCheckpointFrame(wx_sqlite3rbu *p, RbuFrame *pFrame){
static int rbuLockDatabase(wx_sqlite3 *db){
int rc = SQLITE_OK;
wx_sqlite3_file *fd = 0;
- wx_sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
- if( fd->pMethods ){
+ wx_sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd);
+ if( fd ){
+ wx_sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
+ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
+ if( rc==SQLITE_OK ){
+ rc = fd->pMethods->xUnlock(fd, SQLITE_LOCK_NONE);
+ }
+ wx_sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd);
+ }else{
+ wx_sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
+ }
+
+ if( rc==SQLITE_OK && fd->pMethods ){
rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
if( rc==SQLITE_OK ){
rc = fd->pMethods->xLock(fd, SQLITE_LOCK_EXCLUSIVE);
@@ -213043,7 +223216,7 @@ static void rbuSaveState(wx_sqlite3rbu *p, int eStage){
"(%d, %Q), "
"(%d, %Q), "
"(%d, %d), "
- "(%d, %d), "
+ "(%d, %lld), "
"(%d, %lld), "
"(%d, %lld), "
"(%d, %lld), "
@@ -213401,6 +223574,7 @@ static void rbuIndexCntFunc(
wx_sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
assert( nVal==1 );
+ UNUSED_PARAMETER(nVal);
rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
wx_sqlite3_mprintf("SELECT count(*) FROM sqlite_schema "
@@ -213676,7 +223850,7 @@ SQLITE_API wx_sqlite3rbu *wx_sqlite3rbu_vacuum(
){
if( zTarget==0 ){ return rbuMisuseError(); }
if( zState ){
- int n = strlen(zState);
+ size_t n = strlen(zState);
if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){
return rbuMisuseError();
}
@@ -213893,6 +224067,7 @@ SQLITE_API int wx_sqlite3rbu_savestate(wx_sqlite3rbu *p){
*/
static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
int rc = SQLITE_OK;
+ UNUSED_PARAMETER(pArg);
#if defined(_WIN32_WCE)
{
LPWSTR zWideOld;
@@ -214797,6 +224972,9 @@ static int rbuVfsCurrentTime(wx_sqlite3_vfs *pVfs, double *pTimeOut){
** No-op.
*/
static int rbuVfsGetLastError(wx_sqlite3_vfs *pVfs, int a, char *b){
+ UNUSED_PARAMETER(pVfs);
+ UNUSED_PARAMETER(a);
+ UNUSED_PARAMETER(b);
return 0;
}
@@ -215195,6 +225373,7 @@ static int statBestIndex(wx_sqlite3_vtab *tab, wx_sqlite3_index_info *pIdxInfo){
pIdxInfo->orderByConsumed = 1;
pIdxInfo->idxNum |= 0x08;
}
+ pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_HEX;
return SQLITE_OK;
}
@@ -215811,7 +225990,8 @@ SQLITE_PRIVATE int wx_sqlite3DbstatRegister(wx_sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
return wx_sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
}
@@ -215851,7 +226031,13 @@ SQLITE_PRIVATE int wx_sqlite3DbstatRegister(wx_sqlite3 *db){ return SQLITE_OK; }
**
** The data field of sqlite_dbpage table can be updated. The new
** value must be a BLOB which is the correct page size, otherwise the
-** update fails. Rows may not be deleted or inserted.
+** update fails. INSERT operations also work, and operate as if they
+** where REPLACE. The size of the database can be extended by INSERT-ing
+** new pages on the end.
+**
+** Rows may not be deleted. However, doing an INSERT to page number N
+** with NULL page data causes the N-th page and all subsequent pages to be
+** deleted and the database to be truncated.
*/
/* #include "sqliteInt.h" ** Requires access to internal data structures ** */
@@ -215874,6 +226060,8 @@ struct DbpageCursor {
struct DbpageTable {
wx_sqlite3_vtab base; /* Base class. Must be first */
wx_sqlite3 *db; /* The database */
+ int iDbTrunc; /* Database to truncate */
+ Pgno pgnoTrunc; /* Size to truncate to */
};
/* Columns */
@@ -215882,7 +226070,6 @@ struct DbpageTable {
#define DBPAGE_COLUMN_SCHEMA 2
-
/*
** Connect to or create a dbpagevfs virtual table.
*/
@@ -215901,6 +226088,7 @@ static int dbpageConnect(
(void)pzErr;
wx_sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
+ wx_sqlite3_vtab_config(db, SQLITE_VTAB_USES_ALL_SCHEMAS);
rc = wx_sqlite3_declare_vtab(db,
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
if( rc==SQLITE_OK ){
@@ -215984,7 +226172,6 @@ static int dbpageBestIndex(wx_sqlite3_vtab *tab, wx_sqlite3_index_info *pIdxInfo
){
pIdxInfo->orderByConsumed = 1;
}
- wx_sqlite3VtabUsesAllSchemas(pIdxInfo);
return SQLITE_OK;
}
@@ -216144,11 +226331,11 @@ static int dbpageUpdate(
DbPage *pDbPage = 0;
int rc = SQLITE_OK;
char *zErr = 0;
- const char *zSchema;
int iDb;
Btree *pBt;
Pager *pPager;
int szPage;
+ int isInsert;
(void)pRowid;
if( pTab->db->flags & SQLITE_Defensive ){
@@ -216159,21 +226346,29 @@ static int dbpageUpdate(
zErr = "cannot delete";
goto update_fail;
}
- pgno = wx_sqlite3_value_int(argv[0]);
- if( wx_sqlite3_value_type(argv[0])==SQLITE_NULL
- || (Pgno)wx_sqlite3_value_int(argv[1])!=pgno
- ){
- zErr = "cannot insert";
- goto update_fail;
+ if( wx_sqlite3_value_type(argv[0])==SQLITE_NULL ){
+ pgno = (Pgno)wx_sqlite3_value_int(argv[2]);
+ isInsert = 1;
+ }else{
+ pgno = wx_sqlite3_value_int(argv[0]);
+ if( (Pgno)wx_sqlite3_value_int(argv[1])!=pgno ){
+ zErr = "cannot insert";
+ goto update_fail;
+ }
+ isInsert = 0;
}
- zSchema = (const char*)wx_sqlite3_value_text(argv[4]);
- iDb = ALWAYS(zSchema) ? wx_sqlite3FindDbName(pTab->db, zSchema) : -1;
- if( NEVER(iDb<0) ){
- zErr = "no such schema";
- goto update_fail;
+ if( wx_sqlite3_value_type(argv[4])==SQLITE_NULL ){
+ iDb = 0;
+ }else{
+ const char *zSchema = (const char*)wx_sqlite3_value_text(argv[4]);
+ iDb = wx_sqlite3FindDbName(pTab->db, zSchema);
+ if( iDb<0 ){
+ zErr = "no such schema";
+ goto update_fail;
+ }
}
pBt = pTab->db->aDb[iDb].pBt;
- if( NEVER(pgno<1) || NEVER(pBt==0) || NEVER(pgno>wx_sqlite3BtreeLastPage(pBt)) ){
+ if( pgno<1 || NEVER(pBt==0) ){
zErr = "bad page number";
goto update_fail;
}
@@ -216181,18 +226376,25 @@ static int dbpageUpdate(
if( wx_sqlite3_value_type(argv[3])!=SQLITE_BLOB
|| wx_sqlite3_value_bytes(argv[3])!=szPage
){
- zErr = "bad page value";
- goto update_fail;
+ if( wx_sqlite3_value_type(argv[3])==SQLITE_NULL && isInsert && pgno>1 ){
+ /* "INSERT INTO dbpage($PGNO,NULL)" causes page number $PGNO and
+ ** all subsequent pages to be deleted. */
+ pTab->iDbTrunc = iDb;
+ pgno--;
+ pTab->pgnoTrunc = pgno;
+ }else{
+ zErr = "bad page value";
+ goto update_fail;
+ }
}
pPager = wx_sqlite3BtreePager(pBt);
rc = wx_sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
if( rc==SQLITE_OK ){
const void *pData = wx_sqlite3_value_blob(argv[3]);
- assert( pData!=0 || pTab->db->mallocFailed );
- if( pData
- && (rc = wx_sqlite3PagerWrite(pDbPage))==SQLITE_OK
- ){
- memcpy(wx_sqlite3PagerGetData(pDbPage), pData, szPage);
+ if( (rc = wx_sqlite3PagerWrite(pDbPage))==SQLITE_OK && pData ){
+ unsigned char *aPage = wx_sqlite3PagerGetData(pDbPage);
+ memcpy(aPage, pData, szPage);
+ pTab->pgnoTrunc = 0;
}
}
wx_sqlite3PagerUnref(pDbPage);
@@ -216216,9 +226418,31 @@ static int dbpageBegin(wx_sqlite3_vtab *pVtab){
Btree *pBt = db->aDb[i].pBt;
if( pBt ) (void)wx_sqlite3BtreeBeginTrans(pBt, 1, 0);
}
+ pTab->pgnoTrunc = 0;
+ return SQLITE_OK;
+}
+
+/* Invoke wx_sqlite3PagerTruncate() as necessary, just prior to COMMIT
+*/
+static int dbpageSync(wx_sqlite3_vtab *pVtab){
+ DbpageTable *pTab = (DbpageTable *)pVtab;
+ if( pTab->pgnoTrunc>0 ){
+ Btree *pBt = pTab->db->aDb[pTab->iDbTrunc].pBt;
+ Pager *pPager = wx_sqlite3BtreePager(pBt);
+ wx_sqlite3PagerTruncateImage(pPager, pTab->pgnoTrunc);
+ }
+ pTab->pgnoTrunc = 0;
return SQLITE_OK;
}
+/* Cancel any pending truncate.
+*/
+static int dbpageRollbackTo(wx_sqlite3_vtab *pVtab, int notUsed1){
+ DbpageTable *pTab = (DbpageTable *)pVtab;
+ pTab->pgnoTrunc = 0;
+ (void)notUsed1;
+ return SQLITE_OK;
+}
/*
** Invoke this routine to register the "dbpage" virtual table module
@@ -216240,15 +226464,16 @@ SQLITE_PRIVATE int wx_sqlite3DbpageRegister(wx_sqlite3 *db){
dbpageRowid, /* xRowid - read data */
dbpageUpdate, /* xUpdate */
dbpageBegin, /* xBegin */
- 0, /* xSync */
+ dbpageSync, /* xSync */
0, /* xCommit */
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
- 0, /* xRollbackTo */
- 0 /* xShadowName */
+ dbpageRollbackTo, /* xRollbackTo */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
return wx_sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
}
@@ -216285,6 +226510,8 @@ typedef struct SessionInput SessionInput;
# endif
#endif
+#define SESSIONS_ROWID "_rowid_"
+
static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE;
typedef struct SessionHook SessionHook;
@@ -216306,6 +226533,7 @@ struct wx_sqlite3_session {
int bEnable; /* True if currently recording */
int bIndirect; /* True if all changes are indirect */
int bAutoAttach; /* True to auto-attach tables */
+ int bImplicitPK; /* True to handle tables with implicit PK */
int rc; /* Non-zero if an error has occurred */
void *pFilterCtx; /* First argument to pass to xTableFilter */
int (*xTableFilter)(void *pCtx, const char *zTab);
@@ -216331,6 +226559,10 @@ struct SessionBuffer {
** input data. Input data may be supplied either as a single large buffer
** (e.g. wx_sqlite3changeset_start()) or using a stream function (e.g.
** wx_sqlite3changeset_start_strm()).
+**
+** bNoDiscard:
+** If true, then the only time data is discarded is as a result of explicit
+** sessionDiscardData() calls. Not within every sessionInputBuffer() call.
*/
struct SessionInput {
int bNoDiscard; /* If true, do not discard in InputBuffer() */
@@ -216376,17 +226608,32 @@ struct wx_sqlite3_changeset_iter {
** The data associated with each hash-table entry is a structure containing
** a subset of the initial values that the modified row contained at the
** start of the session. Or no initial values if the row was inserted.
+**
+** pDfltStmt:
+** This is only used by the wx_sqlite3changegroup_xxx() APIs, not by
+** regular wx_sqlite3_session objects. It is a SELECT statement that
+** selects the default value for each table column. For example,
+** if the table is
+**
+** CREATE TABLE xx(a DEFAULT 1, b, c DEFAULT 'abc')
+**
+** then this variable is the compiled version of:
+**
+** SELECT 1, NULL, 'abc'
*/
struct SessionTable {
SessionTable *pNext;
char *zName; /* Local name of table */
int nCol; /* Number of columns in table zName */
int bStat1; /* True if this is sqlite_stat1 */
+ int bRowid; /* True if this table uses rowid for PK */
const char **azCol; /* Column names */
+ const char **azDflt; /* Default value expressions */
u8 *abPK; /* Array of primary key flags */
int nEntry; /* Total number of entries in hash table */
int nChange; /* Size of apChange[] array */
SessionChange **apChange; /* Hash table buckets */
+ wx_sqlite3_stmt *pDfltStmt;
};
/*
@@ -216555,6 +226802,7 @@ struct SessionTable {
struct SessionChange {
u8 op; /* One of UPDATE, DELETE, INSERT */
u8 bIndirect; /* True if this change is "indirect" */
+ u16 nRecordField; /* Number of fields in aRecord[] */
int nMaxSize; /* Max size of eventual changeset record */
int nRecord; /* Number of bytes in buffer aRecord[] */
u8 *aRecord; /* Buffer containing old.* record */
@@ -216580,7 +226828,7 @@ static int sessionVarintLen(int iVal){
** Read a varint value from aBuf[] into *piVal. Return the number of
** bytes read.
*/
-static int sessionVarintGet(u8 *aBuf, int *piVal){
+static int sessionVarintGet(const u8 *aBuf, int *piVal){
return getVarint32(aBuf, *piVal);
}
@@ -216774,6 +227022,7 @@ static unsigned int sessionHashAppendType(unsigned int h, int eType){
*/
static int sessionPreupdateHash(
wx_sqlite3_session *pSession, /* Session object that owns pTab */
+ i64 iRowid,
SessionTable *pTab, /* Session table handle */
int bNew, /* True to hash the new.* PK */
int *piHash, /* OUT: Hash value */
@@ -216782,48 +227031,53 @@ static int sessionPreupdateHash(
unsigned int h = 0; /* Hash value to return */
int i; /* Used to iterate through columns */
- assert( *pbNullPK==0 );
- assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
- for(i=0; i<pTab->nCol; i++){
- if( pTab->abPK[i] ){
- int rc;
- int eType;
- wx_sqlite3_value *pVal;
-
- if( bNew ){
- rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
- }else{
- rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
- }
- if( rc!=SQLITE_OK ) return rc;
+ if( pTab->bRowid ){
+ assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) );
+ h = sessionHashAppendI64(h, iRowid);
+ }else{
+ assert( *pbNullPK==0 );
+ assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
+ for(i=0; i<pTab->nCol; i++){
+ if( pTab->abPK[i] ){
+ int rc;
+ int eType;
+ wx_sqlite3_value *pVal;
- eType = wx_sqlite3_value_type(pVal);
- h = sessionHashAppendType(h, eType);
- if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- i64 iVal;
- if( eType==SQLITE_INTEGER ){
- iVal = wx_sqlite3_value_int64(pVal);
+ if( bNew ){
+ rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
}else{
- double rVal = wx_sqlite3_value_double(pVal);
- assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
- memcpy(&iVal, &rVal, 8);
+ rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
}
- h = sessionHashAppendI64(h, iVal);
- }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
- const u8 *z;
- int n;
- if( eType==SQLITE_TEXT ){
- z = (const u8 *)wx_sqlite3_value_text(pVal);
+ if( rc!=SQLITE_OK ) return rc;
+
+ eType = wx_sqlite3_value_type(pVal);
+ h = sessionHashAppendType(h, eType);
+ if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ i64 iVal;
+ if( eType==SQLITE_INTEGER ){
+ iVal = wx_sqlite3_value_int64(pVal);
+ }else{
+ double rVal = wx_sqlite3_value_double(pVal);
+ assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
+ memcpy(&iVal, &rVal, 8);
+ }
+ h = sessionHashAppendI64(h, iVal);
+ }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+ const u8 *z;
+ int n;
+ if( eType==SQLITE_TEXT ){
+ z = (const u8 *)wx_sqlite3_value_text(pVal);
+ }else{
+ z = (const u8 *)wx_sqlite3_value_blob(pVal);
+ }
+ n = wx_sqlite3_value_bytes(pVal);
+ if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
+ h = sessionHashAppendBlob(h, n, z);
}else{
- z = (const u8 *)wx_sqlite3_value_blob(pVal);
+ assert( eType==SQLITE_NULL );
+ assert( pTab->bStat1==0 || i!=1 );
+ *pbNullPK = 1;
}
- n = wx_sqlite3_value_bytes(pVal);
- if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
- h = sessionHashAppendBlob(h, n, z);
- }else{
- assert( eType==SQLITE_NULL );
- assert( pTab->bStat1==0 || i!=1 );
- *pbNullPK = 1;
}
}
}
@@ -216837,9 +227091,11 @@ static int sessionPreupdateHash(
** Return the number of bytes of space occupied by the value (including
** the type byte).
*/
-static int sessionSerialLen(u8 *a){
- int e = *a;
+static int sessionSerialLen(const u8 *a){
+ int e;
int n;
+ assert( a!=0 );
+ e = *a;
if( e==0 || e==0xFF ) return 1;
if( e==SQLITE_NULL ) return 1;
if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
@@ -217106,6 +227362,7 @@ static int sessionMergeUpdate(
*/
static int sessionPreupdateEqual(
wx_sqlite3_session *pSession, /* Session object that owns SessionTable */
+ i64 iRowid, /* Rowid value if pTab->bRowid */
SessionTable *pTab, /* Table associated with change */
SessionChange *pChange, /* Change to compare to */
int op /* Current pre-update operation */
@@ -217113,6 +227370,11 @@ static int sessionPreupdateEqual(
int iCol; /* Used to iterate through columns */
u8 *a = pChange->aRecord; /* Cursor used to scan change record */
+ if( pTab->bRowid ){
+ if( a[0]!=SQLITE_INTEGER ) return 0;
+ return sessionGetI64(&a[1])==iRowid;
+ }
+
assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
for(iCol=0; iCol<pTab->nCol; iCol++){
if( !pTab->abPK[iCol] ){
@@ -217135,6 +227397,7 @@ static int sessionPreupdateEqual(
rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
}
assert( rc==SQLITE_OK );
+ (void)rc; /* Suppress warning about unused variable */
if( wx_sqlite3_value_type(pVal)!=eType ) return 0;
/* A SessionChange object never has a NULL value in a PK column */
@@ -217237,13 +227500,14 @@ static int sessionGrowHash(
**
** For example, if the table is declared as:
**
-** CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
+** CREATE TABLE tbl1(w, x DEFAULT 'abc', y, z, PRIMARY KEY(w, z));
**
-** Then the four output variables are populated as follows:
+** Then the five output variables are populated as follows:
**
** *pnCol = 4
** *pzTab = "tbl1"
** *pazCol = {"w", "x", "y", "z"}
+** *pazDflt = {NULL, 'abc', NULL, NULL}
** *pabPK = {1, 0, 0, 1}
**
** All returned buffers are part of the same single allocation, which must
@@ -217257,7 +227521,9 @@ static int sessionTableInfo(
int *pnCol, /* OUT: number of columns */
const char **pzTab, /* OUT: Copy of zThis */
const char ***pazCol, /* OUT: Array of column names for table */
- u8 **pabPK /* OUT: Array of booleans - true for PK col */
+ const char ***pazDflt, /* OUT: Array of default value expressions */
+ u8 **pabPK, /* OUT: Array of booleans - true for PK col */
+ int *pbRowid /* OUT: True if only PK is a rowid */
){
char *zPragma;
wx_sqlite3_stmt *pStmt;
@@ -217268,10 +227534,18 @@ static int sessionTableInfo(
int i;
u8 *pAlloc = 0;
char **azCol = 0;
+ char **azDflt = 0;
u8 *abPK = 0;
+ int bRowid = 0; /* Set to true to use rowid as PK */
assert( pazCol && pabPK );
+ *pazCol = 0;
+ *pabPK = 0;
+ *pnCol = 0;
+ if( pzTab ) *pzTab = 0;
+ if( pazDflt ) *pazDflt = 0;
+
nThis = wx_sqlite3Strlen30(zThis);
if( nThis==12 && 0==wx_sqlite3_stricmp("sqlite_stat1", zThis) ){
rc = wx_sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
@@ -217285,50 +227559,47 @@ static int sessionTableInfo(
}else if( rc==SQLITE_ERROR ){
zPragma = wx_sqlite3_mprintf("");
}else{
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return rc;
}
}else{
zPragma = wx_sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
}
if( !zPragma ){
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return SQLITE_NOMEM;
}
rc = wx_sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
wx_sqlite3_free(zPragma);
if( rc!=SQLITE_OK ){
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return rc;
}
nByte = nThis + 1;
+ bRowid = (pbRowid!=0);
while( SQLITE_ROW==wx_sqlite3_step(pStmt) ){
- nByte += wx_sqlite3_column_bytes(pStmt, 1);
+ nByte += wx_sqlite3_column_bytes(pStmt, 1); /* name */
+ nByte += wx_sqlite3_column_bytes(pStmt, 4); /* dflt_value */
nDbCol++;
+ if( wx_sqlite3_column_int(pStmt, 5) ) bRowid = 0; /* pk */
}
+ if( nDbCol==0 ) bRowid = 0;
+ nDbCol += bRowid;
+ nByte += strlen(SESSIONS_ROWID);
rc = wx_sqlite3_reset(pStmt);
if( rc==SQLITE_OK ){
- nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
+ nByte += nDbCol * (sizeof(const char *)*2 + sizeof(u8) + 1 + 1);
pAlloc = sessionMalloc64(pSession, nByte);
if( pAlloc==0 ){
rc = SQLITE_NOMEM;
+ }else{
+ memset(pAlloc, 0, nByte);
}
}
if( rc==SQLITE_OK ){
azCol = (char **)pAlloc;
- pAlloc = (u8 *)&azCol[nDbCol];
+ azDflt = (char**)&azCol[nDbCol];
+ pAlloc = (u8 *)&azDflt[nDbCol];
abPK = (u8 *)pAlloc;
pAlloc = &abPK[nDbCol];
if( pzTab ){
@@ -217338,43 +227609,57 @@ static int sessionTableInfo(
}
i = 0;
+ if( bRowid ){
+ size_t nName = strlen(SESSIONS_ROWID);
+ memcpy(pAlloc, SESSIONS_ROWID, nName+1);
+ azCol[i] = (char*)pAlloc;
+ pAlloc += nName+1;
+ abPK[i] = 1;
+ i++;
+ }
while( SQLITE_ROW==wx_sqlite3_step(pStmt) ){
int nName = wx_sqlite3_column_bytes(pStmt, 1);
+ int nDflt = wx_sqlite3_column_bytes(pStmt, 4);
const unsigned char *zName = wx_sqlite3_column_text(pStmt, 1);
+ const unsigned char *zDflt = wx_sqlite3_column_text(pStmt, 4);
+
if( zName==0 ) break;
memcpy(pAlloc, zName, nName+1);
azCol[i] = (char *)pAlloc;
pAlloc += nName+1;
+ if( zDflt ){
+ memcpy(pAlloc, zDflt, nDflt+1);
+ azDflt[i] = (char *)pAlloc;
+ pAlloc += nDflt+1;
+ }else{
+ azDflt[i] = 0;
+ }
abPK[i] = wx_sqlite3_column_int(pStmt, 5);
i++;
}
rc = wx_sqlite3_reset(pStmt);
-
}
/* If successful, populate the output variables. Otherwise, zero them and
** free any allocation made. An error code will be returned in this case.
*/
if( rc==SQLITE_OK ){
- *pazCol = (const char **)azCol;
+ *pazCol = (const char**)azCol;
+ if( pazDflt ) *pazDflt = (const char**)azDflt;
*pabPK = abPK;
*pnCol = nDbCol;
}else{
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
sessionFree(pSession, azCol);
}
+ if( pbRowid ) *pbRowid = bRowid;
wx_sqlite3_finalize(pStmt);
return rc;
}
/*
-** This function is only called from within a pre-update handler for a
-** write to table pTab, part of session pSession. If this is the first
-** write to this table, initalize the SessionTable.nCol, azCol[] and
-** abPK[] arrays accordingly.
+** This function is called to initialize the SessionTable.nCol, azCol[]
+** abPK[] and azDflt[] members of SessionTable object pTab. If these
+** fields are already initilialized, this function is a no-op.
**
** If an error occurs, an error code is stored in wx_sqlite3_session.rc and
** non-zero returned. Or, if no error occurs but the table has no primary
@@ -217382,14 +227667,22 @@ static int sessionTableInfo(
** indicate that updates on this table should be ignored. SessionTable.abPK
** is set to NULL in this case.
*/
-static int sessionInitTable(wx_sqlite3_session *pSession, SessionTable *pTab){
+static int sessionInitTable(
+ wx_sqlite3_session *pSession, /* Optional session handle */
+ SessionTable *pTab, /* Table object to initialize */
+ wx_sqlite3 *db, /* Database handle to read schema from */
+ const char *zDb /* Name of db - "main", "temp" etc. */
+){
+ int rc = SQLITE_OK;
+
if( pTab->nCol==0 ){
u8 *abPK;
assert( pTab->azCol==0 || pTab->abPK==0 );
- pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
- pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
+ rc = sessionTableInfo(pSession, db, zDb,
+ pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->azDflt, &abPK,
+ ((pSession==0 || pSession->bImplicitPK) ? &pTab->bRowid : 0)
);
- if( pSession->rc==SQLITE_OK ){
+ if( rc==SQLITE_OK ){
int i;
for(i=0; i<pTab->nCol; i++){
if( abPK[i] ){
@@ -217401,14 +227694,321 @@ static int sessionInitTable(wx_sqlite3_session *pSession, SessionTable *pTab){
pTab->bStat1 = 1;
}
- if( pSession->bEnableSize ){
+ if( pSession && pSession->bEnableSize ){
pSession->nMaxChangesetSize += (
1 + sessionVarintLen(pTab->nCol) + pTab->nCol + strlen(pTab->zName)+1
);
}
}
}
- return (pSession->rc || pTab->abPK==0);
+
+ if( pSession ){
+ pSession->rc = rc;
+ return (rc || pTab->abPK==0);
+ }
+ return rc;
+}
+
+/*
+** Re-initialize table object pTab.
+*/
+static int sessionReinitTable(wx_sqlite3_session *pSession, SessionTable *pTab){
+ int nCol = 0;
+ const char **azCol = 0;
+ const char **azDflt = 0;
+ u8 *abPK = 0;
+ int bRowid = 0;
+
+ assert( pSession->rc==SQLITE_OK );
+
+ pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
+ pTab->zName, &nCol, 0, &azCol, &azDflt, &abPK,
+ (pSession->bImplicitPK ? &bRowid : 0)
+ );
+ if( pSession->rc==SQLITE_OK ){
+ if( pTab->nCol>nCol || pTab->bRowid!=bRowid ){
+ pSession->rc = SQLITE_SCHEMA;
+ }else{
+ int ii;
+ int nOldCol = pTab->nCol;
+ for(ii=0; ii<nCol; ii++){
+ if( ii<pTab->nCol ){
+ if( pTab->abPK[ii]!=abPK[ii] ){
+ pSession->rc = SQLITE_SCHEMA;
+ }
+ }else if( abPK[ii] ){
+ pSession->rc = SQLITE_SCHEMA;
+ }
+ }
+
+ if( pSession->rc==SQLITE_OK ){
+ const char **a = pTab->azCol;
+ pTab->azCol = azCol;
+ pTab->nCol = nCol;
+ pTab->azDflt = azDflt;
+ pTab->abPK = abPK;
+ azCol = a;
+ }
+ if( pSession->bEnableSize ){
+ pSession->nMaxChangesetSize += (nCol - nOldCol);
+ pSession->nMaxChangesetSize += sessionVarintLen(nCol);
+ pSession->nMaxChangesetSize -= sessionVarintLen(nOldCol);
+ }
+ }
+ }
+
+ wx_sqlite3_free((char*)azCol);
+ return pSession->rc;
+}
+
+/*
+** Session-change object (*pp) contains an old.* record with fewer than
+** nCol fields. This function updates it with the default values for
+** the missing fields.
+*/
+static void sessionUpdateOneChange(
+ wx_sqlite3_session *pSession, /* For memory accounting */
+ int *pRc, /* IN/OUT: Error code */
+ SessionChange **pp, /* IN/OUT: Change object to update */
+ int nCol, /* Number of columns now in table */
+ wx_sqlite3_stmt *pDflt /* SELECT <default-values...> */
+){
+ SessionChange *pOld = *pp;
+
+ while( pOld->nRecordField<nCol ){
+ SessionChange *pNew = 0;
+ int nByte = 0;
+ int nIncr = 0;
+ int iField = pOld->nRecordField;
+ int eType = wx_sqlite3_column_type(pDflt, iField);
+ switch( eType ){
+ case SQLITE_NULL:
+ nIncr = 1;
+ break;
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT:
+ nIncr = 9;
+ break;
+ default: {
+ int n = wx_sqlite3_column_bytes(pDflt, iField);
+ nIncr = 1 + sessionVarintLen(n) + n;
+ assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
+ break;
+ }
+ }
+
+ nByte = nIncr + (sizeof(SessionChange) + pOld->nRecord);
+ pNew = sessionMalloc64(pSession, nByte);
+ if( pNew==0 ){
+ *pRc = SQLITE_NOMEM;
+ return;
+ }else{
+ memcpy(pNew, pOld, sizeof(SessionChange));
+ pNew->aRecord = (u8*)&pNew[1];
+ memcpy(pNew->aRecord, pOld->aRecord, pOld->nRecord);
+ pNew->aRecord[pNew->nRecord++] = (u8)eType;
+ switch( eType ){
+ case SQLITE_INTEGER: {
+ i64 iVal = wx_sqlite3_column_int64(pDflt, iField);
+ sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal);
+ pNew->nRecord += 8;
+ break;
+ }
+
+ case SQLITE_FLOAT: {
+ double rVal = wx_sqlite3_column_double(pDflt, iField);
+ i64 iVal = 0;
+ memcpy(&iVal, &rVal, sizeof(rVal));
+ sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal);
+ pNew->nRecord += 8;
+ break;
+ }
+
+ case SQLITE_TEXT: {
+ int n = wx_sqlite3_column_bytes(pDflt, iField);
+ const char *z = (const char*)wx_sqlite3_column_text(pDflt, iField);
+ pNew->nRecord += sessionVarintPut(&pNew->aRecord[pNew->nRecord], n);
+ memcpy(&pNew->aRecord[pNew->nRecord], z, n);
+ pNew->nRecord += n;
+ break;
+ }
+
+ case SQLITE_BLOB: {
+ int n = wx_sqlite3_column_bytes(pDflt, iField);
+ const u8 *z = (const u8*)wx_sqlite3_column_blob(pDflt, iField);
+ pNew->nRecord += sessionVarintPut(&pNew->aRecord[pNew->nRecord], n);
+ memcpy(&pNew->aRecord[pNew->nRecord], z, n);
+ pNew->nRecord += n;
+ break;
+ }
+
+ default:
+ assert( eType==SQLITE_NULL );
+ break;
+ }
+
+ sessionFree(pSession, pOld);
+ *pp = pOld = pNew;
+ pNew->nRecordField++;
+ pNew->nMaxSize += nIncr;
+ if( pSession ){
+ pSession->nMaxChangesetSize += nIncr;
+ }
+ }
+ }
+}
+
+/*
+** Ensure that there is room in the buffer to append nByte bytes of data.
+** If not, use wx_sqlite3_realloc() to grow the buffer so that there is.
+**
+** If successful, return zero. Otherwise, if an OOM condition is encountered,
+** set *pRc to SQLITE_NOMEM and return non-zero.
+*/
+static int sessionBufferGrow(SessionBuffer *p, i64 nByte, int *pRc){
+#define SESSION_MAX_BUFFER_SZ (0x7FFFFF00 - 1)
+ i64 nReq = p->nBuf + nByte;
+ if( *pRc==SQLITE_OK && nReq>p->nAlloc ){
+ u8 *aNew;
+ i64 nNew = p->nAlloc ? p->nAlloc : 128;
+
+ do {
+ nNew = nNew*2;
+ }while( nNew<nReq );
+
+ /* The value of SESSION_MAX_BUFFER_SZ is copied from the implementation
+ ** of wx_sqlite3_realloc64(). Allocations greater than this size in bytes
+ ** always fail. It is used here to ensure that this routine can always
+ ** allocate up to this limit - instead of up to the largest power of
+ ** two smaller than the limit. */
+ if( nNew>SESSION_MAX_BUFFER_SZ ){
+ nNew = SESSION_MAX_BUFFER_SZ;
+ if( nNew<nReq ){
+ *pRc = SQLITE_NOMEM;
+ return 1;
+ }
+ }
+
+ aNew = (u8 *)wx_sqlite3_realloc64(p->aBuf, nNew);
+ if( 0==aNew ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ p->aBuf = aNew;
+ p->nAlloc = nNew;
+ }
+ }
+ return (*pRc!=SQLITE_OK);
+}
+
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append a string to the buffer. All bytes in the string
+** up to (but not including) the nul-terminator are written to the buffer.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
+*/
+static void sessionAppendStr(
+ SessionBuffer *p,
+ const char *zStr,
+ int *pRc
+){
+ int nStr = wx_sqlite3Strlen30(zStr);
+ if( 0==sessionBufferGrow(p, nStr+1, pRc) ){
+ memcpy(&p->aBuf[p->nBuf], zStr, nStr);
+ p->nBuf += nStr;
+ p->aBuf[p->nBuf] = 0x00;
+ }
+}
+
+/*
+** Format a string using printf() style formatting and then append it to the
+** buffer using sessionAppendString().
+*/
+static void sessionAppendPrintf(
+ SessionBuffer *p, /* Buffer to append to */
+ int *pRc,
+ const char *zFmt,
+ ...
+){
+ if( *pRc==SQLITE_OK ){
+ char *zApp = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zApp = wx_sqlite3_vmprintf(zFmt, ap);
+ if( zApp==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ sessionAppendStr(p, zApp, pRc);
+ }
+ va_end(ap);
+ wx_sqlite3_free(zApp);
+ }
+}
+
+/*
+** Prepare a statement against database handle db that SELECTs a single
+** row containing the default values for each column in table pTab. For
+** example, if pTab is declared as:
+**
+** CREATE TABLE pTab(a PRIMARY KEY, b DEFAULT 123, c DEFAULT 'abcd');
+**
+** Then this function prepares and returns the SQL statement:
+**
+** SELECT NULL, 123, 'abcd';
+*/
+static int sessionPrepareDfltStmt(
+ wx_sqlite3 *db, /* Database handle */
+ SessionTable *pTab, /* Table to prepare statement for */
+ wx_sqlite3_stmt **ppStmt /* OUT: Statement handle */
+){
+ SessionBuffer sql = {0,0,0};
+ int rc = SQLITE_OK;
+ const char *zSep = " ";
+ int ii = 0;
+
+ *ppStmt = 0;
+ sessionAppendPrintf(&sql, &rc, "SELECT");
+ for(ii=0; ii<pTab->nCol; ii++){
+ const char *zDflt = pTab->azDflt[ii] ? pTab->azDflt[ii] : "NULL";
+ sessionAppendPrintf(&sql, &rc, "%s%s", zSep, zDflt);
+ zSep = ", ";
+ }
+ if( rc==SQLITE_OK ){
+ rc = wx_sqlite3_prepare_v2(db, (const char*)sql.aBuf, -1, ppStmt, 0);
+ }
+ wx_sqlite3_free(sql.aBuf);
+
+ return rc;
+}
+
+/*
+** Table pTab has one or more existing change-records with old.* records
+** with fewer than pTab->nCol columns. This function updates all such
+** change-records with the default values for the missing columns.
+*/
+static int sessionUpdateChanges(wx_sqlite3_session *pSession, SessionTable *pTab){
+ wx_sqlite3_stmt *pStmt = 0;
+ int rc = pSession->rc;
+
+ rc = sessionPrepareDfltStmt(pSession->db, pTab, &pStmt);
+ if( rc==SQLITE_OK && SQLITE_ROW==wx_sqlite3_step(pStmt) ){
+ int ii = 0;
+ SessionChange **pp = 0;
+ for(ii=0; ii<pTab->nChange; ii++){
+ for(pp=&pTab->apChange[ii]; *pp; pp=&((*pp)->pNext)){
+ if( (*pp)->nRecordField!=pTab->nCol ){
+ sessionUpdateOneChange(pSession, &rc, pp, pTab->nCol, pStmt);
+ }
+ }
+ }
+ }
+
+ pSession->rc = rc;
+ rc = wx_sqlite3_finalize(pStmt);
+ if( pSession->rc==SQLITE_OK ) pSession->rc = rc;
+ return pSession->rc;
}
/*
@@ -217459,6 +228059,7 @@ static int sessionUpdateMaxSize(
){
i64 nNew = 2;
if( pC->op==SQLITE_INSERT ){
+ if( pTab->bRowid ) nNew += 9;
if( op!=SQLITE_DELETE ){
int ii;
for(ii=0; ii<pTab->nCol; ii++){
@@ -217475,12 +228076,16 @@ static int sessionUpdateMaxSize(
}else{
int ii;
u8 *pCsr = pC->aRecord;
- for(ii=0; ii<pTab->nCol; ii++){
+ if( pTab->bRowid ){
+ nNew += 9 + 1;
+ pCsr += 9;
+ }
+ for(ii=pTab->bRowid; ii<pTab->nCol; ii++){
int bChanged = 1;
int nOld = 0;
int eType;
wx_sqlite3_value *p = 0;
- pSession->hook.xNew(pSession->hook.pCtx, ii, &p);
+ pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p);
if( p==0 ){
return SQLITE_NOMEM;
}
@@ -217559,22 +228164,29 @@ static int sessionUpdateMaxSize(
*/
static void sessionPreupdateOneChange(
int op, /* One of SQLITE_UPDATE, INSERT, DELETE */
+ i64 iRowid,
wx_sqlite3_session *pSession, /* Session object pTab is attached to */
SessionTable *pTab /* Table that change applies to */
){
int iHash;
int bNull = 0;
int rc = SQLITE_OK;
+ int nExpect = 0;
SessionStat1Ctx stat1 = {{0,0,0,0,0},0};
if( pSession->rc ) return;
/* Load table details if required */
- if( sessionInitTable(pSession, pTab) ) return;
+ if( sessionInitTable(pSession, pTab, pSession->db, pSession->zDb) ) return;
/* Check the number of columns in this xPreUpdate call matches the
** number of columns in the table. */
- if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
+ nExpect = pSession->hook.xCount(pSession->hook.pCtx);
+ if( (pTab->nCol-pTab->bRowid)<nExpect ){
+ if( sessionReinitTable(pSession, pTab) ) return;
+ if( sessionUpdateChanges(pSession, pTab) ) return;
+ }
+ if( (pTab->nCol-pTab->bRowid)!=nExpect ){
pSession->rc = SQLITE_SCHEMA;
return;
}
@@ -217607,14 +228219,16 @@ static void sessionPreupdateOneChange(
/* Calculate the hash-key for this change. If the primary key of the row
** includes a NULL value, exit early. Such changes are ignored by the
** session module. */
- rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
+ rc = sessionPreupdateHash(
+ pSession, iRowid, pTab, op==SQLITE_INSERT, &iHash, &bNull
+ );
if( rc!=SQLITE_OK ) goto error_out;
if( bNull==0 ){
/* Search the hash table for an existing record for this row. */
SessionChange *pC;
for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
- if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break;
+ if( sessionPreupdateEqual(pSession, iRowid, pTab, pC, op) ) break;
}
if( pC==0 ){
@@ -217629,24 +228243,30 @@ static void sessionPreupdateOneChange(
/* Figure out how large an allocation is required */
nByte = sizeof(SessionChange);
- for(i=0; i<pTab->nCol; i++){
+ for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
wx_sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
- TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
- assert( trc==SQLITE_OK );
+ /* This may fail if the column has a non-NULL default and was added
+ ** using ALTER TABLE ADD COLUMN after this record was created. */
+ rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p);
}else if( pTab->abPK[i] ){
TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
assert( trc==SQLITE_OK );
}
- /* This may fail if SQLite value p contains a utf-16 string that must
- ** be converted to utf-8 and an OOM error occurs while doing so. */
- rc = sessionSerializeValue(0, p, &nByte);
+ if( rc==SQLITE_OK ){
+ /* This may fail if SQLite value p contains a utf-16 string that must
+ ** be converted to utf-8 and an OOM error occurs while doing so. */
+ rc = sessionSerializeValue(0, p, &nByte);
+ }
if( rc!=SQLITE_OK ) goto error_out;
}
+ if( pTab->bRowid ){
+ nByte += 9; /* Size of rowid field - an integer */
+ }
/* Allocate the change object */
- pC = (SessionChange *)sessionMalloc64(pSession, nByte);
+ pC = (SessionChange*)sessionMalloc64(pSession, nByte);
if( !pC ){
rc = SQLITE_NOMEM;
goto error_out;
@@ -217660,7 +228280,12 @@ static void sessionPreupdateOneChange(
** required values and encodings have already been cached in memory.
** It is not possible for an OOM to occur in this block. */
nByte = 0;
- for(i=0; i<pTab->nCol; i++){
+ if( pTab->bRowid ){
+ pC->aRecord[0] = SQLITE_INTEGER;
+ sessionPutI64(&pC->aRecord[1], iRowid);
+ nByte = 9;
+ }
+ for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
wx_sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
pSession->hook.xOld(pSession->hook.pCtx, i, &p);
@@ -217674,6 +228299,7 @@ static void sessionPreupdateOneChange(
if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){
pC->bIndirect = 1;
}
+ pC->nRecordField = pTab->nCol;
pC->nRecord = nByte;
pC->op = op;
pC->pNext = pTab->apChange[iHash];
@@ -217775,9 +228401,10 @@ static void xPreUpdate(
pSession->rc = sessionFindTable(pSession, zName, &pTab);
if( pTab ){
assert( pSession->rc==SQLITE_OK );
- sessionPreupdateOneChange(op, pSession, pTab);
+ assert( op==SQLITE_UPDATE || iKey1==iKey2 );
+ sessionPreupdateOneChange(op, iKey1, pSession, pTab);
if( op==SQLITE_UPDATE ){
- sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
+ sessionPreupdateOneChange(SQLITE_INSERT, iKey2, pSession, pTab);
}
}
}
@@ -217816,6 +228443,7 @@ static void sessionPreupdateHooks(
typedef struct SessionDiffCtx SessionDiffCtx;
struct SessionDiffCtx {
wx_sqlite3_stmt *pStmt;
+ int bRowid;
int nOldOff;
};
@@ -217824,17 +228452,17 @@ struct SessionDiffCtx {
*/
static int sessionDiffOld(void *pCtx, int iVal, wx_sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = wx_sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
+ *ppVal = wx_sqlite3_column_value(p->pStmt, iVal+p->nOldOff+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffNew(void *pCtx, int iVal, wx_sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = wx_sqlite3_column_value(p->pStmt, iVal);
+ *ppVal = wx_sqlite3_column_value(p->pStmt, iVal+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffCount(void *pCtx){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- return p->nOldOff ? p->nOldOff : wx_sqlite3_column_count(p->pStmt);
+ return (p->nOldOff ? p->nOldOff : wx_sqlite3_column_count(p->pStmt)) - p->bRowid;
}
static int sessionDiffDepth(void *pCtx){
(void)pCtx;
@@ -217913,14 +228541,16 @@ static char *sessionExprCompareOther(
static char *sessionSelectFindNew(
const char *zDb1, /* Pick rows in this db only */
const char *zDb2, /* But not in this one */
+ int bRowid,
const char *zTbl, /* Table name */
const char *zExpr
){
+ const char *zSel = (bRowid ? SESSIONS_ROWID ", *" : "*");
char *zRet = wx_sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
+ "SELECT %s FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
" SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
")",
- zDb1, zTbl, zDb2, zTbl, zExpr
+ zSel, zDb1, zTbl, zDb2, zTbl, zExpr
);
return zRet;
}
@@ -217934,7 +228564,9 @@ static int sessionDiffFindNew(
char *zExpr
){
int rc = SQLITE_OK;
- char *zStmt = sessionSelectFindNew(zDb1, zDb2, pTab->zName,zExpr);
+ char *zStmt = sessionSelectFindNew(
+ zDb1, zDb2, pTab->bRowid, pTab->zName, zExpr
+ );
if( zStmt==0 ){
rc = SQLITE_NOMEM;
@@ -217945,8 +228577,10 @@ static int sessionDiffFindNew(
SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = 0;
+ pDiffCtx->bRowid = pTab->bRowid;
while( SQLITE_ROW==wx_sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(op, pSession, pTab);
+ i64 iRowid = (pTab->bRowid ? wx_sqlite3_column_int64(pStmt, 0) : 0);
+ sessionPreupdateOneChange(op, iRowid, pSession, pTab);
}
rc = wx_sqlite3_finalize(pStmt);
}
@@ -217956,6 +228590,27 @@ static int sessionDiffFindNew(
return rc;
}
+/*
+** Return a comma-separated list of the fully-qualified (with both database
+** and table name) column names from table pTab. e.g.
+**
+** "main"."t1"."a", "main"."t1"."b", "main"."t1"."c"
+*/
+static char *sessionAllCols(
+ const char *zDb,
+ SessionTable *pTab
+){
+ int ii;
+ char *zRet = 0;
+ for(ii=0; ii<pTab->nCol; ii++){
+ zRet = wx_sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"",
+ zRet, (zRet ? ", " : ""), zDb, pTab->zName, pTab->azCol[ii]
+ );
+ if( !zRet ) break;
+ }
+ return zRet;
+}
+
static int sessionDiffFindModified(
wx_sqlite3_session *pSession,
SessionTable *pTab,
@@ -217970,11 +228625,13 @@ static int sessionDiffFindModified(
if( zExpr2==0 ){
rc = SQLITE_NOMEM;
}else{
+ char *z1 = sessionAllCols(pSession->zDb, pTab);
+ char *z2 = sessionAllCols(zFrom, pTab);
char *zStmt = wx_sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
- pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
+ "SELECT %s,%s FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
+ z1, z2, pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
);
- if( zStmt==0 ){
+ if( zStmt==0 || z1==0 || z2==0 ){
rc = SQLITE_NOMEM;
}else{
wx_sqlite3_stmt *pStmt;
@@ -217985,12 +228642,15 @@ static int sessionDiffFindModified(
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = pTab->nCol;
while( SQLITE_ROW==wx_sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
+ i64 iRowid = (pTab->bRowid ? wx_sqlite3_column_int64(pStmt, 0) : 0);
+ sessionPreupdateOneChange(SQLITE_UPDATE, iRowid, pSession, pTab);
}
rc = wx_sqlite3_finalize(pStmt);
}
- wx_sqlite3_free(zStmt);
}
+ wx_sqlite3_free(zStmt);
+ wx_sqlite3_free(z1);
+ wx_sqlite3_free(z2);
}
return rc;
@@ -218019,7 +228679,7 @@ SQLITE_API int wx_sqlite3session_diff(
/* Locate and if necessary initialize the target table object */
rc = sessionFindTable(pSession, zTbl, &pTo);
if( pTo==0 ) goto diff_out;
- if( sessionInitTable(pSession, pTo) ){
+ if( sessionInitTable(pSession, pTo, pSession->db, pSession->zDb) ){
rc = pSession->rc;
goto diff_out;
}
@@ -218029,9 +228689,12 @@ SQLITE_API int wx_sqlite3session_diff(
int bHasPk = 0;
int bMismatch = 0;
int nCol; /* Columns in zFrom.zTbl */
+ int bRowid = 0;
u8 *abPK;
const char **azCol = 0;
- rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
+ rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, 0, &abPK,
+ pSession->bImplicitPK ? &bRowid : 0
+ );
if( rc==SQLITE_OK ){
if( pTo->nCol!=nCol ){
bMismatch = 1;
@@ -218144,6 +228807,7 @@ static void sessionDeleteTable(wx_sqlite3_session *pSession, SessionTable *pList
sessionFree(pSession, p);
}
}
+ wx_sqlite3_finalize(pTab->pDfltStmt);
sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */
sessionFree(pSession, pTab->apChange);
sessionFree(pSession, pTab);
@@ -218176,9 +228840,7 @@ SQLITE_API void wx_sqlite3session_delete(wx_sqlite3_session *pSession){
** associated hash-tables. */
sessionDeleteTable(pSession, pSession->pTable);
- /* Assert that all allocations have been freed and then free the
- ** session object itself. */
- assert( pSession->nMalloc==0 );
+ /* Free the session object. */
wx_sqlite3_free(pSession);
}
@@ -218250,48 +228912,6 @@ SQLITE_API int wx_sqlite3session_attach(
}
/*
-** Ensure that there is room in the buffer to append nByte bytes of data.
-** If not, use wx_sqlite3_realloc() to grow the buffer so that there is.
-**
-** If successful, return zero. Otherwise, if an OOM condition is encountered,
-** set *pRc to SQLITE_NOMEM and return non-zero.
-*/
-static int sessionBufferGrow(SessionBuffer *p, i64 nByte, int *pRc){
-#define SESSION_MAX_BUFFER_SZ (0x7FFFFF00 - 1)
- i64 nReq = p->nBuf + nByte;
- if( *pRc==SQLITE_OK && nReq>p->nAlloc ){
- u8 *aNew;
- i64 nNew = p->nAlloc ? p->nAlloc : 128;
-
- do {
- nNew = nNew*2;
- }while( nNew<nReq );
-
- /* The value of SESSION_MAX_BUFFER_SZ is copied from the implementation
- ** of wx_sqlite3_realloc64(). Allocations greater than this size in bytes
- ** always fail. It is used here to ensure that this routine can always
- ** allocate up to this limit - instead of up to the largest power of
- ** two smaller than the limit. */
- if( nNew>SESSION_MAX_BUFFER_SZ ){
- nNew = SESSION_MAX_BUFFER_SZ;
- if( nNew<nReq ){
- *pRc = SQLITE_NOMEM;
- return 1;
- }
- }
-
- aNew = (u8 *)wx_sqlite3_realloc64(p->aBuf, nNew);
- if( 0==aNew ){
- *pRc = SQLITE_NOMEM;
- }else{
- p->aBuf = aNew;
- p->nAlloc = nNew;
- }
- }
- return (*pRc!=SQLITE_OK);
-}
-
-/*
** Append the value passed as the second argument to the buffer passed
** as the first.
**
@@ -218361,26 +228981,6 @@ static void sessionAppendBlob(
/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append a string to the buffer. All bytes in the string
-** up to (but not including) the nul-terminator are written to the buffer.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendStr(
- SessionBuffer *p,
- const char *zStr,
- int *pRc
-){
- int nStr = wx_sqlite3Strlen30(zStr);
- if( 0==sessionBufferGrow(p, nStr, pRc) ){
- memcpy(&p->aBuf[p->nBuf], zStr, nStr);
- p->nBuf += nStr;
- }
-}
-
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. Otherwise, append the string representation of integer iVal
** to the buffer. No nul-terminator is written.
**
@@ -218411,7 +229011,7 @@ static void sessionAppendIdent(
const char *zStr, /* String to quote, escape and append */
int *pRc /* IN/OUT: Error code */
){
- int nStr = wx_sqlite3Strlen30(zStr)*2 + 2 + 1;
+ int nStr = wx_sqlite3Strlen30(zStr)*2 + 2 + 2;
if( 0==sessionBufferGrow(p, nStr, pRc) ){
char *zOut = (char *)&p->aBuf[p->nBuf];
const char *zIn = zStr;
@@ -218422,6 +229022,7 @@ static void sessionAppendIdent(
}
*zOut++ = '"';
p->nBuf = (int)((u8 *)zOut - p->aBuf);
+ p->aBuf[p->nBuf] = 0x00;
}
}
@@ -218557,7 +229158,7 @@ static int sessionAppendUpdate(
/* If at least one field has been modified, this is not a no-op. */
if( bChanged ) bNoop = 0;
- /* Add a field to the old.* record. This is omitted if this modules is
+ /* Add a field to the old.* record. This is omitted if this module is
** currently generating a patchset. */
if( bPatchset==0 ){
if( bChanged || abPK[i] ){
@@ -218646,12 +229247,20 @@ static int sessionAppendDelete(
** Formulate and prepare a SELECT statement to retrieve a row from table
** zTab in database zDb based on its primary key. i.e.
**
-** SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ...
+** SELECT *, <noop-test> FROM zDb.zTab WHERE (pk1, pk2,...) IS (?1, ?2,...)
+**
+** where <noop-test> is:
+**
+** 1 AND (?A OR ?1 IS <column>) AND ...
+**
+** for each non-pk <column>.
*/
static int sessionSelectStmt(
wx_sqlite3 *db, /* Database handle */
+ int bIgnoreNoop,
const char *zDb, /* Database name */
const char *zTab, /* Table name */
+ int bRowid,
int nCol, /* Number of columns in table */
const char **azCol, /* Names of table columns */
u8 *abPK, /* PRIMARY KEY array */
@@ -218659,8 +229268,50 @@ static int sessionSelectStmt(
){
int rc = SQLITE_OK;
char *zSql = 0;
+ const char *zSep = "";
+ const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*";
int nSql = -1;
+ int i;
+ SessionBuffer nooptest = {0, 0, 0};
+ SessionBuffer pkfield = {0, 0, 0};
+ SessionBuffer pkvar = {0, 0, 0};
+
+ sessionAppendStr(&nooptest, ", 1", &rc);
+
+ if( 0==wx_sqlite3_stricmp("sqlite_stat1", zTab) ){
+ sessionAppendStr(&nooptest, " AND (?6 OR ?3 IS stat)", &rc);
+ sessionAppendStr(&pkfield, "tbl, idx", &rc);
+ sessionAppendStr(&pkvar,
+ "?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc
+ );
+ zCols = "tbl, ?2, stat";
+ }else{
+ for(i=0; i<nCol; i++){
+ if( abPK[i] ){
+ sessionAppendStr(&pkfield, zSep, &rc);
+ sessionAppendStr(&pkvar, zSep, &rc);
+ zSep = ", ";
+ sessionAppendIdent(&pkfield, azCol[i], &rc);
+ sessionAppendPrintf(&pkvar, &rc, "?%d", i+1);
+ }else{
+ sessionAppendPrintf(&nooptest, &rc,
+ " AND (?%d OR ?%d IS %w.%w)", i+1+nCol, i+1, zTab, azCol[i]
+ );
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ zSql = wx_sqlite3_mprintf(
+ "SELECT %s%s FROM %Q.%Q WHERE (%s) IS (%s)",
+ zCols, (bIgnoreNoop ? (char*)nooptest.aBuf : ""),
+ zDb, zTab, (char*)pkfield.aBuf, (char*)pkvar.aBuf
+ );
+ if( zSql==0 ) rc = SQLITE_NOMEM;
+ }
+
+#if 0
if( 0==wx_sqlite3_stricmp("sqlite_stat1", zTab) ){
zSql = wx_sqlite3_mprintf(
"SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
@@ -218668,7 +229319,6 @@ static int sessionSelectStmt(
);
if( zSql==0 ) rc = SQLITE_NOMEM;
}else{
- int i;
const char *zSep = "";
SessionBuffer buf = {0, 0, 0};
@@ -218689,11 +229339,15 @@ static int sessionSelectStmt(
zSql = (char*)buf.aBuf;
nSql = buf.nBuf;
}
+#endif
if( rc==SQLITE_OK ){
rc = wx_sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
}
wx_sqlite3_free(zSql);
+ wx_sqlite3_free(nooptest.aBuf);
+ wx_sqlite3_free(pkfield.aBuf);
+ wx_sqlite3_free(pkvar.aBuf);
return rc;
}
@@ -218833,18 +229487,16 @@ static int sessionGenerateChangeset(
for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
if( pTab->nEntry ){
const char *zName = pTab->zName;
- int nCol = 0; /* Number of columns in table */
- u8 *abPK = 0; /* Primary key array */
- const char **azCol = 0; /* Table columns */
int i; /* Used to iterate through hash buckets */
wx_sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */
int nRewind = buf.nBuf; /* Initial size of write buffer */
int nNoop; /* Size of buffer after writing tbl header */
+ int nOldCol = pTab->nCol;
/* Check the table schema is still Ok. */
- rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK);
- if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
- rc = SQLITE_SCHEMA;
+ rc = sessionReinitTable(pSession, pTab);
+ if( rc==SQLITE_OK && pTab->nCol!=nOldCol ){
+ rc = sessionUpdateChanges(pSession, pTab);
}
/* Write a table header */
@@ -218852,8 +229504,9 @@ static int sessionGenerateChangeset(
/* Build and compile a statement to execute: */
if( rc==SQLITE_OK ){
- rc = sessionSelectStmt(
- db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
+ rc = sessionSelectStmt(db, 0, pSession->zDb,
+ zName, pTab->bRowid, pTab->nCol, pTab->azCol, pTab->abPK, &pSel
+ );
}
nNoop = buf.nBuf;
@@ -218861,22 +229514,22 @@ static int sessionGenerateChangeset(
SessionChange *p; /* Used to iterate through changes */
for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
- rc = sessionSelectBind(pSel, nCol, abPK, p);
+ rc = sessionSelectBind(pSel, pTab->nCol, pTab->abPK, p);
if( rc!=SQLITE_OK ) continue;
if( wx_sqlite3_step(pSel)==SQLITE_ROW ){
if( p->op==SQLITE_INSERT ){
int iCol;
sessionAppendByte(&buf, SQLITE_INSERT, &rc);
sessionAppendByte(&buf, p->bIndirect, &rc);
- for(iCol=0; iCol<nCol; iCol++){
+ for(iCol=0; iCol<pTab->nCol; iCol++){
sessionAppendCol(&buf, pSel, iCol, &rc);
}
}else{
- assert( abPK!=0 ); /* Because sessionSelectStmt() returned ok */
- rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
+ assert( pTab->abPK!=0 );
+ rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, pTab->abPK);
}
}else if( p->op!=SQLITE_INSERT ){
- rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
+ rc = sessionAppendDelete(&buf, bPatchset, p, pTab->nCol,pTab->abPK);
}
if( rc==SQLITE_OK ){
rc = wx_sqlite3_reset(pSel);
@@ -218901,7 +229554,6 @@ static int sessionGenerateChangeset(
if( buf.nBuf==nNoop ){
buf.nBuf = nRewind;
}
- wx_sqlite3_free((char*)azCol); /* cast works around VC++ bug */
}
}
@@ -218936,7 +229588,7 @@ SQLITE_API int wx_sqlite3session_changeset(
int rc;
if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE;
- rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset);
+ rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
assert( rc || pnChangeset==0
|| pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize
);
@@ -219054,6 +229706,19 @@ SQLITE_API int wx_sqlite3session_object_config(wx_sqlite3_session *pSession, int
break;
}
+ case SQLITE_SESSION_OBJCONFIG_ROWID: {
+ int iArg = *(int*)pArg;
+ if( iArg>=0 ){
+ if( pSession->pTable ){
+ rc = SQLITE_MISUSE;
+ }else{
+ pSession->bImplicitPK = (iArg!=0);
+ }
+ }
+ *(int*)pArg = pSession->bImplicitPK;
+ break;
+ }
+
default:
rc = SQLITE_MISUSE;
}
@@ -219312,15 +229977,19 @@ static int sessionReadRecord(
}
}
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- wx_sqlite3_int64 v = sessionGetI64(aVal);
- if( eType==SQLITE_INTEGER ){
- wx_sqlite3VdbeMemSetInt64(apOut[i], v);
+ if( (pIn->nData-pIn->iNext)<8 ){
+ rc = SQLITE_CORRUPT_BKPT;
}else{
- double d;
- memcpy(&d, &v, 8);
- wx_sqlite3VdbeMemSetDouble(apOut[i], d);
+ wx_sqlite3_int64 v = sessionGetI64(aVal);
+ if( eType==SQLITE_INTEGER ){
+ wx_sqlite3VdbeMemSetInt64(apOut[i], v);
+ }else{
+ double d;
+ memcpy(&d, &v, 8);
+ wx_sqlite3VdbeMemSetDouble(apOut[i], d);
+ }
+ pIn->iNext += 8;
}
- pIn->iNext += 8;
}
}
}
@@ -219508,14 +230177,14 @@ static int sessionChangesetNextOne(
p->rc = sessionInputBuffer(&p->in, 2);
if( p->rc!=SQLITE_OK ) return p->rc;
+ sessionDiscardData(&p->in);
+ p->in.iCurrent = p->in.iNext;
+
/* If the iterator is already at the end of the changeset, return DONE. */
if( p->in.iNext>=p->in.nData ){
return SQLITE_DONE;
}
- sessionDiscardData(&p->in);
- p->in.iCurrent = p->in.iNext;
-
op = p->in.aData[p->in.iNext++];
while( op=='T' || op=='P' ){
if( pbNew ) *pbNew = 1;
@@ -220042,6 +230711,8 @@ struct SessionApplyCtx {
SessionBuffer rebase; /* Rebase information (if any) here */
u8 bRebaseStarted; /* If table header is already in rebase */
u8 bRebase; /* True to collect rebase information */
+ u8 bIgnoreNoop; /* True to ignore no-op conflicts */
+ int bRowid;
};
/* Number of prepared UPDATE statements to cache. */
@@ -220292,8 +230963,10 @@ static int sessionSelectRow(
const char *zTab, /* Table name */
SessionApplyCtx *p /* Session changeset-apply context */
){
- return sessionSelectStmt(
- db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
+ /* TODO */
+ return sessionSelectStmt(db, p->bIgnoreNoop,
+ "main", zTab, p->bRowid, p->nCol, p->azCol, p->abPK, &p->pSelect
+ );
}
/*
@@ -220452,20 +231125,33 @@ static int sessionBindRow(
*/
static int sessionSeekToRow(
wx_sqlite3_changeset_iter *pIter, /* Changeset iterator */
- u8 *abPK, /* Primary key flags array */
- wx_sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */
+ SessionApplyCtx *p
){
+ wx_sqlite3_stmt *pSelect = p->pSelect;
int rc; /* Return code */
int nCol; /* Number of columns in table */
int op; /* Changset operation (SQLITE_UPDATE etc.) */
const char *zDummy; /* Unused */
+ wx_sqlite3_clear_bindings(pSelect);
wx_sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
rc = sessionBindRow(pIter,
op==SQLITE_INSERT ? wx_sqlite3changeset_new : wx_sqlite3changeset_old,
- nCol, abPK, pSelect
+ nCol, p->abPK, pSelect
);
+ if( op!=SQLITE_DELETE && p->bIgnoreNoop ){
+ int ii;
+ for(ii=0; rc==SQLITE_OK && ii<nCol; ii++){
+ if( p->abPK[ii]==0 ){
+ wx_sqlite3_value *pVal = 0;
+ wx_sqlite3changeset_new(pIter, ii, &pVal);
+ wx_sqlite3_bind_int(pSelect, ii+1+nCol, (pVal==0));
+ if( pVal ) rc = sessionBindValue(pSelect, ii+1, pVal);
+ }
+ }
+ }
+
if( rc==SQLITE_OK ){
rc = wx_sqlite3_step(pSelect);
if( rc!=SQLITE_ROW ) rc = wx_sqlite3_reset(pSelect);
@@ -220580,16 +231266,22 @@ static int sessionConflictHandler(
/* Bind the new.* PRIMARY KEY values to the SELECT statement. */
if( pbReplace ){
- rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
+ rc = sessionSeekToRow(pIter, p);
}else{
rc = SQLITE_OK;
}
if( rc==SQLITE_ROW ){
/* There exists another row with the new.* primary key. */
- pIter->pConflict = p->pSelect;
- res = xConflict(pCtx, eType, pIter);
- pIter->pConflict = 0;
+ if( p->bIgnoreNoop
+ && wx_sqlite3_column_int(p->pSelect, wx_sqlite3_column_count(p->pSelect)-1)
+ ){
+ res = SQLITE_CHANGESET_OMIT;
+ }else{
+ pIter->pConflict = p->pSelect;
+ res = xConflict(pCtx, eType, pIter);
+ pIter->pConflict = 0;
+ }
rc = wx_sqlite3_reset(p->pSelect);
}else if( rc==SQLITE_OK ){
if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){
@@ -220697,7 +231389,7 @@ static int sessionApplyOneOp(
wx_sqlite3_step(p->pDelete);
rc = wx_sqlite3_reset(p->pDelete);
- if( rc==SQLITE_OK && wx_sqlite3_changes(p->db)==0 ){
+ if( rc==SQLITE_OK && wx_sqlite3_changes(p->db)==0 && p->bIgnoreNoop==0 ){
rc = sessionConflictHandler(
SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
);
@@ -220754,7 +231446,7 @@ static int sessionApplyOneOp(
/* Check if there is a conflicting row. For sqlite_stat1, this needs
** to be done using a SELECT, as there is no PRIMARY KEY in the
** database schema to throw an exception if a duplicate is inserted. */
- rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
+ rc = sessionSeekToRow(pIter, p);
if( rc==SQLITE_ROW ){
rc = SQLITE_CONSTRAINT;
wx_sqlite3_reset(p->pSelect);
@@ -220924,14 +231616,21 @@ static int sessionChangesetApply(
int nTab = 0; /* Result of wx_sqlite3Strlen30(zTab) */
SessionApplyCtx sApply; /* changeset_apply() context object */
int bPatchset;
+ u64 savedFlag = db->flags & SQLITE_FkNoAction;
assert( xConflict!=0 );
+ wx_sqlite3_mutex_enter(wx_sqlite3_db_mutex(db));
+ if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
+ db->flags |= ((u64)SQLITE_FkNoAction);
+ db->aDb[0].pSchema->schema_cookie -= 32;
+ }
+
pIter->in.bNoDiscard = 1;
memset(&sApply, 0, sizeof(sApply));
sApply.bRebase = (ppRebase && pnRebase);
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
- wx_sqlite3_mutex_enter(wx_sqlite3_db_mutex(db));
+ sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
rc = wx_sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
}
@@ -220968,6 +231667,7 @@ static int sessionChangesetApply(
sApply.bStat1 = 0;
sApply.bDeferConstraints = 1;
sApply.bRebaseStarted = 0;
+ sApply.bRowid = 0;
memset(&sApply.constraints, 0, sizeof(SessionBuffer));
/* If an xFilter() callback was specified, invoke it now. If the
@@ -220987,8 +231687,8 @@ static int sessionChangesetApply(
int i;
wx_sqlite3changeset_pk(pIter, &abPK, 0);
- rc = sessionTableInfo(0,
- db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
+ rc = sessionTableInfo(0, db, "main", zNew,
+ &sApply.nCol, &zTab, &sApply.azCol, 0, &sApply.abPK, &sApply.bRowid
);
if( rc!=SQLITE_OK ) break;
for(i=0; i<sApply.nCol; i++){
@@ -221092,6 +231792,12 @@ static int sessionChangesetApply(
wx_sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
wx_sqlite3_free((char*)sApply.constraints.aBuf);
wx_sqlite3_free((char*)sApply.rebase.aBuf);
+
+ if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
+ assert( db->flags & SQLITE_FkNoAction );
+ db->flags &= ~((u64)SQLITE_FkNoAction);
+ db->aDb[0].pSchema->schema_cookie -= 32;
+ }
wx_sqlite3_mutex_leave(wx_sqlite3_db_mutex(db));
return rc;
}
@@ -221120,11 +231826,13 @@ SQLITE_API int wx_sqlite3changeset_apply_v2(
wx_sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
+
if( rc==SQLITE_OK ){
rc = sessionChangesetApply(
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
);
}
+
return rc;
}
@@ -221212,6 +231920,10 @@ struct wx_sqlite3_changegroup {
int rc; /* Error code */
int bPatch; /* True to accumulate patchsets */
SessionTable *pList; /* List of tables in current patch */
+ SessionBuffer rec;
+
+ wx_sqlite3 *db; /* Configured by changegroup_schema() */
+ char *zDb; /* Configured by changegroup_schema() */
};
/*
@@ -221232,6 +231944,7 @@ static int sessionChangeMerge(
){
SessionChange *pNew = 0;
int rc = SQLITE_OK;
+ assert( aRec!=0 );
if( !pExist ){
pNew = (SessionChange *)wx_sqlite3_malloc64(sizeof(SessionChange) + nRec);
@@ -221398,84 +232111,242 @@ static int sessionChangeMerge(
}
/*
-** Add all changes in the changeset traversed by the iterator passed as
-** the first argument to the changegroup hash tables.
+** Check if a changeset entry with nCol columns and the PK array passed
+** as the final argument to this function is compatible with SessionTable
+** pTab. If so, return 1. Otherwise, if they are incompatible in some way,
+** return 0.
*/
-static int sessionChangesetToHash(
- wx_sqlite3_changeset_iter *pIter, /* Iterator to read from */
- wx_sqlite3_changegroup *pGrp, /* Changegroup object to add changeset to */
- int bRebase /* True if hash table is for rebasing */
+static int sessionChangesetCheckCompat(
+ SessionTable *pTab,
+ int nCol,
+ u8 *abPK
){
- u8 *aRec;
- int nRec;
- int rc = SQLITE_OK;
- SessionTable *pTab = 0;
-
- while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, 0) ){
- const char *zNew;
- int nCol;
- int op;
- int iHash;
- int bIndirect;
- SessionChange *pChange;
- SessionChange *pExist = 0;
- SessionChange **pp;
-
- if( pGrp->pList==0 ){
- pGrp->bPatch = pIter->bPatchset;
- }else if( pIter->bPatchset!=pGrp->bPatch ){
- rc = SQLITE_ERROR;
- break;
+ if( pTab->azCol && nCol<pTab->nCol ){
+ int ii;
+ for(ii=0; ii<pTab->nCol; ii++){
+ u8 bPK = (ii < nCol) ? abPK[ii] : 0;
+ if( pTab->abPK[ii]!=bPK ) return 0;
}
+ return 1;
+ }
+ return (pTab->nCol==nCol && 0==memcmp(abPK, pTab->abPK, nCol));
+}
- wx_sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);
- if( !pTab || wx_sqlite3_stricmp(zNew, pTab->zName) ){
- /* Search the list for a matching table */
- int nNew = (int)strlen(zNew);
- u8 *abPK;
+static int sessionChangesetExtendRecord(
+ wx_sqlite3_changegroup *pGrp,
+ SessionTable *pTab,
+ int nCol,
+ int op,
+ const u8 *aRec,
+ int nRec,
+ SessionBuffer *pOut
+){
+ int rc = SQLITE_OK;
+ int ii = 0;
+
+ assert( pTab->azCol );
+ assert( nCol<pTab->nCol );
- wx_sqlite3changeset_pk(pIter, &abPK, 0);
- for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
- if( 0==wx_sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
+ pOut->nBuf = 0;
+ if( op==SQLITE_INSERT || (op==SQLITE_DELETE && pGrp->bPatch==0) ){
+ /* Append the missing default column values to the record. */
+ sessionAppendBlob(pOut, aRec, nRec, &rc);
+ if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){
+ rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt);
+ if( rc==SQLITE_OK && SQLITE_ROW!=wx_sqlite3_step(pTab->pDfltStmt) ){
+ rc = wx_sqlite3_errcode(pGrp->db);
}
- if( !pTab ){
- SessionTable **ppTab;
+ }
+ for(ii=nCol; rc==SQLITE_OK && ii<pTab->nCol; ii++){
+ int eType = wx_sqlite3_column_type(pTab->pDfltStmt, ii);
+ sessionAppendByte(pOut, eType, &rc);
+ switch( eType ){
+ case SQLITE_FLOAT:
+ case SQLITE_INTEGER: {
+ i64 iVal;
+ if( eType==SQLITE_INTEGER ){
+ iVal = wx_sqlite3_column_int64(pTab->pDfltStmt, ii);
+ }else{
+ double rVal = wx_sqlite3_column_int64(pTab->pDfltStmt, ii);
+ memcpy(&iVal, &rVal, sizeof(i64));
+ }
+ if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){
+ sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
+ pOut->nBuf += 8;
+ }
+ break;
+ }
- pTab = wx_sqlite3_malloc64(sizeof(SessionTable) + nCol + nNew+1);
- if( !pTab ){
- rc = SQLITE_NOMEM;
+ case SQLITE_BLOB:
+ case SQLITE_TEXT: {
+ int n = wx_sqlite3_column_bytes(pTab->pDfltStmt, ii);
+ sessionAppendVarint(pOut, n, &rc);
+ if( eType==SQLITE_TEXT ){
+ const u8 *z = (const u8*)wx_sqlite3_column_text(pTab->pDfltStmt, ii);
+ sessionAppendBlob(pOut, z, n, &rc);
+ }else{
+ const u8 *z = (const u8*)wx_sqlite3_column_blob(pTab->pDfltStmt, ii);
+ sessionAppendBlob(pOut, z, n, &rc);
+ }
break;
}
- memset(pTab, 0, sizeof(SessionTable));
- pTab->nCol = nCol;
- pTab->abPK = (u8*)&pTab[1];
- memcpy(pTab->abPK, abPK, nCol);
- pTab->zName = (char*)&pTab->abPK[nCol];
- memcpy(pTab->zName, zNew, nNew+1);
-
- /* The new object must be linked on to the end of the list, not
- ** simply added to the start of it. This is to ensure that the
- ** tables within the output of wx_sqlite3changegroup_output() are in
- ** the right order. */
- for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
- *ppTab = pTab;
- }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){
- rc = SQLITE_SCHEMA;
- break;
+
+ default:
+ assert( eType==SQLITE_NULL );
+ break;
+ }
+ }
+ }else if( op==SQLITE_UPDATE ){
+ /* Append missing "undefined" entries to the old.* record. And, if this
+ ** is an UPDATE, to the new.* record as well. */
+ int iOff = 0;
+ if( pGrp->bPatch==0 ){
+ for(ii=0; ii<nCol; ii++){
+ iOff += sessionSerialLen(&aRec[iOff]);
+ }
+ sessionAppendBlob(pOut, aRec, iOff, &rc);
+ for(ii=0; ii<(pTab->nCol-nCol); ii++){
+ sessionAppendByte(pOut, 0x00, &rc);
}
}
- if( sessionGrowHash(0, pIter->bPatchset, pTab) ){
- rc = SQLITE_NOMEM;
- break;
+ sessionAppendBlob(pOut, &aRec[iOff], nRec-iOff, &rc);
+ for(ii=0; ii<(pTab->nCol-nCol); ii++){
+ sessionAppendByte(pOut, 0x00, &rc);
+ }
+ }else{
+ assert( op==SQLITE_DELETE && pGrp->bPatch );
+ sessionAppendBlob(pOut, aRec, nRec, &rc);
+ }
+
+ return rc;
+}
+
+/*
+** Locate or create a SessionTable object that may be used to add the
+** change currently pointed to by iterator pIter to changegroup pGrp.
+** If successful, set output variable (*ppTab) to point to the table
+** object and return SQLITE_OK. Otherwise, if some error occurs, return
+** an SQLite error code and leave (*ppTab) set to NULL.
+*/
+static int sessionChangesetFindTable(
+ wx_sqlite3_changegroup *pGrp,
+ const char *zTab,
+ wx_sqlite3_changeset_iter *pIter,
+ SessionTable **ppTab
+){
+ int rc = SQLITE_OK;
+ SessionTable *pTab = 0;
+ int nTab = (int)strlen(zTab);
+ u8 *abPK = 0;
+ int nCol = 0;
+
+ *ppTab = 0;
+ wx_sqlite3changeset_pk(pIter, &abPK, &nCol);
+
+ /* Search the list for an existing table */
+ for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
+ if( 0==wx_sqlite3_strnicmp(pTab->zName, zTab, nTab+1) ) break;
+ }
+
+ /* If one was not found above, create a new table now */
+ if( !pTab ){
+ SessionTable **ppNew;
+
+ pTab = wx_sqlite3_malloc64(sizeof(SessionTable) + nCol + nTab+1);
+ if( !pTab ){
+ return SQLITE_NOMEM;
}
+ memset(pTab, 0, sizeof(SessionTable));
+ pTab->nCol = nCol;
+ pTab->abPK = (u8*)&pTab[1];
+ memcpy(pTab->abPK, abPK, nCol);
+ pTab->zName = (char*)&pTab->abPK[nCol];
+ memcpy(pTab->zName, zTab, nTab+1);
+
+ if( pGrp->db ){
+ pTab->nCol = 0;
+ rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb);
+ if( rc ){
+ assert( pTab->azCol==0 );
+ wx_sqlite3_free(pTab);
+ return rc;
+ }
+ }
+
+ /* The new object must be linked on to the end of the list, not
+ ** simply added to the start of it. This is to ensure that the
+ ** tables within the output of wx_sqlite3changegroup_output() are in
+ ** the right order. */
+ for(ppNew=&pGrp->pList; *ppNew; ppNew=&(*ppNew)->pNext);
+ *ppNew = pTab;
+ }
+
+ /* Check that the table is compatible. */
+ if( !sessionChangesetCheckCompat(pTab, nCol, abPK) ){
+ rc = SQLITE_SCHEMA;
+ }
+
+ *ppTab = pTab;
+ return rc;
+}
+
+/*
+** Add the change currently indicated by iterator pIter to the hash table
+** belonging to changegroup pGrp.
+*/
+static int sessionOneChangeToHash(
+ wx_sqlite3_changegroup *pGrp,
+ wx_sqlite3_changeset_iter *pIter,
+ int bRebase
+){
+ int rc = SQLITE_OK;
+ int nCol = 0;
+ int op = 0;
+ int iHash = 0;
+ int bIndirect = 0;
+ SessionChange *pChange = 0;
+ SessionChange *pExist = 0;
+ SessionChange **pp = 0;
+ SessionTable *pTab = 0;
+ u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2];
+ int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2;
+
+ assert( nRec>0 );
+
+ /* Ensure that only changesets, or only patchsets, but not a mixture
+ ** of both, are being combined. It is an error to try to combine a
+ ** changeset and a patchset. */
+ if( pGrp->pList==0 ){
+ pGrp->bPatch = pIter->bPatchset;
+ }else if( pIter->bPatchset!=pGrp->bPatch ){
+ rc = SQLITE_ERROR;
+ }
+
+ if( rc==SQLITE_OK ){
+ const char *zTab = 0;
+ wx_sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect);
+ rc = sessionChangesetFindTable(pGrp, zTab, pIter, &pTab);
+ }
+
+ if( rc==SQLITE_OK && nCol<pTab->nCol ){
+ SessionBuffer *pBuf = &pGrp->rec;
+ rc = sessionChangesetExtendRecord(pGrp, pTab, nCol, op, aRec, nRec, pBuf);
+ aRec = pBuf->aBuf;
+ nRec = pBuf->nBuf;
+ assert( pGrp->db );
+ }
+
+ if( rc==SQLITE_OK && sessionGrowHash(0, pIter->bPatchset, pTab) ){
+ rc = SQLITE_NOMEM;
+ }
+
+ if( rc==SQLITE_OK ){
+ /* Search for existing entry. If found, remove it from the hash table.
+ ** Code below may link it back in. */
iHash = sessionChangeHash(
pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
);
-
- /* Search for existing entry. If found, remove it from the hash table.
- ** Code below may link it back in.
- */
for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
int bPkOnly1 = 0;
int bPkOnly2 = 0;
@@ -221490,16 +232361,40 @@ static int sessionChangesetToHash(
break;
}
}
+ }
+ if( rc==SQLITE_OK ){
rc = sessionChangeMerge(pTab, bRebase,
pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
);
- if( rc ) break;
- if( pChange ){
- pChange->pNext = pTab->apChange[iHash];
- pTab->apChange[iHash] = pChange;
- pTab->nEntry++;
- }
+ }
+ if( rc==SQLITE_OK && pChange ){
+ pChange->pNext = pTab->apChange[iHash];
+ pTab->apChange[iHash] = pChange;
+ pTab->nEntry++;
+ }
+
+ if( rc==SQLITE_OK ) rc = pIter->rc;
+ return rc;
+}
+
+/*
+** Add all changes in the changeset traversed by the iterator passed as
+** the first argument to the changegroup hash tables.
+*/
+static int sessionChangesetToHash(
+ wx_sqlite3_changeset_iter *pIter, /* Iterator to read from */
+ wx_sqlite3_changegroup *pGrp, /* Changegroup object to add changeset to */
+ int bRebase /* True if hash table is for rebasing */
+){
+ u8 *aRec;
+ int nRec;
+ int rc = SQLITE_OK;
+
+ pIter->in.bNoDiscard = 1;
+ while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){
+ rc = sessionOneChangeToHash(pGrp, pIter, bRebase);
+ if( rc!=SQLITE_OK ) break;
}
if( rc==SQLITE_OK ) rc = pIter->rc;
@@ -221589,6 +232484,31 @@ SQLITE_API int wx_sqlite3changegroup_new(wx_sqlite3_changegroup **pp){
}
/*
+** Provide a database schema to the changegroup object.
+*/
+SQLITE_API int wx_sqlite3changegroup_schema(
+ wx_sqlite3_changegroup *pGrp,
+ wx_sqlite3 *db,
+ const char *zDb
+){
+ int rc = SQLITE_OK;
+
+ if( pGrp->pList || pGrp->db ){
+ /* Cannot add a schema after one or more calls to wx_sqlite3changegroup_add(),
+ ** or after wx_sqlite3changegroup_schema() has already been called. */
+ rc = SQLITE_MISUSE;
+ }else{
+ pGrp->zDb = wx_sqlite3_mprintf("%s", zDb);
+ if( pGrp->zDb==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pGrp->db = db;
+ }
+ }
+ return rc;
+}
+
+/*
** Add the changeset currently stored in buffer pData, size nData bytes,
** to changeset-group p.
*/
@@ -221605,6 +232525,23 @@ SQLITE_API int wx_sqlite3changegroup_add(wx_sqlite3_changegroup *pGrp, int nData
}
/*
+** Add a single change to a changeset-group.
+*/
+SQLITE_API int wx_sqlite3changegroup_add_change(
+ wx_sqlite3_changegroup *pGrp,
+ wx_sqlite3_changeset_iter *pIter
+){
+ if( pIter->in.iCurrent==pIter->in.iNext
+ || pIter->rc!=SQLITE_OK
+ || pIter->bInvert
+ ){
+ /* Iterator does not point to any valid entry or is an INVERT iterator. */
+ return SQLITE_ERROR;
+ }
+ return sessionOneChangeToHash(pGrp, pIter, 0);
+}
+
+/*
** Obtain a buffer containing a changeset representing the concatenation
** of all changesets added to the group so far.
*/
@@ -221651,7 +232588,9 @@ SQLITE_API int wx_sqlite3changegroup_output_strm(
*/
SQLITE_API void wx_sqlite3changegroup_delete(wx_sqlite3_changegroup *pGrp){
if( pGrp ){
+ wx_sqlite3_free(pGrp->zDb);
sessionDeleteTable(0, pGrp->pList);
+ wx_sqlite3_free(pGrp->rec.aBuf);
wx_sqlite3_free(pGrp);
}
}
@@ -222053,6 +232992,7 @@ SQLITE_API int wx_sqlite3rebaser_rebase_strm(
SQLITE_API void wx_sqlite3rebaser_delete(wx_sqlite3_rebaser *p){
if( p ){
sessionDeleteTable(0, p->grp.pList);
+ wx_sqlite3_free(p->grp.rec.aBuf);
wx_sqlite3_free(p);
}
}
@@ -222083,7 +233023,27 @@ SQLITE_API int wx_sqlite3session_config(int op, void *pArg){
/************** End of wx_sqlite3session.c **************************************/
/************** Begin file fts5.c ********************************************/
-
+/*
+** This, the "fts5.c" source file, is a composite file that is itself
+** assembled from the following files:
+**
+** fts5.h
+** fts5Int.h
+** fts5parse.h <--- Generated from fts5parse.y by Lemon
+** fts5parse.c <--- Generated from fts5parse.y by Lemon
+** fts5_aux.c
+** fts5_buffer.c
+** fts5_config.c
+** fts5_expr.c
+** fts5_hash.c
+** fts5_index.c
+** fts5_main.c
+** fts5_storage.c
+** fts5_tokenize.c
+** fts5_unicode2.c
+** fts5_varint.c
+** fts5_vocab.c
+*/
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
@@ -222093,6 +233053,12 @@ SQLITE_API int wx_sqlite3session_config(int op, void *pArg){
# undef NDEBUG
#endif
+#ifdef HAVE_STDINT_H
+/* #include <stdint.h> */
+#endif
+#ifdef HAVE_INTTYPES_H
+/* #include <inttypes.h> */
+#endif
/*
** 2014 May 31
**
@@ -222150,8 +233116,8 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
-** registered with.
+** Return a copy of the pUserData pointer passed to the xCreateFunction()
+** API when the extension function was registered.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
@@ -222183,8 +233149,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the text of column iCol of
+** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -222194,8 +233163,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of phrases in the current query, as returned by xPhraseCount,
+** 0 is returned. Otherwise, this function returns the number of tokens in
+** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -222211,12 +233182,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
+** output by xInstCount(). If iIdx is less than zero or greater than
+** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
+** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. Returns SQLITE_OK if successful, or an error
-** code (i.e. SQLITE_NOMEM) if an error occurs.
+** first token of the phrase. SQLITE_OK is returned if successful, or an
+** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -222242,6 +233214,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
+** If parameter iPhrase is less than zero, or greater than or equal to
+** the number of phrases in the query, as returned by xPhraseCount(),
+** this function returns SQLITE_RANGE.
+**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -222323,6 +233299,10 @@ struct Fts5PhraseIter {
** (i.e. if it is a contentless table), then this API always iterates
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
**
+** In all cases, matches are visited in (column ASC, offset ASC) order.
+** i.e. all those in column 0, sorted by offset, followed by those in
+** column 1, etc.
+**
** xPhraseNext()
** See xPhraseFirst above.
**
@@ -222356,9 +233336,65 @@ struct Fts5PhraseIter {
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
+**
+** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase iPhrase of the current
+** query. Before returning, output parameter *ppToken is set to point
+** to a buffer containing the requested token, and *pnToken to the
+** size of this buffer in bytes.
+**
+** If iPhrase or iToken are less than zero, or if iPhrase is greater than
+** or equal to the number of phrases in the query as reported by
+** xPhraseCount(), or if iToken is equal to or greater than the number of
+** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
+ are both zeroed.
+**
+** The output text is not a copy of the query text that specified the
+** token. It is the output of the tokenizer module. For tokendata=1
+** tables, this includes any embedded 0x00 and trailing data.
+**
+** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase hit iIdx within the
+** current row. If iIdx is less than zero or greater than or equal to the
+** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
+** output variable (*ppToken) is set to point to a buffer containing the
+** matching document token, and (*pnToken) to the size of that buffer in
+** bytes. This API is not available if the specified token matches a
+** prefix query term. In that case both output variables are always set
+** to 0.
+**
+** The output text is not a copy of the document text that was tokenized.
+** It is the output of the tokenizer module. For tokendata=1 tables, this
+** includes any embedded 0x00 and trailing data.
+**
+** This API can be quite slow if used with an FTS5 table created with the
+** "detail=none" or "detail=column" option.
+**
+** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the locale associated
+** with column iCol of the current row. Usually, there is no associated
+** locale, and output parameters (*pzLocale) and (*pnLocale) are set
+** to NULL and 0, respectively. However, if the fts5_locale() function
+** was used to associate a locale with the value when it was inserted
+** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
+** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
+** is set to the size in bytes of the buffer, not including the
+** nul-terminator.
+**
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an
+** SQLite error code is returned. The final value of the output parameters
+** is undefined in this case.
+**
+** xTokenize_v2:
+** Tokenize text using the tokenizer belonging to the FTS5 table. This
+** API is the same as the xTokenize() API, except that it allows a tokenizer
+** locale to be specified.
*/
struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
+ int iVersion; /* Currently always set to 4 */
void *(*xUserData)(Fts5Context*);
@@ -222393,6 +233429,22 @@ struct Fts5ExtensionApi {
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
+
+ /* Below this point are iVersion>=3 only */
+ int (*xQueryToken)(Fts5Context*,
+ int iPhrase, int iToken,
+ const char **ppToken, int *pnToken
+ );
+ int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
+
+ /* Below this point are iVersion>=4 only */
+ int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
+ int (*xTokenize_v2)(Fts5Context*,
+ const char *pText, int nText, /* Text to tokenize */
+ const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
+ void *pCtx, /* Context passed to xToken() */
+ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
+ );
};
/*
@@ -222413,7 +233465,7 @@ struct Fts5ExtensionApi {
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
-** pointer provided by the application when the fts5_tokenizer object
+** pointer provided by the application when the fts5_tokenizer_v2 object
** was registered with FTS5 (the third argument to xCreateTokenizer()).
** The second and third arguments are an array of nul-terminated strings
** containing the tokenizer arguments, if any, specified following the
@@ -222437,7 +233489,7 @@ struct Fts5ExtensionApi {
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
**
-** The second argument indicates the reason that FTS5 is requesting
+** The third argument indicates the reason that FTS5 is requesting
** tokenization of the supplied text. This is always one of the following
** four values:
**
@@ -222461,6 +233513,13 @@ struct Fts5ExtensionApi {
** on a columnsize=0 database.
** </ul>
**
+** The sixth and seventh arguments passed to xTokenize() - pLocale and
+** nLocale - are a pointer to a buffer containing the locale to use for
+** tokenization (e.g. "en_US") and its size in bytes, respectively. The
+** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
+** which case nLocale is always 0) to indicate that the tokenizer should
+** use its default locale.
+**
** For each token in the input string, the supplied callback xToken() must
** be invoked. The first argument to it should be a copy of the pointer
** passed as the second argument to xTokenize(). The third and fourth
@@ -222484,6 +233543,30 @@ struct Fts5ExtensionApi {
** may abandon the tokenization and return any error code other than
** SQLITE_OK or SQLITE_DONE.
**
+** If the tokenizer is registered using an fts5_tokenizer_v2 object,
+** then the xTokenize() method has two additional arguments - pLocale
+** and nLocale. These specify the locale that the tokenizer should use
+** for the current request. If pLocale and nLocale are both 0, then the
+** tokenizer should use its default locale. Otherwise, pLocale points to
+** an nLocale byte buffer containing the name of the locale to use as utf-8
+** text. pLocale is not nul-terminated.
+**
+** FTS5_TOKENIZER
+**
+** There is also an fts5_tokenizer object. This is an older, deprecated,
+** version of fts5_tokenizer_v2. It is similar except that:
+**
+** <ul>
+** <li> There is no "iVersion" field, and
+** <li> The xTokenize() method does not take a locale argument.
+** </ul>
+**
+** Legacy fts5_tokenizer tokenizers must be registered using the
+** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
+**
+** Tokenizer implementations registered using either API may be retrieved
+** using both xFindTokenizer() and xFindTokenizer_v2().
+**
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
@@ -222587,11 +233670,38 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
+typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
+struct fts5_tokenizer_v2 {
+ int iVersion; /* Currently always 2 */
+
+ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
+ void (*xDelete)(Fts5Tokenizer*);
+ int (*xTokenize)(Fts5Tokenizer*,
+ void *pCtx,
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
+ const char *pText, int nText,
+ const char *pLocale, int nLocale,
+ int (*xToken)(
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
+ const char *pToken, /* Pointer to buffer containing token */
+ int nToken, /* Size of token in bytes */
+ int iStart, /* Byte offset of token within input text */
+ int iEnd /* Byte offset of end of token within input text */
+ )
+ );
+};
+
+/*
+** New code should use the fts5_tokenizer_v2 type to define tokenizer
+** implementations. The following type is included for legacy applications
+** that still use it.
+*/
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
@@ -222611,6 +233721,7 @@ struct fts5_tokenizer {
);
};
+
/* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002
@@ -222630,13 +233741,13 @@ struct fts5_tokenizer {
*/
typedef struct fts5_api fts5_api;
struct fts5_api {
- int iVersion; /* Currently always set to 2 */
+ int iVersion; /* Currently always set to 3 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -222645,7 +233756,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -222653,10 +233764,29 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
+
+ /* APIs below this point are only available if iVersion>=3 */
+
+ /* Create a new tokenizer */
+ int (*xCreateTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void *pUserData,
+ fts5_tokenizer_v2 *pTokenizer,
+ void (*xDestroy)(void*)
+ );
+
+ /* Find an existing tokenizer */
+ int (*xFindTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void **ppUserData,
+ fts5_tokenizer_v2 **ppTokenizer
+ );
};
/*
@@ -222730,6 +233860,22 @@ typedef wx_sqlite3_uint64 u64;
# define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
+/* The uptr type is an unsigned integer large enough to hold a pointer
+*/
+#if defined(HAVE_STDINT_H)
+ typedef uintptr_t uptr;
+#elif SQLITE_PTRSIZE==4
+ typedef u32 uptr;
+#else
+ typedef u64 uptr;
+#endif
+
+#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0)
+#else
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0)
+#endif
+
#endif
/* Truncate very long tokens to this many bytes. Hard limit is
@@ -222813,6 +233959,18 @@ struct Fts5Colset {
*/
typedef struct Fts5Config Fts5Config;
+typedef struct Fts5TokenizerConfig Fts5TokenizerConfig;
+
+struct Fts5TokenizerConfig {
+ Fts5Tokenizer *pTok;
+ fts5_tokenizer_v2 *pApi2;
+ fts5_tokenizer *pApi1;
+ const char **azArg;
+ int nArg;
+ int ePattern; /* FTS_PATTERN_XXX constant */
+ const char *pLocale; /* Current locale to use */
+ int nLocale; /* Size of pLocale in bytes */
+};
/*
** An instance of the following structure encodes all information that can
@@ -222825,6 +233983,10 @@ typedef struct Fts5Config Fts5Config;
** attempt to merge together. A value of 1 sets the object to use the
** compile time default. Zero disables auto-merge altogether.
**
+** bContentlessDelete:
+** True if the contentless_delete option was present in the CREATE
+** VIRTUAL TABLE statement.
+**
** zContent:
**
** zContentRowid:
@@ -222848,9 +234010,12 @@ typedef struct Fts5Config Fts5Config;
**
** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex);
**
+** bLocale:
+** Set to true if locale=1 was specified when the table was created.
*/
struct Fts5Config {
wx_sqlite3 *db; /* Database handle */
+ Fts5Global *pGlobal; /* Global fts5 object for handle db */
char *zDb; /* Database holding FTS index (e.g. "main") */
char *zName; /* Name of FTS index */
int nCol; /* Number of columns */
@@ -222859,17 +234024,21 @@ struct Fts5Config {
int nPrefix; /* Number of prefix indexes */
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
int eContent; /* An FTS5_CONTENT value */
+ int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
+ int bContentlessUnindexed; /* "contentless_unindexed=" option (dflt=0) */
char *zContent; /* content table */
char *zContentRowid; /* "content_rowid=" option value */
int bColumnsize; /* "columnsize=" option value (dflt==1) */
+ int bTokendata; /* "tokendata=" option value (dflt==0) */
+ int bLocale; /* "locale=" option value (dflt==0) */
int eDetail; /* FTS5_DETAIL_XXX value */
char *zContentExprlist;
- Fts5Tokenizer *pTok;
- fts5_tokenizer *pTokApi;
+ Fts5TokenizerConfig t;
int bLock; /* True when table is preparing statement */
- int ePattern; /* FTS_PATTERN_XXX constant */
+
/* Values loaded from the %_config table */
+ int iVersion; /* fts5 file format 'version' */
int iCookie; /* Incremented when %_config is modified */
int pgsz; /* Approximate page size used in %_data */
int nAutomerge; /* 'automerge' setting */
@@ -222878,6 +234047,8 @@ struct Fts5Config {
int nHashSize; /* Bytes of memory for in-memory hash */
char *zRank; /* Name of rank function */
char *zRankArgs; /* Arguments to rank function */
+ int bSecureDelete; /* 'secure-delete' */
+ int nDeleteMerge; /* 'deletemerge' */
/* If non-NULL, points to wx_sqlite3_vtab.base.zErrmsg. Often NULL. */
char **pzErrmsg;
@@ -222887,12 +234058,16 @@ struct Fts5Config {
#endif
};
-/* Current expected value of %_config table 'version' field */
-#define FTS5_CURRENT_VERSION 4
+/* Current expected value of %_config table 'version' field. And
+** the expected version if the 'secure-delete' option has ever been
+** set on the table. */
+#define FTS5_CURRENT_VERSION 4
+#define FTS5_CURRENT_VERSION_SECUREDELETE 5
-#define FTS5_CONTENT_NORMAL 0
-#define FTS5_CONTENT_NONE 1
-#define FTS5_CONTENT_EXTERNAL 2
+#define FTS5_CONTENT_NORMAL 0
+#define FTS5_CONTENT_NONE 1
+#define FTS5_CONTENT_EXTERNAL 2
+#define FTS5_CONTENT_UNINDEXED 3
#define FTS5_DETAIL_FULL 0
#define FTS5_DETAIL_NONE 1
@@ -222927,6 +234102,8 @@ static int wx_sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, wx_sqlite3_val
static int wx_sqlite3Fts5ConfigParseRank(const char*, char**, char**);
+static void wx_sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...);
+
/*
** End of interface to code in fts5_config.c.
**************************************************************************/
@@ -222971,7 +234148,7 @@ static char *wx_sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
static void wx_sqlite3Fts5Put32(u8*, int);
static int wx_sqlite3Fts5Get32(const u8*);
-#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32)
+#define FTS5_POS2COLUMN(iPos) (int)((iPos >> 32) & 0x7FFFFFFF)
#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF)
typedef struct Fts5PoslistReader Fts5PoslistReader;
@@ -223044,16 +234221,19 @@ struct Fts5IndexIter {
/*
** Values used as part of the flags argument passed to IndexQuery().
*/
-#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */
-#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */
-#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
-#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
+#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */
+#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */
+#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
+#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
/* The following are used internally by the fts5_index.c module. They are
** defined here only to make it easier to avoid clashes with the flags
** above. */
-#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
-#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
+#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
+#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
+#define FTS5INDEX_QUERY_SKIPHASH 0x0040
+#define FTS5INDEX_QUERY_NOTOKENDATA 0x0080
+#define FTS5INDEX_QUERY_SCANONETERM 0x0100
/*
** Create/destroy an Fts5Index object.
@@ -223122,6 +234302,10 @@ static void *wx_sqlite3Fts5StructureRef(Fts5Index*);
static void wx_sqlite3Fts5StructureRelease(void*);
static int wx_sqlite3Fts5StructureTest(Fts5Index*, void*);
+/*
+** Used by xInstToken():
+*/
+static int wx_sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*);
/*
** Insert or remove data to or from the index. Each time a document is
@@ -223196,6 +234380,16 @@ static int wx_sqlite3Fts5IndexReset(Fts5Index *p);
static int wx_sqlite3Fts5IndexLoadConfig(Fts5Index *p);
+static int wx_sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin);
+static int wx_sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid);
+
+static void wx_sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter*);
+
+/* Used to populate hash tables for xInstToken in detail=none/column mode. */
+static int wx_sqlite3Fts5IndexIterWriteTokendata(
+ Fts5IndexIter*, const char*, int, i64 iRowid, int iCol, int iOff
+);
+
/*
** End of interface to code in fts5_index.c.
**************************************************************************/
@@ -223208,7 +234402,7 @@ static int wx_sqlite3Fts5GetVarintLen(u32 iVal);
static u8 wx_sqlite3Fts5GetVarint(const unsigned char*, u64*);
static int wx_sqlite3Fts5PutVarint(unsigned char *p, u64 v);
-#define fts5GetVarint32(a,b) wx_sqlite3Fts5GetVarint32(a,(u32*)&b)
+#define fts5GetVarint32(a,b) wx_sqlite3Fts5GetVarint32(a,(u32*)&(b))
#define fts5GetVarint wx_sqlite3Fts5GetVarint
#define fts5FastGetVarint32(a, iOff, nVal) { \
@@ -223239,18 +234433,20 @@ struct Fts5Table {
Fts5Index *pIndex; /* Full-text index */
};
-static int wx_sqlite3Fts5GetTokenizer(
- Fts5Global*,
- const char **azArg,
- int nArg,
- Fts5Config*,
- char **pzErr
-);
+static int wx_sqlite3Fts5LoadTokenizer(Fts5Config *pConfig);
static Fts5Table *wx_sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
static int wx_sqlite3Fts5FlushToDisk(Fts5Table*);
+static void wx_sqlite3Fts5ClearLocale(Fts5Config *pConfig);
+static void wx_sqlite3Fts5SetLocale(Fts5Config *pConfig, const char *pLoc, int nLoc);
+
+static int wx_sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, wx_sqlite3_value *pVal);
+static int wx_sqlite3Fts5DecodeLocaleValue(wx_sqlite3_value *pVal,
+ const char **ppText, int *pnText, const char **ppLoc, int *pnLoc
+);
+
/*
** End of interface to code in fts5.c.
**************************************************************************/
@@ -223280,6 +234476,11 @@ static int wx_sqlite3Fts5HashWrite(
*/
static void wx_sqlite3Fts5HashClear(Fts5Hash*);
+/*
+** Return true if the hash is empty, false otherwise.
+*/
+static int wx_sqlite3Fts5HashIsEmpty(Fts5Hash*);
+
static int wx_sqlite3Fts5HashQuery(
Fts5Hash*, /* Hash table to query */
int nPre,
@@ -223296,11 +234497,13 @@ static void wx_sqlite3Fts5HashScanNext(Fts5Hash*);
static int wx_sqlite3Fts5HashScanEof(Fts5Hash*);
static void wx_sqlite3Fts5HashScanEntry(Fts5Hash *,
const char **pzTerm, /* OUT: term (nul-terminated) */
+ int *pnTerm, /* OUT: Size of term in bytes */
const u8 **ppDoclist, /* OUT: pointer to doclist */
int *pnDoclist /* OUT: size of doclist in bytes */
);
+
/*
** End of interface to code in fts5_hash.c.
**************************************************************************/
@@ -223323,8 +234526,8 @@ static int wx_sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
static int wx_sqlite3Fts5DropAll(Fts5Config*);
static int wx_sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
-static int wx_sqlite3Fts5StorageDelete(Fts5Storage *p, i64, wx_sqlite3_value**);
-static int wx_sqlite3Fts5StorageContentInsert(Fts5Storage *p, wx_sqlite3_value**, i64*);
+static int wx_sqlite3Fts5StorageDelete(Fts5Storage *p, i64, wx_sqlite3_value**, int);
+static int wx_sqlite3Fts5StorageContentInsert(Fts5Storage *p, int, wx_sqlite3_value**, i64*);
static int wx_sqlite3Fts5StorageIndexInsert(Fts5Storage *p, wx_sqlite3_value**, i64);
static int wx_sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
@@ -223349,6 +234552,9 @@ static int wx_sqlite3Fts5StorageOptimize(Fts5Storage *p);
static int wx_sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
static int wx_sqlite3Fts5StorageReset(Fts5Storage *p);
+static void wx_sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage*);
+static int wx_sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel);
+
/*
** End of interface to code in fts5_storage.c.
**************************************************************************/
@@ -223421,6 +234627,10 @@ static int wx_sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**);
static int wx_sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
+static int wx_sqlite3Fts5ExprQueryToken(Fts5Expr*, int, int, const char**, int*);
+static int wx_sqlite3Fts5ExprInstToken(Fts5Expr*, i64, int, int, int, int, const char**, int*);
+static void wx_sqlite3Fts5ExprClearTokens(Fts5Expr*);
+
/*******************************************
** The fts5_expr.c API above this point is used by the other hand-written
** C code in this module. The interfaces below this point are called by
@@ -223497,6 +234707,7 @@ static int wx_sqlite3Fts5TokenizerPattern(
int (*xCreate)(void*, const char**, int, Fts5Tokenizer**),
Fts5Tokenizer *pTok
);
+static int wx_sqlite3Fts5TokenizerPreload(Fts5TokenizerConfig*);
/*
** End of interface to code in fts5_tokenizer.c.
**************************************************************************/
@@ -223544,7 +234755,8 @@ static void wx_sqlite3Fts5UnicodeAscii(u8*, u8*);
#define FTS5_STAR 15
/* This file is automatically generated by Lemon from input grammar
-** source file "fts5parse.y". */
+** source file "fts5parse.y".
+*/
/*
** 2000-05-29
**
@@ -223656,6 +234868,9 @@ static void wx_sqlite3Fts5UnicodeAscii(u8*, u8*);
** wx_sqlite3Fts5ParserARG_STORE Code to store %extra_argument into fts5yypParser
** wx_sqlite3Fts5ParserARG_FETCH Code to extract %extra_argument from fts5yypParser
** wx_sqlite3Fts5ParserCTX_* As wx_sqlite3Fts5ParserARG_ except for %extra_context
+** fts5YYREALLOC Name of the realloc() function to use
+** fts5YYFREE Name of the free() function to use
+** fts5YYDYNSTACK True if stack space should be extended on heap
** fts5YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing.
** fts5YYNSTATE the combined number of states.
@@ -223669,6 +234884,8 @@ static void wx_sqlite3Fts5UnicodeAscii(u8*, u8*);
** fts5YY_NO_ACTION The fts5yy_action[] code for no-op
** fts5YY_MIN_REDUCE Minimum value for reduce actions
** fts5YY_MAX_REDUCE Maximum value for reduce actions
+** fts5YY_MIN_DSTRCTR Minimum symbol value that has a destructor
+** fts5YY_MAX_DSTRCTR Maximum symbol value that has a destructor
*/
#ifndef INTERFACE
# define INTERFACE 1
@@ -223695,6 +234912,9 @@ typedef union {
#define wx_sqlite3Fts5ParserARG_PARAM ,pParse
#define wx_sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse=fts5yypParser->pParse;
#define wx_sqlite3Fts5ParserARG_STORE fts5yypParser->pParse=pParse;
+#define fts5YYREALLOC realloc
+#define fts5YYFREE free
+#define fts5YYDYNSTACK 0
#define wx_sqlite3Fts5ParserCTX_SDECL
#define wx_sqlite3Fts5ParserCTX_PDECL
#define wx_sqlite3Fts5ParserCTX_PARAM
@@ -223712,6 +234932,8 @@ typedef union {
#define fts5YY_NO_ACTION 82
#define fts5YY_MIN_REDUCE 83
#define fts5YY_MAX_REDUCE 110
+#define fts5YY_MIN_DSTRCTR 16
+#define fts5YY_MAX_DSTRCTR 24
/************* End control #defines *******************************************/
#define fts5YY_NLOOKAHEAD ((int)(sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0])))
@@ -223727,6 +234949,22 @@ typedef union {
# define fts5yytestcase(X)
#endif
+/* Macro to determine if stack space has the ability to grow using
+** heap memory.
+*/
+#if fts5YYSTACKDEPTH<=0 || fts5YYDYNSTACK
+# define fts5YYGROWABLESTACK 1
+#else
+# define fts5YYGROWABLESTACK 0
+#endif
+
+/* Guarantee a minimum number of initial stack slots.
+*/
+#if fts5YYSTACKDEPTH<=0
+# undef fts5YYSTACKDEPTH
+# define fts5YYSTACKDEPTH 2 /* Need a minimum stack size */
+#endif
+
/* Next are the tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
@@ -223887,14 +235125,9 @@ struct fts5yyParser {
#endif
wx_sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */
wx_sqlite3Fts5ParserCTX_SDECL /* A place to hold %extra_context */
-#if fts5YYSTACKDEPTH<=0
- int fts5yystksz; /* Current side of the stack */
- fts5yyStackEntry *fts5yystack; /* The parser's stack */
- fts5yyStackEntry fts5yystk0; /* First stack entry */
-#else
- fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH]; /* The parser's stack */
- fts5yyStackEntry *fts5yystackEnd; /* Last entry in the stack */
-#endif
+ fts5yyStackEntry *fts5yystackEnd; /* Last entry in the stack */
+ fts5yyStackEntry *fts5yystack; /* The parser stack */
+ fts5yyStackEntry fts5yystk0[fts5YYSTACKDEPTH]; /* Initial stack space */
};
typedef struct fts5yyParser fts5yyParser;
@@ -224001,37 +235234,45 @@ static const char *const fts5yyRuleName[] = {
#endif /* NDEBUG */
-#if fts5YYSTACKDEPTH<=0
+#if fts5YYGROWABLESTACK
/*
** Try to increase the size of the parser stack. Return the number
** of errors. Return 0 on success.
*/
static int fts5yyGrowStack(fts5yyParser *p){
+ int oldSize = 1 + (int)(p->fts5yystackEnd - p->fts5yystack);
int newSize;
int idx;
fts5yyStackEntry *pNew;
- newSize = p->fts5yystksz*2 + 100;
- idx = p->fts5yytos ? (int)(p->fts5yytos - p->fts5yystack) : 0;
- if( p->fts5yystack==&p->fts5yystk0 ){
- pNew = malloc(newSize*sizeof(pNew[0]));
- if( pNew ) pNew[0] = p->fts5yystk0;
+ newSize = oldSize*2 + 100;
+ idx = (int)(p->fts5yytos - p->fts5yystack);
+ if( p->fts5yystack==p->fts5yystk0 ){
+ pNew = fts5YYREALLOC(0, newSize*sizeof(pNew[0]));
+ if( pNew==0 ) return 1;
+ memcpy(pNew, p->fts5yystack, oldSize*sizeof(pNew[0]));
}else{
- pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0]));
+ pNew = fts5YYREALLOC(p->fts5yystack, newSize*sizeof(pNew[0]));
+ if( pNew==0 ) return 1;
}
- if( pNew ){
- p->fts5yystack = pNew;
- p->fts5yytos = &p->fts5yystack[idx];
+ p->fts5yystack = pNew;
+ p->fts5yytos = &p->fts5yystack[idx];
#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n",
- fts5yyTracePrompt, p->fts5yystksz, newSize);
- }
-#endif
- p->fts5yystksz = newSize;
+ if( fts5yyTraceFILE ){
+ fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n",
+ fts5yyTracePrompt, oldSize, newSize);
}
- return pNew==0;
+#endif
+ p->fts5yystackEnd = &p->fts5yystack[newSize-1];
+ return 0;
}
+#endif /* fts5YYGROWABLESTACK */
+
+#if !fts5YYGROWABLESTACK
+/* For builds that do no have a growable stack, fts5yyGrowStack always
+** returns an error.
+*/
+# define fts5yyGrowStack(X) 1
#endif
/* Datatype of the argument to the memory allocated passed as the
@@ -224051,24 +235292,14 @@ static void wx_sqlite3Fts5ParserInit(void *fts5yypRawParser wx_sqlite3Fts5Parser
#ifdef fts5YYTRACKMAXSTACKDEPTH
fts5yypParser->fts5yyhwm = 0;
#endif
-#if fts5YYSTACKDEPTH<=0
- fts5yypParser->fts5yytos = NULL;
- fts5yypParser->fts5yystack = NULL;
- fts5yypParser->fts5yystksz = 0;
- if( fts5yyGrowStack(fts5yypParser) ){
- fts5yypParser->fts5yystack = &fts5yypParser->fts5yystk0;
- fts5yypParser->fts5yystksz = 1;
- }
-#endif
+ fts5yypParser->fts5yystack = fts5yypParser->fts5yystk0;
+ fts5yypParser->fts5yystackEnd = &fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1];
#ifndef fts5YYNOERRORRECOVERY
fts5yypParser->fts5yyerrcnt = -1;
#endif
fts5yypParser->fts5yytos = fts5yypParser->fts5yystack;
fts5yypParser->fts5yystack[0].stateno = 0;
fts5yypParser->fts5yystack[0].major = 0;
-#if fts5YYSTACKDEPTH>0
- fts5yypParser->fts5yystackEnd = &fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1];
-#endif
}
#ifndef wx_sqlite3Fts5Parser_ENGINEALWAYSONSTACK
@@ -224182,9 +235413,26 @@ static void fts5yy_pop_parser_stack(fts5yyParser *pParser){
*/
static void wx_sqlite3Fts5ParserFinalize(void *p){
fts5yyParser *pParser = (fts5yyParser*)p;
- while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser);
-#if fts5YYSTACKDEPTH<=0
- if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack);
+
+ /* In-lined version of calling fts5yy_pop_parser_stack() for each
+ ** element left in the stack */
+ fts5yyStackEntry *fts5yytos = pParser->fts5yytos;
+ while( fts5yytos>pParser->fts5yystack ){
+#ifndef NDEBUG
+ if( fts5yyTraceFILE ){
+ fprintf(fts5yyTraceFILE,"%sPopping %s\n",
+ fts5yyTracePrompt,
+ fts5yyTokenName[fts5yytos->major]);
+ }
+#endif
+ if( fts5yytos->major>=fts5YY_MIN_DSTRCTR ){
+ fts5yy_destructor(pParser, fts5yytos->major, &fts5yytos->minor);
+ }
+ fts5yytos--;
+ }
+
+#if fts5YYGROWABLESTACK
+ if( pParser->fts5yystack!=pParser->fts5yystk0 ) fts5YYFREE(pParser->fts5yystack);
#endif
}
@@ -224411,25 +235659,19 @@ static void fts5yy_shift(
assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) );
}
#endif
-#if fts5YYSTACKDEPTH>0
- if( fts5yypParser->fts5yytos>fts5yypParser->fts5yystackEnd ){
- fts5yypParser->fts5yytos--;
- fts5yyStackOverflow(fts5yypParser);
- return;
- }
-#else
- if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz] ){
+ fts5yytos = fts5yypParser->fts5yytos;
+ if( fts5yytos>fts5yypParser->fts5yystackEnd ){
if( fts5yyGrowStack(fts5yypParser) ){
fts5yypParser->fts5yytos--;
fts5yyStackOverflow(fts5yypParser);
return;
}
+ fts5yytos = fts5yypParser->fts5yytos;
+ assert( fts5yytos <= fts5yypParser->fts5yystackEnd );
}
-#endif
if( fts5yyNewState > fts5YY_MAX_SHIFT ){
fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
}
- fts5yytos = fts5yypParser->fts5yytos;
fts5yytos->stateno = fts5yyNewState;
fts5yytos->major = fts5yyMajor;
fts5yytos->minor.fts5yy0 = fts5yyMinor;
@@ -224866,19 +236108,12 @@ static void wx_sqlite3Fts5Parser(
(int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack));
}
#endif
-#if fts5YYSTACKDEPTH>0
if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){
- fts5yyStackOverflow(fts5yypParser);
- break;
- }
-#else
- if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){
if( fts5yyGrowStack(fts5yypParser) ){
fts5yyStackOverflow(fts5yypParser);
break;
}
}
-#endif
}
fts5yyact = fts5yy_reduce(fts5yypParser,fts5yyruleno,fts5yymajor,fts5yyminor wx_sqlite3Fts5ParserCTX_PARAM);
}else if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
@@ -225134,15 +236369,19 @@ static int fts5CInstIterInit(
*/
typedef struct HighlightContext HighlightContext;
struct HighlightContext {
- CInstIter iter; /* Coalesced Instance Iterator */
- int iPos; /* Current token offset in zIn[] */
+ /* Constant parameters to fts5HighlightCb() */
int iRangeStart; /* First token to include */
int iRangeEnd; /* If non-zero, last token to include */
const char *zOpen; /* Opening highlight */
const char *zClose; /* Closing highlight */
const char *zIn; /* Input text */
int nIn; /* Size of input text in bytes */
- int iOff; /* Current offset within zIn[] */
+
+ /* Variables modified by fts5HighlightCb() */
+ CInstIter iter; /* Coalesced Instance Iterator */
+ int iPos; /* Current token offset in zIn[] */
+ int iOff; /* Have copied up to this offset in zIn[] */
+ int bOpen; /* True if highlight is open */
char *zOut; /* Output value */
};
@@ -225175,8 +236414,8 @@ static int fts5HighlightCb(
int tflags, /* Mask of FTS5_TOKEN_* flags */
const char *pToken, /* Buffer containing token */
int nToken, /* Size of token in bytes */
- int iStartOff, /* Start offset of token */
- int iEndOff /* End offset of token */
+ int iStartOff, /* Start byte offset of token */
+ int iEndOff /* End byte offset of token */
){
HighlightContext *p = (HighlightContext*)pContext;
int rc = SQLITE_OK;
@@ -225187,40 +236426,66 @@ static int fts5HighlightCb(
if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK;
iPos = p->iPos++;
- if( p->iRangeEnd>0 ){
+ if( p->iRangeEnd>=0 ){
if( iPos<p->iRangeStart || iPos>p->iRangeEnd ) return SQLITE_OK;
if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff;
}
- if( iPos==p->iter.iStart ){
+ /* If the parenthesis is open, and this token is not part of the current
+ ** phrase, and the starting byte offset of this token is past the point
+ ** that has currently been copied into the output buffer, close the
+ ** parenthesis. */
+ if( p->bOpen
+ && (iPos<=p->iter.iStart || p->iter.iStart<0)
+ && iStartOff>p->iOff
+ ){
+ fts5HighlightAppend(&rc, p, p->zClose, -1);
+ p->bOpen = 0;
+ }
+
+ /* If this is the start of a new phrase, and the highlight is not open:
+ **
+ ** * copy text from the input up to the start of the phrase, and
+ ** * open the highlight.
+ */
+ if( iPos==p->iter.iStart && p->bOpen==0 ){
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iStartOff - p->iOff);
fts5HighlightAppend(&rc, p, p->zOpen, -1);
p->iOff = iStartOff;
+ p->bOpen = 1;
}
if( iPos==p->iter.iEnd ){
- if( p->iRangeEnd && p->iter.iStart<p->iRangeStart ){
+ if( p->bOpen==0 ){
+ assert( p->iRangeEnd>=0 );
fts5HighlightAppend(&rc, p, p->zOpen, -1);
+ p->bOpen = 1;
}
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
- fts5HighlightAppend(&rc, p, p->zClose, -1);
p->iOff = iEndOff;
+
if( rc==SQLITE_OK ){
rc = fts5CInstIterNext(&p->iter);
}
}
- if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){
- fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
- p->iOff = iEndOff;
- if( iPos>=p->iter.iStart && iPos<p->iter.iEnd ){
+ if( iPos==p->iRangeEnd ){
+ if( p->bOpen ){
+ if( p->iter.iStart>=0 && iPos>=p->iter.iStart ){
+ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
+ p->iOff = iEndOff;
+ }
fts5HighlightAppend(&rc, p, p->zClose, -1);
+ p->bOpen = 0;
}
+ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
+ p->iOff = iEndOff;
}
return rc;
}
+
/*
** Implementation of highlight() function.
*/
@@ -225245,15 +236510,28 @@ static void fts5HighlightFunction(
memset(&ctx, 0, sizeof(HighlightContext));
ctx.zOpen = (const char*)wx_sqlite3_value_text(apVal[1]);
ctx.zClose = (const char*)wx_sqlite3_value_text(apVal[2]);
+ ctx.iRangeEnd = -1;
rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
-
- if( ctx.zIn ){
+ if( rc==SQLITE_RANGE ){
+ wx_sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
+ rc = SQLITE_OK;
+ }else if( ctx.zIn ){
+ const char *pLoc = 0; /* Locale of column iCol */
+ int nLoc = 0; /* Size of pLoc in bytes */
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
}
if( rc==SQLITE_OK ){
- rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
+ rc = pApi->xColumnLocale(pFts, iCol, &pLoc, &nLoc);
+ }
+ if( rc==SQLITE_OK ){
+ rc = pApi->xTokenize_v2(
+ pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx, fts5HighlightCb
+ );
+ }
+ if( ctx.bOpen ){
+ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
}
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
@@ -225430,6 +236708,7 @@ static void fts5SnippetFunction(
iCol = wx_sqlite3_value_int(apVal[0]);
ctx.zOpen = fts5ValueToText(apVal[1]);
ctx.zClose = fts5ValueToText(apVal[2]);
+ ctx.iRangeEnd = -1;
zEllips = fts5ValueToText(apVal[3]);
nToken = wx_sqlite3_value_int(apVal[4]);
@@ -225446,6 +236725,8 @@ static void fts5SnippetFunction(
memset(&sFinder, 0, sizeof(Fts5SFinder));
for(i=0; i<nCol; i++){
if( iCol<0 || iCol==i ){
+ const char *pLoc = 0; /* Locale of column iCol */
+ int nLoc = 0; /* Size of pLoc in bytes */
int nDoc;
int nDocsize;
int ii;
@@ -225453,8 +236734,10 @@ static void fts5SnippetFunction(
sFinder.nFirst = 0;
rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc);
if( rc!=SQLITE_OK ) break;
- rc = pApi->xTokenize(pFts,
- sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb
+ rc = pApi->xColumnLocale(pFts, i, &pLoc, &nLoc);
+ if( rc!=SQLITE_OK ) break;
+ rc = pApi->xTokenize_v2(pFts,
+ sFinder.zDoc, nDoc, pLoc, nLoc, (void*)&sFinder, fts5SentenceFinderCb
);
if( rc!=SQLITE_OK ) break;
rc = pApi->xColumnSize(pFts, i, &nDocsize);
@@ -225512,6 +236795,9 @@ static void fts5SnippetFunction(
rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
}
if( ctx.zIn ){
+ const char *pLoc = 0; /* Locale of column iBestCol */
+ int nLoc = 0; /* Bytes in pLoc */
+
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
}
@@ -225530,7 +236816,15 @@ static void fts5SnippetFunction(
}
if( rc==SQLITE_OK ){
- rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
+ rc = pApi->xColumnLocale(pFts, iBestCol, &pLoc, &nLoc);
+ }
+ if( rc==SQLITE_OK ){
+ rc = pApi->xTokenize_v2(
+ pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx,fts5HighlightCb
+ );
+ }
+ if( ctx.bOpen ){
+ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
}
if( ctx.iRangeEnd>=(nColSize-1) ){
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
@@ -225711,6 +237005,53 @@ static void fts5Bm25Function(
}
}
+/*
+** Implementation of fts5_get_locale() function.
+*/
+static void fts5GetLocaleFunction(
+ const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
+ Fts5Context *pFts, /* First arg to pass to pApi functions */
+ wx_sqlite3_context *pCtx, /* Context for returning result/error */
+ int nVal, /* Number of values in apVal[] array */
+ wx_sqlite3_value **apVal /* Array of trailing arguments */
+){
+ int iCol = 0;
+ int eType = 0;
+ int rc = SQLITE_OK;
+ const char *zLocale = 0;
+ int nLocale = 0;
+
+ /* xColumnLocale() must be available */
+ assert( pApi->iVersion>=4 );
+
+ if( nVal!=1 ){
+ const char *z = "wrong number of arguments to function fts5_get_locale()";
+ wx_sqlite3_result_error(pCtx, z, -1);
+ return;
+ }
+
+ eType = wx_sqlite3_value_numeric_type(apVal[0]);
+ if( eType!=SQLITE_INTEGER ){
+ const char *z = "non-integer argument passed to function fts5_get_locale()";
+ wx_sqlite3_result_error(pCtx, z, -1);
+ return;
+ }
+
+ iCol = wx_sqlite3_value_int(apVal[0]);
+ if( iCol<0 || iCol>=pApi->xColumnCount(pFts) ){
+ wx_sqlite3_result_error_code(pCtx, SQLITE_RANGE);
+ return;
+ }
+
+ rc = pApi->xColumnLocale(pFts, iCol, &zLocale, &nLocale);
+ if( rc!=SQLITE_OK ){
+ wx_sqlite3_result_error_code(pCtx, rc);
+ return;
+ }
+
+ wx_sqlite3_result_text(pCtx, zLocale, nLocale, SQLITE_TRANSIENT);
+}
+
static int wx_sqlite3Fts5AuxInit(fts5_api *pApi){
struct Builtin {
const char *zFunc; /* Function name (nul-terminated) */
@@ -225718,9 +237059,10 @@ static int wx_sqlite3Fts5AuxInit(fts5_api *pApi){
fts5_extension_function xFunc;/* Callback function */
void (*xDestroy)(void*); /* Destructor function */
} aBuiltin [] = {
- { "snippet", 0, fts5SnippetFunction, 0 },
- { "highlight", 0, fts5HighlightFunction, 0 },
- { "bm25", 0, fts5Bm25Function, 0 },
+ { "snippet", 0, fts5SnippetFunction, 0 },
+ { "highlight", 0, fts5HighlightFunction, 0 },
+ { "bm25", 0, fts5Bm25Function, 0 },
+ { "fts5_get_locale", 0, fts5GetLocaleFunction, 0 },
};
int rc = SQLITE_OK; /* Return code */
int i; /* To iterate through builtin functions */
@@ -225807,6 +237149,7 @@ static void wx_sqlite3Fts5BufferAppendBlob(
){
if( nData ){
if( fts5BufferGrow(pRc, pBuf, nData) ) return;
+ assert( pBuf->p!=0 );
memcpy(&pBuf->p[pBuf->n], pData, nData);
pBuf->n += nData;
}
@@ -225908,6 +237251,7 @@ static int wx_sqlite3Fts5PoslistNext64(
i64 *piOff /* IN/OUT: Current offset */
){
int i = *pi;
+ assert( a!=0 || i==0 );
if( i>=n ){
/* EOF */
*piOff = -1;
@@ -225915,6 +237259,7 @@ static int wx_sqlite3Fts5PoslistNext64(
}else{
i64 iOff = *piOff;
u32 iVal;
+ assert( a!=0 );
fts5FastGetVarint32(a, i, iVal);
if( iVal<=1 ){
if( iVal==0 ){
@@ -226170,6 +237515,8 @@ static void wx_sqlite3Fts5TermsetFree(Fts5Termset *p){
#define FTS5_DEFAULT_CRISISMERGE 16
#define FTS5_DEFAULT_HASHSIZE (1024*1024)
+#define FTS5_DEFAULT_DELETE_AUTOMERGE 10 /* default 10% */
+
/* Maximum allowed page size */
#define FTS5_MAX_PAGE_SIZE (64*1024)
@@ -226380,7 +237727,6 @@ static int fts5ConfigSetEnum(
** eventually free any such error message using wx_sqlite3_free().
*/
static int fts5ConfigParseSpecial(
- Fts5Global *pGlobal,
Fts5Config *pConfig, /* Configuration object to update */
const char *zCmd, /* Special command to parse */
const char *zArg, /* Argument to parse */
@@ -226388,6 +237734,7 @@ static int fts5ConfigParseSpecial(
){
int rc = SQLITE_OK;
int nCmd = (int)strlen(zCmd);
+
if( wx_sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){
const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
const char *p;
@@ -226444,12 +237791,11 @@ static int fts5ConfigParseSpecial(
if( wx_sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
const char *p = (const char*)zArg;
wx_sqlite3_int64 nArg = strlen(zArg) + 1;
- char **azArg = wx_sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
- char *pDel = wx_sqlite3Fts5MallocZero(&rc, nArg * 2);
- char *pSpace = pDel;
+ char **azArg = wx_sqlite3Fts5MallocZero(&rc, (sizeof(char*) + 2) * nArg);
- if( azArg && pSpace ){
- if( pConfig->pTok ){
+ if( azArg ){
+ char *pSpace = (char*)&azArg[nArg];
+ if( pConfig->t.azArg ){
*pzErr = wx_sqlite3_mprintf("multiple tokenize=... directives");
rc = SQLITE_ERROR;
}else{
@@ -226472,16 +237818,14 @@ static int fts5ConfigParseSpecial(
*pzErr = wx_sqlite3_mprintf("parse error in tokenize directive");
rc = SQLITE_ERROR;
}else{
- rc = wx_sqlite3Fts5GetTokenizer(pGlobal,
- (const char**)azArg, (int)nArg, pConfig,
- pzErr
- );
+ pConfig->t.azArg = (const char**)azArg;
+ pConfig->t.nArg = nArg;
+ azArg = 0;
}
}
}
-
wx_sqlite3_free(azArg);
- wx_sqlite3_free(pDel);
+
return rc;
}
@@ -226500,6 +237844,26 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( wx_sqlite3_strnicmp("contentless_delete", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = wx_sqlite3_mprintf("malformed contentless_delete=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bContentlessDelete = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
+ if( wx_sqlite3_strnicmp("contentless_unindexed", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = wx_sqlite3_mprintf("malformed contentless_delete=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bContentlessUnindexed = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
if( wx_sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
if( pConfig->zContentRowid ){
*pzErr = wx_sqlite3_mprintf("multiple content_rowid=... directives");
@@ -226520,6 +237884,16 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( wx_sqlite3_strnicmp("locale", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = wx_sqlite3_mprintf("malformed locale=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bLocale = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
if( wx_sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
const Fts5Enum aDetail[] = {
{ "none", FTS5_DETAIL_NONE },
@@ -226534,21 +237908,21 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( wx_sqlite3_strnicmp("tokendata", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = wx_sqlite3_mprintf("malformed tokendata=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bTokendata = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
*pzErr = wx_sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
return SQLITE_ERROR;
}
/*
-** Allocate an instance of the default tokenizer ("simple") at
-** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error
-** code if an error occurs.
-*/
-static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){
- assert( pConfig->pTok==0 && pConfig->pTokApi==0 );
- return wx_sqlite3Fts5GetTokenizer(pGlobal, 0, 0, pConfig, 0);
-}
-
-/*
** Gobble up the first bareword or quoted word from the input buffer zIn.
** Return a pointer to the character immediately following the last in
** the gobbled word if successful, or a NULL pointer otherwise (failed
@@ -226607,7 +237981,8 @@ static int fts5ConfigParseColumn(
Fts5Config *p,
char *zCol,
char *zArg,
- char **pzErr
+ char **pzErr,
+ int *pbUnindexed
){
int rc = SQLITE_OK;
if( 0==wx_sqlite3_stricmp(zCol, FTS5_RANK_NAME)
@@ -226618,6 +237993,7 @@ static int fts5ConfigParseColumn(
}else if( zArg ){
if( 0==wx_sqlite3_stricmp(zArg, "unindexed") ){
p->abUnindexed[p->nCol] = 1;
+ *pbUnindexed = 1;
}else{
*pzErr = wx_sqlite3_mprintf("unrecognized column option: %s", zArg);
rc = SQLITE_ERROR;
@@ -226638,11 +238014,26 @@ static int fts5ConfigMakeExprlist(Fts5Config *p){
wx_sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid);
if( p->eContent!=FTS5_CONTENT_NONE ){
+ assert( p->eContent==FTS5_CONTENT_EXTERNAL
+ || p->eContent==FTS5_CONTENT_NORMAL
+ || p->eContent==FTS5_CONTENT_UNINDEXED
+ );
for(i=0; i<p->nCol; i++){
if( p->eContent==FTS5_CONTENT_EXTERNAL ){
wx_sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]);
- }else{
+ }else if( p->eContent==FTS5_CONTENT_NORMAL || p->abUnindexed[i] ){
wx_sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i);
+ }else{
+ wx_sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
+ }
+ }
+ }
+ if( p->eContent==FTS5_CONTENT_NORMAL && p->bLocale ){
+ for(i=0; i<p->nCol; i++){
+ if( p->abUnindexed[i]==0 ){
+ wx_sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.l%d", i);
+ }else{
+ wx_sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
}
}
}
@@ -226676,10 +238067,12 @@ static int wx_sqlite3Fts5ConfigParse(
Fts5Config *pRet; /* New object to return */
int i;
wx_sqlite3_int64 nByte;
+ int bUnindexed = 0; /* True if there are one or more UNINDEXED */
*ppOut = pRet = (Fts5Config*)wx_sqlite3_malloc(sizeof(Fts5Config));
if( pRet==0 ) return SQLITE_NOMEM;
memset(pRet, 0, sizeof(Fts5Config));
+ pRet->pGlobal = pGlobal;
pRet->db = db;
pRet->iCookie = -1;
@@ -226698,6 +238091,7 @@ static int wx_sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR;
}
+ assert( (pRet->abUnindexed && pRet->azCol) || rc!=SQLITE_OK );
for(i=3; rc==SQLITE_OK && i<nArg; i++){
const char *zOrig = azArg[i];
const char *z;
@@ -226727,13 +238121,13 @@ static int wx_sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR;
}else{
if( bOption ){
- rc = fts5ConfigParseSpecial(pGlobal, pRet,
+ rc = fts5ConfigParseSpecial(pRet,
ALWAYS(zOne)?zOne:"",
zTwo?zTwo:"",
pzErr
);
}else{
- rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr);
+ rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr, &bUnindexed);
zOne = 0;
}
}
@@ -226743,11 +238137,39 @@ static int wx_sqlite3Fts5ConfigParse(
wx_sqlite3_free(zTwo);
}
- /* If a tokenizer= option was successfully parsed, the tokenizer has
- ** already been allocated. Otherwise, allocate an instance of the default
- ** tokenizer (unicode61) now. */
- if( rc==SQLITE_OK && pRet->pTok==0 ){
- rc = fts5ConfigDefaultTokenizer(pGlobal, pRet);
+ /* We only allow contentless_delete=1 if the table is indeed contentless. */
+ if( rc==SQLITE_OK
+ && pRet->bContentlessDelete
+ && pRet->eContent!=FTS5_CONTENT_NONE
+ ){
+ *pzErr = wx_sqlite3_mprintf(
+ "contentless_delete=1 requires a contentless table"
+ );
+ rc = SQLITE_ERROR;
+ }
+
+ /* We only allow contentless_delete=1 if columnsize=0 is not present.
+ **
+ ** This restriction may be removed at some point.
+ */
+ if( rc==SQLITE_OK && pRet->bContentlessDelete && pRet->bColumnsize==0 ){
+ *pzErr = wx_sqlite3_mprintf(
+ "contentless_delete=1 is incompatible with columnsize=0"
+ );
+ rc = SQLITE_ERROR;
+ }
+
+ /* We only allow contentless_unindexed=1 if the table is actually a
+ ** contentless one.
+ */
+ if( rc==SQLITE_OK
+ && pRet->bContentlessUnindexed
+ && pRet->eContent!=FTS5_CONTENT_NONE
+ ){
+ *pzErr = wx_sqlite3_mprintf(
+ "contentless_unindexed=1 requires a contentless table"
+ );
+ rc = SQLITE_ERROR;
}
/* If no zContent option was specified, fill in the default values. */
@@ -226758,6 +238180,9 @@ static int wx_sqlite3Fts5ConfigParse(
);
if( pRet->eContent==FTS5_CONTENT_NORMAL ){
zTail = "content";
+ }else if( bUnindexed && pRet->bContentlessUnindexed ){
+ pRet->eContent = FTS5_CONTENT_UNINDEXED;
+ zTail = "content";
}else if( pRet->bColumnsize ){
zTail = "docsize";
}
@@ -226791,9 +238216,14 @@ static int wx_sqlite3Fts5ConfigParse(
static void wx_sqlite3Fts5ConfigFree(Fts5Config *pConfig){
if( pConfig ){
int i;
- if( pConfig->pTok ){
- pConfig->pTokApi->xDelete(pConfig->pTok);
+ if( pConfig->t.pTok ){
+ if( pConfig->t.pApi1 ){
+ pConfig->t.pApi1->xDelete(pConfig->t.pTok);
+ }else{
+ pConfig->t.pApi2->xDelete(pConfig->t.pTok);
+ }
}
+ wx_sqlite3_free((char*)pConfig->t.azArg);
wx_sqlite3_free(pConfig->zDb);
wx_sqlite3_free(pConfig->zName);
for(i=0; i<pConfig->nCol; i++){
@@ -226868,10 +238298,24 @@ static int wx_sqlite3Fts5Tokenize(
void *pCtx, /* Context passed to xToken() */
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
){
- if( pText==0 ) return SQLITE_OK;
- return pConfig->pTokApi->xTokenize(
- pConfig->pTok, pCtx, flags, pText, nText, xToken
- );
+ int rc = SQLITE_OK;
+ if( pText ){
+ if( pConfig->t.pTok==0 ){
+ rc = wx_sqlite3Fts5LoadTokenizer(pConfig);
+ }
+ if( rc==SQLITE_OK ){
+ if( pConfig->t.pApi1 ){
+ rc = pConfig->t.pApi1->xTokenize(
+ pConfig->t.pTok, pCtx, flags, pText, nText, xToken
+ );
+ }else{
+ rc = pConfig->t.pApi2->xTokenize(pConfig->t.pTok, pCtx, flags,
+ pText, nText, pConfig->t.pLocale, pConfig->t.nLocale, xToken
+ );
+ }
+ }
+ }
+ return rc;
}
/*
@@ -227037,6 +238481,18 @@ static int wx_sqlite3Fts5ConfigSetValue(
}
}
+ else if( 0==wx_sqlite3_stricmp(zKey, "deletemerge") ){
+ int nVal = -1;
+ if( SQLITE_INTEGER==wx_sqlite3_value_numeric_type(pVal) ){
+ nVal = wx_sqlite3_value_int(pVal);
+ }else{
+ *pbBadkey = 1;
+ }
+ if( nVal<0 ) nVal = FTS5_DEFAULT_DELETE_AUTOMERGE;
+ if( nVal>100 ) nVal = 0;
+ pConfig->nDeleteMerge = nVal;
+ }
+
else if( 0==wx_sqlite3_stricmp(zKey, "rank") ){
const char *zIn = (const char*)wx_sqlite3_value_text(pVal);
char *zRank;
@@ -227051,6 +238507,18 @@ static int wx_sqlite3Fts5ConfigSetValue(
rc = SQLITE_OK;
*pbBadkey = 1;
}
+ }
+
+ else if( 0==wx_sqlite3_stricmp(zKey, "secure-delete") ){
+ int bVal = -1;
+ if( SQLITE_INTEGER==wx_sqlite3_value_numeric_type(pVal) ){
+ bVal = wx_sqlite3_value_int(pVal);
+ }
+ if( bVal<0 ){
+ *pbBadkey = 1;
+ }else{
+ pConfig->bSecureDelete = (bVal ? 1 : 0);
+ }
}else{
*pbBadkey = 1;
}
@@ -227073,6 +238541,7 @@ static int wx_sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE;
pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE;
+ pConfig->nDeleteMerge = FTS5_DEFAULT_DELETE_AUTOMERGE;
zSql = wx_sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName);
if( zSql ){
@@ -227095,15 +238564,17 @@ static int wx_sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
rc = wx_sqlite3_finalize(p);
}
- if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){
+ if( rc==SQLITE_OK
+ && iVersion!=FTS5_CURRENT_VERSION
+ && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
+ ){
rc = SQLITE_ERROR;
- if( pConfig->pzErrmsg ){
- assert( 0==*pConfig->pzErrmsg );
- *pConfig->pzErrmsg = wx_sqlite3_mprintf(
- "invalid fts5 file format (found %d, expected %d) - run 'rebuild'",
- iVersion, FTS5_CURRENT_VERSION
- );
- }
+ wx_sqlite3Fts5ConfigErrmsg(pConfig, "invalid fts5 file format "
+ "(found %d, expected %d or %d) - run 'rebuild'",
+ iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
+ );
+ }else{
+ pConfig->iVersion = iVersion;
}
if( rc==SQLITE_OK ){
@@ -227113,6 +238584,29 @@ static int wx_sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
}
/*
+** Set (*pConfig->pzErrmsg) to point to an wx_sqlite3_malloc()ed buffer
+** containing the error message created using printf() style formatting
+** string zFmt and its trailing arguments.
+*/
+static void wx_sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){
+ va_list ap; /* ... printf arguments */
+ char *zMsg = 0;
+
+ va_start(ap, zFmt);
+ zMsg = wx_sqlite3_vmprintf(zFmt, ap);
+ if( pConfig->pzErrmsg ){
+ assert( *pConfig->pzErrmsg==0 );
+ *pConfig->pzErrmsg = zMsg;
+ }else{
+ wx_sqlite3_free(zMsg);
+ }
+
+ va_end(ap);
+}
+
+
+
+/*
** 2014 May 31
**
** The author disclaims copyright to this source code. In place of
@@ -227131,6 +238625,10 @@ static int wx_sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
/* #include "fts5Int.h" */
/* #include "fts5parse.h" */
+#ifndef SQLITE_FTS5_MAX_EXPR_DEPTH
+# define SQLITE_FTS5_MAX_EXPR_DEPTH 256
+#endif
+
/*
** All token types in the generated fts5parse.h file are greater than 0.
*/
@@ -227164,18 +238662,28 @@ struct Fts5Expr {
/*
** eType:
-** Expression node type. Always one of:
+** Expression node type. Usually one of:
**
** FTS5_AND (nChild, apChild valid)
** FTS5_OR (nChild, apChild valid)
** FTS5_NOT (nChild, apChild valid)
** FTS5_STRING (pNear valid)
** FTS5_TERM (pNear valid)
+**
+** An expression node with eType==0 may also exist. It always matches zero
+** rows. This is created when a phrase containing no tokens is parsed.
+** e.g. "".
+**
+** iHeight:
+** Distance from this node to furthest leaf. This is always 0 for nodes
+** of type FTS5_STRING and FTS5_TERM. For all other nodes it is one
+** greater than the largest child value.
*/
struct Fts5ExprNode {
int eType; /* Node type */
int bEof; /* True at EOF */
int bNomatch; /* True if entry is not a match */
+ int iHeight; /* Distance to tree leaf nodes */
/* Next method for this node. */
int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64);
@@ -227204,7 +238712,9 @@ struct Fts5ExprNode {
struct Fts5ExprTerm {
u8 bPrefix; /* True for a prefix term */
u8 bFirst; /* True if token must be first in column */
- char *zTerm; /* nul-terminated term */
+ char *pTerm; /* Term data */
+ int nQueryTerm; /* Effective size of term in bytes */
+ int nFullTerm; /* Size of term in bytes incl. tokendata */
Fts5IndexIter *pIter; /* Iterator for this term */
Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */
};
@@ -227245,6 +238755,31 @@ struct Fts5Parse {
int bPhraseToAnd; /* Convert "a+b" to "a AND b" */
};
+/*
+** Check that the Fts5ExprNode.iHeight variables are set correctly in
+** the expression tree passed as the only argument.
+*/
+#ifndef NDEBUG
+static void assert_expr_depth_ok(int rc, Fts5ExprNode *p){
+ if( rc==SQLITE_OK ){
+ if( p->eType==FTS5_TERM || p->eType==FTS5_STRING || p->eType==0 ){
+ assert( p->iHeight==0 );
+ }else{
+ int ii;
+ int iMaxChild = 0;
+ for(ii=0; ii<p->nChild; ii++){
+ Fts5ExprNode *pChild = p->apChild[ii];
+ iMaxChild = MAX(iMaxChild, pChild->iHeight);
+ assert_expr_depth_ok(SQLITE_OK, pChild);
+ }
+ assert( p->iHeight==iMaxChild+1 );
+ }
+ }
+}
+#else
+# define assert_expr_depth_ok(rc, p)
+#endif
+
static void wx_sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){
va_list ap;
va_start(ap, zFmt);
@@ -227359,9 +238894,12 @@ static int wx_sqlite3Fts5ExprNew(
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
wx_sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
+ assert( sParse.pExpr || sParse.rc!=SQLITE_OK );
+ assert_expr_depth_ok(sParse.rc, sParse.pExpr);
+
/* If the LHS of the MATCH expression was a user column, apply the
** implicit column-filter. */
- if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
+ if( sParse.rc==SQLITE_OK && iCol<pConfig->nCol ){
int n = sizeof(Fts5Colset);
Fts5Colset *pColset = (Fts5Colset*)wx_sqlite3Fts5MallocZero(&sParse.rc, n);
if( pColset ){
@@ -227378,15 +238916,7 @@ static int wx_sqlite3Fts5ExprNew(
sParse.rc = SQLITE_NOMEM;
wx_sqlite3Fts5ParseNodeFree(sParse.pExpr);
}else{
- if( !sParse.pExpr ){
- const int nByte = sizeof(Fts5ExprNode);
- pNew->pRoot = (Fts5ExprNode*)wx_sqlite3Fts5MallocZero(&sParse.rc, nByte);
- if( pNew->pRoot ){
- pNew->pRoot->bEof = 1;
- }
- }else{
- pNew->pRoot = sParse.pExpr;
- }
+ pNew->pRoot = sParse.pExpr;
pNew->pIndex = 0;
pNew->pConfig = pConfig;
pNew->apExprPhrase = sParse.apPhrase;
@@ -227399,7 +238929,11 @@ static int wx_sqlite3Fts5ExprNew(
}
wx_sqlite3_free(sParse.apPhrase);
- *pzErr = sParse.zErr;
+ if( 0==*pzErr ){
+ *pzErr = sParse.zErr;
+ }else{
+ wx_sqlite3_free(sParse.zErr);
+ }
return sParse.rc;
}
@@ -227521,7 +239055,7 @@ static int wx_sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
Fts5Parse sParse;
memset(&sParse, 0, sizeof(sParse));
- if( *pp1 ){
+ if( *pp1 && p2 ){
Fts5Expr *p1 = *pp1;
int nPhrase = p1->nPhrase + p2->nPhrase;
@@ -227546,7 +239080,7 @@ static int wx_sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
}
wx_sqlite3_free(p2->apExprPhrase);
wx_sqlite3_free(p2);
- }else{
+ }else if( p2 ){
*pp1 = p2;
}
@@ -228044,7 +239578,7 @@ static int fts5ExprNearInitAll(
p->pIter = 0;
}
rc = wx_sqlite3Fts5IndexQuery(
- pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
+ pExpr->pIndex, p->pTerm, p->nQueryTerm,
(pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
(pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
pNear->pColset,
@@ -228200,7 +239734,7 @@ static int fts5ExprNodeTest_STRING(
}
}else{
Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
- if( pIter->iRowid==iLast || pIter->bEof ) continue;
+ if( pIter->iRowid==iLast ) continue;
bMatch = 0;
if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
return rc;
@@ -228681,7 +240215,7 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
Fts5ExprTerm *pSyn;
Fts5ExprTerm *pNext;
Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
- wx_sqlite3_free(pTerm->zTerm);
+ wx_sqlite3_free(pTerm->pTerm);
wx_sqlite3Fts5IterClose(pTerm->pIter);
for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){
pNext = pSyn->pSynonym;
@@ -228722,9 +240256,6 @@ static Fts5ExprNearset *wx_sqlite3Fts5ParseNearset(
Fts5ExprNearset *pRet = 0;
if( pParse->rc==SQLITE_OK ){
- if( pPhrase==0 ){
- return pNear;
- }
if( pNear==0 ){
wx_sqlite3_int64 nByte;
nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
@@ -228779,6 +240310,7 @@ static Fts5ExprNearset *wx_sqlite3Fts5ParseNearset(
typedef struct TokenCtx TokenCtx;
struct TokenCtx {
Fts5ExprPhrase *pPhrase;
+ Fts5Config *pConfig;
int rc;
};
@@ -228812,8 +240344,12 @@ static int fts5ParseTokenize(
rc = SQLITE_NOMEM;
}else{
memset(pSyn, 0, (size_t)nByte);
- pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
- memcpy(pSyn->zTerm, pToken, nToken);
+ pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
+ pSyn->nFullTerm = pSyn->nQueryTerm = nToken;
+ if( pCtx->pConfig->bTokendata ){
+ pSyn->nQueryTerm = (int)strlen(pSyn->pTerm);
+ }
+ memcpy(pSyn->pTerm, pToken, nToken);
pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
}
@@ -228838,7 +240374,11 @@ static int fts5ParseTokenize(
if( rc==SQLITE_OK ){
pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
memset(pTerm, 0, sizeof(Fts5ExprTerm));
- pTerm->zTerm = wx_sqlite3Fts5Strndup(&rc, pToken, nToken);
+ pTerm->pTerm = wx_sqlite3Fts5Strndup(&rc, pToken, nToken);
+ pTerm->nFullTerm = pTerm->nQueryTerm = nToken;
+ if( pCtx->pConfig->bTokendata && rc==SQLITE_OK ){
+ pTerm->nQueryTerm = (int)strlen(pTerm->pTerm);
+ }
}
}
@@ -228905,6 +240445,7 @@ static Fts5ExprPhrase *wx_sqlite3Fts5ParseTerm(
memset(&sCtx, 0, sizeof(TokenCtx));
sCtx.pPhrase = pAppend;
+ sCtx.pConfig = pConfig;
rc = fts5ParseStringFromToken(pToken, &z);
if( rc==SQLITE_OK ){
@@ -228936,6 +240477,7 @@ static Fts5ExprPhrase *wx_sqlite3Fts5ParseTerm(
}else if( sCtx.pPhrase->nTerm ){
sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix;
}
+ assert( pParse->apPhrase!=0 );
pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
}
@@ -228952,12 +240494,15 @@ static int wx_sqlite3Fts5ExprClonePhrase(
Fts5Expr **ppNew
){
int rc = SQLITE_OK; /* Return code */
- Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */
+ Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */
Fts5Expr *pNew = 0; /* Expression to return via *ppNew */
- TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */
-
- pOrig = pExpr->apExprPhrase[iPhrase];
- pNew = (Fts5Expr*)wx_sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
+ TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */
+ if( !pExpr || iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ rc = SQLITE_RANGE;
+ }else{
+ pOrig = pExpr->apExprPhrase[iPhrase];
+ pNew = (Fts5Expr*)wx_sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
+ }
if( rc==SQLITE_OK ){
pNew->apExprPhrase = (Fts5ExprPhrase**)wx_sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprPhrase*));
@@ -228970,7 +240515,7 @@ static int wx_sqlite3Fts5ExprClonePhrase(
pNew->pRoot->pNear = (Fts5ExprNearset*)wx_sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
}
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
if( pColsetOrig ){
wx_sqlite3_int64 nByte;
@@ -228984,26 +240529,27 @@ static int wx_sqlite3Fts5ExprClonePhrase(
}
}
- if( pOrig->nTerm ){
- int i; /* Used to iterate through phrase terms */
- for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
- int tflags = 0;
- Fts5ExprTerm *p;
- for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
- const char *zTerm = p->zTerm;
- rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
- 0, 0);
- tflags = FTS5_TOKEN_COLOCATED;
- }
- if( rc==SQLITE_OK ){
- sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
- sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
+ if( rc==SQLITE_OK ){
+ if( pOrig->nTerm ){
+ int i; /* Used to iterate through phrase terms */
+ sCtx.pConfig = pExpr->pConfig;
+ for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
+ int tflags = 0;
+ Fts5ExprTerm *p;
+ for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
+ rc = fts5ParseTokenize((void*)&sCtx,tflags,p->pTerm,p->nFullTerm,0,0);
+ tflags = FTS5_TOKEN_COLOCATED;
+ }
+ if( rc==SQLITE_OK ){
+ sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
+ sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
+ }
}
+ }else{
+ /* This happens when parsing a token or quoted phrase that contains
+ ** no token characters at all. (e.g ... MATCH '""'). */
+ sCtx.pPhrase = wx_sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
}
- }else{
- /* This happens when parsing a token or quoted phrase that contains
- ** no token characters at all. (e.g ... MATCH '""'). */
- sCtx.pPhrase = wx_sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
}
if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){
@@ -229319,7 +240865,11 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
}
}
+/*
+** Add pSub as a child of p.
+*/
static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
+ int ii = p->nChild;
if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
int nByte = sizeof(Fts5ExprNode*) * pSub->nChild;
memcpy(&p->apChild[p->nChild], pSub->apChild, nByte);
@@ -229328,6 +240878,9 @@ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
}else{
p->apChild[p->nChild++] = pSub;
}
+ for( ; ii<p->nChild; ii++){
+ p->iHeight = MAX(p->iHeight, p->apChild[ii]->iHeight + 1);
+ }
}
/*
@@ -229358,6 +240911,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
if( pRet ){
pRet->eType = FTS5_AND;
pRet->nChild = nTerm;
+ pRet->iHeight = 1;
fts5ExprAssignXNext(pRet);
pParse->nPhrase--;
for(ii=0; ii<nTerm; ii++){
@@ -229368,11 +240922,13 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
if( parseGrowPhraseArray(pParse) ){
fts5ExprPhraseFree(pPhrase);
}else{
+ Fts5ExprTerm *p = &pNear->apPhrase[0]->aTerm[ii];
+ Fts5ExprTerm *pTo = &pPhrase->aTerm[0];
pParse->apPhrase[pParse->nPhrase++] = pPhrase;
pPhrase->nTerm = 1;
- pPhrase->aTerm[0].zTerm = wx_sqlite3Fts5Strndup(
- &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1
- );
+ pTo->pTerm = wx_sqlite3Fts5Strndup(&pParse->rc, p->pTerm, p->nFullTerm);
+ pTo->nQueryTerm = p->nQueryTerm;
+ pTo->nFullTerm = p->nFullTerm;
pRet->apChild[ii] = wx_sqlite3Fts5ParseNode(pParse, FTS5_STRING,
0, 0, wx_sqlite3Fts5ParseNearset(pParse, 0, pPhrase)
);
@@ -229456,13 +241012,25 @@ static Fts5ExprNode *wx_sqlite3Fts5ParseNode(
"fts5: %s queries are not supported (detail!=full)",
pNear->nPhrase==1 ? "phrase": "NEAR"
);
- wx_sqlite3_free(pRet);
+ wx_sqlite3Fts5ParseNodeFree(pRet);
pRet = 0;
+ pNear = 0;
+ assert( pLeft==0 && pRight==0 );
}
}
}else{
+ assert( pNear==0 );
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
+ pLeft = pRight = 0;
+ if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){
+ wx_sqlite3Fts5ParseError(pParse,
+ "fts5 expression tree is too large (maximum depth %d)",
+ SQLITE_FTS5_MAX_EXPR_DEPTH
+ );
+ wx_sqlite3Fts5ParseNodeFree(pRet);
+ pRet = 0;
+ }
}
}
}
@@ -229498,6 +241066,7 @@ static Fts5ExprNode *wx_sqlite3Fts5ParseImplicitAnd(
assert( pRight->eType==FTS5_STRING
|| pRight->eType==FTS5_TERM
|| pRight->eType==FTS5_EOF
+ || (pRight->eType==FTS5_AND && pParse->bPhraseToAnd)
);
if( pLeft->eType==FTS5_AND ){
@@ -229511,6 +241080,8 @@ static Fts5ExprNode *wx_sqlite3Fts5ParseImplicitAnd(
);
if( pRight->eType==FTS5_EOF ){
+ assert( pParse->apPhrase!=0 );
+ assert( pParse->nPhrase>0 );
assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] );
wx_sqlite3Fts5ParseNodeFree(pRight);
pRet = pLeft;
@@ -229541,7 +241112,7 @@ static Fts5ExprNode *wx_sqlite3Fts5ParseImplicitAnd(
return pRet;
}
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
wx_sqlite3_int64 nByte = 0;
Fts5ExprTerm *p;
@@ -229549,16 +241120,17 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
/* Determine the maximum amount of space required. */
for(p=pTerm; p; p=p->pSynonym){
- nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
+ nByte += pTerm->nQueryTerm * 2 + 3 + 2;
}
zQuoted = wx_sqlite3_malloc64(nByte);
if( zQuoted ){
int i = 0;
for(p=pTerm; p; p=p->pSynonym){
- char *zIn = p->zTerm;
+ char *zIn = p->pTerm;
+ char *zEnd = &zIn[p->nQueryTerm];
zQuoted[i++] = '"';
- while( *zIn ){
+ while( zIn<zEnd ){
if( *zIn=='"' ) zQuoted[i++] = '"';
zQuoted[i++] = *zIn++;
}
@@ -229636,8 +241208,10 @@ static char *fts5ExprPrintTcl(
zRet = fts5PrintfAppend(zRet, " {");
for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
- char *zTerm = pPhrase->aTerm[iTerm].zTerm;
- zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
+ Fts5ExprTerm *p = &pPhrase->aTerm[iTerm];
+ zRet = fts5PrintfAppend(zRet, "%s%.*s", iTerm==0?"":" ",
+ p->nQueryTerm, p->pTerm
+ );
if( pPhrase->aTerm[iTerm].bPrefix ){
zRet = fts5PrintfAppend(zRet, "*");
}
@@ -229647,6 +241221,8 @@ static char *fts5ExprPrintTcl(
if( zRet==0 ) return 0;
}
+ }else if( pExpr->eType==0 ){
+ zRet = wx_sqlite3_mprintf("{}");
}else{
char const *zOp = 0;
int i;
@@ -229908,14 +241484,14 @@ static void fts5ExprFold(
wx_sqlite3_result_int(pCtx, wx_sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics));
}
}
-#endif /* ifdef SQLITE_TEST */
+#endif /* if SQLITE_TEST || SQLITE_FTS5_DEBUG */
/*
** This is called during initialization to register the fts5_expr() scalar
** UDF with the SQLite handle passed as the only argument.
*/
static int wx_sqlite3Fts5ExprInit(Fts5Global *pGlobal, wx_sqlite3 *db){
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
struct Fts5ExprFunc {
const char *z;
void (*x)(wx_sqlite3_context*,int,wx_sqlite3_value**);
@@ -230036,6 +241612,17 @@ static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){
return 0;
}
+/*
+** pToken is a buffer nToken bytes in size that may or may not contain
+** an embedded 0x00 byte. If it does, return the number of bytes in
+** the buffer before the 0x00. If it does not, return nToken.
+*/
+static int fts5QueryTerm(const char *pToken, int nToken){
+ int ii;
+ for(ii=0; ii<nToken && pToken[ii]; ii++){}
+ return ii;
+}
+
static int fts5ExprPopulatePoslistsCb(
void *pCtx, /* Copy of 2nd argument to xTokenize() */
int tflags, /* Mask of FTS5_TOKEN_* flags */
@@ -230047,22 +241634,33 @@ static int fts5ExprPopulatePoslistsCb(
Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx;
Fts5Expr *pExpr = p->pExpr;
int i;
+ int nQuery = nToken;
+ i64 iRowid = pExpr->pRoot->iRowid;
UNUSED_PARAM2(iUnused1, iUnused2);
- if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
+ if( nQuery>FTS5_MAX_TOKEN_SIZE ) nQuery = FTS5_MAX_TOKEN_SIZE;
+ if( pExpr->pConfig->bTokendata ){
+ nQuery = fts5QueryTerm(pToken, nQuery);
+ }
if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
for(i=0; i<pExpr->nPhrase; i++){
- Fts5ExprTerm *pTerm;
+ Fts5ExprTerm *pT;
if( p->aPopulator[i].bOk==0 ) continue;
- for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
- int nTerm = (int)strlen(pTerm->zTerm);
- if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
- && memcmp(pTerm->zTerm, pToken, nTerm)==0
+ for(pT=&pExpr->apExprPhrase[i]->aTerm[0]; pT; pT=pT->pSynonym){
+ if( (pT->nQueryTerm==nQuery || (pT->nQueryTerm<nQuery && pT->bPrefix))
+ && memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0
){
int rc = wx_sqlite3Fts5PoslistWriterAppend(
&pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
);
+ if( rc==SQLITE_OK && pExpr->pConfig->bTokendata && !pT->bPrefix ){
+ int iCol = p->iOff>>32;
+ int iTokOff = p->iOff & 0x7FFFFFFF;
+ rc = wx_sqlite3Fts5IndexIterWriteTokendata(
+ pT->pIter, pToken, nToken, iRowid, iCol, iTokOff
+ );
+ }
if( rc ) return rc;
break;
}
@@ -230116,6 +241714,7 @@ static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){
pNode->iRowid = iRowid;
pNode->bEof = 0;
switch( pNode->eType ){
+ case 0:
case FTS5_TERM:
case FTS5_STRING:
return (pNode->pNear->apPhrase[0]->poslist.n>0);
@@ -230199,6 +241798,83 @@ static int wx_sqlite3Fts5ExprPhraseCollist(
}
/*
+** Does the work of the fts5_api.xQueryToken() API method.
+*/
+static int wx_sqlite3Fts5ExprQueryToken(
+ Fts5Expr *pExpr,
+ int iPhrase,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5ExprPhrase *pPhrase = 0;
+
+ if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ return SQLITE_RANGE;
+ }
+ pPhrase = pExpr->apExprPhrase[iPhrase];
+ if( iToken<0 || iToken>=pPhrase->nTerm ){
+ return SQLITE_RANGE;
+ }
+
+ *ppOut = pPhrase->aTerm[iToken].pTerm;
+ *pnOut = pPhrase->aTerm[iToken].nFullTerm;
+ return SQLITE_OK;
+}
+
+/*
+** Does the work of the fts5_api.xInstToken() API method.
+*/
+static int wx_sqlite3Fts5ExprInstToken(
+ Fts5Expr *pExpr,
+ i64 iRowid,
+ int iPhrase,
+ int iCol,
+ int iOff,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5ExprPhrase *pPhrase = 0;
+ Fts5ExprTerm *pTerm = 0;
+ int rc = SQLITE_OK;
+
+ if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ return SQLITE_RANGE;
+ }
+ pPhrase = pExpr->apExprPhrase[iPhrase];
+ if( iToken<0 || iToken>=pPhrase->nTerm ){
+ return SQLITE_RANGE;
+ }
+ pTerm = &pPhrase->aTerm[iToken];
+ if( pTerm->bPrefix==0 ){
+ if( pExpr->pConfig->bTokendata ){
+ rc = wx_sqlite3Fts5IterToken(
+ pTerm->pIter, iRowid, iCol, iOff+iToken, ppOut, pnOut
+ );
+ }else{
+ *ppOut = pTerm->pTerm;
+ *pnOut = pTerm->nFullTerm;
+ }
+ }
+ return rc;
+}
+
+/*
+** Clear the token mappings for all Fts5IndexIter objects mannaged by
+** the expression passed as the only argument.
+*/
+static void wx_sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){
+ int ii;
+ for(ii=0; ii<pExpr->nPhrase; ii++){
+ Fts5ExprTerm *pT;
+ for(pT=&pExpr->apExprPhrase[ii]->aTerm[0]; pT; pT=pT->pSynonym){
+ wx_sqlite3Fts5IndexIterClearTokendata(pT->pIter);
+ }
+ }
+}
+
+/*
** 2014 August 11
**
** The author disclaims copyright to this source code. In place of
@@ -230236,10 +241912,15 @@ struct Fts5Hash {
/*
** Each entry in the hash table is represented by an object of the
-** following type. Each object, its key (a nul-terminated string) and
-** its current data are stored in a single memory allocation. The
-** key immediately follows the object in memory. The position list
-** data immediately follows the key data in memory.
+** following type. Each object, its key, and its current data are stored
+** in a single memory allocation. The key immediately follows the object
+** in memory. The position list data immediately follows the key data
+** in memory.
+**
+** The key is Fts5HashEntry.nKey bytes in size. It consists of a single
+** byte identifying the index (either the main term index or a prefix-index),
+** followed by the term data. For example: "0token". There is no
+** nul-terminator - in this case nKey=6.
**
** The data that follows the key is in a similar, but not identical format
** to the doclist data stored in the database. It is:
@@ -230374,8 +242055,7 @@ static int fts5HashResize(Fts5Hash *pHash){
unsigned int iHash;
Fts5HashEntry *p = apOld[i];
apOld[i] = p->pHashNext;
- iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p),
- (int)strlen(fts5EntryKey(p)));
+ iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), p->nKey);
p->pHashNext = apNew[iHash];
apNew[iHash] = p;
}
@@ -230459,7 +242139,7 @@ static int wx_sqlite3Fts5HashWrite(
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
char *zKey = fts5EntryKey(p);
if( zKey[0]==bByte
- && p->nKey==nToken
+ && p->nKey==nToken+1
&& memcmp(&zKey[1], pToken, nToken)==0
){
break;
@@ -230489,9 +242169,9 @@ static int wx_sqlite3Fts5HashWrite(
zKey[0] = bByte;
memcpy(&zKey[1], pToken, nToken);
assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) );
- p->nKey = nToken;
+ p->nKey = nToken+1;
zKey[nToken+1] = '\0';
- p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry);
+ p->nData = nToken+1 + sizeof(Fts5HashEntry);
p->pHashNext = pHash->aSlot[iHash];
pHash->aSlot[iHash] = p;
pHash->nEntry++;
@@ -230608,12 +242288,17 @@ static Fts5HashEntry *fts5HashEntryMerge(
*ppOut = p1;
p1 = 0;
}else{
- int i = 0;
char *zKey1 = fts5EntryKey(p1);
char *zKey2 = fts5EntryKey(p2);
- while( zKey1[i]==zKey2[i] ) i++;
+ int nMin = MIN(p1->nKey, p2->nKey);
- if( ((u8)zKey1[i])>((u8)zKey2[i]) ){
+ int cmp = memcmp(zKey1, zKey2, nMin);
+ if( cmp==0 ){
+ cmp = p1->nKey - p2->nKey;
+ }
+ assert( cmp!=0 );
+
+ if( cmp>0 ){
/* p2 is smaller */
*ppOut = p2;
ppOut = &p2->pScanNext;
@@ -230632,10 +242317,8 @@ static Fts5HashEntry *fts5HashEntryMerge(
}
/*
-** Extract all tokens from hash table iHash and link them into a list
-** in sorted order. The hash table is cleared before returning. It is
-** the responsibility of the caller to free the elements of the returned
-** list.
+** Link all tokens from hash table iHash into a list in sorted order. The
+** tokens are not removed from the hash table.
*/
static int fts5HashEntrySort(
Fts5Hash *pHash,
@@ -230657,7 +242340,7 @@ static int fts5HashEntrySort(
Fts5HashEntry *pIter;
for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
if( pTerm==0
- || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
+ || (pIter->nKey>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
){
Fts5HashEntry *pEntry = pIter;
pEntry->pScanNext = 0;
@@ -230675,7 +242358,6 @@ static int fts5HashEntrySort(
pList = fts5HashEntryMerge(pList, ap[i]);
}
- pHash->nEntry = 0;
wx_sqlite3_free(ap);
*ppSorted = pList;
return SQLITE_OK;
@@ -230697,12 +242379,11 @@ static int wx_sqlite3Fts5HashQuery(
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
zKey = fts5EntryKey(p);
- assert( p->nKey+1==(int)strlen(zKey) );
- if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break;
+ if( nTerm==p->nKey && memcmp(zKey, pTerm, nTerm)==0 ) break;
}
if( p ){
- int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1;
+ int nHashPre = sizeof(Fts5HashEntry) + nTerm;
int nList = p->nData - nHashPre;
u8 *pRet = (u8*)(*ppOut = wx_sqlite3_malloc64(nPre + nList + 10));
if( pRet ){
@@ -230729,6 +242410,28 @@ static int wx_sqlite3Fts5HashScanInit(
return fts5HashEntrySort(p, pTerm, nTerm, &p->pScan);
}
+#ifdef SQLITE_DEBUG
+static int fts5HashCount(Fts5Hash *pHash){
+ int nEntry = 0;
+ int ii;
+ for(ii=0; ii<pHash->nSlot; ii++){
+ Fts5HashEntry *p = 0;
+ for(p=pHash->aSlot[ii]; p; p=p->pHashNext){
+ nEntry++;
+ }
+ }
+ return nEntry;
+}
+#endif
+
+/*
+** Return true if the hash table is empty, false otherwise.
+*/
+static int wx_sqlite3Fts5HashIsEmpty(Fts5Hash *pHash){
+ assert( pHash->nEntry==fts5HashCount(pHash) );
+ return pHash->nEntry==0;
+}
+
static void wx_sqlite3Fts5HashScanNext(Fts5Hash *p){
assert( !wx_sqlite3Fts5HashScanEof(p) );
p->pScan = p->pScan->pScanNext;
@@ -230741,19 +242444,22 @@ static int wx_sqlite3Fts5HashScanEof(Fts5Hash *p){
static void wx_sqlite3Fts5HashScanEntry(
Fts5Hash *pHash,
const char **pzTerm, /* OUT: term (nul-terminated) */
+ int *pnTerm, /* OUT: Size of term in bytes */
const u8 **ppDoclist, /* OUT: pointer to doclist */
int *pnDoclist /* OUT: size of doclist in bytes */
){
Fts5HashEntry *p;
if( (p = pHash->pScan) ){
char *zKey = fts5EntryKey(p);
- int nTerm = (int)strlen(zKey);
+ int nTerm = p->nKey;
fts5HashAddPoslistSize(pHash, p, 0);
*pzTerm = zKey;
- *ppDoclist = (const u8*)&zKey[nTerm+1];
- *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
+ *pnTerm = nTerm;
+ *ppDoclist = (const u8*)&zKey[nTerm];
+ *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm);
}else{
*pzTerm = 0;
+ *pnTerm = 0;
*ppDoclist = 0;
*pnDoclist = 0;
}
@@ -230818,13 +242524,31 @@ static void wx_sqlite3Fts5HashScanEntry(
#define FTS5_MAX_LEVEL 64
/*
+** There are two versions of the format used for the structure record:
+**
+** 1. the legacy format, that may be read by all fts5 versions, and
+**
+** 2. the V2 format, which is used by contentless_delete=1 databases.
+**
+** Both begin with a 4-byte "configuration cookie" value. Then, a legacy
+** format structure record contains a varint - the number of levels in
+** the structure. Whereas a V2 structure record contains the constant
+** 4 bytes [0xff 0x00 0x00 0x01]. This is unambiguous as the value of a
+** varint has to be at least 16256 to begin with "0xFF". And the default
+** maximum number of levels is 64.
+**
+** See below for more on structure record formats.
+*/
+#define FTS5_STRUCTURE_V2 "\xFF\x00\x00\x01"
+
+/*
** Details:
**
** The %_data table managed by this module,
**
** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB);
**
-** , contains the following 5 types of records. See the comments surrounding
+** , contains the following 6 types of records. See the comments surrounding
** the FTS5_*_ROWID macros below for a description of how %_data rowids are
** assigned to each fo them.
**
@@ -230833,12 +242557,12 @@ static void wx_sqlite3Fts5HashScanEntry(
** The set of segments that make up an index - the index structure - are
** recorded in a single record within the %_data table. The record consists
** of a single 32-bit configuration cookie value followed by a list of
-** SQLite varints. If the FTS table features more than one index (because
-** there are one or more prefix indexes), it is guaranteed that all share
-** the same cookie value.
+** SQLite varints.
+**
+** If the structure record is a V2 record, the configuration cookie is
+** followed by the following 4 bytes: [0xFF 0x00 0x00 0x01].
**
-** Immediately following the configuration cookie, the record begins with
-** three varints:
+** Next, the record continues with three varints:
**
** + number of levels,
** + total number of segments on all levels,
@@ -230853,6 +242577,12 @@ static void wx_sqlite3Fts5HashScanEntry(
** + first leaf page number (often 1, always greater than 0)
** + final leaf page number
**
+** Then, for V2 structures only:
+**
+** + lower origin counter value,
+** + upper origin counter value,
+** + the number of tombstone hash pages.
+**
** 2. The Averages Record:
**
** A single record within the %_data table. The data is a list of varints.
@@ -230968,6 +242698,38 @@ static void wx_sqlite3Fts5HashScanEntry(
** * A list of delta-encoded varints - the first rowid on each subsequent
** child page.
**
+** 6. Tombstone Hash Page
+**
+** These records are only ever present in contentless_delete=1 tables.
+** There are zero or more of these associated with each segment. They
+** are used to store the tombstone rowids for rows contained in the
+** associated segments.
+**
+** The set of nHashPg tombstone hash pages associated with a single
+** segment together form a single hash table containing tombstone rowids.
+** To find the page of the hash on which a key might be stored:
+**
+** iPg = (rowid % nHashPg)
+**
+** Then, within page iPg, which has nSlot slots:
+**
+** iSlot = (rowid / nHashPg) % nSlot
+**
+** Each tombstone hash page begins with an 8 byte header:
+**
+** 1-byte: Key-size (the size in bytes of each slot). Either 4 or 8.
+** 1-byte: rowid-0-tombstone flag. This flag is only valid on the
+** first tombstone hash page for each segment (iPg=0). If set,
+** the hash table contains rowid 0. If clear, it does not.
+** Rowid 0 is handled specially.
+** 2-bytes: unused.
+** 4-bytes: Big-endian integer containing number of entries on page.
+**
+** Following this are nSlot 4 or 8 byte slots (depending on the key-size
+** in the first byte of the page header). The number of slots may be
+** determined based on the size of the page record and the key-size:
+**
+** nSlot = (nByte - 8) / key-size
*/
/*
@@ -231001,6 +242763,7 @@ static void wx_sqlite3Fts5HashScanEntry(
#define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno)
#define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno)
+#define FTS5_TOMBSTONE_ROWID(segid,ipg) fts5_dri(segid+(1<<16), 0, 0, ipg)
#ifdef SQLITE_DEBUG
static int wx_sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; }
@@ -231027,6 +242790,9 @@ typedef struct Fts5SegWriter Fts5SegWriter;
typedef struct Fts5Structure Fts5Structure;
typedef struct Fts5StructureLevel Fts5StructureLevel;
typedef struct Fts5StructureSegment Fts5StructureSegment;
+typedef struct Fts5TokenDataIter Fts5TokenDataIter;
+typedef struct Fts5TokenDataMap Fts5TokenDataMap;
+typedef struct Fts5TombstoneArray Fts5TombstoneArray;
struct Fts5Data {
u8 *p; /* Pointer to buffer containing record */
@@ -231036,6 +242802,12 @@ struct Fts5Data {
/*
** One object per %_data table.
+**
+** nContentlessDelete:
+** The number of contentless delete operations since the most recent
+** call to fts5IndexFlush() or fts5IndexDiscardData(). This is tracked
+** so that extra auto-merge work can be done by fts5IndexFlush() to
+** account for the delete operations.
*/
struct Fts5Index {
Fts5Config *pConfig; /* Virtual table configuration */
@@ -231050,9 +242822,12 @@ struct Fts5Index {
int nPendingData; /* Current bytes of pending data */
i64 iWriteRowid; /* Rowid for current doc being written */
int bDelete; /* Current write is a delete */
+ int nContentlessDelete; /* Number of contentless delete ops */
+ int nPendingRow; /* Number of INSERT in hash table */
/* Error state. */
int rc; /* Current error code */
+ int flushRc;
/* State used by the fts5DataXXX() functions. */
wx_sqlite3_blob *pReader; /* RO incr-blob open on %_data table */
@@ -231061,8 +242836,11 @@ struct Fts5Index {
wx_sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */
wx_sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=?" */
wx_sqlite3_stmt *pIdxSelect;
+ wx_sqlite3_stmt *pIdxNextSelect;
int nRead; /* Total number of blocks read */
+ wx_sqlite3_stmt *pDeleteFromIdx;
+
wx_sqlite3_stmt *pDataVersion;
i64 iStructVersion; /* data_version when pStruct read */
Fts5Structure *pStruct; /* Current db structure (or NULL) */
@@ -231082,11 +242860,23 @@ struct Fts5DoclistIter {
** The contents of the "structure" record for each index are represented
** using an Fts5Structure record in memory. Which uses instances of the
** other Fts5StructureXXX types as components.
+**
+** nOriginCntr:
+** This value is set to non-zero for structure records created for
+** contentlessdelete=1 tables only. In that case it represents the
+** origin value to apply to the next top-level segment created.
*/
struct Fts5StructureSegment {
int iSegid; /* Segment id */
int pgnoFirst; /* First leaf page number in segment */
int pgnoLast; /* Last leaf page number in segment */
+
+ /* contentlessdelete=1 tables only: */
+ u64 iOrigin1;
+ u64 iOrigin2;
+ int nPgTombstone; /* Number of tombstone hash table pages */
+ u64 nEntryTombstone; /* Number of tombstone entries that "count" */
+ u64 nEntry; /* Number of rows in this segment */
};
struct Fts5StructureLevel {
int nMerge; /* Number of segments in incr-merge */
@@ -231096,6 +242886,7 @@ struct Fts5StructureLevel {
struct Fts5Structure {
int nRef; /* Object reference count */
u64 nWriteCounter; /* Total leaves written to level 0 */
+ u64 nOriginCntr; /* Origin value for next top-level segment */
int nSegment; /* Total segments in this structure */
int nLevel; /* Number of levels in this index */
Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */
@@ -231155,9 +242946,6 @@ struct Fts5CResult {
** iLeafOffset:
** Byte offset within the current leaf that is the first byte of the
** position list data (one byte passed the position-list size field).
-** rowid field of the current entry. Usually this is the size field of the
-** position list data. The exception is if the rowid for the current entry
-** is the last thing on the leaf page.
**
** pLeaf:
** Buffer containing current leaf page data. Set to NULL at EOF.
@@ -231187,6 +242975,13 @@ struct Fts5CResult {
**
** iTermIdx:
** Index of current term on iTermLeafPgno.
+**
+** apTombstone/nTombstone:
+** These are used for contentless_delete=1 tables only. When the cursor
+** is first allocated, the apTombstone[] array is allocated so that it
+** is large enough for all tombstones hash pages associated with the
+** segment. The pages themselves are loaded lazily from the database as
+** they are required.
*/
struct Fts5SegIter {
Fts5StructureSegment *pSeg; /* Segment to iterate through */
@@ -231195,6 +242990,7 @@ struct Fts5SegIter {
Fts5Data *pLeaf; /* Current leaf data */
Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */
i64 iLeafOffset; /* Byte offset within current leaf */
+ Fts5TombstoneArray *pTombArray; /* Array of tombstone pages */
/* Next method */
void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
@@ -231222,6 +243018,15 @@ struct Fts5SegIter {
};
/*
+** Array of tombstone pages. Reference counted.
+*/
+struct Fts5TombstoneArray {
+ int nRef; /* Number of pointers to this object */
+ int nTombstone;
+ Fts5Data *apTombstone[1]; /* Array of tombstone pages */
+};
+
+/*
** Argument is a pointer to an Fts5Data structure that contains a
** leaf page.
*/
@@ -231265,9 +243070,16 @@ struct Fts5SegIter {
** poslist:
** Used by wx_sqlite3Fts5IterPoslist() when the poslist needs to be buffered.
** There is no way to tell if this is populated or not.
+**
+** pColset:
+** If not NULL, points to an object containing a set of column indices.
+** Only matches that occur in one of these columns will be returned.
+** The Fts5Iter does not own the Fts5Colset object, and so it is not
+** freed when the iterator is closed - it is owned by the upper layer.
*/
struct Fts5Iter {
Fts5IndexIter base; /* Base class containing output vars */
+ Fts5TokenDataIter *pTokenDataIter;
Fts5Index *pIndex; /* Index that owns this iterator */
Fts5Buffer poslist; /* Buffer containing current poslist */
@@ -231285,7 +243097,6 @@ struct Fts5Iter {
Fts5SegIter aSeg[1]; /* Array of segment iterators */
};
-
/*
** An instance of the following type is used to iterate through the contents
** of a doclist-index record.
@@ -231325,6 +243136,60 @@ static u16 fts5GetU16(const u8 *aIn){
}
/*
+** The only argument points to a buffer at least 8 bytes in size. This
+** function interprets the first 8 bytes of the buffer as a 64-bit big-endian
+** unsigned integer and returns the result.
+*/
+static u64 fts5GetU64(u8 *a){
+ return ((u64)a[0] << 56)
+ + ((u64)a[1] << 48)
+ + ((u64)a[2] << 40)
+ + ((u64)a[3] << 32)
+ + ((u64)a[4] << 24)
+ + ((u64)a[5] << 16)
+ + ((u64)a[6] << 8)
+ + ((u64)a[7] << 0);
+}
+
+/*
+** The only argument points to a buffer at least 4 bytes in size. This
+** function interprets the first 4 bytes of the buffer as a 32-bit big-endian
+** unsigned integer and returns the result.
+*/
+static u32 fts5GetU32(const u8 *a){
+ return ((u32)a[0] << 24)
+ + ((u32)a[1] << 16)
+ + ((u32)a[2] << 8)
+ + ((u32)a[3] << 0);
+}
+
+/*
+** Write iVal, formated as a 64-bit big-endian unsigned integer, to the
+** buffer indicated by the first argument.
+*/
+static void fts5PutU64(u8 *a, u64 iVal){
+ a[0] = ((iVal >> 56) & 0xFF);
+ a[1] = ((iVal >> 48) & 0xFF);
+ a[2] = ((iVal >> 40) & 0xFF);
+ a[3] = ((iVal >> 32) & 0xFF);
+ a[4] = ((iVal >> 24) & 0xFF);
+ a[5] = ((iVal >> 16) & 0xFF);
+ a[6] = ((iVal >> 8) & 0xFF);
+ a[7] = ((iVal >> 0) & 0xFF);
+}
+
+/*
+** Write iVal, formated as a 32-bit big-endian unsigned integer, to the
+** buffer indicated by the first argument.
+*/
+static void fts5PutU32(u8 *a, u32 iVal){
+ a[0] = ((iVal >> 24) & 0xFF);
+ a[1] = ((iVal >> 16) & 0xFF);
+ a[2] = ((iVal >> 8) & 0xFF);
+ a[3] = ((iVal >> 0) & 0xFF);
+}
+
+/*
** Allocate and return a buffer at least nByte bytes in size.
**
** If an OOM error is encountered, return NULL and set the error code in
@@ -231433,11 +243298,12 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
if( rc==SQLITE_OK ){
u8 *aOut = 0; /* Read blob data into this buffer */
int nByte = wx_sqlite3_blob_bytes(p->pReader);
- wx_sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
+ int szData = (sizeof(Fts5Data) + 7) & ~7;
+ wx_sqlite3_int64 nAlloc = szData + nByte + FTS5_DATA_PADDING;
pRet = (Fts5Data*)wx_sqlite3_malloc64(nAlloc);
if( pRet ){
pRet->nn = nByte;
- aOut = pRet->p = (u8*)&pRet[1];
+ aOut = pRet->p = (u8*)pRet + szData;
}else{
rc = SQLITE_NOMEM;
}
@@ -231460,6 +243326,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
}
assert( (pRet==0)==(p->rc!=SQLITE_OK) );
+ assert( pRet==0 || EIGHT_BYTE_ALIGNMENT( pRet->p ) );
return pRet;
}
@@ -231551,10 +243418,17 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
/*
** Remove all records associated with segment iSegid.
*/
-static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){
+static void fts5DataRemoveSegment(Fts5Index *p, Fts5StructureSegment *pSeg){
+ int iSegid = pSeg->iSegid;
i64 iFirst = FTS5_SEGMENT_ROWID(iSegid, 0);
i64 iLast = FTS5_SEGMENT_ROWID(iSegid+1, 0)-1;
fts5DataDelete(p, iFirst, iLast);
+
+ if( pSeg->nPgTombstone ){
+ i64 iTomb1 = FTS5_TOMBSTONE_ROWID(iSegid, 0);
+ i64 iTomb2 = FTS5_TOMBSTONE_ROWID(iSegid, pSeg->nPgTombstone-1);
+ fts5DataDelete(p, iTomb1, iTomb2);
+ }
if( p->pIdxDeleter==0 ){
Fts5Config *pConfig = p->pConfig;
fts5IndexPrepareStmt(p, &p->pIdxDeleter, wx_sqlite3_mprintf(
@@ -231665,11 +243539,19 @@ static int fts5StructureDecode(
int nSegment = 0;
wx_sqlite3_int64 nByte; /* Bytes of space to allocate at pRet */
Fts5Structure *pRet = 0; /* Structure object to return */
+ int bStructureV2 = 0; /* True for FTS5_STRUCTURE_V2 */
+ u64 nOriginCntr = 0; /* Largest origin value seen so far */
/* Grab the cookie value */
if( piCookie ) *piCookie = wx_sqlite3Fts5Get32(pData);
i = 4;
+ /* Check if this is a V2 structure record. Set bStructureV2 if it is. */
+ if( 0==memcmp(&pData[i], FTS5_STRUCTURE_V2, 4) ){
+ i += 4;
+ bStructureV2 = 1;
+ }
+
/* Read the total number of levels and segments from the start of the
** structure record. */
i += fts5GetVarint32(&pData[i], nLevel);
@@ -231716,9 +243598,18 @@ static int fts5StructureDecode(
rc = FTS5_CORRUPT;
break;
}
+ assert( pSeg!=0 );
i += fts5GetVarint32(&pData[i], pSeg->iSegid);
i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst);
i += fts5GetVarint32(&pData[i], pSeg->pgnoLast);
+ if( bStructureV2 ){
+ i += fts5GetVarint(&pData[i], &pSeg->iOrigin1);
+ i += fts5GetVarint(&pData[i], &pSeg->iOrigin2);
+ i += fts5GetVarint32(&pData[i], pSeg->nPgTombstone);
+ i += fts5GetVarint(&pData[i], &pSeg->nEntryTombstone);
+ i += fts5GetVarint(&pData[i], &pSeg->nEntry);
+ nOriginCntr = MAX(nOriginCntr, pSeg->iOrigin2);
+ }
if( pSeg->pgnoLast<pSeg->pgnoFirst ){
rc = FTS5_CORRUPT;
break;
@@ -231729,6 +243620,9 @@ static int fts5StructureDecode(
}
}
if( nSegment!=0 && rc==SQLITE_OK ) rc = FTS5_CORRUPT;
+ if( bStructureV2 ){
+ pRet->nOriginCntr = nOriginCntr+1;
+ }
if( rc!=SQLITE_OK ){
fts5StructureRelease(pRet);
@@ -231746,6 +243640,7 @@ static int fts5StructureDecode(
*/
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
fts5StructureMakeWritable(pRc, ppStruct);
+ assert( (ppStruct!=0 && (*ppStruct)!=0) || (*pRc)!=SQLITE_OK );
if( *pRc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
int nLevel = pStruct->nLevel;
@@ -231940,6 +243835,7 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
Fts5Buffer buf; /* Buffer to serialize record into */
int iLvl; /* Used to iterate through levels */
int iCookie; /* Cookie value to store */
+ int nHdr = (pStruct->nOriginCntr>0 ? (4+4+9+9+9) : (4+9+9));
assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
memset(&buf, 0, sizeof(Fts5Buffer));
@@ -231948,9 +243844,12 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
iCookie = p->pConfig->iCookie;
if( iCookie<0 ) iCookie = 0;
- if( 0==wx_sqlite3Fts5BufferSize(&p->rc, &buf, 4+9+9+9) ){
+ if( 0==wx_sqlite3Fts5BufferSize(&p->rc, &buf, nHdr) ){
wx_sqlite3Fts5Put32(buf.p, iCookie);
buf.n = 4;
+ if( pStruct->nOriginCntr>0 ){
+ fts5BufferSafeAppendBlob(&buf, FTS5_STRUCTURE_V2, 4);
+ }
fts5BufferSafeAppendVarint(&buf, pStruct->nLevel);
fts5BufferSafeAppendVarint(&buf, pStruct->nSegment);
fts5BufferSafeAppendVarint(&buf, (i64)pStruct->nWriteCounter);
@@ -231964,9 +243863,17 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
assert( pLvl->nMerge<=pLvl->nSeg );
for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].iSegid);
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoFirst);
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoLast);
+ Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iSegid);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->pgnoFirst);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->pgnoLast);
+ if( pStruct->nOriginCntr>0 ){
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iOrigin1);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iOrigin2);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nPgTombstone);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nEntryTombstone);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nEntry);
+ }
}
}
@@ -232109,9 +244016,9 @@ static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){
}
if( iOff<pData->nn ){
- i64 iVal;
+ u64 iVal;
pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1;
- iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal);
+ iOff += fts5GetVarint(&pData->p[iOff], &iVal);
pLvl->iRowid += iVal;
pLvl->iOff = iOff;
}else{
@@ -232204,42 +244111,25 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
pLvl->bEof = 1;
}else{
u8 *a = pLvl->pData->p;
- i64 iVal;
- int iLimit;
- int ii;
- int nZero = 0;
-
- /* Currently iOff points to the first byte of a varint. This block
- ** decrements iOff until it points to the first byte of the previous
- ** varint. Taking care not to read any memory locations that occur
- ** before the buffer in memory. */
- iLimit = (iOff>9 ? iOff-9 : 0);
- for(iOff--; iOff>iLimit; iOff--){
- if( (a[iOff-1] & 0x80)==0 ) break;
- }
-
- fts5GetVarint(&a[iOff], (u64*)&iVal);
- pLvl->iRowid -= iVal;
- pLvl->iLeafPgno--;
-
- /* Skip backwards past any 0x00 varints. */
- for(ii=iOff-1; ii>=pLvl->iFirstOff && a[ii]==0x00; ii--){
- nZero++;
- }
- if( ii>=pLvl->iFirstOff && (a[ii] & 0x80) ){
- /* The byte immediately before the last 0x00 byte has the 0x80 bit
- ** set. So the last 0x00 is only a varint 0 if there are 8 more 0x80
- ** bytes before a[ii]. */
- int bZero = 0; /* True if last 0x00 counts */
- if( (ii-8)>=pLvl->iFirstOff ){
- int j;
- for(j=1; j<=8 && (a[ii-j] & 0x80); j++);
- bZero = (j>8);
+
+ pLvl->iOff = 0;
+ fts5DlidxLvlNext(pLvl);
+ while( 1 ){
+ int nZero = 0;
+ int ii = pLvl->iOff;
+ u64 delta = 0;
+
+ while( a[ii]==0 ){
+ nZero++;
+ ii++;
}
- if( bZero==0 ) nZero--;
+ ii += wx_sqlite3Fts5GetVarint(&a[ii], &delta);
+
+ if( ii>=iOff ) break;
+ pLvl->iLeafPgno += nZero+1;
+ pLvl->iRowid += delta;
+ pLvl->iOff = ii;
}
- pLvl->iLeafPgno -= nZero;
- pLvl->iOff = iOff - nZero;
}
return pLvl->bEof;
@@ -232435,7 +244325,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
i64 iOff = pIter->iLeafOffset;
ASSERT_SZLEAF_OK(pIter->pLeaf);
- if( iOff>=pIter->pLeaf->szLeaf ){
+ while( iOff>=pIter->pLeaf->szLeaf ){
fts5SegIterNextPage(p, pIter);
if( pIter->pLeaf==0 ){
if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
@@ -232507,6 +244397,25 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
}
/*
+** Allocate a tombstone hash page array object (pIter->pTombArray) for
+** the iterator passed as the second argument. If an OOM error occurs,
+** leave an error in the Fts5Index object.
+*/
+static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
+ const int nTomb = pIter->pSeg->nPgTombstone;
+ if( nTomb>0 ){
+ int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray);
+ Fts5TombstoneArray *pNew;
+ pNew = (Fts5TombstoneArray*)wx_sqlite3Fts5MallocZero(&p->rc, nByte);
+ if( pNew ){
+ pNew->nTombstone = nTomb;
+ pNew->nRef = 1;
+ pIter->pTombArray = pNew;
+ }
+ }
+}
+
+/*
** Initialize the iterator object pIter to iterate through the entries in
** segment pSeg. The iterator is left pointing to the first entry when
** this function returns.
@@ -232534,10 +244443,12 @@ static void fts5SegIterInit(
fts5SegIterSetNext(p, pIter);
pIter->pSeg = pSeg;
pIter->iLeafPgno = pSeg->pgnoFirst-1;
- fts5SegIterNextPage(p, pIter);
+ do {
+ fts5SegIterNextPage(p, pIter);
+ }while( p->rc==SQLITE_OK && pIter->pLeaf && pIter->pLeaf->nn==4 );
}
- if( p->rc==SQLITE_OK ){
+ if( p->rc==SQLITE_OK && pIter->pLeaf ){
pIter->iLeafOffset = 4;
assert( pIter->pLeaf!=0 );
assert_nc( pIter->pLeaf->nn>4 );
@@ -232545,6 +244456,7 @@ static void fts5SegIterInit(
pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
fts5SegIterLoadTerm(p, pIter, 0);
fts5SegIterLoadNPos(p, pIter);
+ fts5SegIterAllocTombstone(p, pIter);
}
}
@@ -232731,7 +244643,7 @@ static void fts5SegIterNext_None(
iOff = pIter->iLeafOffset;
/* Next entry is on the next page */
- if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
+ while( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
fts5SegIterNextPage(p, pIter);
if( p->rc || pIter->pLeaf==0 ) return;
pIter->iRowid = 0;
@@ -232740,7 +244652,7 @@ static void fts5SegIterNext_None(
if( iOff<pIter->iEndofDoclist ){
/* Next entry is on the current page */
- i64 iDelta;
+ u64 iDelta;
iOff += wx_sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
pIter->iLeafOffset = iOff;
pIter->iRowid += iDelta;
@@ -232755,15 +244667,16 @@ static void fts5SegIterNext_None(
}else{
const u8 *pList = 0;
const char *zTerm = 0;
+ int nTerm = 0;
int nList;
wx_sqlite3Fts5HashScanNext(p->pHash);
- wx_sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
+ wx_sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList);
if( pList==0 ) goto next_none_eof;
pIter->pLeaf->p = (u8*)pList;
pIter->pLeaf->nn = nList;
pIter->pLeaf->szLeaf = nList;
pIter->iEndofDoclist = nList;
- wx_sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm);
+ wx_sqlite3Fts5BufferSet(&p->rc,&pIter->term, nTerm, (u8*)zTerm);
pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
}
@@ -232829,11 +244742,12 @@ static void fts5SegIterNext(
}else if( pIter->pSeg==0 ){
const u8 *pList = 0;
const char *zTerm = 0;
+ int nTerm = 0;
int nList = 0;
assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
wx_sqlite3Fts5HashScanNext(p->pHash);
- wx_sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
+ wx_sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList);
}
if( pList==0 ){
fts5DataRelease(pIter->pLeaf);
@@ -232843,8 +244757,7 @@ static void fts5SegIterNext(
pIter->pLeaf->nn = nList;
pIter->pLeaf->szLeaf = nList;
pIter->iEndofDoclist = nList+1;
- wx_sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
- (u8*)zTerm);
+ wx_sqlite3Fts5BufferSet(&p->rc, &pIter->term, nTerm, (u8*)zTerm);
pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
*pbNewTerm = 1;
}
@@ -232924,7 +244837,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
Fts5Data *pLast = 0;
int pgnoLast = 0;
- if( pDlidx ){
+ if( pDlidx && p->pConfig->iVersion==FTS5_CURRENT_VERSION ){
int iSegid = pIter->pSeg->iSegid;
pgnoLast = fts5DlidxIterPgno(pDlidx);
pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
@@ -233230,7 +245143,7 @@ static void fts5SegIterSeekInit(
fts5LeafSeek(p, bGe, pIter, pTerm, nTerm);
}
- if( p->rc==SQLITE_OK && bGe==0 ){
+ if( p->rc==SQLITE_OK && (bGe==0 || (flags & FTS5INDEX_QUERY_SCANONETERM)) ){
pIter->flags |= FTS5_SEGITER_ONETERM;
if( pIter->pLeaf ){
if( flags & FTS5INDEX_QUERY_DESC ){
@@ -233246,6 +245159,9 @@ static void fts5SegIterSeekInit(
}
fts5SegIterSetNext(p, pIter);
+ if( 0==(flags & FTS5INDEX_QUERY_SCANONETERM) ){
+ fts5SegIterAllocTombstone(p, pIter);
+ }
/* Either:
**
@@ -233262,6 +245178,79 @@ static void fts5SegIterSeekInit(
);
}
+
+/*
+** SQL used by fts5SegIterNextInit() to find the page to open.
+*/
+static wx_sqlite3_stmt *fts5IdxNextStmt(Fts5Index *p){
+ if( p->pIdxNextSelect==0 ){
+ Fts5Config *pConfig = p->pConfig;
+ fts5IndexPrepareStmt(p, &p->pIdxNextSelect, wx_sqlite3_mprintf(
+ "SELECT pgno FROM '%q'.'%q_idx' WHERE "
+ "segid=? AND term>? ORDER BY term ASC LIMIT 1",
+ pConfig->zDb, pConfig->zName
+ ));
+
+ }
+ return p->pIdxNextSelect;
+}
+
+/*
+** This is similar to fts5SegIterSeekInit(), except that it initializes
+** the segment iterator to point to the first term following the page
+** with pToken/nToken on it.
+*/
+static void fts5SegIterNextInit(
+ Fts5Index *p,
+ const char *pTerm, int nTerm,
+ Fts5StructureSegment *pSeg, /* Description of segment */
+ Fts5SegIter *pIter /* Object to populate */
+){
+ int iPg = -1; /* Page of segment to open */
+ int bDlidx = 0;
+ wx_sqlite3_stmt *pSel = 0; /* SELECT to find iPg */
+
+ pSel = fts5IdxNextStmt(p);
+ if( pSel ){
+ assert( p->rc==SQLITE_OK );
+ wx_sqlite3_bind_int(pSel, 1, pSeg->iSegid);
+ wx_sqlite3_bind_blob(pSel, 2, pTerm, nTerm, SQLITE_STATIC);
+
+ if( wx_sqlite3_step(pSel)==SQLITE_ROW ){
+ i64 val = wx_sqlite3_column_int64(pSel, 0);
+ iPg = (int)(val>>1);
+ bDlidx = (val & 0x0001);
+ }
+ p->rc = wx_sqlite3_reset(pSel);
+ wx_sqlite3_bind_null(pSel, 2);
+ if( p->rc ) return;
+ }
+
+ memset(pIter, 0, sizeof(*pIter));
+ pIter->pSeg = pSeg;
+ pIter->flags |= FTS5_SEGITER_ONETERM;
+ if( iPg>=0 ){
+ pIter->iLeafPgno = iPg - 1;
+ fts5SegIterNextPage(p, pIter);
+ fts5SegIterSetNext(p, pIter);
+ }
+ if( pIter->pLeaf ){
+ const u8 *a = pIter->pLeaf->p;
+ int iTermOff = 0;
+
+ pIter->iPgidxOff = pIter->pLeaf->szLeaf;
+ pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], iTermOff);
+ pIter->iLeafOffset = iTermOff;
+ fts5SegIterLoadTerm(p, pIter, 0);
+ fts5SegIterLoadNPos(p, pIter);
+ if( bDlidx ) fts5SegIterLoadDlidx(p, pIter);
+
+ assert( p->rc!=SQLITE_OK ||
+ fts5BufferCompareBlob(&pIter->term, (const u8*)pTerm, nTerm)>0
+ );
+ }
+}
+
/*
** Initialize the object pIter to point to term pTerm/nTerm within the
** in-memory hash table. If there is no such term in the hash-table, the
@@ -233288,14 +245277,21 @@ static void fts5SegIterHashInit(
const u8 *pList = 0;
p->rc = wx_sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm);
- wx_sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList);
- n = (z ? (int)strlen((const char*)z) : 0);
+ wx_sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &n, &pList, &nList);
if( pList ){
pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
if( pLeaf ){
pLeaf->p = (u8*)pList;
}
}
+
+ /* The call to wx_sqlite3Fts5HashScanInit() causes the hash table to
+ ** fill the size field of all existing position lists. This means they
+ ** can no longer be appended to. Since the only scenario in which they
+ ** can be appended to is if the previous operation on this table was
+ ** a DELETE, by clearing the Fts5Index.bDelete flag we can avoid this
+ ** possibility altogether. */
+ p->bDelete = 0;
}else{
p->rc = wx_sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data),
(const char*)pTerm, nTerm, (void**)&pLeaf, &nList
@@ -233327,12 +245323,44 @@ static void fts5SegIterHashInit(
}
/*
+** Array ap[] contains n elements. Release each of these elements using
+** fts5DataRelease(). Then free the array itself using wx_sqlite3_free().
+*/
+static void fts5IndexFreeArray(Fts5Data **ap, int n){
+ if( ap ){
+ int ii;
+ for(ii=0; ii<n; ii++){
+ fts5DataRelease(ap[ii]);
+ }
+ wx_sqlite3_free(ap);
+ }
+}
+
+/*
+** Decrement the ref-count of the object passed as the only argument. If it
+** reaches 0, free it and its contents.
+*/
+static void fts5TombstoneArrayDelete(Fts5TombstoneArray *p){
+ if( p ){
+ p->nRef--;
+ if( p->nRef<=0 ){
+ int ii;
+ for(ii=0; ii<p->nTombstone; ii++){
+ fts5DataRelease(p->apTombstone[ii]);
+ }
+ wx_sqlite3_free(p);
+ }
+ }
+}
+
+/*
** Zero the iterator passed as the only argument.
*/
static void fts5SegIterClear(Fts5SegIter *pIter){
fts5BufferFree(&pIter->term);
fts5DataRelease(pIter->pLeaf);
fts5DataRelease(pIter->pNextLeaf);
+ fts5TombstoneArrayDelete(pIter->pTombArray);
fts5DlidxIterFree(pIter->pDlidx);
wx_sqlite3_free(pIter->aRowidOffset);
memset(pIter, 0, sizeof(Fts5SegIter));
@@ -233466,7 +245494,6 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
assert_nc( i2!=0 );
pRes->bTermEq = 1;
if( p1->iRowid==p2->iRowid ){
- p1->bDel = p2->bDel;
return i2;
}
res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1;
@@ -233485,7 +245512,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
/*
** Move the seg-iter so that it points to the first rowid on page iLeafPgno.
-** It is an error if leaf iLeafPgno does not exist or contains no rowids.
+** It is an error if leaf iLeafPgno does not exist. Unless the db is
+** a 'secure-delete' db, if it contains no rowids then this is also an error.
*/
static void fts5SegIterGotoPage(
Fts5Index *p, /* FTS5 backend object */
@@ -233500,21 +245528,23 @@ static void fts5SegIterGotoPage(
fts5DataRelease(pIter->pNextLeaf);
pIter->pNextLeaf = 0;
pIter->iLeafPgno = iLeafPgno-1;
- fts5SegIterNextPage(p, pIter);
- assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno );
- if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){
+ while( p->rc==SQLITE_OK ){
int iOff;
- u8 *a = pIter->pLeaf->p;
- int n = pIter->pLeaf->szLeaf;
-
+ fts5SegIterNextPage(p, pIter);
+ if( pIter->pLeaf==0 ) break;
iOff = fts5LeafFirstRowidOff(pIter->pLeaf);
- if( iOff<4 || iOff>=n ){
- p->rc = FTS5_CORRUPT;
- }else{
- iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
- pIter->iLeafOffset = iOff;
- fts5SegIterLoadNPos(p, pIter);
+ if( iOff>0 ){
+ u8 *a = pIter->pLeaf->p;
+ int n = pIter->pLeaf->szLeaf;
+ if( iOff<4 || iOff>=n ){
+ p->rc = FTS5_CORRUPT;
+ }else{
+ iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
+ pIter->iLeafOffset = iOff;
+ fts5SegIterLoadNPos(p, pIter);
+ }
+ break;
}
}
}
@@ -233575,7 +245605,6 @@ static void fts5SegIterNextFrom(
}while( p->rc==SQLITE_OK );
}
-
/*
** Free the iterator object passed as the second argument.
*/
@@ -233668,6 +245697,85 @@ static void fts5MultiIterSetEof(Fts5Iter *pIter){
}
/*
+** The argument to this macro must be an Fts5Data structure containing a
+** tombstone hash page. This macro returns the key-size of the hash-page.
+*/
+#define TOMBSTONE_KEYSIZE(pPg) (pPg->p[0]==4 ? 4 : 8)
+
+#define TOMBSTONE_NSLOT(pPg) \
+ ((pPg->nn > 16) ? ((pPg->nn-8) / TOMBSTONE_KEYSIZE(pPg)) : 1)
+
+/*
+** Query a single tombstone hash table for rowid iRowid. Return true if
+** it is found or false otherwise. The tombstone hash table is one of
+** nHashTable tables.
+*/
+static int fts5IndexTombstoneQuery(
+ Fts5Data *pHash, /* Hash table page to query */
+ int nHashTable, /* Number of pages attached to segment */
+ u64 iRowid /* Rowid to query hash for */
+){
+ const int szKey = TOMBSTONE_KEYSIZE(pHash);
+ const int nSlot = TOMBSTONE_NSLOT(pHash);
+ int iSlot = (iRowid / nHashTable) % nSlot;
+ int nCollide = nSlot;
+
+ if( iRowid==0 ){
+ return pHash->p[1];
+ }else if( szKey==4 ){
+ u32 *aSlot = (u32*)&pHash->p[8];
+ while( aSlot[iSlot] ){
+ if( fts5GetU32((u8*)&aSlot[iSlot])==iRowid ) return 1;
+ if( nCollide--==0 ) break;
+ iSlot = (iSlot+1)%nSlot;
+ }
+ }else{
+ u64 *aSlot = (u64*)&pHash->p[8];
+ while( aSlot[iSlot] ){
+ if( fts5GetU64((u8*)&aSlot[iSlot])==iRowid ) return 1;
+ if( nCollide--==0 ) break;
+ iSlot = (iSlot+1)%nSlot;
+ }
+ }
+
+ return 0;
+}
+
+/*
+** Return true if the iterator passed as the only argument points
+** to an segment entry for which there is a tombstone. Return false
+** if there is no tombstone or if the iterator is already at EOF.
+*/
+static int fts5MultiIterIsDeleted(Fts5Iter *pIter){
+ int iFirst = pIter->aFirst[1].iFirst;
+ Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
+ Fts5TombstoneArray *pArray = pSeg->pTombArray;
+
+ if( pSeg->pLeaf && pArray ){
+ /* Figure out which page the rowid might be present on. */
+ int iPg = ((u64)pSeg->iRowid) % pArray->nTombstone;
+ assert( iPg>=0 );
+
+ /* If tombstone hash page iPg has not yet been loaded from the
+ ** database, load it now. */
+ if( pArray->apTombstone[iPg]==0 ){
+ pArray->apTombstone[iPg] = fts5DataRead(pIter->pIndex,
+ FTS5_TOMBSTONE_ROWID(pSeg->pSeg->iSegid, iPg)
+ );
+ if( pArray->apTombstone[iPg]==0 ) return 0;
+ }
+
+ return fts5IndexTombstoneQuery(
+ pArray->apTombstone[iPg],
+ pArray->nTombstone,
+ pSeg->iRowid
+ );
+ }
+
+ return 0;
+}
+
+/*
** Move the iterator to the next entry.
**
** If an error occurs, an error code is left in Fts5Index.rc. It is not
@@ -233704,7 +245812,9 @@ static void fts5MultiIterNext(
fts5AssertMultiIterSetup(p, pIter);
assert( pSeg==&pIter->aSeg[pIter->aFirst[1].iFirst] && pSeg->pLeaf );
- if( pIter->bSkipEmpty==0 || pSeg->nPos ){
+ if( (pIter->bSkipEmpty==0 || pSeg->nPos)
+ && 0==fts5MultiIterIsDeleted(pIter)
+ ){
pIter->xSetOutputs(pIter, pSeg);
return;
}
@@ -233736,7 +245846,9 @@ static void fts5MultiIterNext2(
}
fts5AssertMultiIterSetup(p, pIter);
- }while( fts5MultiIterIsEmpty(p, pIter) );
+ }while( (fts5MultiIterIsEmpty(p, pIter) || fts5MultiIterIsDeleted(pIter))
+ && (p->rc==SQLITE_OK)
+ );
}
}
@@ -233749,7 +245861,7 @@ static Fts5Iter *fts5MultiIterAlloc(
int nSeg
){
Fts5Iter *pNew;
- int nSlot; /* Power of two >= nSeg */
+ i64 nSlot; /* Power of two >= nSeg */
for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
pNew = fts5IdxMalloc(p,
@@ -234194,6 +246306,32 @@ static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
}
}
+/*
+** All the component segment-iterators of pIter have been set up. This
+** functions finishes setup for iterator pIter itself.
+*/
+static void fts5MultiIterFinishSetup(Fts5Index *p, Fts5Iter *pIter){
+ int iIter;
+ for(iIter=pIter->nSeg-1; iIter>0; iIter--){
+ int iEq;
+ if( (iEq = fts5MultiIterDoCompare(pIter, iIter)) ){
+ Fts5SegIter *pSeg = &pIter->aSeg[iEq];
+ if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
+ fts5MultiIterAdvanced(p, pIter, iEq, iIter);
+ }
+ }
+ fts5MultiIterSetEof(pIter);
+ fts5AssertMultiIterSetup(p, pIter);
+
+ if( (pIter->bSkipEmpty && fts5MultiIterIsEmpty(p, pIter))
+ || fts5MultiIterIsDeleted(pIter)
+ ){
+ fts5MultiIterNext(p, pIter, 0, 0);
+ }else if( pIter->base.bEof==0 ){
+ Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
+ pIter->xSetOutputs(pIter, pSeg);
+ }
+}
/*
** Allocate a new Fts5Iter object.
@@ -234229,7 +246367,7 @@ static void fts5MultiIterNew(
if( iLevel<0 ){
assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
nSeg = pStruct->nSegment;
- nSeg += (p->pHash ? 1 : 0);
+ nSeg += (p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH));
}else{
nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment);
}
@@ -234250,7 +246388,7 @@ static void fts5MultiIterNew(
if( p->rc==SQLITE_OK ){
if( iLevel<0 ){
Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
- if( p->pHash ){
+ if( p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH) ){
/* Add a segment iterator for the current contents of the hash table. */
Fts5SegIter *pIter = &pNew->aSeg[iIter++];
fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
@@ -234275,29 +246413,12 @@ static void fts5MultiIterNew(
assert( iIter==nSeg );
}
- /* If the above was successful, each component iterators now points
+ /* If the above was successful, each component iterator now points
** to the first entry in its segment. In this case initialize the
** aFirst[] array. Or, if an error has occurred, free the iterator
** object and set the output variable to NULL. */
if( p->rc==SQLITE_OK ){
- for(iIter=pNew->nSeg-1; iIter>0; iIter--){
- int iEq;
- if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
- Fts5SegIter *pSeg = &pNew->aSeg[iEq];
- if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
- fts5MultiIterAdvanced(p, pNew, iEq, iIter);
- }
- }
- fts5MultiIterSetEof(pNew);
- fts5AssertMultiIterSetup(p, pNew);
-
- if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){
- fts5MultiIterNext(p, pNew, 0, 0);
- }else if( pNew->base.bEof==0 ){
- Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst];
- pNew->xSetOutputs(pNew, pSeg);
- }
-
+ fts5MultiIterFinishSetup(p, pNew);
}else{
fts5MultiIterFree(pNew);
*ppOut = 0;
@@ -234322,7 +246443,6 @@ static void fts5MultiIterNew2(
pNew = fts5MultiIterAlloc(p, 2);
if( pNew ){
Fts5SegIter *pIter = &pNew->aSeg[1];
-
pIter->flags = FTS5_SEGITER_ONETERM;
if( pData->szLeaf>0 ){
pIter->pLeaf = pData;
@@ -234469,7 +246589,10 @@ static void fts5IndexDiscardData(Fts5Index *p){
if( p->pHash ){
wx_sqlite3Fts5HashClear(p->pHash);
p->nPendingData = 0;
+ p->nPendingRow = 0;
+ p->flushRc = SQLITE_OK;
}
+ p->nContentlessDelete = 0;
}
/*
@@ -234683,7 +246806,7 @@ static void fts5WriteDlidxAppend(
}
if( pDlidx->bPrevValid ){
- iVal = iRowid - pDlidx->iPrev;
+ iVal = (u64)iRowid - (u64)pDlidx->iPrev;
}else{
i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno);
assert( pDlidx->buf.n==0 );
@@ -234870,7 +246993,7 @@ static void fts5WriteAppendPoslistData(
const u8 *a = aData;
int n = nData;
- assert( p->pConfig->pgsz>0 );
+ assert( p->pConfig->pgsz>0 || p->rc!=SQLITE_OK );
while( p->rc==SQLITE_OK
&& (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz
){
@@ -235005,7 +247128,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
- fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]);
+ fts5BufferAppendBlob(&p->rc, &buf,pData->szLeaf-iOff,&pData->p[iOff]);
if( p->rc==SQLITE_OK ){
/* Set the szLeaf field */
fts5PutU16(&buf.p[2], (u16)buf.n);
@@ -235106,6 +247229,12 @@ static void fts5IndexMergeLevel(
/* Read input from all segments in the input level */
nInput = pLvl->nSeg;
+
+ /* Set the range of origins that will go into the output segment. */
+ if( pStruct->nOriginCntr>0 ){
+ pSeg->iOrigin1 = pLvl->aSeg[0].iOrigin1;
+ pSeg->iOrigin2 = pLvl->aSeg[pLvl->nSeg-1].iOrigin2;
+ }
}
bOldest = (pLvlOut->nSeg==1 && pStruct->nLevel==iLvl+2);
@@ -235165,8 +247294,11 @@ static void fts5IndexMergeLevel(
int i;
/* Remove the redundant segments from the %_data table */
+ assert( pSeg->nEntry==0 );
for(i=0; i<nInput; i++){
- fts5DataRemoveSegment(p, pLvl->aSeg[i].iSegid);
+ Fts5StructureSegment *pOld = &pLvl->aSeg[i];
+ pSeg->nEntry += (pOld->nEntry - pOld->nEntryTombstone);
+ fts5DataRemoveSegment(p, pOld);
}
/* Remove the redundant segments from the input level */
@@ -235193,6 +247325,48 @@ static void fts5IndexMergeLevel(
}
/*
+** If this is not a contentless_delete=1 table, or if the 'deletemerge'
+** configuration option is set to 0, then this function always returns -1.
+** Otherwise, it searches the structure object passed as the second argument
+** for a level suitable for merging due to having a large number of
+** tombstones in the tombstone hash. If one is found, its index is returned.
+** Otherwise, if there is no suitable level, -1.
+*/
+static int fts5IndexFindDeleteMerge(Fts5Index *p, Fts5Structure *pStruct){
+ Fts5Config *pConfig = p->pConfig;
+ int iRet = -1;
+ if( pConfig->bContentlessDelete && pConfig->nDeleteMerge>0 ){
+ int ii;
+ int nBest = 0;
+
+ for(ii=0; ii<pStruct->nLevel; ii++){
+ Fts5StructureLevel *pLvl = &pStruct->aLevel[ii];
+ i64 nEntry = 0;
+ i64 nTomb = 0;
+ int iSeg;
+ for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
+ nEntry += pLvl->aSeg[iSeg].nEntry;
+ nTomb += pLvl->aSeg[iSeg].nEntryTombstone;
+ }
+ assert_nc( nEntry>0 || pLvl->nSeg==0 );
+ if( nEntry>0 ){
+ int nPercent = (nTomb * 100) / nEntry;
+ if( nPercent>=pConfig->nDeleteMerge && nPercent>nBest ){
+ iRet = ii;
+ nBest = nPercent;
+ }
+ }
+
+ /* If pLvl is already the input level to an ongoing merge, look no
+ ** further for a merge candidate. The caller should be allowed to
+ ** continue merging from pLvl first. */
+ if( pLvl->nMerge ) break;
+ }
+ }
+ return iRet;
+}
+
+/*
** Do up to nPg pages of automerge work on the index.
**
** Return true if any changes were actually made, or false otherwise.
@@ -235211,14 +247385,15 @@ static int fts5IndexMerge(
int iBestLvl = 0; /* Level offering the most input segments */
int nBest = 0; /* Number of input segments on best level */
- /* Set iBestLvl to the level to read input segments from. */
+ /* Set iBestLvl to the level to read input segments from. Or to -1 if
+ ** there is no level suitable to merge segments from. */
assert( pStruct->nLevel>0 );
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
if( pLvl->nMerge ){
if( pLvl->nMerge>nBest ){
iBestLvl = iLvl;
- nBest = pLvl->nMerge;
+ nBest = nMin;
}
break;
}
@@ -235227,22 +247402,18 @@ static int fts5IndexMerge(
iBestLvl = iLvl;
}
}
-
- /* If nBest is still 0, then the index must be empty. */
-#ifdef SQLITE_DEBUG
- for(iLvl=0; nBest==0 && iLvl<pStruct->nLevel; iLvl++){
- assert( pStruct->aLevel[iLvl].nSeg==0 );
+ if( nBest<nMin ){
+ iBestLvl = fts5IndexFindDeleteMerge(p, pStruct);
}
-#endif
- if( nBest<nMin && pStruct->aLevel[iBestLvl].nMerge==0 ){
- break;
- }
+ if( iBestLvl<0 ) break;
bRet = 1;
fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem);
if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
fts5StructurePromote(p, iBestLvl+1, pStruct);
}
+
+ if( nMin==1 ) nMin = 2;
}
*ppStruct = pStruct;
return bRet;
@@ -235283,16 +247454,16 @@ static void fts5IndexCrisismerge(
){
const int nCrisis = p->pConfig->nCrisisMerge;
Fts5Structure *pStruct = *ppStruct;
- int iLvl = 0;
-
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 );
- while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
- fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
- fts5StructurePromote(p, iLvl+1, pStruct);
- iLvl++;
+ if( pStruct && pStruct->nLevel>0 ){
+ int iLvl = 0;
+ while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
+ fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
+ assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
+ fts5StructurePromote(p, iLvl+1, pStruct);
+ iLvl++;
+ }
+ *ppStruct = pStruct;
}
- *ppStruct = pStruct;
}
static int fts5IndexReturn(Fts5Index *p){
@@ -235327,6 +247498,469 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
}
/*
+** Execute the SQL statement:
+**
+** DELETE FROM %_idx WHERE (segid, (pgno/2)) = ($iSegid, $iPgno);
+**
+** This is used when a secure-delete operation removes the last term
+** from a segment leaf page. In that case the %_idx entry is removed
+** too. This is done to ensure that if all instances of a token are
+** removed from an fts5 database in secure-delete mode, no trace of
+** the token itself remains in the database.
+*/
+static void fts5SecureDeleteIdxEntry(
+ Fts5Index *p, /* FTS5 backend object */
+ int iSegid, /* Id of segment to delete entry for */
+ int iPgno /* Page number within segment */
+){
+ if( iPgno!=1 ){
+ assert( p->pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE );
+ if( p->pDeleteFromIdx==0 ){
+ fts5IndexPrepareStmt(p, &p->pDeleteFromIdx, wx_sqlite3_mprintf(
+ "DELETE FROM '%q'.'%q_idx' WHERE (segid, (pgno/2)) = (?1, ?2)",
+ p->pConfig->zDb, p->pConfig->zName
+ ));
+ }
+ if( p->rc==SQLITE_OK ){
+ wx_sqlite3_bind_int(p->pDeleteFromIdx, 1, iSegid);
+ wx_sqlite3_bind_int(p->pDeleteFromIdx, 2, iPgno);
+ wx_sqlite3_step(p->pDeleteFromIdx);
+ p->rc = wx_sqlite3_reset(p->pDeleteFromIdx);
+ }
+ }
+}
+
+/*
+** This is called when a secure-delete operation removes a position-list
+** that overflows onto segment page iPgno of segment pSeg. This function
+** rewrites node iPgno, and possibly one or more of its right-hand peers,
+** to remove this portion of the position list.
+**
+** Output variable (*pbLastInDoclist) is set to true if the position-list
+** removed is followed by a new term or the end-of-segment, or false if
+** it is followed by another rowid/position list.
+*/
+static void fts5SecureDeleteOverflow(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg,
+ int iPgno,
+ int *pbLastInDoclist
+){
+ const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
+ int pgno;
+ Fts5Data *pLeaf = 0;
+ assert( iPgno!=1 );
+
+ *pbLastInDoclist = 1;
+ for(pgno=iPgno; p->rc==SQLITE_OK && pgno<=pSeg->pgnoLast; pgno++){
+ i64 iRowid = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno);
+ int iNext = 0;
+ u8 *aPg = 0;
+
+ pLeaf = fts5DataRead(p, iRowid);
+ if( pLeaf==0 ) break;
+ aPg = pLeaf->p;
+
+ iNext = fts5GetU16(&aPg[0]);
+ if( iNext!=0 ){
+ *pbLastInDoclist = 0;
+ }
+ if( iNext==0 && pLeaf->szLeaf!=pLeaf->nn ){
+ fts5GetVarint32(&aPg[pLeaf->szLeaf], iNext);
+ }
+
+ if( iNext==0 ){
+ /* The page contains no terms or rowids. Replace it with an empty
+ ** page and move on to the right-hand peer. */
+ const u8 aEmpty[] = {0x00, 0x00, 0x00, 0x04};
+ assert_nc( bDetailNone==0 || pLeaf->nn==4 );
+ if( bDetailNone==0 ) fts5DataWrite(p, iRowid, aEmpty, sizeof(aEmpty));
+ fts5DataRelease(pLeaf);
+ pLeaf = 0;
+ }else if( bDetailNone ){
+ break;
+ }else if( iNext>=pLeaf->szLeaf || pLeaf->nn<pLeaf->szLeaf || iNext<4 ){
+ p->rc = FTS5_CORRUPT;
+ break;
+ }else{
+ int nShift = iNext - 4;
+ int nPg;
+
+ int nIdx = 0;
+ u8 *aIdx = 0;
+
+ /* Unless the current page footer is 0 bytes in size (in which case
+ ** the new page footer will be as well), allocate and populate a
+ ** buffer containing the new page footer. Set stack variables aIdx
+ ** and nIdx accordingly. */
+ if( pLeaf->nn>pLeaf->szLeaf ){
+ int iFirst = 0;
+ int i1 = pLeaf->szLeaf;
+ int i2 = 0;
+
+ i1 += fts5GetVarint32(&aPg[i1], iFirst);
+ if( iFirst<iNext ){
+ p->rc = FTS5_CORRUPT;
+ break;
+ }
+ aIdx = wx_sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2);
+ if( aIdx==0 ) break;
+ i2 = wx_sqlite3Fts5PutVarint(aIdx, iFirst-nShift);
+ if( i1<pLeaf->nn ){
+ memcpy(&aIdx[i2], &aPg[i1], pLeaf->nn-i1);
+ i2 += (pLeaf->nn-i1);
+ }
+ nIdx = i2;
+ }
+
+ /* Modify the contents of buffer aPg[]. Set nPg to the new size
+ ** in bytes. The new page is always smaller than the old. */
+ nPg = pLeaf->szLeaf - nShift;
+ memmove(&aPg[4], &aPg[4+nShift], nPg-4);
+ fts5PutU16(&aPg[2], nPg);
+ if( fts5GetU16(&aPg[0]) ) fts5PutU16(&aPg[0], 4);
+ if( nIdx>0 ){
+ memcpy(&aPg[nPg], aIdx, nIdx);
+ nPg += nIdx;
+ }
+ wx_sqlite3_free(aIdx);
+
+ /* Write the new page to disk and exit the loop */
+ assert( nPg>4 || fts5GetU16(aPg)==0 );
+ fts5DataWrite(p, iRowid, aPg, nPg);
+ break;
+ }
+ }
+ fts5DataRelease(pLeaf);
+}
+
+/*
+** Completely remove the entry that pSeg currently points to from
+** the database.
+*/
+static void fts5DoSecureDelete(
+ Fts5Index *p,
+ Fts5SegIter *pSeg
+){
+ const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
+ int iSegid = pSeg->pSeg->iSegid;
+ u8 *aPg = pSeg->pLeaf->p;
+ int nPg = pSeg->pLeaf->nn;
+ int iPgIdx = pSeg->pLeaf->szLeaf;
+
+ u64 iDelta = 0;
+ int iNextOff = 0;
+ int iOff = 0;
+ int nIdx = 0;
+ u8 *aIdx = 0;
+ int bLastInDoclist = 0;
+ int iIdx = 0;
+ int iStart = 0;
+ int iDelKeyOff = 0; /* Offset of deleted key, if any */
+
+ nIdx = nPg-iPgIdx;
+ aIdx = wx_sqlite3Fts5MallocZero(&p->rc, nIdx+16);
+ if( p->rc ) return;
+ memcpy(aIdx, &aPg[iPgIdx], nIdx);
+
+ /* At this point segment iterator pSeg points to the entry
+ ** this function should remove from the b-tree segment.
+ **
+ ** In detail=full or detail=column mode, pSeg->iLeafOffset is the
+ ** offset of the first byte in the position-list for the entry to
+ ** remove. Immediately before this comes two varints that will also
+ ** need to be removed:
+ **
+ ** + the rowid or delta rowid value for the entry, and
+ ** + the size of the position list in bytes.
+ **
+ ** Or, in detail=none mode, there is a single varint prior to
+ ** pSeg->iLeafOffset - the rowid or delta rowid value.
+ **
+ ** This block sets the following variables:
+ **
+ ** iStart:
+ ** The offset of the first byte of the rowid or delta-rowid
+ ** value for the doclist entry being removed.
+ **
+ ** iDelta:
+ ** The value of the rowid or delta-rowid value for the doclist
+ ** entry being removed.
+ **
+ ** iNextOff:
+ ** The offset of the next entry following the position list
+ ** for the one being removed. If the position list for this
+ ** entry overflows onto the next leaf page, this value will be
+ ** greater than pLeaf->szLeaf.
+ */
+ {
+ int iSOP; /* Start-Of-Position-list */
+ if( pSeg->iLeafPgno==pSeg->iTermLeafPgno ){
+ iStart = pSeg->iTermLeafOffset;
+ }else{
+ iStart = fts5GetU16(&aPg[0]);
+ }
+
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ assert_nc( iSOP<=pSeg->iLeafOffset );
+
+ if( bDetailNone ){
+ while( iSOP<pSeg->iLeafOffset ){
+ if( aPg[iSOP]==0x00 ) iSOP++;
+ if( aPg[iSOP]==0x00 ) iSOP++;
+ iStart = iSOP;
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ }
+
+ iNextOff = iSOP;
+ if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
+ if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
+
+ }else{
+ int nPos = 0;
+ iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
+ while( iSOP<pSeg->iLeafOffset ){
+ iStart = iSOP + (nPos/2);
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
+ }
+ assert_nc( iSOP==pSeg->iLeafOffset );
+ iNextOff = pSeg->iLeafOffset + pSeg->nPos;
+ }
+ }
+
+ iOff = iStart;
+
+ /* If the position-list for the entry being removed flows over past
+ ** the end of this page, delete the portion of the position-list on the
+ ** next page and beyond.
+ **
+ ** Set variable bLastInDoclist to true if this entry happens
+ ** to be the last rowid in the doclist for its term. */
+ if( iNextOff>=iPgIdx ){
+ int pgno = pSeg->iLeafPgno+1;
+ fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
+ iNextOff = iPgIdx;
+ }
+
+ if( pSeg->bDel==0 ){
+ if( iNextOff!=iPgIdx ){
+ /* Loop through the page-footer. If iNextOff (offset of the
+ ** entry following the one we are removing) is equal to the
+ ** offset of a key on this page, then the entry is the last
+ ** in its doclist. */
+ int iKeyOff = 0;
+ for(iIdx=0; iIdx<nIdx; /* no-op */){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ iKeyOff += iVal;
+ if( iKeyOff==iNextOff ){
+ bLastInDoclist = 1;
+ }
+ }
+ }
+
+ /* If this is (a) the first rowid on a page and (b) is not followed by
+ ** another position list on the same page, set the "first-rowid" field
+ ** of the header to 0. */
+ if( fts5GetU16(&aPg[0])==iStart && (bLastInDoclist || iNextOff==iPgIdx) ){
+ fts5PutU16(&aPg[0], 0);
+ }
+ }
+
+ if( pSeg->bDel ){
+ iOff += wx_sqlite3Fts5PutVarint(&aPg[iOff], iDelta);
+ aPg[iOff++] = 0x01;
+ }else if( bLastInDoclist==0 ){
+ if( iNextOff!=iPgIdx ){
+ u64 iNextDelta = 0;
+ iNextOff += fts5GetVarint(&aPg[iNextOff], &iNextDelta);
+ iOff += wx_sqlite3Fts5PutVarint(&aPg[iOff], iDelta + iNextDelta);
+ }
+ }else if(
+ pSeg->iLeafPgno==pSeg->iTermLeafPgno
+ && iStart==pSeg->iTermLeafOffset
+ ){
+ /* The entry being removed was the only position list in its
+ ** doclist. Therefore the term needs to be removed as well. */
+ int iKey = 0;
+ int iKeyOff = 0;
+
+ /* Set iKeyOff to the offset of the term that will be removed - the
+ ** last offset in the footer that is not greater than iStart. */
+ for(iIdx=0; iIdx<nIdx; iKey++){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ if( (iKeyOff+iVal)>(u32)iStart ) break;
+ iKeyOff += iVal;
+ }
+ assert_nc( iKey>=1 );
+
+ /* Set iDelKeyOff to the value of the footer entry to remove from
+ ** the page. */
+ iDelKeyOff = iOff = iKeyOff;
+
+ if( iNextOff!=iPgIdx ){
+ /* This is the only position-list associated with the term, and there
+ ** is another term following it on this page. So the subsequent term
+ ** needs to be moved to replace the term associated with the entry
+ ** being removed. */
+ int nPrefix = 0;
+ int nSuffix = 0;
+ int nPrefix2 = 0;
+ int nSuffix2 = 0;
+
+ iDelKeyOff = iNextOff;
+ iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2);
+ iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2);
+
+ if( iKey!=1 ){
+ iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix);
+ }
+ iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix);
+
+ nPrefix = MIN(nPrefix, nPrefix2);
+ nSuffix = (nPrefix2 + nSuffix2) - nPrefix;
+
+ if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){
+ p->rc = FTS5_CORRUPT;
+ }else{
+ if( iKey!=1 ){
+ iOff += wx_sqlite3Fts5PutVarint(&aPg[iOff], nPrefix);
+ }
+ iOff += wx_sqlite3Fts5PutVarint(&aPg[iOff], nSuffix);
+ if( nPrefix2>pSeg->term.n ){
+ p->rc = FTS5_CORRUPT;
+ }else if( nPrefix2>nPrefix ){
+ memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix);
+ iOff += (nPrefix2-nPrefix);
+ }
+ memmove(&aPg[iOff], &aPg[iNextOff], nSuffix2);
+ iOff += nSuffix2;
+ iNextOff += nSuffix2;
+ }
+ }
+ }else if( iStart==4 ){
+ int iPgno;
+
+ assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno );
+ /* The entry being removed may be the only position list in
+ ** its doclist. */
+ for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){
+ Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno));
+ int bEmpty = (pPg && pPg->nn==4);
+ fts5DataRelease(pPg);
+ if( bEmpty==0 ) break;
+ }
+
+ if( iPgno==pSeg->iTermLeafPgno ){
+ i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno);
+ Fts5Data *pTerm = fts5DataRead(p, iId);
+ if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){
+ u8 *aTermIdx = &pTerm->p[pTerm->szLeaf];
+ int nTermIdx = pTerm->nn - pTerm->szLeaf;
+ int iTermIdx = 0;
+ int iTermOff = 0;
+
+ while( 1 ){
+ u32 iVal = 0;
+ int nByte = fts5GetVarint32(&aTermIdx[iTermIdx], iVal);
+ iTermOff += iVal;
+ if( (iTermIdx+nByte)>=nTermIdx ) break;
+ iTermIdx += nByte;
+ }
+ nTermIdx = iTermIdx;
+
+ memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
+ fts5PutU16(&pTerm->p[2], iTermOff);
+
+ fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
+ if( nTermIdx==0 ){
+ fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
+ }
+ }
+ fts5DataRelease(pTerm);
+ }
+ }
+
+ /* Assuming no error has occurred, this block does final edits to the
+ ** leaf page before writing it back to disk. Input variables are:
+ **
+ ** nPg: Total initial size of leaf page.
+ ** iPgIdx: Initial offset of page footer.
+ **
+ ** iOff: Offset to move data to
+ ** iNextOff: Offset to move data from
+ */
+ if( p->rc==SQLITE_OK ){
+ const int nMove = nPg - iNextOff; /* Number of bytes to move */
+ int nShift = iNextOff - iOff; /* Distance to move them */
+
+ int iPrevKeyOut = 0;
+ int iKeyIn = 0;
+
+ memmove(&aPg[iOff], &aPg[iNextOff], nMove);
+ iPgIdx -= nShift;
+ nPg = iPgIdx;
+ fts5PutU16(&aPg[2], iPgIdx);
+
+ for(iIdx=0; iIdx<nIdx; /* no-op */){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ iKeyIn += iVal;
+ if( iKeyIn!=iDelKeyOff ){
+ int iKeyOut = (iKeyIn - (iKeyIn>iOff ? nShift : 0));
+ nPg += wx_sqlite3Fts5PutVarint(&aPg[nPg], iKeyOut - iPrevKeyOut);
+ iPrevKeyOut = iKeyOut;
+ }
+ }
+
+ if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){
+ fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iLeafPgno);
+ }
+
+ assert_nc( nPg>4 || fts5GetU16(aPg)==0 );
+ fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg, nPg);
+ }
+ wx_sqlite3_free(aIdx);
+}
+
+/*
+** This is called as part of flushing a delete to disk in 'secure-delete'
+** mode. It edits the segments within the database described by argument
+** pStruct to remove the entries for term zTerm, rowid iRowid.
+*/
+static void fts5FlushSecureDelete(
+ Fts5Index *p,
+ Fts5Structure *pStruct,
+ const char *zTerm,
+ int nTerm,
+ i64 iRowid
+){
+ const int f = FTS5INDEX_QUERY_SKIPHASH;
+ Fts5Iter *pIter = 0; /* Used to find term instance */
+
+ fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter);
+ if( fts5MultiIterEof(p, pIter)==0 ){
+ i64 iThis = fts5MultiIterRowid(pIter);
+ if( iThis<iRowid ){
+ fts5MultiIterNextFrom(p, pIter, iRowid);
+ }
+
+ if( p->rc==SQLITE_OK
+ && fts5MultiIterEof(p, pIter)==0
+ && iRowid==fts5MultiIterRowid(pIter)
+ ){
+ Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
+ fts5DoSecureDelete(p, pSeg);
+ }
+ }
+
+ fts5MultiIterFree(pIter);
+}
+
+
+/*
** Flush the contents of in-memory hash table iHash to a new level-0
** segment on disk. Also update the corresponding structure record.
**
@@ -235342,143 +247976,197 @@ static void fts5FlushOneHash(Fts5Index *p){
/* Obtain a reference to the index structure and allocate a new segment-id
** for the new level-0 segment. */
pStruct = fts5StructureRead(p);
- iSegid = fts5AllocateSegid(p, pStruct);
fts5StructureInvalidate(p);
- if( iSegid ){
- const int pgsz = p->pConfig->pgsz;
- int eDetail = p->pConfig->eDetail;
- Fts5StructureSegment *pSeg; /* New segment within pStruct */
- Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
- Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
+ if( wx_sqlite3Fts5HashIsEmpty(pHash)==0 ){
+ iSegid = fts5AllocateSegid(p, pStruct);
+ if( iSegid ){
+ const int pgsz = p->pConfig->pgsz;
+ int eDetail = p->pConfig->eDetail;
+ int bSecureDelete = p->pConfig->bSecureDelete;
+ Fts5StructureSegment *pSeg; /* New segment within pStruct */
+ Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
+ Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
+
+ Fts5SegWriter writer;
+ fts5WriteInit(p, &writer, iSegid);
+
+ pBuf = &writer.writer.buf;
+ pPgidx = &writer.writer.pgidx;
+
+ /* fts5WriteInit() should have initialized the buffers to (most likely)
+ ** the maximum space required. */
+ assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+ assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+
+ /* Begin scanning through hash table entries. This loop runs once for each
+ ** term/doclist currently stored within the hash table. */
+ if( p->rc==SQLITE_OK ){
+ p->rc = wx_sqlite3Fts5HashScanInit(pHash, 0, 0);
+ }
+ while( p->rc==SQLITE_OK && 0==wx_sqlite3Fts5HashScanEof(pHash) ){
+ const char *zTerm; /* Buffer containing term */
+ int nTerm; /* Size of zTerm in bytes */
+ const u8 *pDoclist; /* Pointer to doclist for this term */
+ int nDoclist; /* Size of doclist in bytes */
- Fts5SegWriter writer;
- fts5WriteInit(p, &writer, iSegid);
+ /* Get the term and doclist for this entry. */
+ wx_sqlite3Fts5HashScanEntry(pHash, &zTerm, &nTerm, &pDoclist, &nDoclist);
+ if( bSecureDelete==0 ){
+ fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
+ if( p->rc!=SQLITE_OK ) break;
+ assert( writer.bFirstRowidInPage==0 );
+ }
- pBuf = &writer.writer.buf;
- pPgidx = &writer.writer.pgidx;
+ if( !bSecureDelete && pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
+ /* The entire doclist will fit on the current leaf. */
+ fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
+ }else{
+ int bTermWritten = !bSecureDelete;
+ i64 iRowid = 0;
+ i64 iPrev = 0;
+ int iOff = 0;
+
+ /* The entire doclist will not fit on this leaf. The following
+ ** loop iterates through the poslists that make up the current
+ ** doclist. */
+ while( p->rc==SQLITE_OK && iOff<nDoclist ){
+ u64 iDelta = 0;
+ iOff += fts5GetVarint(&pDoclist[iOff], &iDelta);
+ iRowid += iDelta;
+
+ /* If in secure delete mode, and if this entry in the poslist is
+ ** in fact a delete, then edit the existing segments directly
+ ** using fts5FlushSecureDelete(). */
+ if( bSecureDelete ){
+ if( eDetail==FTS5_DETAIL_NONE ){
+ if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
+ fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
+ iOff++;
+ if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
+ iOff++;
+ nDoclist = 0;
+ }else{
+ continue;
+ }
+ }
+ }else if( (pDoclist[iOff] & 0x01) ){
+ fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
+ if( p->rc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
+ iOff++;
+ continue;
+ }
+ }
+ }
- /* fts5WriteInit() should have initialized the buffers to (most likely)
- ** the maximum space required. */
- assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) );
- assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+ if( p->rc==SQLITE_OK && bTermWritten==0 ){
+ fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
+ bTermWritten = 1;
+ assert( p->rc!=SQLITE_OK || writer.bFirstRowidInPage==0 );
+ }
- /* Begin scanning through hash table entries. This loop runs once for each
- ** term/doclist currently stored within the hash table. */
- if( p->rc==SQLITE_OK ){
- p->rc = wx_sqlite3Fts5HashScanInit(pHash, 0, 0);
- }
- while( p->rc==SQLITE_OK && 0==wx_sqlite3Fts5HashScanEof(pHash) ){
- const char *zTerm; /* Buffer containing term */
- const u8 *pDoclist; /* Pointer to doclist for this term */
- int nDoclist; /* Size of doclist in bytes */
-
- /* Write the term for this entry to disk. */
- wx_sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
- fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
- if( p->rc!=SQLITE_OK ) break;
-
- assert( writer.bFirstRowidInPage==0 );
- if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
- /* The entire doclist will fit on the current leaf. */
- fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
- }else{
- i64 iRowid = 0;
- u64 iDelta = 0;
- int iOff = 0;
-
- /* The entire doclist will not fit on this leaf. The following
- ** loop iterates through the poslists that make up the current
- ** doclist. */
- while( p->rc==SQLITE_OK && iOff<nDoclist ){
- iOff += fts5GetVarint(&pDoclist[iOff], &iDelta);
- iRowid += iDelta;
-
- if( writer.bFirstRowidInPage ){
- fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
- pBuf->n += wx_sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
- writer.bFirstRowidInPage = 0;
- fts5WriteDlidxAppend(p, &writer, iRowid);
+ if( writer.bFirstRowidInPage ){
+ fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
+ pBuf->n += wx_sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
+ writer.bFirstRowidInPage = 0;
+ fts5WriteDlidxAppend(p, &writer, iRowid);
+ }else{
+ u64 iRowidDelta = (u64)iRowid - (u64)iPrev;
+ pBuf->n += wx_sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowidDelta);
+ }
if( p->rc!=SQLITE_OK ) break;
- }else{
- pBuf->n += wx_sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
- }
- assert( pBuf->n<=pBuf->nSpace );
+ assert( pBuf->n<=pBuf->nSpace );
+ iPrev = iRowid;
- if( eDetail==FTS5_DETAIL_NONE ){
- if( iOff<nDoclist && pDoclist[iOff]==0 ){
- pBuf->p[pBuf->n++] = 0;
- iOff++;
+ if( eDetail==FTS5_DETAIL_NONE ){
if( iOff<nDoclist && pDoclist[iOff]==0 ){
pBuf->p[pBuf->n++] = 0;
iOff++;
+ if( iOff<nDoclist && pDoclist[iOff]==0 ){
+ pBuf->p[pBuf->n++] = 0;
+ iOff++;
+ }
+ }
+ if( (pBuf->n + pPgidx->n)>=pgsz ){
+ fts5WriteFlushLeaf(p, &writer);
}
- }
- if( (pBuf->n + pPgidx->n)>=pgsz ){
- fts5WriteFlushLeaf(p, &writer);
- }
- }else{
- int bDummy;
- int nPos;
- int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
- nCopy += nPos;
- if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
- /* The entire poslist will fit on the current leaf. So copy
- ** it in one go. */
- fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
}else{
- /* The entire poslist will not fit on this leaf. So it needs
- ** to be broken into sections. The only qualification being
- ** that each varint must be stored contiguously. */
- const u8 *pPoslist = &pDoclist[iOff];
- int iPos = 0;
- while( p->rc==SQLITE_OK ){
- int nSpace = pgsz - pBuf->n - pPgidx->n;
- int n = 0;
- if( (nCopy - iPos)<=nSpace ){
- n = nCopy - iPos;
- }else{
- n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
- }
- assert( n>0 );
- fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
- iPos += n;
- if( (pBuf->n + pPgidx->n)>=pgsz ){
- fts5WriteFlushLeaf(p, &writer);
+ int bDel = 0;
+ int nPos = 0;
+ int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDel);
+ if( bDel && bSecureDelete ){
+ fts5BufferAppendVarint(&p->rc, pBuf, nPos*2);
+ iOff += nCopy;
+ nCopy = nPos;
+ }else{
+ nCopy += nPos;
+ }
+ if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
+ /* The entire poslist will fit on the current leaf. So copy
+ ** it in one go. */
+ fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
+ }else{
+ /* The entire poslist will not fit on this leaf. So it needs
+ ** to be broken into sections. The only qualification being
+ ** that each varint must be stored contiguously. */
+ const u8 *pPoslist = &pDoclist[iOff];
+ int iPos = 0;
+ while( p->rc==SQLITE_OK ){
+ int nSpace = pgsz - pBuf->n - pPgidx->n;
+ int n = 0;
+ if( (nCopy - iPos)<=nSpace ){
+ n = nCopy - iPos;
+ }else{
+ n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
+ }
+ assert( n>0 );
+ fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
+ iPos += n;
+ if( (pBuf->n + pPgidx->n)>=pgsz ){
+ fts5WriteFlushLeaf(p, &writer);
+ }
+ if( iPos>=nCopy ) break;
}
- if( iPos>=nCopy ) break;
}
+ iOff += nCopy;
}
- iOff += nCopy;
}
}
- }
- /* TODO2: Doclist terminator written here. */
- /* pBuf->p[pBuf->n++] = '\0'; */
- assert( pBuf->n<=pBuf->nSpace );
- if( p->rc==SQLITE_OK ) wx_sqlite3Fts5HashScanNext(pHash);
- }
- wx_sqlite3Fts5HashClear(pHash);
- fts5WriteFinish(p, &writer, &pgnoLast);
+ /* TODO2: Doclist terminator written here. */
+ /* pBuf->p[pBuf->n++] = '\0'; */
+ assert( pBuf->n<=pBuf->nSpace );
+ if( p->rc==SQLITE_OK ) wx_sqlite3Fts5HashScanNext(pHash);
+ }
+ fts5WriteFinish(p, &writer, &pgnoLast);
- /* Update the Fts5Structure. It is written back to the database by the
- ** fts5StructureRelease() call below. */
- if( pStruct->nLevel==0 ){
- fts5StructureAddLevel(&p->rc, &pStruct);
- }
- fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
- if( p->rc==SQLITE_OK ){
- pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
- pSeg->iSegid = iSegid;
- pSeg->pgnoFirst = 1;
- pSeg->pgnoLast = pgnoLast;
- pStruct->nSegment++;
+ assert( p->rc!=SQLITE_OK || bSecureDelete || pgnoLast>0 );
+ if( pgnoLast>0 ){
+ /* Update the Fts5Structure. It is written back to the database by the
+ ** fts5StructureRelease() call below. */
+ if( pStruct->nLevel==0 ){
+ fts5StructureAddLevel(&p->rc, &pStruct);
+ }
+ fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
+ if( p->rc==SQLITE_OK ){
+ pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
+ pSeg->iSegid = iSegid;
+ pSeg->pgnoFirst = 1;
+ pSeg->pgnoLast = pgnoLast;
+ if( pStruct->nOriginCntr>0 ){
+ pSeg->iOrigin1 = pStruct->nOriginCntr;
+ pSeg->iOrigin2 = pStruct->nOriginCntr;
+ pSeg->nEntry = p->nPendingRow;
+ pStruct->nOriginCntr++;
+ }
+ pStruct->nSegment++;
+ }
+ fts5StructurePromote(p, 0, pStruct);
+ }
}
- fts5StructurePromote(p, 0, pStruct);
}
- fts5IndexAutomerge(p, &pStruct, pgnoLast);
+ fts5IndexAutomerge(p, &pStruct, pgnoLast + p->nContentlessDelete);
fts5IndexCrisismerge(p, &pStruct);
fts5StructureWrite(p, pStruct);
fts5StructureRelease(pStruct);
@@ -235489,10 +248177,21 @@ static void fts5FlushOneHash(Fts5Index *p){
*/
static void fts5IndexFlush(Fts5Index *p){
/* Unless it is empty, flush the hash table to disk */
- if( p->nPendingData ){
+ if( p->flushRc ){
+ p->rc = p->flushRc;
+ return;
+ }
+ if( p->nPendingData || p->nContentlessDelete ){
assert( p->pHash );
- p->nPendingData = 0;
fts5FlushOneHash(p);
+ if( p->rc==SQLITE_OK ){
+ wx_sqlite3Fts5HashClear(p->pHash);
+ p->nPendingData = 0;
+ p->nPendingRow = 0;
+ p->nContentlessDelete = 0;
+ }else if( p->nPendingData || p->nContentlessDelete ){
+ p->flushRc = p->rc;
+ }
}
}
@@ -235508,17 +248207,22 @@ static Fts5Structure *fts5IndexOptimizeStruct(
/* Figure out if this structure requires optimization. A structure does
** not require optimization if either:
**
- ** + it consists of fewer than two segments, or
- ** + all segments are on the same level, or
- ** + all segments except one are currently inputs to a merge operation.
+ ** 1. it consists of fewer than two segments, or
+ ** 2. all segments are on the same level, or
+ ** 3. all segments except one are currently inputs to a merge operation.
**
- ** In the first case, return NULL. In the second, increment the ref-count
- ** on *pStruct and return a copy of the pointer to it.
+ ** In the first case, if there are no tombstone hash pages, return NULL. In
+ ** the second, increment the ref-count on *pStruct and return a copy of the
+ ** pointer to it.
*/
- if( nSeg<2 ) return 0;
+ if( nSeg==0 ) return 0;
for(i=0; i<pStruct->nLevel; i++){
int nThis = pStruct->aLevel[i].nSeg;
- if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){
+ int nMerge = pStruct->aLevel[i].nMerge;
+ if( nThis>0 && (nThis==nSeg || (nThis==nSeg-1 && nMerge==nThis)) ){
+ if( nSeg==1 && nThis==1 && pStruct->aLevel[i].aSeg[0].nPgTombstone==0 ){
+ return 0;
+ }
fts5StructureRef(pStruct);
return pStruct;
}
@@ -235534,6 +248238,7 @@ static Fts5Structure *fts5IndexOptimizeStruct(
pNew->nLevel = MIN(pStruct->nLevel+1, FTS5_MAX_LEVEL);
pNew->nRef = 1;
pNew->nWriteCounter = pStruct->nWriteCounter;
+ pNew->nOriginCntr = pStruct->nOriginCntr;
pLvl = &pNew->aLevel[pNew->nLevel-1];
pLvl->aSeg = (Fts5StructureSegment*)wx_sqlite3Fts5MallocZero(&p->rc, nByte);
if( pLvl->aSeg ){
@@ -235564,7 +248269,9 @@ static int wx_sqlite3Fts5IndexOptimize(Fts5Index *p){
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
+ assert( p->rc!=SQLITE_OK || p->nContentlessDelete==0 );
pStruct = fts5StructureRead(p);
+ assert( p->rc!=SQLITE_OK || pStruct!=0 );
fts5StructureInvalidate(p);
if( pStruct ){
@@ -235593,7 +248300,10 @@ static int wx_sqlite3Fts5IndexOptimize(Fts5Index *p){
** INSERT command.
*/
static int wx_sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
- Fts5Structure *pStruct = fts5StructureRead(p);
+ Fts5Structure *pStruct = 0;
+
+ fts5IndexFlush(p);
+ pStruct = fts5StructureRead(p);
if( pStruct ){
int nMin = p->pConfig->nUsermerge;
fts5StructureInvalidate(p);
@@ -235601,7 +248311,7 @@ static int wx_sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct);
fts5StructureRelease(pStruct);
pStruct = pNew;
- nMin = 2;
+ nMin = 1;
nMerge = nMerge*-1;
}
if( pStruct && pStruct->nLevel ){
@@ -235967,7 +248677,7 @@ static void fts5SetupPrefixIter(
u8 *pToken, /* Buffer containing prefix to match */
int nToken, /* Size of buffer pToken in bytes */
Fts5Colset *pColset, /* Restrict matches to these columns */
- Fts5Iter **ppIter /* OUT: New iterator */
+ Fts5Iter **ppIter /* OUT: New iterator */
){
Fts5Structure *pStruct;
Fts5Buffer *aBuf;
@@ -235988,8 +248698,9 @@ static void fts5SetupPrefixIter(
aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
pStruct = fts5StructureRead(p);
+ assert( p->rc!=SQLITE_OK || (aBuf && pStruct) );
- if( aBuf && pStruct ){
+ if( p->rc==SQLITE_OK ){
const int flags = FTS5INDEX_QUERY_SCAN
| FTS5INDEX_QUERY_SKIPEMPTY
| FTS5INDEX_QUERY_NOOUTPUT;
@@ -236001,6 +248712,12 @@ static void fts5SetupPrefixIter(
int bNewTerm = 1;
memset(&doclist, 0, sizeof(doclist));
+
+ /* If iIdx is non-zero, then it is the number of a prefix-index for
+ ** prefixes 1 character longer than the prefix being queried for. That
+ ** index contains all the doclists required, except for the one
+ ** corresponding to the prefix itself. That one is extracted from the
+ ** main term index here. */
if( iIdx!=0 ){
int dummy = 0;
const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT;
@@ -236024,6 +248741,7 @@ static void fts5SetupPrefixIter(
pToken[0] = FTS5_MAIN_PREFIX + iIdx;
fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
fts5IterSetOutputCb(&p->rc, p1);
+
for( /* no-op */ ;
fts5MultiIterEof(p, p1)==0;
fts5MultiIterNext2(p, p1, &bNewTerm)
@@ -236039,7 +248757,6 @@ static void fts5SetupPrefixIter(
}
if( p1->base.nData==0 ) continue;
-
if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
int i1 = i*nMerge;
@@ -236078,7 +248795,7 @@ static void fts5SetupPrefixIter(
}
fts5MultiIterFree(p1);
- pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING);
+ pData = fts5IdxMalloc(p, sizeof(*pData)+doclist.n+FTS5_DATA_ZERO_PADDING);
if( pData ){
pData->p = (u8*)&pData[1];
pData->nn = pData->szLeaf = doclist.n;
@@ -236115,6 +248832,9 @@ static int wx_sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
p->iWriteRowid = iRowid;
p->bDelete = bDelete;
+ if( bDelete==0 ){
+ p->nPendingRow++;
+ }
return fts5IndexReturn(p);
}
@@ -236152,6 +248872,9 @@ static int wx_sqlite3Fts5IndexReinit(Fts5Index *p){
fts5StructureInvalidate(p);
fts5IndexDiscardData(p);
memset(&s, 0, sizeof(Fts5Structure));
+ if( p->pConfig->bContentlessDelete ){
+ s.nOriginCntr = 1;
+ }
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
fts5StructureWrite(p, &s);
return fts5IndexReturn(p);
@@ -236215,7 +248938,9 @@ static int wx_sqlite3Fts5IndexClose(Fts5Index *p){
wx_sqlite3_finalize(p->pIdxWriter);
wx_sqlite3_finalize(p->pIdxDeleter);
wx_sqlite3_finalize(p->pIdxSelect);
+ wx_sqlite3_finalize(p->pIdxNextSelect);
wx_sqlite3_finalize(p->pDataVersion);
+ wx_sqlite3_finalize(p->pDeleteFromIdx);
wx_sqlite3Fts5HashFree(p->pHash);
wx_sqlite3_free(p->zDataTbl);
wx_sqlite3_free(p);
@@ -236310,6 +249035,457 @@ static int wx_sqlite3Fts5IndexWrite(
}
/*
+** pToken points to a buffer of size nToken bytes containing a search
+** term, including the index number at the start, used on a tokendata=1
+** table. This function returns true if the term in buffer pBuf matches
+** token pToken/nToken.
+*/
+static int fts5IsTokendataPrefix(
+ Fts5Buffer *pBuf,
+ const u8 *pToken,
+ int nToken
+){
+ return (
+ pBuf->n>=nToken
+ && 0==memcmp(pBuf->p, pToken, nToken)
+ && (pBuf->n==nToken || pBuf->p[nToken]==0x00)
+ );
+}
+
+/*
+** Ensure the segment-iterator passed as the only argument points to EOF.
+*/
+static void fts5SegIterSetEOF(Fts5SegIter *pSeg){
+ fts5DataRelease(pSeg->pLeaf);
+ pSeg->pLeaf = 0;
+}
+
+/*
+** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
+** array of these for each row it visits. Or, for an iterator used by an
+** "ORDER BY rank" query, it accumulates an array of these for the entire
+** query.
+**
+** Each instance in the array indicates the iterator (and therefore term)
+** associated with position iPos of rowid iRowid. This is used by the
+** xInstToken() API.
+*/
+struct Fts5TokenDataMap {
+ i64 iRowid; /* Row this token is located in */
+ i64 iPos; /* Position of token */
+ int iIter; /* Iterator token was read from */
+};
+
+/*
+** An object used to supplement Fts5Iter for tokendata=1 iterators.
+*/
+struct Fts5TokenDataIter {
+ int nIter;
+ int nIterAlloc;
+
+ int nMap;
+ int nMapAlloc;
+ Fts5TokenDataMap *aMap;
+
+ Fts5PoslistReader *aPoslistReader;
+ int *aPoslistToIter;
+ Fts5Iter *apIter[1];
+};
+
+/*
+** This function appends iterator pAppend to Fts5TokenDataIter pIn and
+** returns the result.
+*/
+static Fts5TokenDataIter *fts5AppendTokendataIter(
+ Fts5Index *p, /* Index object (for error code) */
+ Fts5TokenDataIter *pIn, /* Current Fts5TokenDataIter struct */
+ Fts5Iter *pAppend /* Append this iterator */
+){
+ Fts5TokenDataIter *pRet = pIn;
+
+ if( p->rc==SQLITE_OK ){
+ if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
+ int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
+ int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter);
+ Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)wx_sqlite3_realloc(pIn, nByte);
+
+ if( pNew==0 ){
+ p->rc = SQLITE_NOMEM;
+ }else{
+ if( pIn==0 ) memset(pNew, 0, nByte);
+ pRet = pNew;
+ pNew->nIterAlloc = nAlloc;
+ }
+ }
+ }
+ if( p->rc ){
+ wx_sqlite3Fts5IterClose((Fts5IndexIter*)pAppend);
+ }else{
+ pRet->apIter[pRet->nIter++] = pAppend;
+ }
+ assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc );
+
+ return pRet;
+}
+
+/*
+** Delete an Fts5TokenDataIter structure and its contents.
+*/
+static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
+ if( pSet ){
+ int ii;
+ for(ii=0; ii<pSet->nIter; ii++){
+ fts5MultiIterFree(pSet->apIter[ii]);
+ }
+ wx_sqlite3_free(pSet->aPoslistReader);
+ wx_sqlite3_free(pSet->aMap);
+ wx_sqlite3_free(pSet);
+ }
+}
+
+/*
+** Append a mapping to the token-map belonging to object pT.
+*/
+static void fts5TokendataIterAppendMap(
+ Fts5Index *p,
+ Fts5TokenDataIter *pT,
+ int iIter,
+ i64 iRowid,
+ i64 iPos
+){
+ if( p->rc==SQLITE_OK ){
+ if( pT->nMap==pT->nMapAlloc ){
+ int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
+ int nByte = nNew * sizeof(Fts5TokenDataMap);
+ Fts5TokenDataMap *aNew;
+
+ aNew = (Fts5TokenDataMap*)wx_sqlite3_realloc(pT->aMap, nByte);
+ if( aNew==0 ){
+ p->rc = SQLITE_NOMEM;
+ return;
+ }
+
+ pT->aMap = aNew;
+ pT->nMapAlloc = nNew;
+ }
+
+ pT->aMap[pT->nMap].iRowid = iRowid;
+ pT->aMap[pT->nMap].iPos = iPos;
+ pT->aMap[pT->nMap].iIter = iIter;
+ pT->nMap++;
+ }
+}
+
+/*
+** The iterator passed as the only argument must be a tokendata=1 iterator
+** (pIter->pTokenDataIter!=0). This function sets the iterator output
+** variables (pIter->base.*) according to the contents of the current
+** row.
+*/
+static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){
+ int ii;
+ int nHit = 0;
+ i64 iRowid = SMALLEST_INT64;
+ int iMin = 0;
+
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+
+ pIter->base.nData = 0;
+ pIter->base.pData = 0;
+
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( p->base.bEof==0 ){
+ if( nHit==0 || p->base.iRowid<iRowid ){
+ iRowid = p->base.iRowid;
+ nHit = 1;
+ pIter->base.pData = p->base.pData;
+ pIter->base.nData = p->base.nData;
+ iMin = ii;
+ }else if( p->base.iRowid==iRowid ){
+ nHit++;
+ }
+ }
+ }
+
+ if( nHit==0 ){
+ pIter->base.bEof = 1;
+ }else{
+ int eDetail = pIter->pIndex->pConfig->eDetail;
+ pIter->base.bEof = 0;
+ pIter->base.iRowid = iRowid;
+
+ if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){
+ fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, iRowid, -1);
+ }else
+ if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){
+ int nReader = 0;
+ int nByte = 0;
+ i64 iPrev = 0;
+
+ /* Allocate array of iterators if they are not already allocated. */
+ if( pT->aPoslistReader==0 ){
+ pT->aPoslistReader = (Fts5PoslistReader*)wx_sqlite3Fts5MallocZero(
+ &pIter->pIndex->rc,
+ pT->nIter * (sizeof(Fts5PoslistReader) + sizeof(int))
+ );
+ if( pT->aPoslistReader==0 ) return;
+ pT->aPoslistToIter = (int*)&pT->aPoslistReader[pT->nIter];
+ }
+
+ /* Populate an iterator for each poslist that will be merged */
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( iRowid==p->base.iRowid ){
+ pT->aPoslistToIter[nReader] = ii;
+ wx_sqlite3Fts5PoslistReaderInit(
+ p->base.pData, p->base.nData, &pT->aPoslistReader[nReader++]
+ );
+ nByte += p->base.nData;
+ }
+ }
+
+ /* Ensure the output buffer is large enough */
+ if( fts5BufferGrow(&pIter->pIndex->rc, &pIter->poslist, nByte+nHit*10) ){
+ return;
+ }
+
+ /* Ensure the token-mapping is large enough */
+ if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){
+ int nNew = (pT->nMapAlloc + nByte) * 2;
+ Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)wx_sqlite3_realloc(
+ pT->aMap, nNew*sizeof(Fts5TokenDataMap)
+ );
+ if( aNew==0 ){
+ pIter->pIndex->rc = SQLITE_NOMEM;
+ return;
+ }
+ pT->aMap = aNew;
+ pT->nMapAlloc = nNew;
+ }
+
+ pIter->poslist.n = 0;
+
+ while( 1 ){
+ i64 iMinPos = LARGEST_INT64;
+
+ /* Find smallest position */
+ iMin = 0;
+ for(ii=0; ii<nReader; ii++){
+ Fts5PoslistReader *pReader = &pT->aPoslistReader[ii];
+ if( pReader->bEof==0 ){
+ if( pReader->iPos<iMinPos ){
+ iMinPos = pReader->iPos;
+ iMin = ii;
+ }
+ }
+ }
+
+ /* If all readers were at EOF, break out of the loop. */
+ if( iMinPos==LARGEST_INT64 ) break;
+
+ wx_sqlite3Fts5PoslistSafeAppend(&pIter->poslist, &iPrev, iMinPos);
+ wx_sqlite3Fts5PoslistReaderNext(&pT->aPoslistReader[iMin]);
+
+ if( eDetail==FTS5_DETAIL_FULL ){
+ pT->aMap[pT->nMap].iPos = iMinPos;
+ pT->aMap[pT->nMap].iIter = pT->aPoslistToIter[iMin];
+ pT->aMap[pT->nMap].iRowid = iRowid;
+ pT->nMap++;
+ }
+ }
+
+ pIter->base.pData = pIter->poslist.p;
+ pIter->base.nData = pIter->poslist.n;
+ }
+ }
+}
+
+/*
+** The iterator passed as the only argument must be a tokendata=1 iterator
+** (pIter->pTokenDataIter!=0). This function advances the iterator. If
+** argument bFrom is false, then the iterator is advanced to the next
+** entry. Or, if bFrom is true, it is advanced to the first entry with
+** a rowid of iFrom or greater.
+*/
+static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){
+ int ii;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ Fts5Index *pIndex = pIter->pIndex;
+
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( p->base.bEof==0
+ && (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowid<iFrom))
+ ){
+ fts5MultiIterNext(pIndex, p, bFrom, iFrom);
+ while( bFrom && p->base.bEof==0
+ && p->base.iRowid<iFrom
+ && pIndex->rc==SQLITE_OK
+ ){
+ fts5MultiIterNext(pIndex, p, 0, 0);
+ }
+ }
+ }
+
+ if( pIndex->rc==SQLITE_OK ){
+ fts5IterSetOutputsTokendata(pIter);
+ }
+}
+
+/*
+** If the segment-iterator passed as the first argument is at EOF, then
+** set pIter->term to a copy of buffer pTerm.
+*/
+static void fts5TokendataSetTermIfEof(Fts5Iter *pIter, Fts5Buffer *pTerm){
+ if( pIter && pIter->aSeg[0].pLeaf==0 ){
+ fts5BufferSet(&pIter->pIndex->rc, &pIter->aSeg[0].term, pTerm->n, pTerm->p);
+ }
+}
+
+/*
+** This function sets up an iterator to use for a non-prefix query on a
+** tokendata=1 table.
+*/
+static Fts5Iter *fts5SetupTokendataIter(
+ Fts5Index *p, /* FTS index to query */
+ const u8 *pToken, /* Buffer containing query term */
+ int nToken, /* Size of buffer pToken in bytes */
+ Fts5Colset *pColset /* Colset to filter on */
+){
+ Fts5Iter *pRet = 0;
+ Fts5TokenDataIter *pSet = 0;
+ Fts5Structure *pStruct = 0;
+ const int flags = FTS5INDEX_QUERY_SCANONETERM | FTS5INDEX_QUERY_SCAN;
+
+ Fts5Buffer bSeek = {0, 0, 0};
+ Fts5Buffer *pSmall = 0;
+
+ fts5IndexFlush(p);
+ pStruct = fts5StructureRead(p);
+
+ while( p->rc==SQLITE_OK ){
+ Fts5Iter *pPrev = pSet ? pSet->apIter[pSet->nIter-1] : 0;
+ Fts5Iter *pNew = 0;
+ Fts5SegIter *pNewIter = 0;
+ Fts5SegIter *pPrevIter = 0;
+
+ int iLvl, iSeg, ii;
+
+ pNew = fts5MultiIterAlloc(p, pStruct->nSegment);
+ if( pSmall ){
+ fts5BufferSet(&p->rc, &bSeek, pSmall->n, pSmall->p);
+ fts5BufferAppendBlob(&p->rc, &bSeek, 1, (const u8*)"\0");
+ }else{
+ fts5BufferSet(&p->rc, &bSeek, nToken, pToken);
+ }
+ if( p->rc ){
+ wx_sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
+ break;
+ }
+
+ pNewIter = &pNew->aSeg[0];
+ pPrevIter = (pPrev ? &pPrev->aSeg[0] : 0);
+ for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+ for(iSeg=pStruct->aLevel[iLvl].nSeg-1; iSeg>=0; iSeg--){
+ Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
+ int bDone = 0;
+
+ if( pPrevIter ){
+ if( fts5BufferCompare(pSmall, &pPrevIter->term) ){
+ memcpy(pNewIter, pPrevIter, sizeof(Fts5SegIter));
+ memset(pPrevIter, 0, sizeof(Fts5SegIter));
+ bDone = 1;
+ }else if( pPrevIter->iEndofDoclist>pPrevIter->pLeaf->szLeaf ){
+ fts5SegIterNextInit(p,(const char*)bSeek.p,bSeek.n-1,pSeg,pNewIter);
+ bDone = 1;
+ }
+ }
+
+ if( bDone==0 ){
+ fts5SegIterSeekInit(p, bSeek.p, bSeek.n, flags, pSeg, pNewIter);
+ }
+
+ if( pPrevIter ){
+ if( pPrevIter->pTombArray ){
+ pNewIter->pTombArray = pPrevIter->pTombArray;
+ pNewIter->pTombArray->nRef++;
+ }
+ }else{
+ fts5SegIterAllocTombstone(p, pNewIter);
+ }
+
+ pNewIter++;
+ if( pPrevIter ) pPrevIter++;
+ if( p->rc ) break;
+ }
+ }
+ fts5TokendataSetTermIfEof(pPrev, pSmall);
+
+ pNew->bSkipEmpty = 1;
+ pNew->pColset = pColset;
+ fts5IterSetOutputCb(&p->rc, pNew);
+
+ /* Loop through all segments in the new iterator. Find the smallest
+ ** term that any segment-iterator points to. Iterator pNew will be
+ ** used for this term. Also, set any iterator that points to a term that
+ ** does not match pToken/nToken to point to EOF */
+ pSmall = 0;
+ for(ii=0; ii<pNew->nSeg; ii++){
+ Fts5SegIter *pII = &pNew->aSeg[ii];
+ if( 0==fts5IsTokendataPrefix(&pII->term, pToken, nToken) ){
+ fts5SegIterSetEOF(pII);
+ }
+ if( pII->pLeaf && (!pSmall || fts5BufferCompare(pSmall, &pII->term)>0) ){
+ pSmall = &pII->term;
+ }
+ }
+
+ /* If pSmall is still NULL at this point, then the new iterator does
+ ** not point to any terms that match the query. So delete it and break
+ ** out of the loop - all required iterators have been collected. */
+ if( pSmall==0 ){
+ wx_sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
+ break;
+ }
+
+ /* Append this iterator to the set and continue. */
+ pSet = fts5AppendTokendataIter(p, pSet, pNew);
+ }
+
+ if( p->rc==SQLITE_OK && pSet ){
+ int ii;
+ for(ii=0; ii<pSet->nIter; ii++){
+ Fts5Iter *pIter = pSet->apIter[ii];
+ int iSeg;
+ for(iSeg=0; iSeg<pIter->nSeg; iSeg++){
+ pIter->aSeg[iSeg].flags |= FTS5_SEGITER_ONETERM;
+ }
+ fts5MultiIterFinishSetup(p, pIter);
+ }
+ }
+
+ if( p->rc==SQLITE_OK ){
+ pRet = fts5MultiIterAlloc(p, 0);
+ }
+ if( pRet ){
+ pRet->pTokenDataIter = pSet;
+ if( pSet ){
+ fts5IterSetOutputsTokendata(pRet);
+ }else{
+ pRet->base.bEof = 1;
+ }
+ }else{
+ fts5TokendataIterDelete(pSet);
+ }
+
+ fts5StructureRelease(pStruct);
+ fts5BufferFree(&bSeek);
+ return pRet;
+}
+
+
+/*
** Open a new iterator to iterate though all rowid that match the
** specified token or token prefix.
*/
@@ -236330,8 +249506,13 @@ static int wx_sqlite3Fts5IndexQuery(
if( wx_sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
int iIdx = 0; /* Index to search */
int iPrefixIdx = 0; /* +1 prefix index */
+ int bTokendata = pConfig->bTokendata;
if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
+ if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){
+ bTokendata = 0;
+ }
+
/* Figure out which index to search and set iIdx accordingly. If this
** is a prefix query for which there is no prefix index, set iIdx to
** greater than pConfig->nPrefix to indicate that the query will be
@@ -236357,7 +249538,10 @@ static int wx_sqlite3Fts5IndexQuery(
}
}
- if( iIdx<=pConfig->nPrefix ){
+ if( bTokendata && iIdx==0 ){
+ buf.p[0] = '0';
+ pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset);
+ }else if( iIdx<=pConfig->nPrefix ){
/* Straight index lookup */
Fts5Structure *pStruct = fts5StructureRead(p);
buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
@@ -236404,7 +249588,11 @@ static int wx_sqlite3Fts5IndexQuery(
static int wx_sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
assert( pIter->pIndex->rc==SQLITE_OK );
- fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
+ if( pIter->pTokenDataIter ){
+ fts5TokendataIterNext(pIter, 0, 0);
+ }else{
+ fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
+ }
return fts5IndexReturn(pIter->pIndex);
}
@@ -236437,7 +249625,11 @@ static int wx_sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){
*/
static int wx_sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
+ if( pIter->pTokenDataIter ){
+ fts5TokendataIterNext(pIter, 1, iMatch);
+ }else{
+ fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
+ }
return fts5IndexReturn(pIter->pIndex);
}
@@ -236453,12 +249645,106 @@ static const char *wx_sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){
}
/*
+** This is used by xInstToken() to access the token at offset iOff, column
+** iCol of row iRowid. The token is returned via output variables *ppOut
+** and *pnOut. The iterator passed as the first argument must be a tokendata=1
+** iterator (pIter->pTokenDataIter!=0).
+*/
+static int wx_sqlite3Fts5IterToken(
+ Fts5IndexIter *pIndexIter,
+ i64 iRowid,
+ int iCol,
+ int iOff,
+ const char **ppOut, int *pnOut
+){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ Fts5TokenDataMap *aMap = pT->aMap;
+ i64 iPos = (((i64)iCol)<<32) + iOff;
+
+ int i1 = 0;
+ int i2 = pT->nMap;
+ int iTest = 0;
+
+ while( i2>i1 ){
+ iTest = (i1 + i2) / 2;
+
+ if( aMap[iTest].iRowid<iRowid ){
+ i1 = iTest+1;
+ }else if( aMap[iTest].iRowid>iRowid ){
+ i2 = iTest;
+ }else{
+ if( aMap[iTest].iPos<iPos ){
+ if( aMap[iTest].iPos<0 ){
+ break;
+ }
+ i1 = iTest+1;
+ }else if( aMap[iTest].iPos>iPos ){
+ i2 = iTest;
+ }else{
+ break;
+ }
+ }
+ }
+
+ if( i2>i1 ){
+ Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
+ *ppOut = (const char*)pMap->aSeg[0].term.p+1;
+ *pnOut = pMap->aSeg[0].term.n-1;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Clear any existing entries from the token-map associated with the
+** iterator passed as the only argument.
+*/
+static void wx_sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ if( pIter && pIter->pTokenDataIter ){
+ pIter->pTokenDataIter->nMap = 0;
+ }
+}
+
+/*
+** Set a token-mapping for the iterator passed as the first argument. This
+** is used in detail=column or detail=none mode when a token is requested
+** using the xInstToken() API. In this case the caller tokenizers the
+** current row and configures the token-mapping via multiple calls to this
+** function.
+*/
+static int wx_sqlite3Fts5IndexIterWriteTokendata(
+ Fts5IndexIter *pIndexIter,
+ const char *pToken, int nToken,
+ i64 iRowid, int iCol, int iOff
+){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ Fts5Index *p = pIter->pIndex;
+ int ii;
+
+ assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL );
+ assert( pIter->pTokenDataIter );
+
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
+ if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
+ }
+ if( ii<pT->nIter ){
+ fts5TokendataIterAppendMap(p, pT, ii, iRowid, (((i64)iCol)<<32) + iOff);
+ }
+ return fts5IndexReturn(p);
+}
+
+/*
** Close an iterator opened by an earlier call to wx_sqlite3Fts5IndexQuery().
*/
static void wx_sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
if( pIndexIter ){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
Fts5Index *pIndex = pIter->pIndex;
+ fts5TokendataIterDelete(pIter->pTokenDataIter);
fts5MultiIterFree(pIter);
wx_sqlite3Fts5IndexCloseReader(pIndex);
}
@@ -236542,6 +249828,347 @@ static int wx_sqlite3Fts5IndexLoadConfig(Fts5Index *p){
return fts5IndexReturn(p);
}
+/*
+** Retrieve the origin value that will be used for the segment currently
+** being accumulated in the in-memory hash table when it is flushed to
+** disk. If successful, SQLITE_OK is returned and (*piOrigin) set to
+** the queried value. Or, if an error occurs, an error code is returned
+** and the final value of (*piOrigin) is undefined.
+*/
+static int wx_sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin){
+ Fts5Structure *pStruct;
+ pStruct = fts5StructureRead(p);
+ if( pStruct ){
+ *piOrigin = pStruct->nOriginCntr;
+ fts5StructureRelease(pStruct);
+ }
+ return fts5IndexReturn(p);
+}
+
+/*
+** Buffer pPg contains a page of a tombstone hash table - one of nPg pages
+** associated with the same segment. This function adds rowid iRowid to
+** the hash table. The caller is required to guarantee that there is at
+** least one free slot on the page.
+**
+** If parameter bForce is false and the hash table is deemed to be full
+** (more than half of the slots are occupied), then non-zero is returned
+** and iRowid not inserted. Or, if bForce is true or if the hash table page
+** is not full, iRowid is inserted and zero returned.
+*/
+static int fts5IndexTombstoneAddToPage(
+ Fts5Data *pPg,
+ int bForce,
+ int nPg,
+ u64 iRowid
+){
+ const int szKey = TOMBSTONE_KEYSIZE(pPg);
+ const int nSlot = TOMBSTONE_NSLOT(pPg);
+ const int nElem = fts5GetU32(&pPg->p[4]);
+ int iSlot = (iRowid / nPg) % nSlot;
+ int nCollide = nSlot;
+
+ if( szKey==4 && iRowid>0xFFFFFFFF ) return 2;
+ if( iRowid==0 ){
+ pPg->p[1] = 0x01;
+ return 0;
+ }
+
+ if( bForce==0 && nElem>=(nSlot/2) ){
+ return 1;
+ }
+
+ fts5PutU32(&pPg->p[4], nElem+1);
+ if( szKey==4 ){
+ u32 *aSlot = (u32*)&pPg->p[8];
+ while( aSlot[iSlot] ){
+ iSlot = (iSlot + 1) % nSlot;
+ if( nCollide--==0 ) return 0;
+ }
+ fts5PutU32((u8*)&aSlot[iSlot], (u32)iRowid);
+ }else{
+ u64 *aSlot = (u64*)&pPg->p[8];
+ while( aSlot[iSlot] ){
+ iSlot = (iSlot + 1) % nSlot;
+ if( nCollide--==0 ) return 0;
+ }
+ fts5PutU64((u8*)&aSlot[iSlot], iRowid);
+ }
+
+ return 0;
+}
+
+/*
+** This function attempts to build a new hash containing all the keys
+** currently in the tombstone hash table for segment pSeg. The new
+** hash will be stored in the nOut buffers passed in array apOut[].
+** All pages of the new hash use key-size szKey (4 or 8).
+**
+** Return 0 if the hash is successfully rebuilt into the nOut pages.
+** Or non-zero if it is not (because one page became overfull). In this
+** case the caller should retry with a larger nOut parameter.
+**
+** Parameter pData1 is page iPg1 of the hash table being rebuilt.
+*/
+static int fts5IndexTombstoneRehash(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg, /* Segment to rebuild hash of */
+ Fts5Data *pData1, /* One page of current hash - or NULL */
+ int iPg1, /* Which page of the current hash is pData1 */
+ int szKey, /* 4 or 8, the keysize */
+ int nOut, /* Number of output pages */
+ Fts5Data **apOut /* Array of output hash pages */
+){
+ int ii;
+ int res = 0;
+
+ /* Initialize the headers of all the output pages */
+ for(ii=0; ii<nOut; ii++){
+ apOut[ii]->p[0] = szKey;
+ fts5PutU32(&apOut[ii]->p[4], 0);
+ }
+
+ /* Loop through the current pages of the hash table. */
+ for(ii=0; res==0 && ii<pSeg->nPgTombstone; ii++){
+ Fts5Data *pData = 0; /* Page ii of the current hash table */
+ Fts5Data *pFree = 0; /* Free this at the end of the loop */
+
+ if( iPg1==ii ){
+ pData = pData1;
+ }else{
+ pFree = pData = fts5DataRead(p, FTS5_TOMBSTONE_ROWID(pSeg->iSegid, ii));
+ }
+
+ if( pData ){
+ int szKeyIn = TOMBSTONE_KEYSIZE(pData);
+ int nSlotIn = (pData->nn - 8) / szKeyIn;
+ int iIn;
+ for(iIn=0; iIn<nSlotIn; iIn++){
+ u64 iVal = 0;
+
+ /* Read the value from slot iIn of the input page into iVal. */
+ if( szKeyIn==4 ){
+ u32 *aSlot = (u32*)&pData->p[8];
+ if( aSlot[iIn] ) iVal = fts5GetU32((u8*)&aSlot[iIn]);
+ }else{
+ u64 *aSlot = (u64*)&pData->p[8];
+ if( aSlot[iIn] ) iVal = fts5GetU64((u8*)&aSlot[iIn]);
+ }
+
+ /* If iVal is not 0 at this point, insert it into the new hash table */
+ if( iVal ){
+ Fts5Data *pPg = apOut[(iVal % nOut)];
+ res = fts5IndexTombstoneAddToPage(pPg, 0, nOut, iVal);
+ if( res ) break;
+ }
+ }
+
+ /* If this is page 0 of the old hash, copy the rowid-0-flag from the
+ ** old hash to the new. */
+ if( ii==0 ){
+ apOut[0]->p[1] = pData->p[1];
+ }
+ }
+ fts5DataRelease(pFree);
+ }
+
+ return res;
+}
+
+/*
+** This is called to rebuild the hash table belonging to segment pSeg.
+** If parameter pData1 is not NULL, then one page of the existing hash table
+** has already been loaded - pData1, which is page iPg1. The key-size for
+** the new hash table is szKey (4 or 8).
+**
+** If successful, the new hash table is not written to disk. Instead,
+** output parameter (*pnOut) is set to the number of pages in the new
+** hash table, and (*papOut) to point to an array of buffers containing
+** the new page data.
+**
+** If an error occurs, an error code is left in the Fts5Index object and
+** both output parameters set to 0 before returning.
+*/
+static void fts5IndexTombstoneRebuild(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg, /* Segment to rebuild hash of */
+ Fts5Data *pData1, /* One page of current hash - or NULL */
+ int iPg1, /* Which page of the current hash is pData1 */
+ int szKey, /* 4 or 8, the keysize */
+ int *pnOut, /* OUT: Number of output pages */
+ Fts5Data ***papOut /* OUT: Output hash pages */
+){
+ const int MINSLOT = 32;
+ int nSlotPerPage = MAX(MINSLOT, (p->pConfig->pgsz - 8) / szKey);
+ int nSlot = 0; /* Number of slots in each output page */
+ int nOut = 0;
+
+ /* Figure out how many output pages (nOut) and how many slots per
+ ** page (nSlot). There are three possibilities:
+ **
+ ** 1. The hash table does not yet exist. In this case the new hash
+ ** table will consist of a single page with MINSLOT slots.
+ **
+ ** 2. The hash table exists but is currently a single page. In this
+ ** case an attempt is made to grow the page to accommodate the new
+ ** entry. The page is allowed to grow up to nSlotPerPage (see above)
+ ** slots.
+ **
+ ** 3. The hash table already consists of more than one page, or of
+ ** a single page already so large that it cannot be grown. In this
+ ** case the new hash consists of (nPg*2+1) pages of nSlotPerPage
+ ** slots each, where nPg is the current number of pages in the
+ ** hash table.
+ */
+ if( pSeg->nPgTombstone==0 ){
+ /* Case 1. */
+ nOut = 1;
+ nSlot = MINSLOT;
+ }else if( pSeg->nPgTombstone==1 ){
+ /* Case 2. */
+ int nElem = (int)fts5GetU32(&pData1->p[4]);
+ assert( pData1 && iPg1==0 );
+ nOut = 1;
+ nSlot = MAX(nElem*4, MINSLOT);
+ if( nSlot>nSlotPerPage ) nOut = 0;
+ }
+ if( nOut==0 ){
+ /* Case 3. */
+ nOut = (pSeg->nPgTombstone * 2 + 1);
+ nSlot = nSlotPerPage;
+ }
+
+ /* Allocate the required array and output pages */
+ while( 1 ){
+ int res = 0;
+ int ii = 0;
+ int szPage = 0;
+ Fts5Data **apOut = 0;
+
+ /* Allocate space for the new hash table */
+ assert( nSlot>=MINSLOT );
+ apOut = (Fts5Data**)wx_sqlite3Fts5MallocZero(&p->rc, sizeof(Fts5Data*) * nOut);
+ szPage = 8 + nSlot*szKey;
+ for(ii=0; ii<nOut; ii++){
+ Fts5Data *pNew = (Fts5Data*)wx_sqlite3Fts5MallocZero(&p->rc,
+ sizeof(Fts5Data)+szPage
+ );
+ if( pNew ){
+ pNew->nn = szPage;
+ pNew->p = (u8*)&pNew[1];
+ apOut[ii] = pNew;
+ }
+ }
+
+ /* Rebuild the hash table. */
+ if( p->rc==SQLITE_OK ){
+ res = fts5IndexTombstoneRehash(p, pSeg, pData1, iPg1, szKey, nOut, apOut);
+ }
+ if( res==0 ){
+ if( p->rc ){
+ fts5IndexFreeArray(apOut, nOut);
+ apOut = 0;
+ nOut = 0;
+ }
+ *pnOut = nOut;
+ *papOut = apOut;
+ break;
+ }
+
+ /* If control flows to here, it was not possible to rebuild the hash
+ ** table. Free all buffers and then try again with more pages. */
+ assert( p->rc==SQLITE_OK );
+ fts5IndexFreeArray(apOut, nOut);
+ nSlot = nSlotPerPage;
+ nOut = nOut*2 + 1;
+ }
+}
+
+
+/*
+** Add a tombstone for rowid iRowid to segment pSeg.
+*/
+static void fts5IndexTombstoneAdd(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg,
+ u64 iRowid
+){
+ Fts5Data *pPg = 0;
+ int iPg = -1;
+ int szKey = 0;
+ int nHash = 0;
+ Fts5Data **apHash = 0;
+
+ p->nContentlessDelete++;
+
+ if( pSeg->nPgTombstone>0 ){
+ iPg = iRowid % pSeg->nPgTombstone;
+ pPg = fts5DataRead(p, FTS5_TOMBSTONE_ROWID(pSeg->iSegid,iPg));
+ if( pPg==0 ){
+ assert( p->rc!=SQLITE_OK );
+ return;
+ }
+
+ if( 0==fts5IndexTombstoneAddToPage(pPg, 0, pSeg->nPgTombstone, iRowid) ){
+ fts5DataWrite(p, FTS5_TOMBSTONE_ROWID(pSeg->iSegid,iPg), pPg->p, pPg->nn);
+ fts5DataRelease(pPg);
+ return;
+ }
+ }
+
+ /* Have to rebuild the hash table. First figure out the key-size (4 or 8). */
+ szKey = pPg ? TOMBSTONE_KEYSIZE(pPg) : 4;
+ if( iRowid>0xFFFFFFFF ) szKey = 8;
+
+ /* Rebuild the hash table */
+ fts5IndexTombstoneRebuild(p, pSeg, pPg, iPg, szKey, &nHash, &apHash);
+ assert( p->rc==SQLITE_OK || (nHash==0 && apHash==0) );
+
+ /* If all has succeeded, write the new rowid into one of the new hash
+ ** table pages, then write them all out to disk. */
+ if( nHash ){
+ int ii = 0;
+ fts5IndexTombstoneAddToPage(apHash[iRowid % nHash], 1, nHash, iRowid);
+ for(ii=0; ii<nHash; ii++){
+ i64 iTombstoneRowid = FTS5_TOMBSTONE_ROWID(pSeg->iSegid, ii);
+ fts5DataWrite(p, iTombstoneRowid, apHash[ii]->p, apHash[ii]->nn);
+ }
+ pSeg->nPgTombstone = nHash;
+ fts5StructureWrite(p, p->pStruct);
+ }
+
+ fts5DataRelease(pPg);
+ fts5IndexFreeArray(apHash, nHash);
+}
+
+/*
+** Add iRowid to the tombstone list of the segment or segments that contain
+** rows from origin iOrigin. Return SQLITE_OK if successful, or an SQLite
+** error code otherwise.
+*/
+static int wx_sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid){
+ Fts5Structure *pStruct;
+ pStruct = fts5StructureRead(p);
+ if( pStruct ){
+ int bFound = 0; /* True after pSeg->nEntryTombstone incr. */
+ int iLvl;
+ for(iLvl=pStruct->nLevel-1; iLvl>=0; iLvl--){
+ int iSeg;
+ for(iSeg=pStruct->aLevel[iLvl].nSeg-1; iSeg>=0; iSeg--){
+ Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
+ if( pSeg->iOrigin1<=(u64)iOrigin && pSeg->iOrigin2>=(u64)iOrigin ){
+ if( bFound==0 ){
+ pSeg->nEntryTombstone++;
+ bFound = 1;
+ }
+ fts5IndexTombstoneAdd(p, pSeg, iRowid);
+ }
+ }
+ }
+ fts5StructureRelease(pStruct);
+ }
+ return fts5IndexReturn(p);
+}
/*************************************************************************
**************************************************************************
@@ -236625,7 +250252,9 @@ static int fts5QueryCksum(
int eDetail = p->pConfig->eDetail;
u64 cksum = *pCksum;
Fts5IndexIter *pIter = 0;
- int rc = wx_sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter);
+ int rc = wx_sqlite3Fts5IndexQuery(
+ p, z, n, (flags | FTS5INDEX_QUERY_NOTOKENDATA), 0, &pIter
+ );
while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==wx_sqlite3Fts5IterEof(pIter) ){
i64 rowid = pIter->iRowid;
@@ -236792,7 +250421,7 @@ static void fts5IndexIntegrityCheckEmpty(
}
static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
- int iTermOff = 0;
+ i64 iTermOff = 0;
int ii;
Fts5Buffer buf1 = {0,0,0};
@@ -236801,7 +250430,7 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
ii = pLeaf->szLeaf;
while( ii<pLeaf->nn && p->rc==SQLITE_OK ){
int res;
- int iOff;
+ i64 iOff;
int nIncr;
ii += fts5GetVarint32(&pLeaf->p[ii], nIncr);
@@ -236846,6 +250475,7 @@ static void fts5IndexIntegrityCheckSegment(
Fts5StructureSegment *pSeg /* Segment to check internal consistency */
){
Fts5Config *pConfig = p->pConfig;
+ int bSecureDelete = (pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE);
wx_sqlite3_stmt *pStmt = 0;
int rc2;
int iIdxPrevLeaf = pSeg->pgnoFirst-1;
@@ -236881,7 +250511,19 @@ static void fts5IndexIntegrityCheckSegment(
** is also a rowid pointer within the leaf page header, it points to a
** location before the term. */
if( pLeaf->nn<=pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
+
+ if( nIdxTerm==0
+ && pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE
+ && pLeaf->nn==pLeaf->szLeaf
+ && pLeaf->nn==4
+ ){
+ /* special case - the very first page in a segment keeps its %_idx
+ ** entry even if all the terms are removed from it by secure-delete
+ ** operations. */
+ }else{
+ p->rc = FTS5_CORRUPT;
+ }
+
}else{
int iOff; /* Offset of first term on leaf */
int iRowidOff; /* Offset of first rowid on leaf */
@@ -236945,9 +250587,12 @@ static void fts5IndexIntegrityCheckSegment(
ASSERT_SZLEAF_OK(pLeaf);
if( iRowidOff>=pLeaf->szLeaf ){
p->rc = FTS5_CORRUPT;
- }else{
+ }else if( bSecureDelete==0 || iRowidOff>0 ){
+ i64 iDlRowid = fts5DlidxIterRowid(pDlidx);
fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid);
- if( iRowid!=fts5DlidxIterRowid(pDlidx) ) p->rc = FTS5_CORRUPT;
+ if( iRowid<iDlRowid || (bSecureDelete==0 && iRowid!=iDlRowid) ){
+ p->rc = FTS5_CORRUPT;
+ }
}
fts5DataRelease(pLeaf);
}
@@ -237077,13 +250722,14 @@ static int wx_sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCk
** function only.
*/
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** Decode a segment-data rowid from the %_data table. This function is
** the opposite of macro FTS5_SEGMENT_ROWID().
*/
static void fts5DecodeRowid(
i64 iRowid, /* Rowid from %_data table */
+ int *pbTombstone, /* OUT: Tombstone hash flag */
int *piSegid, /* OUT: Segment id */
int *pbDlidx, /* OUT: Dlidx flag */
int *piHeight, /* OUT: Height */
@@ -237099,13 +250745,16 @@ static void fts5DecodeRowid(
iRowid >>= FTS5_DATA_DLI_B;
*piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1));
+ iRowid >>= FTS5_DATA_ID_B;
+
+ *pbTombstone = (int)(iRowid & 0x0001);
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
- int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */
- fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno);
+ int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid compenents */
+ fts5DecodeRowid(iKey, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno);
if( iSegid==0 ){
if( iKey==FTS5_AVERAGES_ROWID ){
@@ -237115,14 +250764,16 @@ static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
}
}
else{
- wx_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%ssegid=%d h=%d pgno=%d}",
- bDlidx ? "dlidx " : "", iSegid, iHeight, iPgno
+ wx_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%s%ssegid=%d h=%d pgno=%d}",
+ bDlidx ? "dlidx " : "",
+ bTomb ? "tombstone " : "",
+ iSegid, iHeight, iPgno
);
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static void fts5DebugStructure(
int *pRc, /* IN/OUT: error code */
Fts5Buffer *pBuf,
@@ -237137,16 +250788,22 @@ static void fts5DebugStructure(
);
for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
- wx_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}",
+ wx_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d",
pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast
);
+ if( pSeg->iOrigin1>0 ){
+ wx_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " origin=%lld..%lld",
+ pSeg->iOrigin1, pSeg->iOrigin2
+ );
+ }
+ wx_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}");
}
wx_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}");
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** This is part of the fts5_decode() debugging aid.
**
@@ -237171,9 +250828,9 @@ static void fts5DecodeStructure(
fts5DebugStructure(pRc, pBuf, p);
fts5StructureRelease(p);
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** This is part of the fts5_decode() debugging aid.
**
@@ -237196,9 +250853,9 @@ static void fts5DecodeAverages(
zSpace = " ";
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** Buffer (a/n) is assumed to contain a list of serialized varints. Read
** each varint and append its string representation to buffer pBuf. Return
@@ -237215,9 +250872,9 @@ static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
}
return iOff;
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** The start of buffer (a/n) contains the start of a doclist. The doclist
** may or may not finish within the buffer. This function appends a text
@@ -237250,9 +250907,9 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
return iOff;
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** This function is part of the fts5_decode() debugging function. It is
** only ever used with detail=none tables.
@@ -237293,9 +250950,27 @@ static void fts5DecodeRowidList(
wx_sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp);
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
+static void fts5BufferAppendTerm(int *pRc, Fts5Buffer *pBuf, Fts5Buffer *pTerm){
+ int ii;
+ fts5BufferGrow(pRc, pBuf, pTerm->n*2 + 1);
+ if( *pRc==SQLITE_OK ){
+ for(ii=0; ii<pTerm->n; ii++){
+ if( pTerm->p[ii]==0x00 ){
+ pBuf->p[pBuf->n++] = '\\';
+ pBuf->p[pBuf->n++] = '0';
+ }else{
+ pBuf->p[pBuf->n++] = pTerm->p[ii];
+ }
+ }
+ pBuf->p[pBuf->n] = 0x00;
+ }
+}
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
+
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** The implementation of user-defined scalar function fts5_decode().
*/
@@ -237306,6 +250981,7 @@ static void fts5DecodeFunction(
){
i64 iRowid; /* Rowid for record being decoded */
int iSegid,iHeight,iPgno,bDlidx;/* Rowid components */
+ int bTomb;
const u8 *aBlob; int n; /* Record to decode */
u8 *a = 0;
Fts5Buffer s; /* Build up text to return here */
@@ -237328,7 +251004,7 @@ static void fts5DecodeFunction(
if( a==0 ) goto decode_out;
if( n>0 ) memcpy(a, aBlob, n);
- fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno);
+ fts5DecodeRowid(iRowid, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno);
fts5DebugRowid(&rc, &s, iRowid);
if( bDlidx ){
@@ -237347,6 +251023,28 @@ static void fts5DecodeFunction(
" %d(%lld)", lvl.iLeafPgno, lvl.iRowid
);
}
+ }else if( bTomb ){
+ u32 nElem = fts5GetU32(&a[4]);
+ int szKey = (aBlob[0]==4 || aBlob[0]==8) ? aBlob[0] : 8;
+ int nSlot = (n - 8) / szKey;
+ int ii;
+ wx_sqlite3Fts5BufferAppendPrintf(&rc, &s, " nElem=%d", (int)nElem);
+ if( aBlob[1] ){
+ wx_sqlite3Fts5BufferAppendPrintf(&rc, &s, " 0");
+ }
+ for(ii=0; ii<nSlot; ii++){
+ u64 iVal = 0;
+ if( szKey==4 ){
+ u32 *aSlot = (u32*)&aBlob[8];
+ if( aSlot[ii] ) iVal = fts5GetU32((u8*)&aSlot[ii]);
+ }else{
+ u64 *aSlot = (u64*)&aBlob[8];
+ if( aSlot[ii] ) iVal = fts5GetU64((u8*)&aSlot[ii]);
+ }
+ if( iVal!=0 ){
+ wx_sqlite3Fts5BufferAppendPrintf(&rc, &s, " %lld", (i64)iVal);
+ }
+ }
}else if( iSegid==0 ){
if( iRowid==FTS5_AVERAGES_ROWID ){
fts5DecodeAverages(&rc, &s, a, n);
@@ -237372,16 +251070,15 @@ static void fts5DecodeFunction(
fts5DecodeRowidList(&rc, &s, &a[4], iTermOff-4);
iOff = iTermOff;
- while( iOff<szLeaf ){
+ while( iOff<szLeaf && rc==SQLITE_OK ){
int nAppend;
/* Read the term data for the next term*/
iOff += fts5GetVarint32(&a[iOff], nAppend);
term.n = nKeep;
fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]);
- wx_sqlite3Fts5BufferAppendPrintf(
- &rc, &s, " term=%.*s", term.n, (const char*)term.p
- );
+ wx_sqlite3Fts5BufferAppendPrintf(&rc, &s, " term=");
+ fts5BufferAppendTerm(&rc, &s, &term);
iOff += nAppend;
/* Figure out where the doclist for this term ends */
@@ -237392,8 +251089,11 @@ static void fts5DecodeFunction(
}else{
iTermOff = szLeaf;
}
-
- fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff);
+ if( iTermOff>szLeaf ){
+ rc = FTS5_CORRUPT;
+ }else{
+ fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff);
+ }
iOff = iTermOff;
if( iOff<szLeaf ){
iOff += fts5GetVarint32(&a[iOff], nKeep);
@@ -237486,9 +251186,8 @@ static void fts5DecodeFunction(
fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]);
iOff += nByte;
- wx_sqlite3Fts5BufferAppendPrintf(
- &rc, &s, " term=%.*s", term.n, (const char*)term.p
- );
+ wx_sqlite3Fts5BufferAppendPrintf(&rc, &s, " term=");
+ fts5BufferAppendTerm(&rc, &s, &term);
iOff += fts5DecodeDoclist(&rc, &s, &a[iOff], iEnd-iOff);
}
@@ -237504,9 +251203,9 @@ static void fts5DecodeFunction(
}
fts5BufferFree(&s);
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** The implementation of user-defined scalar function fts5_rowid().
*/
@@ -237540,7 +251239,235 @@ static void fts5RowidFunction(
}
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
+
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
+
+typedef struct Fts5StructVtab Fts5StructVtab;
+struct Fts5StructVtab {
+ wx_sqlite3_vtab base;
+};
+
+typedef struct Fts5StructVcsr Fts5StructVcsr;
+struct Fts5StructVcsr {
+ wx_sqlite3_vtab_cursor base;
+ Fts5Structure *pStruct;
+ int iLevel;
+ int iSeg;
+ int iRowid;
+};
+
+/*
+** Create a new fts5_structure() table-valued function.
+*/
+static int fts5structConnectMethod(
+ wx_sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ wx_sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ Fts5StructVtab *pNew = 0;
+ int rc = SQLITE_OK;
+
+ rc = wx_sqlite3_declare_vtab(db,
+ "CREATE TABLE xyz("
+ "level, segment, merge, segid, leaf1, leaf2, loc1, loc2, "
+ "npgtombstone, nentrytombstone, nentry, struct HIDDEN);"
+ );
+ if( rc==SQLITE_OK ){
+ pNew = wx_sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
+ }
+
+ *ppVtab = (wx_sqlite3_vtab*)pNew;
+ return rc;
+}
+
+/*
+** We must have a single struct=? constraint that will be passed through
+** into the xFilter method. If there is no valid struct=? constraint,
+** then return an SQLITE_CONSTRAINT error.
+*/
+static int fts5structBestIndexMethod(
+ wx_sqlite3_vtab *tab,
+ wx_sqlite3_index_info *pIdxInfo
+){
+ int i;
+ int rc = SQLITE_CONSTRAINT;
+ struct wx_sqlite3_index_constraint *p;
+ pIdxInfo->estimatedCost = (double)100;
+ pIdxInfo->estimatedRows = 100;
+ pIdxInfo->idxNum = 0;
+ for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
+ if( p->usable==0 ) continue;
+ if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==11 ){
+ rc = SQLITE_OK;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ break;
+ }
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for bytecodevtab objects.
+*/
+static int fts5structDisconnectMethod(wx_sqlite3_vtab *pVtab){
+ Fts5StructVtab *p = (Fts5StructVtab*)pVtab;
+ wx_sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new bytecodevtab_cursor object.
+*/
+static int fts5structOpenMethod(wx_sqlite3_vtab *p, wx_sqlite3_vtab_cursor **ppCsr){
+ int rc = SQLITE_OK;
+ Fts5StructVcsr *pNew = 0;
+
+ pNew = wx_sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
+ *ppCsr = (wx_sqlite3_vtab_cursor*)pNew;
+
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a bytecodevtab_cursor.
+*/
+static int fts5structCloseMethod(wx_sqlite3_vtab_cursor *cur){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ fts5StructureRelease(pCsr->pStruct);
+ wx_sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a bytecodevtab_cursor to its next row of output.
+*/
+static int fts5structNextMethod(wx_sqlite3_vtab_cursor *cur){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ Fts5Structure *p = pCsr->pStruct;
+
+ assert( pCsr->pStruct );
+ pCsr->iSeg++;
+ pCsr->iRowid++;
+ while( pCsr->iLevel<p->nLevel && pCsr->iSeg>=p->aLevel[pCsr->iLevel].nSeg ){
+ pCsr->iLevel++;
+ pCsr->iSeg = 0;
+ }
+ if( pCsr->iLevel>=p->nLevel ){
+ fts5StructureRelease(pCsr->pStruct);
+ pCsr->pStruct = 0;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int fts5structEofMethod(wx_sqlite3_vtab_cursor *cur){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ return pCsr->pStruct==0;
+}
+
+static int fts5structRowidMethod(
+ wx_sqlite3_vtab_cursor *cur,
+ sqlite_int64 *piRowid
+){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ *piRowid = pCsr->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the bytecodevtab_cursor
+** is currently pointing.
+*/
+static int fts5structColumnMethod(
+ wx_sqlite3_vtab_cursor *cur, /* The cursor */
+ wx_sqlite3_context *ctx, /* First argument to wx_sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ Fts5Structure *p = pCsr->pStruct;
+ Fts5StructureSegment *pSeg = &p->aLevel[pCsr->iLevel].aSeg[pCsr->iSeg];
+
+ switch( i ){
+ case 0: /* level */
+ wx_sqlite3_result_int(ctx, pCsr->iLevel);
+ break;
+ case 1: /* segment */
+ wx_sqlite3_result_int(ctx, pCsr->iSeg);
+ break;
+ case 2: /* merge */
+ wx_sqlite3_result_int(ctx, pCsr->iSeg < p->aLevel[pCsr->iLevel].nMerge);
+ break;
+ case 3: /* segid */
+ wx_sqlite3_result_int(ctx, pSeg->iSegid);
+ break;
+ case 4: /* leaf1 */
+ wx_sqlite3_result_int(ctx, pSeg->pgnoFirst);
+ break;
+ case 5: /* leaf2 */
+ wx_sqlite3_result_int(ctx, pSeg->pgnoLast);
+ break;
+ case 6: /* origin1 */
+ wx_sqlite3_result_int64(ctx, pSeg->iOrigin1);
+ break;
+ case 7: /* origin2 */
+ wx_sqlite3_result_int64(ctx, pSeg->iOrigin2);
+ break;
+ case 8: /* npgtombstone */
+ wx_sqlite3_result_int(ctx, pSeg->nPgTombstone);
+ break;
+ case 9: /* nentrytombstone */
+ wx_sqlite3_result_int64(ctx, pSeg->nEntryTombstone);
+ break;
+ case 10: /* nentry */
+ wx_sqlite3_result_int64(ctx, pSeg->nEntry);
+ break;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Initialize a cursor.
+**
+** idxNum==0 means show all subprograms
+** idxNum==1 means show only the main bytecode and omit subprograms.
+*/
+static int fts5structFilterMethod(
+ wx_sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, wx_sqlite3_value **argv
+){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr *)pVtabCursor;
+ int rc = SQLITE_OK;
+
+ const u8 *aBlob = 0;
+ int nBlob = 0;
+
+ assert( argc==1 );
+ fts5StructureRelease(pCsr->pStruct);
+ pCsr->pStruct = 0;
+
+ nBlob = wx_sqlite3_value_bytes(argv[0]);
+ aBlob = (const u8*)wx_sqlite3_value_blob(argv[0]);
+ rc = fts5StructureDecode(aBlob, nBlob, 0, &pCsr->pStruct);
+ if( rc==SQLITE_OK ){
+ pCsr->iLevel = 0;
+ pCsr->iRowid = 0;
+ pCsr->iSeg = -1;
+ rc = fts5structNextMethod(pVtabCursor);
+ }
+
+ return rc;
+}
+
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
/*
** This is called as part of registering the FTS5 module with database
@@ -237551,7 +251478,7 @@ static void fts5RowidFunction(
** SQLite error code is returned instead.
*/
static int wx_sqlite3Fts5IndexInit(wx_sqlite3 *db){
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
int rc = wx_sqlite3_create_function(
db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
);
@@ -237568,6 +251495,37 @@ static int wx_sqlite3Fts5IndexInit(wx_sqlite3 *db){
db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0
);
}
+
+ if( rc==SQLITE_OK ){
+ static const wx_sqlite3_module fts5structure_module = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ fts5structConnectMethod, /* xConnect */
+ fts5structBestIndexMethod, /* xBestIndex */
+ fts5structDisconnectMethod, /* xDisconnect */
+ 0, /* xDestroy */
+ fts5structOpenMethod, /* xOpen */
+ fts5structCloseMethod, /* xClose */
+ fts5structFilterMethod, /* xFilter */
+ fts5structNextMethod, /* xNext */
+ fts5structEofMethod, /* xEof */
+ fts5structColumnMethod, /* xColumn */
+ fts5structRowidMethod, /* xRowid */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindFunction */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
+ };
+ rc = wx_sqlite3_create_module(db, "fts5_structure", &fts5structure_module, 0);
+ }
return rc;
#else
return SQLITE_OK;
@@ -237669,9 +251627,18 @@ struct Fts5Global {
Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */
Fts5Cursor *pCsr; /* First in list of all open cursors */
+ u32 aLocaleHdr[4];
};
/*
+** Size of header on fts5_locale() values. And macro to access a buffer
+** containing a copy of the header from an Fts5Config pointer.
+*/
+#define FTS5_LOCALE_HDR_SIZE ((int)sizeof( ((Fts5Global*)0)->aLocaleHdr ))
+#define FTS5_LOCALE_HDR(pConfig) ((const u8*)(pConfig->pGlobal->aLocaleHdr))
+
+
+/*
** Each auxiliary function registered with the FTS5 module is represented
** by an object of the following type. All such objects are stored as part
** of the Fts5Global.pAux list.
@@ -237689,11 +251656,28 @@ struct Fts5Auxiliary {
** Each tokenizer module registered with the FTS5 module is represented
** by an object of the following type. All such objects are stored as part
** of the Fts5Global.pTok list.
+**
+** bV2Native:
+** True if the tokenizer was registered using xCreateTokenizer_v2(), false
+** for xCreateTokenizer(). If this variable is true, then x2 is populated
+** with the routines as supplied by the caller and x1 contains synthesized
+** wrapper routines. In this case the user-data pointer passed to
+** x1.xCreate should be a pointer to the Fts5TokenizerModule structure,
+** not a copy of pUserData.
+**
+** Of course, if bV2Native is false, then x1 contains the real routines and
+** x2 the synthesized ones. In this case a pointer to the Fts5TokenizerModule
+** object should be passed to x2.xCreate.
+**
+** The synthesized wrapper routines are necessary for xFindTokenizer(_v2)
+** calls.
*/
struct Fts5TokenizerModule {
char *zName; /* Name of tokenizer */
void *pUserData; /* User pointer passed to xCreate() */
- fts5_tokenizer x; /* Tokenizer functions */
+ int bV2Native; /* True if v2 native tokenizer */
+ fts5_tokenizer x1; /* Tokenizer functions */
+ fts5_tokenizer_v2 x2; /* V2 tokenizer functions */
void (*xDestroy)(void*); /* Destructor function */
Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
};
@@ -237703,6 +251687,8 @@ struct Fts5FullTable {
Fts5Storage *pStorage; /* Document store */
Fts5Global *pGlobal; /* Global (connection wide) data */
Fts5Cursor *pSortCsr; /* Sort data from this cursor */
+ int iSavepoint; /* Successful xSavepoint()+1 */
+
#ifdef SQLITE_DEBUG
struct Fts5TransactionState ts;
#endif
@@ -237779,7 +251765,7 @@ struct Fts5Cursor {
Fts5Auxiliary *pAux; /* Currently executing extension function */
Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
- /* Cache used by auxiliary functions xInst() and xInstCount() */
+ /* Cache used by auxiliary API functions xInst() and xInstCount() */
Fts5PoslistReader *aInstIter; /* One for each phrase */
int nInstAlloc; /* Size of aInst[] array (entries / 3) */
int nInstCount; /* Number of phrase instances */
@@ -237890,10 +251876,16 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
#endif
/*
-** Return true if pTab is a contentless table.
+** Return true if pTab is a contentless table. If parameter bIncludeUnindexed
+** is true, this includes contentless tables that store UNINDEXED columns
+** only.
*/
-static int fts5IsContentless(Fts5FullTable *pTab){
- return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE;
+static int fts5IsContentless(Fts5FullTable *pTab, int bIncludeUnindexed){
+ int eContent = pTab->p.pConfig->eContent;
+ return (
+ eContent==FTS5_CONTENT_NONE
+ || (bIncludeUnindexed && eContent==FTS5_CONTENT_UNINDEXED)
+ );
}
/*
@@ -237961,8 +251953,12 @@ static int fts5InitVtab(
assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
}
if( rc==SQLITE_OK ){
+ pConfig->pzErrmsg = pzErr;
pTab->p.pConfig = pConfig;
pTab->pGlobal = pGlobal;
+ if( bCreate || wx_sqlite3Fts5TokenizerPreload(&pConfig->t) ){
+ rc = wx_sqlite3Fts5LoadTokenizer(pConfig);
+ }
}
/* Open the index sub-system */
@@ -237984,13 +251980,17 @@ static int fts5InitVtab(
/* Load the initial configuration */
if( rc==SQLITE_OK ){
- assert( pConfig->pzErrmsg==0 );
- pConfig->pzErrmsg = pzErr;
- rc = wx_sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
- wx_sqlite3Fts5IndexRollback(pTab->p.pIndex);
- pConfig->pzErrmsg = 0;
+ rc = wx_sqlite3Fts5ConfigLoad(pTab->p.pConfig, pTab->p.pConfig->iCookie-1);
+ }
+
+ if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ rc = wx_sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, (int)1);
+ }
+ if( rc==SQLITE_OK ){
+ rc = wx_sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
}
+ if( pConfig ) pConfig->pzErrmsg = 0;
if( rc!=SQLITE_OK ){
fts5FreeVtab(pTab);
pTab = 0;
@@ -238058,10 +252058,10 @@ static int fts5UsePatternMatch(
){
assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB );
assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE );
- if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
+ if( pConfig->t.ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
return 1;
}
- if( pConfig->ePattern==FTS5_PATTERN_LIKE
+ if( pConfig->t.ePattern==FTS5_PATTERN_LIKE
&& (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB)
){
return 1;
@@ -238108,10 +252108,10 @@ static int fts5UsePatternMatch(
** This function ensures that there is at most one "r" or "=". And that if
** there exists an "=" then there is no "<" or ">".
**
-** Costs are assigned as follows:
+** If an unusable MATCH operator is present in the WHERE clause, then
+** SQLITE_CONSTRAINT is returned.
**
-** a) If an unusable MATCH operator is present in the WHERE clause, the
-** cost is unconditionally set to 1e50 (a really big number).
+** Costs are assigned as follows:
**
** a) If a MATCH operator is present, the cost depends on the other
** constraints also present. As follows:
@@ -238144,7 +252144,7 @@ static int fts5BestIndexMethod(wx_sqlite3_vtab *pVTab, wx_sqlite3_index_info *pI
int bSeenEq = 0;
int bSeenGt = 0;
int bSeenLt = 0;
- int bSeenMatch = 0;
+ int nSeenMatch = 0;
int bSeenRank = 0;
@@ -238175,18 +252175,15 @@ static int fts5BestIndexMethod(wx_sqlite3_vtab *pVTab, wx_sqlite3_index_info *pI
/* A MATCH operator or equivalent */
if( p->usable==0 || iCol<0 ){
/* As there exists an unusable MATCH constraint this is an
- ** unusable plan. Set a prohibitively high cost. */
- pInfo->estimatedCost = 1e50;
- assert( iIdxStr < pInfo->nConstraint*6 + 1 );
- idxStr[iIdxStr] = 0;
- return SQLITE_OK;
+ ** unusable plan. Return SQLITE_CONSTRAINT. */
+ return SQLITE_CONSTRAINT;
}else{
if( iCol==nCol+1 ){
if( bSeenRank ) continue;
idxStr[iIdxStr++] = 'r';
bSeenRank = 1;
- }else if( iCol>=0 ){
- bSeenMatch = 1;
+ }else{
+ nSeenMatch++;
idxStr[iIdxStr++] = 'M';
wx_sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
idxStr += strlen(&idxStr[iIdxStr]);
@@ -238203,6 +252200,7 @@ static int fts5BestIndexMethod(wx_sqlite3_vtab *pVTab, wx_sqlite3_index_info *pI
idxStr += strlen(&idxStr[iIdxStr]);
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
assert( idxStr[iIdxStr]=='\0' );
+ nSeenMatch++;
}else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){
idxStr[iIdxStr++] = '=';
bSeenEq = 1;
@@ -238233,12 +252231,15 @@ static int fts5BestIndexMethod(wx_sqlite3_vtab *pVTab, wx_sqlite3_index_info *pI
}
idxStr[iIdxStr] = '\0';
- /* Set idxFlags flags for the ORDER BY clause */
+ /* Set idxFlags flags for the ORDER BY clause
+ **
+ ** Note that tokendata=1 tables cannot currently handle "ORDER BY rowid DESC".
+ */
if( pInfo->nOrderBy==1 ){
int iSort = pInfo->aOrderBy[0].iColumn;
- if( iSort==(pConfig->nCol+1) && bSeenMatch ){
+ if( iSort==(pConfig->nCol+1) && nSeenMatch>0 ){
idxFlags |= FTS5_BI_ORDER_RANK;
- }else if( iSort==-1 ){
+ }else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){
idxFlags |= FTS5_BI_ORDER_ROWID;
}
if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
@@ -238251,14 +252252,17 @@ static int fts5BestIndexMethod(wx_sqlite3_vtab *pVTab, wx_sqlite3_index_info *pI
/* Calculate the estimated cost based on the flags set in idxFlags. */
if( bSeenEq ){
- pInfo->estimatedCost = bSeenMatch ? 100.0 : 10.0;
- if( bSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
+ pInfo->estimatedCost = nSeenMatch ? 1000.0 : 10.0;
+ if( nSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
}else if( bSeenLt && bSeenGt ){
- pInfo->estimatedCost = bSeenMatch ? 500.0 : 250000.0;
+ pInfo->estimatedCost = nSeenMatch ? 5000.0 : 250000.0;
}else if( bSeenLt || bSeenGt ){
- pInfo->estimatedCost = bSeenMatch ? 750.0 : 750000.0;
+ pInfo->estimatedCost = nSeenMatch ? 7500.0 : 750000.0;
}else{
- pInfo->estimatedCost = bSeenMatch ? 1000.0 : 1000000.0;
+ pInfo->estimatedCost = nSeenMatch ? 10000.0 : 1000000.0;
+ }
+ for(i=1; i<nSeenMatch; i++){
+ pInfo->estimatedCost *= 0.4;
}
pInfo->idxNum = idxFlags;
@@ -238490,6 +252494,16 @@ static int fts5NextMethod(wx_sqlite3_vtab_cursor *pCursor){
);
assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
+ /* If this cursor uses FTS5_PLAN_MATCH and this is a tokendata=1 table,
+ ** clear any token mappings accumulated at the fts5_index.c level. In
+ ** other cases, specifically FTS5_PLAN_SOURCE and FTS5_PLAN_SORTED_MATCH,
+ ** we need to retain the mappings for the entire query. */
+ if( pCsr->ePlan==FTS5_PLAN_MATCH
+ && ((Fts5Table*)pCursor->pVtab)->pConfig->bTokendata
+ ){
+ wx_sqlite3Fts5ExprClearTokens(pCsr->pExpr);
+ }
+
if( pCsr->ePlan<3 ){
int bSkip = 0;
if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
@@ -238524,6 +252538,7 @@ static int fts5NextMethod(wx_sqlite3_vtab_cursor *pCursor){
}
}else{
rc = SQLITE_OK;
+ CsrFlagSet(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
}
break;
}
@@ -238553,7 +252568,7 @@ static int fts5PrepareStatement(
rc = wx_sqlite3_prepare_v3(pConfig->db, zSql, -1,
SQLITE_PREPARE_PERSISTENT, &pRet, 0);
if( rc!=SQLITE_OK ){
- *pConfig->pzErrmsg = wx_sqlite3_mprintf("%s", wx_sqlite3_errmsg(pConfig->db));
+ wx_sqlite3Fts5ConfigErrmsg(pConfig, "%s", wx_sqlite3_errmsg(pConfig->db));
}
wx_sqlite3_free(zSql);
}
@@ -238778,6 +252793,145 @@ static i64 fts5GetRowidLimit(wx_sqlite3_value *pVal, i64 iDefault){
}
/*
+** Set the error message on the virtual table passed as the first argument.
+*/
+static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
+ va_list ap; /* ... printf arguments */
+ va_start(ap, zFormat);
+ wx_sqlite3_free(p->p.base.zErrMsg);
+ p->p.base.zErrMsg = wx_sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+}
+
+/*
+** Arrange for subsequent calls to wx_sqlite3Fts5Tokenize() to use the locale
+** specified by pLocale/nLocale. The buffer indicated by pLocale must remain
+** valid until after the final call to wx_sqlite3Fts5Tokenize() that will use
+** the locale.
+*/
+static void wx_sqlite3Fts5SetLocale(
+ Fts5Config *pConfig,
+ const char *zLocale,
+ int nLocale
+){
+ Fts5TokenizerConfig *pT = &pConfig->t;
+ pT->pLocale = zLocale;
+ pT->nLocale = nLocale;
+}
+
+/*
+** Clear any locale configured by an earlier call to wx_sqlite3Fts5SetLocale().
+*/
+static void wx_sqlite3Fts5ClearLocale(Fts5Config *pConfig){
+ wx_sqlite3Fts5SetLocale(pConfig, 0, 0);
+}
+
+/*
+** Return true if the value passed as the only argument is an
+** fts5_locale() value.
+*/
+static int wx_sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, wx_sqlite3_value *pVal){
+ int ret = 0;
+ if( wx_sqlite3_value_type(pVal)==SQLITE_BLOB ){
+ /* Call wx_sqlite3_value_bytes() after wx_sqlite3_value_blob() in this case.
+ ** If the blob was created using zeroblob(), then wx_sqlite3_value_blob()
+ ** may call malloc(). If this malloc() fails, then the values returned
+ ** by both value_blob() and value_bytes() will be 0. If value_bytes() were
+ ** called first, then the NULL pointer returned by value_blob() might
+ ** be dereferenced. */
+ const u8 *pBlob = wx_sqlite3_value_blob(pVal);
+ int nBlob = wx_sqlite3_value_bytes(pVal);
+ if( nBlob>FTS5_LOCALE_HDR_SIZE
+ && 0==memcmp(pBlob, FTS5_LOCALE_HDR(pConfig), FTS5_LOCALE_HDR_SIZE)
+ ){
+ ret = 1;
+ }
+ }
+ return ret;
+}
+
+/*
+** Value pVal is guaranteed to be an fts5_locale() value, according to
+** wx_sqlite3Fts5IsLocaleValue(). This function extracts the text and locale
+** from the value and returns them separately.
+**
+** If successful, SQLITE_OK is returned and (*ppText) and (*ppLoc) set
+** to point to buffers containing the text and locale, as utf-8,
+** respectively. In this case output parameters (*pnText) and (*pnLoc) are
+** set to the sizes in bytes of these two buffers.
+**
+** Or, if an error occurs, then an SQLite error code is returned. The final
+** value of the four output parameters is undefined in this case.
+*/
+static int wx_sqlite3Fts5DecodeLocaleValue(
+ wx_sqlite3_value *pVal,
+ const char **ppText,
+ int *pnText,
+ const char **ppLoc,
+ int *pnLoc
+){
+ const char *p = wx_sqlite3_value_blob(pVal);
+ int n = wx_sqlite3_value_bytes(pVal);
+ int nLoc = 0;
+
+ assert( wx_sqlite3_value_type(pVal)==SQLITE_BLOB );
+ assert( n>FTS5_LOCALE_HDR_SIZE );
+
+ for(nLoc=FTS5_LOCALE_HDR_SIZE; p[nLoc]; nLoc++){
+ if( nLoc==(n-1) ){
+ return SQLITE_MISMATCH;
+ }
+ }
+ *ppLoc = &p[FTS5_LOCALE_HDR_SIZE];
+ *pnLoc = nLoc - FTS5_LOCALE_HDR_SIZE;
+
+ *ppText = &p[nLoc+1];
+ *pnText = n - nLoc - 1;
+ return SQLITE_OK;
+}
+
+/*
+** Argument pVal is the text of a full-text search expression. It may or
+** may not have been wrapped by fts5_locale(). This function extracts
+** the text of the expression, and sets output variable (*pzText) to
+** point to a nul-terminated buffer containing the expression.
+**
+** If pVal was an fts5_locale() value, then wx_sqlite3Fts5SetLocale() is called
+** to set the tokenizer to use the specified locale.
+**
+** If output variable (*pbFreeAndReset) is set to true, then the caller
+** is required to (a) call wx_sqlite3Fts5ClearLocale() to reset the tokenizer
+** locale, and (b) call wx_sqlite3_free() to free (*pzText).
+*/
+static int fts5ExtractExprText(
+ Fts5Config *pConfig, /* Fts5 configuration */
+ wx_sqlite3_value *pVal, /* Value to extract expression text from */
+ char **pzText, /* OUT: nul-terminated buffer of text */
+ int *pbFreeAndReset /* OUT: Free (*pzText) and clear locale */
+){
+ int rc = SQLITE_OK;
+
+ if( wx_sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ const char *pText = 0;
+ int nText = 0;
+ const char *pLoc = 0;
+ int nLoc = 0;
+ rc = wx_sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ *pzText = wx_sqlite3Fts5Mprintf(&rc, "%.*s", nText, pText);
+ if( rc==SQLITE_OK ){
+ wx_sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ }
+ *pbFreeAndReset = 1;
+ }else{
+ *pzText = (char*)wx_sqlite3_value_text(pVal);
+ *pbFreeAndReset = 0;
+ }
+
+ return rc;
+}
+
+
+/*
** This is the xFilter interface for the virtual table. See
** the virtual table xFilter method documentation for additional
** information.
@@ -238811,13 +252965,7 @@ static int fts5FilterMethod(
int iIdxStr = 0;
Fts5Expr *pExpr = 0;
- if( pConfig->bLock ){
- pTab->p.base.zErrMsg = wx_sqlite3_mprintf(
- "recursively defined fts5 content table"
- );
- return SQLITE_ERROR;
- }
-
+ assert( pConfig->bLock==0 );
if( pCsr->ePlan ){
fts5FreeCursorComponents(pCsr);
memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
@@ -238841,8 +252989,14 @@ static int fts5FilterMethod(
pRank = apVal[i];
break;
case 'M': {
- const char *zText = (const char*)wx_sqlite3_value_text(apVal[i]);
+ char *zText = 0;
+ int bFreeAndReset = 0;
+ int bInternal = 0;
+
+ rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset);
+ if( rc!=SQLITE_OK ) goto filter_out;
if( zText==0 ) zText = "";
+
iCol = 0;
do{
iCol = iCol*10 + (idxStr[iIdxStr]-'0');
@@ -238854,7 +253008,7 @@ static int fts5FilterMethod(
** indicates that the MATCH expression is not a full text query,
** but a request for an internal parameter. */
rc = fts5SpecialMatch(pTab, pCsr, &zText[1]);
- goto filter_out;
+ bInternal = 1;
}else{
char **pzErr = &pTab->p.base.zErrMsg;
rc = wx_sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr);
@@ -238862,9 +253016,15 @@ static int fts5FilterMethod(
rc = wx_sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
pExpr = 0;
}
- if( rc!=SQLITE_OK ) goto filter_out;
}
+ if( bFreeAndReset ){
+ wx_sqlite3_free(zText);
+ wx_sqlite3Fts5ClearLocale(pConfig);
+ }
+
+ if( bInternal || rc!=SQLITE_OK ) goto filter_out;
+
break;
}
case 'L':
@@ -238915,6 +253075,9 @@ static int fts5FilterMethod(
pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
}
+ rc = wx_sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ if( rc!=SQLITE_OK ) goto filter_out;
+
if( pTab->pSortCsr ){
/* If pSortCsr is non-NULL, then this call is being made as part of
** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
@@ -238937,6 +253100,7 @@ static int fts5FilterMethod(
pCsr->pExpr = pTab->pSortCsr->pExpr;
rc = fts5CursorFirst(pTab, pCsr, bDesc);
}else if( pCsr->pExpr ){
+ assert( rc==SQLITE_OK );
rc = fts5CursorParseRank(pConfig, pCsr, pRank);
if( rc==SQLITE_OK ){
if( bOrderByRank ){
@@ -238948,9 +253112,7 @@ static int fts5FilterMethod(
}
}
}else if( pConfig->zContent==0 ){
- *pConfig->pzErrmsg = wx_sqlite3_mprintf(
- "%s: table does not support scanning", pConfig->zName
- );
+ fts5SetVtabError(pTab,"%s: table does not support scanning",pConfig->zName);
rc = SQLITE_ERROR;
}else{
/* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
@@ -238993,9 +253155,13 @@ static i64 fts5CursorRowid(Fts5Cursor *pCsr){
assert( pCsr->ePlan==FTS5_PLAN_MATCH
|| pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
|| pCsr->ePlan==FTS5_PLAN_SOURCE
+ || pCsr->ePlan==FTS5_PLAN_SCAN
+ || pCsr->ePlan==FTS5_PLAN_ROWID
);
if( pCsr->pSorter ){
return pCsr->pSorter->iRowid;
+ }else if( pCsr->ePlan>=FTS5_PLAN_SCAN ){
+ return wx_sqlite3_column_int64(pCsr->pStmt, 0);
}else{
return wx_sqlite3Fts5ExprRowid(pCsr->pExpr);
}
@@ -239012,25 +253178,16 @@ static int fts5RowidMethod(wx_sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid
int ePlan = pCsr->ePlan;
assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
- switch( ePlan ){
- case FTS5_PLAN_SPECIAL:
- *pRowid = 0;
- break;
-
- case FTS5_PLAN_SOURCE:
- case FTS5_PLAN_MATCH:
- case FTS5_PLAN_SORTED_MATCH:
- *pRowid = fts5CursorRowid(pCsr);
- break;
-
- default:
- *pRowid = wx_sqlite3_column_int64(pCsr->pStmt, 0);
- break;
+ if( ePlan==FTS5_PLAN_SPECIAL ){
+ *pRowid = 0;
+ }else{
+ *pRowid = fts5CursorRowid(pCsr);
}
return SQLITE_OK;
}
+
/*
** If the cursor requires seeking (bSeekRequired flag is set), seek it.
** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
@@ -239067,8 +253224,13 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
rc = wx_sqlite3_reset(pCsr->pStmt);
if( rc==SQLITE_OK ){
rc = FTS5_CORRUPT;
+ fts5SetVtabError((Fts5FullTable*)pTab,
+ "fts5: missing row %lld from content table %s",
+ fts5CursorRowid(pCsr),
+ pTab->pConfig->zContent
+ );
}else if( pTab->pConfig->pzErrmsg ){
- *pTab->pConfig->pzErrmsg = wx_sqlite3_mprintf(
+ fts5SetVtabError((Fts5FullTable*)pTab,
"%s", wx_sqlite3_errmsg(pTab->pConfig->db)
);
}
@@ -239077,14 +253239,6 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
return rc;
}
-static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
- va_list ap; /* ... printf arguments */
- va_start(ap, zFormat);
- assert( p->p.base.zErrMsg==0 );
- p->p.base.zErrMsg = wx_sqlite3_vmprintf(zFormat, ap);
- va_end(ap);
-}
-
/*
** This function is called to handle an FTS INSERT command. In other words,
** an INSERT statement of the form:
@@ -239108,6 +253262,7 @@ static int fts5SpecialInsert(
Fts5Config *pConfig = pTab->p.pConfig;
int rc = SQLITE_OK;
int bError = 0;
+ int bLoadConfig = 0;
if( 0==wx_sqlite3_stricmp("delete-all", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
@@ -239119,8 +253274,9 @@ static int fts5SpecialInsert(
}else{
rc = wx_sqlite3Fts5StorageDeleteAll(pTab->pStorage);
}
+ bLoadConfig = 1;
}else if( 0==wx_sqlite3_stricmp("rebuild", zCmd) ){
- if( pConfig->eContent==FTS5_CONTENT_NONE ){
+ if( fts5IsContentless(pTab, 1) ){
fts5SetVtabError(pTab,
"'rebuild' may not be used with a contentless fts5 table"
);
@@ -239128,6 +253284,7 @@ static int fts5SpecialInsert(
}else{
rc = wx_sqlite3Fts5StorageRebuild(pTab->pStorage);
}
+ bLoadConfig = 1;
}else if( 0==wx_sqlite3_stricmp("optimize", zCmd) ){
rc = wx_sqlite3Fts5StorageOptimize(pTab->pStorage);
}else if( 0==wx_sqlite3_stricmp("merge", zCmd) ){
@@ -239140,8 +253297,13 @@ static int fts5SpecialInsert(
}else if( 0==wx_sqlite3_stricmp("prefix-index", zCmd) ){
pConfig->bPrefixIndex = wx_sqlite3_value_int(pVal);
#endif
+ }else if( 0==wx_sqlite3_stricmp("flush", zCmd) ){
+ rc = wx_sqlite3Fts5FlushToDisk(&pTab->p);
}else{
- rc = wx_sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ rc = wx_sqlite3Fts5FlushToDisk(&pTab->p);
+ if( rc==SQLITE_OK ){
+ rc = wx_sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ }
if( rc==SQLITE_OK ){
rc = wx_sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError);
}
@@ -239153,6 +253315,12 @@ static int fts5SpecialInsert(
}
}
}
+
+ if( rc==SQLITE_OK && bLoadConfig ){
+ pTab->p.pConfig->iCookie--;
+ rc = wx_sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ }
+
return rc;
}
@@ -239164,7 +253332,7 @@ static int fts5SpecialDelete(
int eType1 = wx_sqlite3_value_type(apVal[1]);
if( eType1==SQLITE_INTEGER ){
wx_sqlite3_int64 iDel = wx_sqlite3_value_int64(apVal[1]);
- rc = wx_sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
+ rc = wx_sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2], 0);
}
return rc;
}
@@ -239177,7 +253345,7 @@ static void fts5StorageInsert(
){
int rc = *pRc;
if( rc==SQLITE_OK ){
- rc = wx_sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
+ rc = wx_sqlite3Fts5StorageContentInsert(pTab->pStorage, 0, apVal, piRowid);
}
if( rc==SQLITE_OK ){
rc = wx_sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
@@ -239186,6 +253354,67 @@ static void fts5StorageInsert(
}
/*
+**
+** This function is called when the user attempts an UPDATE on a contentless
+** table. Parameter bRowidModified is true if the UPDATE statement modifies
+** the rowid value. Parameter apVal[] contains the new values for each user
+** defined column of the fts5 table. pConfig is the configuration object of the
+** table being updated (guaranteed to be contentless). The contentless_delete=1
+** and contentless_unindexed=1 options may or may not be set.
+**
+** This function returns SQLITE_OK if the UPDATE can go ahead, or an SQLite
+** error code if it cannot. In this case an error message is also loaded into
+** pConfig. Output parameter (*pbContent) is set to true if the caller should
+** update the %_content table only - not the FTS index or any other shadow
+** table. This occurs when an UPDATE modifies only UNINDEXED columns of the
+** table.
+**
+** An UPDATE may proceed if:
+**
+** * The only columns modified are UNINDEXED columns, or
+**
+** * The contentless_delete=1 option was specified and all of the indexed
+** columns (not a subset) have been modified.
+*/
+static int fts5ContentlessUpdate(
+ Fts5Config *pConfig,
+ wx_sqlite3_value **apVal,
+ int bRowidModified,
+ int *pbContent
+){
+ int ii;
+ int bSeenIndex = 0; /* Have seen modified indexed column */
+ int bSeenIndexNC = 0; /* Have seen unmodified indexed column */
+ int rc = SQLITE_OK;
+
+ for(ii=0; ii<pConfig->nCol; ii++){
+ if( pConfig->abUnindexed[ii]==0 ){
+ if( wx_sqlite3_value_nochange(apVal[ii]) ){
+ bSeenIndexNC++;
+ }else{
+ bSeenIndex++;
+ }
+ }
+ }
+
+ if( bSeenIndex==0 && bRowidModified==0 ){
+ *pbContent = 1;
+ }else{
+ if( bSeenIndexNC || pConfig->bContentlessDelete==0 ){
+ rc = SQLITE_ERROR;
+ wx_sqlite3Fts5ConfigErrmsg(pConfig,
+ (pConfig->bContentlessDelete ?
+ "%s a subset of columns on fts5 contentless-delete table: %s" :
+ "%s contentless fts5 table: %s")
+ , "cannot UPDATE", pConfig->zName
+ );
+ }
+ }
+
+ return rc;
+}
+
+/*
** This function is the implementation of the xUpdate callback used by
** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
** inserted, updated or deleted.
@@ -239209,6 +253438,7 @@ static int fts5UpdateMethod(
Fts5Config *pConfig = pTab->p.pConfig;
int eType0; /* value_type() of apVal[0] */
int rc = SQLITE_OK; /* Return code */
+ int bUpdateOrDelete = 0;
/* A transaction must be open when this is called. */
assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
@@ -239219,6 +253449,11 @@ static int fts5UpdateMethod(
|| wx_sqlite3_value_type(apVal[0])==SQLITE_NULL
);
assert( pTab->p.pConfig->pzErrmsg==0 );
+ if( pConfig->pgsz==0 ){
+ rc = wx_sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
/* Put any active cursors into REQUIRE_SEEK state. */
@@ -239233,7 +253468,15 @@ static int fts5UpdateMethod(
if( pConfig->eContent!=FTS5_CONTENT_NORMAL
&& 0==wx_sqlite3_stricmp("delete", z)
){
- rc = fts5SpecialDelete(pTab, apVal);
+ if( pConfig->bContentlessDelete ){
+ fts5SetVtabError(pTab,
+ "'delete' may not be used with a contentless_delete=1 table"
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ rc = fts5SpecialDelete(pTab, apVal);
+ bUpdateOrDelete = 1;
+ }
}else{
rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
}
@@ -239250,74 +253493,128 @@ static int fts5UpdateMethod(
** Cases 3 and 4 may violate the rowid constraint.
*/
int eConflict = SQLITE_ABORT;
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->bContentlessDelete ){
eConflict = wx_sqlite3_vtab_on_conflict(pConfig->db);
}
assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
assert( nArg!=1 || eType0==SQLITE_INTEGER );
- /* Filter out attempts to run UPDATE or DELETE on contentless tables.
- ** This is not suported. */
- if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
- pTab->p.base.zErrMsg = wx_sqlite3_mprintf(
- "cannot %s contentless fts5 table: %s",
- (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
- );
- rc = SQLITE_ERROR;
- }
-
/* DELETE */
- else if( nArg==1 ){
- i64 iDel = wx_sqlite3_value_int64(apVal[0]); /* Rowid to delete */
- rc = wx_sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
+ if( nArg==1 ){
+ /* It is only possible to DELETE from a contentless table if the
+ ** contentless_delete=1 flag is set. */
+ if( fts5IsContentless(pTab, 1) && pConfig->bContentlessDelete==0 ){
+ fts5SetVtabError(pTab,
+ "cannot DELETE from contentless fts5 table: %s", pConfig->zName
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ i64 iDel = wx_sqlite3_value_int64(apVal[0]); /* Rowid to delete */
+ rc = wx_sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0);
+ bUpdateOrDelete = 1;
+ }
}
/* INSERT or UPDATE */
else{
int eType1 = wx_sqlite3_value_numeric_type(apVal[1]);
- if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){
- rc = SQLITE_MISMATCH;
+ /* It is an error to write an fts5_locale() value to a table without
+ ** the locale=1 option. */
+ if( pConfig->bLocale==0 ){
+ int ii;
+ for(ii=0; ii<pConfig->nCol; ii++){
+ wx_sqlite3_value *pVal = apVal[ii+2];
+ if( wx_sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ fts5SetVtabError(pTab, "fts5_locale() requires locale=1");
+ rc = SQLITE_MISMATCH;
+ goto update_out;
+ }
+ }
}
- else if( eType0!=SQLITE_INTEGER ){
- /* If this is a REPLACE, first remove the current entry (if any) */
+ if( eType0!=SQLITE_INTEGER ){
+ /* An INSERT statement. If the conflict-mode is REPLACE, first remove
+ ** the current entry (if any). */
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
i64 iNew = wx_sqlite3_value_int64(apVal[1]); /* Rowid to delete */
- rc = wx_sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
+ rc = wx_sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
+ bUpdateOrDelete = 1;
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
/* UPDATE */
else{
+ Fts5Storage *pStorage = pTab->pStorage;
i64 iOld = wx_sqlite3_value_int64(apVal[0]); /* Old rowid */
i64 iNew = wx_sqlite3_value_int64(apVal[1]); /* New rowid */
- if( eType1==SQLITE_INTEGER && iOld!=iNew ){
+ int bContent = 0; /* Content only update */
+
+ /* If this is a contentless table (including contentless_unindexed=1
+ ** tables), check if the UPDATE may proceed. */
+ if( fts5IsContentless(pTab, 1) ){
+ rc = fts5ContentlessUpdate(pConfig, &apVal[2], iOld!=iNew, &bContent);
+ if( rc!=SQLITE_OK ) goto update_out;
+ }
+
+ if( eType1!=SQLITE_INTEGER ){
+ rc = SQLITE_MISMATCH;
+ }else if( iOld!=iNew ){
+ assert( bContent==0 );
if( eConflict==SQLITE_REPLACE ){
- rc = wx_sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ rc = wx_sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1);
if( rc==SQLITE_OK ){
- rc = wx_sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
+ rc = wx_sqlite3Fts5StorageDelete(pStorage, iNew, 0, 0);
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}else{
- rc = wx_sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
+ rc = wx_sqlite3Fts5StorageFindDeleteRow(pStorage, iOld);
+ if( rc==SQLITE_OK ){
+ rc = wx_sqlite3Fts5StorageContentInsert(pStorage, 0, apVal, pRowid);
+ }
if( rc==SQLITE_OK ){
- rc = wx_sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ rc = wx_sqlite3Fts5StorageDelete(pStorage, iOld, 0, 0);
}
if( rc==SQLITE_OK ){
- rc = wx_sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
+ rc = wx_sqlite3Fts5StorageIndexInsert(pStorage, apVal, *pRowid);
}
}
+ }else if( bContent ){
+ /* This occurs when an UPDATE on a contentless table affects *only*
+ ** UNINDEXED columns. This is a no-op for contentless_unindexed=0
+ ** tables, or a write to the %_content table only for =1 tables. */
+ assert( fts5IsContentless(pTab, 1) );
+ rc = wx_sqlite3Fts5StorageFindDeleteRow(pStorage, iOld);
+ if( rc==SQLITE_OK ){
+ rc = wx_sqlite3Fts5StorageContentInsert(pStorage, 1, apVal, pRowid);
+ }
}else{
- rc = wx_sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ rc = wx_sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1);
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
+ bUpdateOrDelete = 1;
+ wx_sqlite3Fts5StorageReleaseDeleteRow(pStorage);
}
+
+ }
+ }
+
+ if( rc==SQLITE_OK
+ && bUpdateOrDelete
+ && pConfig->bSecureDelete
+ && pConfig->iVersion==FTS5_CURRENT_VERSION
+ ){
+ rc = wx_sqlite3Fts5StorageConfigValue(
+ pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE
+ );
+ if( rc==SQLITE_OK ){
+ pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
}
}
+ update_out:
pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
@@ -239330,8 +253627,7 @@ static int fts5SyncMethod(wx_sqlite3_vtab *pVtab){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
- fts5TripCursors(pTab);
- rc = wx_sqlite3Fts5StorageSync(pTab->pStorage);
+ rc = wx_sqlite3Fts5FlushToDisk(&pTab->p);
pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
@@ -239340,9 +253636,11 @@ static int fts5SyncMethod(wx_sqlite3_vtab *pVtab){
** Implementation of xBegin() method.
*/
static int fts5BeginMethod(wx_sqlite3_vtab *pVtab){
- fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
- fts5NewTransaction((Fts5FullTable*)pVtab);
- return SQLITE_OK;
+ int rc = fts5NewTransaction((Fts5FullTable*)pVtab);
+ if( rc==SQLITE_OK ){
+ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
+ }
+ return rc;
}
/*
@@ -239396,17 +253694,40 @@ static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
return wx_sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
}
-static int fts5ApiTokenize(
+/*
+** Implementation of xTokenize_v2() API.
+*/
+static int fts5ApiTokenize_v2(
Fts5Context *pCtx,
const char *pText, int nText,
+ const char *pLoc, int nLoc,
void *pUserData,
int (*xToken)(void*, int, const char*, int, int, int)
){
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- return wx_sqlite3Fts5Tokenize(
- pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
+ int rc = SQLITE_OK;
+
+ wx_sqlite3Fts5SetLocale(pTab->pConfig, pLoc, nLoc);
+ rc = wx_sqlite3Fts5Tokenize(pTab->pConfig,
+ FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
);
+ wx_sqlite3Fts5SetLocale(pTab->pConfig, 0, 0);
+
+ return rc;
+}
+
+/*
+** Implementation of xTokenize() API. This is just xTokenize_v2() with NULL/0
+** passed as the locale.
+*/
+static int fts5ApiTokenize(
+ Fts5Context *pCtx,
+ const char *pText, int nText,
+ void *pUserData,
+ int (*xToken)(void*, int, const char*, int, int, int)
+){
+ return fts5ApiTokenize_v2(pCtx, pText, nText, 0, 0, pUserData, xToken);
}
static int fts5ApiPhraseCount(Fts5Context *pCtx){
@@ -239419,6 +253740,49 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
return wx_sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
}
+/*
+** Argument pStmt is an SQL statement of the type used by Fts5Cursor. This
+** function extracts the text value of column iCol of the current row.
+** Additionally, if there is an associated locale, it invokes
+** wx_sqlite3Fts5SetLocale() to configure the tokenizer. In all cases the caller
+** should invoke wx_sqlite3Fts5ClearLocale() to clear the locale at some point
+** after this function returns.
+**
+** If successful, (*ppText) is set to point to a buffer containing the text
+** value as utf-8 and SQLITE_OK returned. (*pnText) is set to the size of that
+** buffer in bytes. It is not guaranteed to be nul-terminated. If an error
+** occurs, an SQLite error code is returned. The final values of the two
+** output parameters are undefined in this case.
+*/
+static int fts5TextFromStmt(
+ Fts5Config *pConfig,
+ wx_sqlite3_stmt *pStmt,
+ int iCol,
+ const char **ppText,
+ int *pnText
+){
+ wx_sqlite3_value *pVal = wx_sqlite3_column_value(pStmt, iCol+1);
+ const char *pLoc = 0;
+ int nLoc = 0;
+ int rc = SQLITE_OK;
+
+ if( pConfig->bLocale
+ && pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && wx_sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ rc = wx_sqlite3Fts5DecodeLocaleValue(pVal, ppText, pnText, &pLoc, &nLoc);
+ }else{
+ *ppText = (const char*)wx_sqlite3_value_text(pVal);
+ *pnText = wx_sqlite3_value_bytes(pVal);
+ if( pConfig->bLocale && pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ pLoc = (const char*)wx_sqlite3_column_text(pStmt, iCol+1+pConfig->nCol);
+ nLoc = wx_sqlite3_column_bytes(pStmt, iCol+1+pConfig->nCol);
+ }
+ }
+ wx_sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ return rc;
+}
+
static int fts5ApiColumnText(
Fts5Context *pCtx,
int iCol,
@@ -239427,46 +253791,69 @@ static int fts5ApiColumnText(
){
int rc = SQLITE_OK;
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
- || pCsr->ePlan==FTS5_PLAN_SPECIAL
- ){
+ Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
+ if( iCol<0 || iCol>=pTab->pConfig->nCol ){
+ rc = SQLITE_RANGE;
+ }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab), 0) ){
*pz = 0;
*pn = 0;
}else{
rc = fts5SeekCursor(pCsr, 0);
if( rc==SQLITE_OK ){
- *pz = (const char*)wx_sqlite3_column_text(pCsr->pStmt, iCol+1);
- *pn = wx_sqlite3_column_bytes(pCsr->pStmt, iCol+1);
+ rc = fts5TextFromStmt(pTab->pConfig, pCsr->pStmt, iCol, pz, pn);
+ wx_sqlite3Fts5ClearLocale(pTab->pConfig);
}
}
return rc;
}
+/*
+** This is called by various API functions - xInst, xPhraseFirst,
+** xPhraseFirstColumn etc. - to obtain the position list for phrase iPhrase
+** of the current row. This function works for both detail=full tables (in
+** which case the position-list was read from the fts index) or for other
+** detail= modes if the row content is available.
+*/
static int fts5CsrPoslist(
- Fts5Cursor *pCsr,
- int iPhrase,
- const u8 **pa,
- int *pn
+ Fts5Cursor *pCsr, /* Fts5 cursor object */
+ int iPhrase, /* Phrase to find position list for */
+ const u8 **pa, /* OUT: Pointer to position list buffer */
+ int *pn /* OUT: Size of (*pa) in bytes */
){
Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
int rc = SQLITE_OK;
int bLive = (pCsr->pSorter==0);
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
-
+ if( iPhrase<0 || iPhrase>=wx_sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
+ rc = SQLITE_RANGE;
+ }else if( pConfig->eDetail!=FTS5_DETAIL_FULL
+ && fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
+ ){
+ *pa = 0;
+ *pn = 0;
+ return SQLITE_OK;
+ }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
Fts5PoslistPopulator *aPopulator;
int i;
+
aPopulator = wx_sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
if( aPopulator==0 ) rc = SQLITE_NOMEM;
+ if( rc==SQLITE_OK ){
+ rc = fts5SeekCursor(pCsr, 0);
+ }
for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
- int n; const char *z;
- rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
+ const char *z = 0;
+ int n = 0;
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n);
if( rc==SQLITE_OK ){
rc = wx_sqlite3Fts5ExprPopulatePoslists(
pConfig, pCsr->pExpr, aPopulator, i, z, n
);
}
+ wx_sqlite3Fts5ClearLocale(pConfig);
}
wx_sqlite3_free(aPopulator);
@@ -239477,13 +253864,18 @@ static int fts5CsrPoslist(
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
}
- if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
- Fts5Sorter *pSorter = pCsr->pSorter;
- int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
- *pn = pSorter->aIdx[iPhrase] - i1;
- *pa = &pSorter->aPoslist[i1];
+ if( rc==SQLITE_OK ){
+ if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
+ Fts5Sorter *pSorter = pCsr->pSorter;
+ int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
+ *pn = pSorter->aIdx[iPhrase] - i1;
+ *pa = &pSorter->aPoslist[i1];
+ }else{
+ *pn = wx_sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
+ }
}else{
- *pn = wx_sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
+ *pa = 0;
+ *pn = 0;
}
return rc;
@@ -239554,7 +253946,8 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
aInst[0] = iBest;
aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
- if( aInst[1]<0 || aInst[1]>=nCol ){
+ assert( aInst[1]>=0 );
+ if( aInst[1]>=nCol ){
rc = FTS5_CORRUPT;
break;
}
@@ -239592,12 +253985,6 @@ static int fts5ApiInst(
){
if( iIdx<0 || iIdx>=pCsr->nInstCount ){
rc = SQLITE_RANGE;
-#if 0
- }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
- *piPhrase = pCsr->aInst[iIdx*3];
- *piCol = pCsr->aInst[iIdx*3 + 2];
- *piOff = -1;
-#endif
}else{
*piPhrase = pCsr->aInst[iIdx*3];
*piCol = pCsr->aInst[iIdx*3 + 1];
@@ -239638,7 +254025,7 @@ static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
if( pConfig->bColumnsize ){
i64 iRowid = fts5CursorRowid(pCsr);
rc = wx_sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
- }else if( pConfig->zContent==0 ){
+ }else if( !pConfig->zContent || pConfig->eContent==FTS5_CONTENT_UNINDEXED ){
int i;
for(i=0; i<pConfig->nCol; i++){
if( pConfig->abUnindexed[i]==0 ){
@@ -239647,17 +254034,19 @@ static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
}
}else{
int i;
+ rc = fts5SeekCursor(pCsr, 0);
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
if( pConfig->abUnindexed[i]==0 ){
- const char *z; int n;
- void *p = (void*)(&pCsr->aColumnSize[i]);
+ const char *z = 0;
+ int n = 0;
pCsr->aColumnSize[i] = 0;
- rc = fts5ApiColumnText(pCtx, i, &z, &n);
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n);
if( rc==SQLITE_OK ){
- rc = wx_sqlite3Fts5Tokenize(
- pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
+ rc = wx_sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX,
+ z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb
);
}
+ wx_sqlite3Fts5ClearLocale(pConfig);
}
}
}
@@ -239737,11 +254126,10 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
}
static void fts5ApiPhraseNext(
- Fts5Context *pUnused,
+ Fts5Context *pCtx,
Fts5PhraseIter *pIter,
int *piCol, int *piOff
){
- UNUSED_PARAM(pUnused);
if( pIter->a>=pIter->b ){
*piCol = -1;
*piOff = -1;
@@ -239749,8 +254137,12 @@ static void fts5ApiPhraseNext(
int iVal;
pIter->a += fts5GetVarint32(pIter->a, iVal);
if( iVal==1 ){
+ /* Avoid returning a (*piCol) value that is too large for the table,
+ ** even if the position-list is corrupt. The caller might not be
+ ** expecting it. */
+ int nCol = ((Fts5Table*)(((Fts5Cursor*)pCtx)->base.pVtab))->pConfig->nCol;
pIter->a += fts5GetVarint32(pIter->a, iVal);
- *piCol = iVal;
+ *piCol = (iVal>=nCol ? nCol-1 : iVal);
*piOff = 0;
pIter->a += fts5GetVarint32(pIter->a, iVal);
}
@@ -239852,13 +254244,96 @@ static int fts5ApiPhraseFirstColumn(
return rc;
}
+/*
+** xQueryToken() API implemenetation.
+*/
+static int fts5ApiQueryToken(
+ Fts5Context* pCtx,
+ int iPhrase,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ return wx_sqlite3Fts5ExprQueryToken(pCsr->pExpr, iPhrase, iToken, ppOut, pnOut);
+}
+
+/*
+** xInstToken() API implemenetation.
+*/
+static int fts5ApiInstToken(
+ Fts5Context *pCtx,
+ int iIdx,
+ int iToken,
+ const char **ppOut, int *pnOut
+){
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ int rc = SQLITE_OK;
+ if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
+ || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
+ ){
+ if( iIdx<0 || iIdx>=pCsr->nInstCount ){
+ rc = SQLITE_RANGE;
+ }else{
+ int iPhrase = pCsr->aInst[iIdx*3];
+ int iCol = pCsr->aInst[iIdx*3 + 1];
+ int iOff = pCsr->aInst[iIdx*3 + 2];
+ i64 iRowid = fts5CursorRowid(pCsr);
+ rc = wx_sqlite3Fts5ExprInstToken(
+ pCsr->pExpr, iRowid, iPhrase, iCol, iOff, iToken, ppOut, pnOut
+ );
+ }
+ }
+ return rc;
+}
+
static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
);
+/*
+** The xColumnLocale() API.
+*/
+static int fts5ApiColumnLocale(
+ Fts5Context *pCtx,
+ int iCol,
+ const char **pzLocale,
+ int *pnLocale
+){
+ int rc = SQLITE_OK;
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
+
+ *pzLocale = 0;
+ *pnLocale = 0;
+
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
+ if( iCol<0 || iCol>=pConfig->nCol ){
+ rc = SQLITE_RANGE;
+ }else if(
+ pConfig->abUnindexed[iCol]==0
+ && 0==fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
+ && pConfig->bLocale
+ ){
+ rc = fts5SeekCursor(pCsr, 0);
+ if( rc==SQLITE_OK ){
+ const char *zDummy = 0;
+ int nDummy = 0;
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &zDummy, &nDummy);
+ if( rc==SQLITE_OK ){
+ *pzLocale = pConfig->t.pLocale;
+ *pnLocale = pConfig->t.nLocale;
+ }
+ wx_sqlite3Fts5ClearLocale(pConfig);
+ }
+ }
+
+ return rc;
+}
+
static const Fts5ExtensionApi sFts5Api = {
- 2, /* iVersion */
+ 4, /* iVersion */
fts5ApiUserData,
fts5ApiColumnCount,
fts5ApiRowCount,
@@ -239878,6 +254353,10 @@ static const Fts5ExtensionApi sFts5Api = {
fts5ApiPhraseNext,
fts5ApiPhraseFirstColumn,
fts5ApiPhraseNextColumn,
+ fts5ApiQueryToken,
+ fts5ApiInstToken,
+ fts5ApiColumnLocale,
+ fts5ApiTokenize_v2
};
/*
@@ -239928,6 +254407,7 @@ static void fts5ApiInvoke(
wx_sqlite3_value **argv
){
assert( pCsr->pAux==0 );
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
pCsr->pAux = pAux;
pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
pCsr->pAux = 0;
@@ -239941,6 +254421,21 @@ static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){
return pCsr;
}
+/*
+** Parameter zFmt is a printf() style formatting string. This function
+** formats it using the trailing arguments and returns the result as
+** an error message to the context passed as the first argument.
+*/
+static void fts5ResultError(wx_sqlite3_context *pCtx, const char *zFmt, ...){
+ char *zErr = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zErr = wx_sqlite3_vmprintf(zFmt, ap);
+ wx_sqlite3_result_error(pCtx, zErr, -1);
+ wx_sqlite3_free(zErr);
+ va_end(ap);
+}
+
static void fts5ApiCallback(
wx_sqlite3_context *context,
int argc,
@@ -239956,12 +254451,13 @@ static void fts5ApiCallback(
iCsrId = wx_sqlite3_value_int64(argv[0]);
pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
- if( pCsr==0 || pCsr->ePlan==0 ){
- char *zErr = wx_sqlite3_mprintf("no such cursor: %lld", iCsrId);
- wx_sqlite3_result_error(context, zErr, -1);
- wx_sqlite3_free(zErr);
+ if( pCsr==0 || (pCsr->ePlan==0 || pCsr->ePlan==FTS5_PLAN_SPECIAL) ){
+ fts5ResultError(context, "no such cursor: %lld", iCsrId);
}else{
+ wx_sqlite3_vtab *pTab = pCsr->base.pVtab;
fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
+ wx_sqlite3_free(pTab->zErrMsg);
+ pTab->zErrMsg = 0;
}
}
@@ -240079,8 +254575,8 @@ static int fts5ColumnMethod(
** auxiliary function. */
wx_sqlite3_result_int64(pCtx, pCsr->iCsrId);
}else if( iCol==pConfig->nCol+1 ){
-
/* The value of the "rank" column. */
+
if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
fts5PoslistBlob(pCtx, pCsr);
}else if(
@@ -240091,14 +254587,32 @@ static int fts5ColumnMethod(
fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
}
}
- }else if( !fts5IsContentless(pTab) ){
- pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
- rc = fts5SeekCursor(pCsr, 1);
- if( rc==SQLITE_OK ){
- wx_sqlite3_result_value(pCtx, wx_sqlite3_column_value(pCsr->pStmt, iCol+1));
+ }else{
+ if( !wx_sqlite3_vtab_nochange(pCtx) && pConfig->eContent!=FTS5_CONTENT_NONE ){
+ pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
+ rc = fts5SeekCursor(pCsr, 1);
+ if( rc==SQLITE_OK ){
+ wx_sqlite3_value *pVal = wx_sqlite3_column_value(pCsr->pStmt, iCol+1);
+ if( pConfig->bLocale
+ && pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && wx_sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ const char *z = 0;
+ int n = 0;
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &z, &n);
+ if( rc==SQLITE_OK ){
+ wx_sqlite3_result_text(pCtx, z, n, SQLITE_TRANSIENT);
+ }
+ wx_sqlite3Fts5ClearLocale(pConfig);
+ }else{
+ wx_sqlite3_result_value(pCtx, pVal);
+ }
+ }
+
+ pConfig->pzErrmsg = 0;
}
- pConfig->pzErrmsg = 0;
}
+
return rc;
}
@@ -240136,8 +254650,10 @@ static int fts5RenameMethod(
wx_sqlite3_vtab *pVtab, /* Virtual table handle */
const char *zName /* New name of table */
){
+ int rc;
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
- return wx_sqlite3Fts5StorageRename(pTab->pStorage, zName);
+ rc = wx_sqlite3Fts5StorageRename(pTab->pStorage, zName);
+ return rc;
}
static int wx_sqlite3Fts5FlushToDisk(Fts5Table *pTab){
@@ -240151,9 +254667,15 @@ static int wx_sqlite3Fts5FlushToDisk(Fts5Table *pTab){
** Flush the contents of the pending-terms table to disk.
*/
static int fts5SavepointMethod(wx_sqlite3_vtab *pVtab, int iSavepoint){
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint);
- return wx_sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
+ int rc = SQLITE_OK;
+
+ fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
+ rc = wx_sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint+1;
+ }
+ return rc;
}
/*
@@ -240162,9 +254684,16 @@ static int fts5SavepointMethod(wx_sqlite3_vtab *pVtab, int iSavepoint){
** This is a no-op.
*/
static int fts5ReleaseMethod(wx_sqlite3_vtab *pVtab, int iSavepoint){
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint);
- return wx_sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
+ int rc = SQLITE_OK;
+ fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
+ if( (iSavepoint+1)<pTab->iSavepoint ){
+ rc = wx_sqlite3Fts5FlushToDisk(&pTab->p);
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint;
+ }
+ }
+ return rc;
}
/*
@@ -240174,10 +254703,14 @@ static int fts5ReleaseMethod(wx_sqlite3_vtab *pVtab, int iSavepoint){
*/
static int fts5RollbackToMethod(wx_sqlite3_vtab *pVtab, int iSavepoint){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
+ int rc = SQLITE_OK;
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
fts5TripCursors(pTab);
- return wx_sqlite3Fts5StorageRollback(pTab->pStorage);
+ if( (iSavepoint+1)<=pTab->iSavepoint ){
+ pTab->p.pConfig->pgsz = 0;
+ rc = wx_sqlite3Fts5StorageRollback(pTab->pStorage);
+ }
+ return rc;
}
/*
@@ -240219,47 +254752,210 @@ static int fts5CreateAux(
}
/*
-** Register a new tokenizer. This is the implementation of the
-** fts5_api.xCreateTokenizer() method.
+** This function is used by xCreateTokenizer_v2() and xCreateTokenizer().
+** It allocates and partially populates a new Fts5TokenizerModule object.
+** The new object is already linked into the Fts5Global context before
+** returning.
+**
+** If successful, SQLITE_OK is returned and a pointer to the new
+** Fts5TokenizerModule object returned via output parameter (*ppNew). All
+** that is required is for the caller to fill in the methods in
+** Fts5TokenizerModule.x1 and x2, and to set Fts5TokenizerModule.bV2Native
+** as appropriate.
+**
+** If an error occurs, an SQLite error code is returned and the final value
+** of (*ppNew) undefined.
*/
-static int fts5CreateTokenizer(
- fts5_api *pApi, /* Global context (one per db handle) */
+static int fts5NewTokenizerModule(
+ Fts5Global *pGlobal, /* Global context (one per db handle) */
const char *zName, /* Name of new function */
void *pUserData, /* User data for aux. function */
- fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
- void(*xDestroy)(void*) /* Destructor for pUserData */
+ void(*xDestroy)(void*), /* Destructor for pUserData */
+ Fts5TokenizerModule **ppNew
){
- Fts5Global *pGlobal = (Fts5Global*)pApi;
- Fts5TokenizerModule *pNew;
- wx_sqlite3_int64 nName; /* Size of zName and its \0 terminator */
- wx_sqlite3_int64 nByte; /* Bytes of space to allocate */
int rc = SQLITE_OK;
+ Fts5TokenizerModule *pNew;
+ wx_sqlite3_int64 nName; /* Size of zName and its \0 terminator */
+ wx_sqlite3_int64 nByte; /* Bytes of space to allocate */
nName = strlen(zName) + 1;
nByte = sizeof(Fts5TokenizerModule) + nName;
- pNew = (Fts5TokenizerModule*)wx_sqlite3_malloc64(nByte);
+ *ppNew = pNew = (Fts5TokenizerModule*)wx_sqlite3Fts5MallocZero(&rc, nByte);
if( pNew ){
- memset(pNew, 0, (size_t)nByte);
pNew->zName = (char*)&pNew[1];
memcpy(pNew->zName, zName, nName);
pNew->pUserData = pUserData;
- pNew->x = *pTokenizer;
pNew->xDestroy = xDestroy;
pNew->pNext = pGlobal->pTok;
pGlobal->pTok = pNew;
if( pNew->pNext==0 ){
pGlobal->pDfltTok = pNew;
}
+ }
+
+ return rc;
+}
+
+/*
+** An instance of this type is used as the Fts5Tokenizer object for
+** wrapper tokenizers - those that provide access to a v1 tokenizer via
+** the fts5_tokenizer_v2 API, and those that provide access to a v2 tokenizer
+** via the fts5_tokenizer API.
+*/
+typedef struct Fts5VtoVTokenizer Fts5VtoVTokenizer;
+struct Fts5VtoVTokenizer {
+ int bV2Native; /* True if v2 native tokenizer */
+ fts5_tokenizer x1; /* Tokenizer functions */
+ fts5_tokenizer_v2 x2; /* V2 tokenizer functions */
+ Fts5Tokenizer *pReal;
+};
+
+/*
+** Create a wrapper tokenizer. The context argument pCtx points to the
+** Fts5TokenizerModule object.
+*/
+static int fts5VtoVCreate(
+ void *pCtx,
+ const char **azArg,
+ int nArg,
+ Fts5Tokenizer **ppOut
+){
+ Fts5TokenizerModule *pMod = (Fts5TokenizerModule*)pCtx;
+ Fts5VtoVTokenizer *pNew = 0;
+ int rc = SQLITE_OK;
+
+ pNew = (Fts5VtoVTokenizer*)wx_sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
+ if( rc==SQLITE_OK ){
+ pNew->x1 = pMod->x1;
+ pNew->x2 = pMod->x2;
+ pNew->bV2Native = pMod->bV2Native;
+ if( pMod->bV2Native ){
+ rc = pMod->x2.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal);
+ }else{
+ rc = pMod->x1.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal);
+ }
+ if( rc!=SQLITE_OK ){
+ wx_sqlite3_free(pNew);
+ pNew = 0;
+ }
+ }
+
+ *ppOut = (Fts5Tokenizer*)pNew;
+ return rc;
+}
+
+/*
+** Delete an Fts5VtoVTokenizer wrapper tokenizer.
+*/
+static void fts5VtoVDelete(Fts5Tokenizer *pTok){
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
+ if( p ){
+ if( p->bV2Native ){
+ p->x2.xDelete(p->pReal);
+ }else{
+ p->x1.xDelete(p->pReal);
+ }
+ wx_sqlite3_free(p);
+ }
+}
+
+
+/*
+** xTokenizer method for a wrapper tokenizer that offers the v1 interface
+** (no support for locales).
+*/
+static int fts5V1toV2Tokenize(
+ Fts5Tokenizer *pTok,
+ void *pCtx, int flags,
+ const char *pText, int nText,
+ int (*xToken)(void*, int, const char*, int, int, int)
+){
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
+ assert( p->bV2Native );
+ return p->x2.xTokenize(p->pReal, pCtx, flags, pText, nText, 0, 0, xToken);
+}
+
+/*
+** xTokenizer method for a wrapper tokenizer that offers the v2 interface
+** (with locale support).
+*/
+static int fts5V2toV1Tokenize(
+ Fts5Tokenizer *pTok,
+ void *pCtx, int flags,
+ const char *pText, int nText,
+ const char *pLocale, int nLocale,
+ int (*xToken)(void*, int, const char*, int, int, int)
+){
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
+ assert( p->bV2Native==0 );
+ UNUSED_PARAM2(pLocale,nLocale);
+ return p->x1.xTokenize(p->pReal, pCtx, flags, pText, nText, xToken);
+}
+
+/*
+** Register a new tokenizer. This is the implementation of the
+** fts5_api.xCreateTokenizer_v2() method.
+*/
+static int fts5CreateTokenizer_v2(
+ fts5_api *pApi, /* Global context (one per db handle) */
+ const char *zName, /* Name of new function */
+ void *pUserData, /* User data for aux. function */
+ fts5_tokenizer_v2 *pTokenizer, /* Tokenizer implementation */
+ void(*xDestroy)(void*) /* Destructor for pUserData */
+){
+ Fts5Global *pGlobal = (Fts5Global*)pApi;
+ int rc = SQLITE_OK;
+
+ if( pTokenizer->iVersion>2 ){
+ rc = SQLITE_ERROR;
}else{
- rc = SQLITE_NOMEM;
+ Fts5TokenizerModule *pNew = 0;
+ rc = fts5NewTokenizerModule(pGlobal, zName, pUserData, xDestroy, &pNew);
+ if( pNew ){
+ pNew->x2 = *pTokenizer;
+ pNew->bV2Native = 1;
+ pNew->x1.xCreate = fts5VtoVCreate;
+ pNew->x1.xTokenize = fts5V1toV2Tokenize;
+ pNew->x1.xDelete = fts5VtoVDelete;
+ }
}
return rc;
}
+/*
+** The fts5_api.xCreateTokenizer() method.
+*/
+static int fts5CreateTokenizer(
+ fts5_api *pApi, /* Global context (one per db handle) */
+ const char *zName, /* Name of new function */
+ void *pUserData, /* User data for aux. function */
+ fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
+ void(*xDestroy)(void*) /* Destructor for pUserData */
+){
+ Fts5TokenizerModule *pNew = 0;
+ int rc = SQLITE_OK;
+
+ rc = fts5NewTokenizerModule(
+ (Fts5Global*)pApi, zName, pUserData, xDestroy, &pNew
+ );
+ if( pNew ){
+ pNew->x1 = *pTokenizer;
+ pNew->x2.xCreate = fts5VtoVCreate;
+ pNew->x2.xTokenize = fts5V2toV1Tokenize;
+ pNew->x2.xDelete = fts5VtoVDelete;
+ }
+ return rc;
+}
+
+/*
+** Search the global context passed as the first argument for a tokenizer
+** module named zName. If found, return a pointer to the Fts5TokenizerModule
+** object. Otherwise, return NULL.
+*/
static Fts5TokenizerModule *fts5LocateTokenizer(
- Fts5Global *pGlobal,
- const char *zName
+ Fts5Global *pGlobal, /* Global (one per db handle) object */
+ const char *zName /* Name of tokenizer module to find */
){
Fts5TokenizerModule *pMod = 0;
@@ -240276,6 +254972,36 @@ static Fts5TokenizerModule *fts5LocateTokenizer(
/*
** Find a tokenizer. This is the implementation of the
+** fts5_api.xFindTokenizer_v2() method.
+*/
+static int fts5FindTokenizer_v2(
+ fts5_api *pApi, /* Global context (one per db handle) */
+ const char *zName, /* Name of tokenizer */
+ void **ppUserData,
+ fts5_tokenizer_v2 **ppTokenizer /* Populate this object */
+){
+ int rc = SQLITE_OK;
+ Fts5TokenizerModule *pMod;
+
+ pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
+ if( pMod ){
+ if( pMod->bV2Native ){
+ *ppUserData = pMod->pUserData;
+ }else{
+ *ppUserData = (void*)pMod;
+ }
+ *ppTokenizer = &pMod->x2;
+ }else{
+ *ppTokenizer = 0;
+ *ppUserData = 0;
+ rc = SQLITE_ERROR;
+ }
+
+ return rc;
+}
+
+/*
+** Find a tokenizer. This is the implementation of the
** fts5_api.xFindTokenizer() method.
*/
static int fts5FindTokenizer(
@@ -240289,53 +255015,75 @@ static int fts5FindTokenizer(
pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
if( pMod ){
- *pTokenizer = pMod->x;
- *ppUserData = pMod->pUserData;
+ if( pMod->bV2Native==0 ){
+ *ppUserData = pMod->pUserData;
+ }else{
+ *ppUserData = (void*)pMod;
+ }
+ *pTokenizer = pMod->x1;
}else{
- memset(pTokenizer, 0, sizeof(fts5_tokenizer));
+ memset(pTokenizer, 0, sizeof(*pTokenizer));
+ *ppUserData = 0;
rc = SQLITE_ERROR;
}
return rc;
}
-static int wx_sqlite3Fts5GetTokenizer(
- Fts5Global *pGlobal,
- const char **azArg,
- int nArg,
- Fts5Config *pConfig,
- char **pzErr
-){
- Fts5TokenizerModule *pMod;
+/*
+** Attempt to instantiate the tokenizer.
+*/
+static int wx_sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){
+ const char **azArg = pConfig->t.azArg;
+ const int nArg = pConfig->t.nArg;
+ Fts5TokenizerModule *pMod = 0;
int rc = SQLITE_OK;
- pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
+ pMod = fts5LocateTokenizer(pConfig->pGlobal, nArg==0 ? 0 : azArg[0]);
if( pMod==0 ){
assert( nArg>0 );
rc = SQLITE_ERROR;
- *pzErr = wx_sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
+ wx_sqlite3Fts5ConfigErrmsg(pConfig, "no such tokenizer: %s", azArg[0]);
}else{
- rc = pMod->x.xCreate(
- pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok
+ int (*xCreate)(void*, const char**, int, Fts5Tokenizer**) = 0;
+ if( pMod->bV2Native ){
+ xCreate = pMod->x2.xCreate;
+ pConfig->t.pApi2 = &pMod->x2;
+ }else{
+ pConfig->t.pApi1 = &pMod->x1;
+ xCreate = pMod->x1.xCreate;
+ }
+
+ rc = xCreate(pMod->pUserData,
+ (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok
);
- pConfig->pTokApi = &pMod->x;
+
if( rc!=SQLITE_OK ){
- if( pzErr ) *pzErr = wx_sqlite3_mprintf("error in tokenizer constructor");
- }else{
- pConfig->ePattern = wx_sqlite3Fts5TokenizerPattern(
- pMod->x.xCreate, pConfig->pTok
+ if( rc!=SQLITE_NOMEM ){
+ wx_sqlite3Fts5ConfigErrmsg(pConfig, "error in tokenizer constructor");
+ }
+ }else if( pMod->bV2Native==0 ){
+ pConfig->t.ePattern = wx_sqlite3Fts5TokenizerPattern(
+ pMod->x1.xCreate, pConfig->t.pTok
);
}
}
if( rc!=SQLITE_OK ){
- pConfig->pTokApi = 0;
- pConfig->pTok = 0;
+ pConfig->t.pApi1 = 0;
+ pConfig->t.pApi2 = 0;
+ pConfig->t.pTok = 0;
}
return rc;
}
+
+/*
+** xDestroy callback passed to wx_sqlite3_create_module(). This is invoked
+** when the db handle is being closed. Free memory associated with
+** tokenizers and aux functions registered with this db handle.
+*/
static void fts5ModuleDestroy(void *pCtx){
Fts5TokenizerModule *pTok, *pNextTok;
Fts5Auxiliary *pAux, *pNextAux;
@@ -240356,6 +255104,10 @@ static void fts5ModuleDestroy(void *pCtx){
wx_sqlite3_free(pGlobal);
}
+/*
+** Implementation of the fts5() function used by clients to obtain the
+** API pointer.
+*/
static void fts5Fts5Func(
wx_sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
@@ -240379,7 +255131,68 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- wx_sqlite3_result_text(pCtx, "fts5: 2023-03-22 11:56:21 0d1fc92f94cb6b76bffe3ec34d69cffde2924203304e8ffc4155597af0c191da", -1, SQLITE_TRANSIENT);
+ wx_sqlite3_result_text(pCtx, "fts5: 2024-12-07 20:39:59 2aabe05e2e8cae4847a802ee2daddc1d7413d8fc560254d93ee3e72c14685b6c", -1, SQLITE_TRANSIENT);
+}
+
+/*
+** Implementation of fts5_locale(LOCALE, TEXT) function.
+**
+** If parameter LOCALE is NULL, or a zero-length string, then a copy of
+** TEXT is returned. Otherwise, both LOCALE and TEXT are interpreted as
+** text, and the value returned is a blob consisting of:
+**
+** * The 4 bytes 0x00, 0xE0, 0xB2, 0xEb (FTS5_LOCALE_HEADER).
+** * The LOCALE, as utf-8 text, followed by
+** * 0x00, followed by
+** * The TEXT, as utf-8 text.
+**
+** There is no final nul-terminator following the TEXT value.
+*/
+static void fts5LocaleFunc(
+ wx_sqlite3_context *pCtx, /* Function call context */
+ int nArg, /* Number of args */
+ wx_sqlite3_value **apArg /* Function arguments */
+){
+ const char *zLocale = 0;
+ int nLocale = 0;
+ const char *zText = 0;
+ int nText = 0;
+
+ assert( nArg==2 );
+ UNUSED_PARAM(nArg);
+
+ zLocale = (const char*)wx_sqlite3_value_text(apArg[0]);
+ nLocale = wx_sqlite3_value_bytes(apArg[0]);
+
+ zText = (const char*)wx_sqlite3_value_text(apArg[1]);
+ nText = wx_sqlite3_value_bytes(apArg[1]);
+
+ if( zLocale==0 || zLocale[0]=='\0' ){
+ wx_sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT);
+ }else{
+ Fts5Global *p = (Fts5Global*)wx_sqlite3_user_data(pCtx);
+ u8 *pBlob = 0;
+ u8 *pCsr = 0;
+ int nBlob = 0;
+
+ nBlob = FTS5_LOCALE_HDR_SIZE + nLocale + 1 + nText;
+ pBlob = (u8*)wx_sqlite3_malloc(nBlob);
+ if( pBlob==0 ){
+ wx_sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+
+ pCsr = pBlob;
+ memcpy(pCsr, (const u8*)p->aLocaleHdr, FTS5_LOCALE_HDR_SIZE);
+ pCsr += FTS5_LOCALE_HDR_SIZE;
+ memcpy(pCsr, zLocale, nLocale);
+ pCsr += nLocale;
+ (*pCsr++) = 0x00;
+ if( zText ) memcpy(pCsr, zText, nText);
+ assert( &pCsr[nText]==&pBlob[nBlob] );
+
+ wx_sqlite3_result_blob(pCtx, pBlob, nBlob, wx_sqlite3_free);
+ }
}
/*
@@ -240397,9 +255210,47 @@ static int fts5ShadowName(const char *zName){
return 0;
}
+/*
+** Run an integrity check on the FTS5 data structures. Return a string
+** if anything is found amiss. Return a NULL pointer if everything is
+** OK.
+*/
+static int fts5IntegrityMethod(
+ wx_sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */
+ const char *zSchema, /* Name of schema in which this table lives */
+ const char *zTabname, /* Name of the table itself */
+ int isQuick, /* True if this is a quick-check */
+ char **pzErr /* Write error message here */
+){
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
+ int rc;
+
+ assert( pzErr!=0 && *pzErr==0 );
+ UNUSED_PARAM(isQuick);
+ assert( pTab->p.pConfig->pzErrmsg==0 );
+ pTab->p.pConfig->pzErrmsg = pzErr;
+ rc = wx_sqlite3Fts5StorageIntegrity(pTab->pStorage, 0);
+ if( *pzErr==0 && rc!=SQLITE_OK ){
+ if( (rc&0xff)==SQLITE_CORRUPT ){
+ *pzErr = wx_sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
+ zSchema, zTabname);
+ rc = (*pzErr) ? SQLITE_OK : SQLITE_NOMEM;
+ }else{
+ *pzErr = wx_sqlite3_mprintf("unable to validate the inverted index for"
+ " FTS5 table %s.%s: %s",
+ zSchema, zTabname, wx_sqlite3_errstr(rc));
+ }
+ }
+
+ wx_sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
+ pTab->p.pConfig->pzErrmsg = 0;
+
+ return rc;
+}
+
static int fts5Init(wx_sqlite3 *db){
static const wx_sqlite3_module fts5Mod = {
- /* iVersion */ 3,
+ /* iVersion */ 4,
/* xCreate */ fts5CreateMethod,
/* xConnect */ fts5ConnectMethod,
/* xBestIndex */ fts5BestIndexMethod,
@@ -240422,7 +255273,8 @@ static int fts5Init(wx_sqlite3 *db){
/* xSavepoint */ fts5SavepointMethod,
/* xRelease */ fts5ReleaseMethod,
/* xRollbackTo */ fts5RollbackToMethod,
- /* xShadowName */ fts5ShadowName
+ /* xShadowName */ fts5ShadowName,
+ /* xIntegrity */ fts5IntegrityMethod
};
int rc;
@@ -240435,10 +255287,22 @@ static int fts5Init(wx_sqlite3 *db){
void *p = (void*)pGlobal;
memset(pGlobal, 0, sizeof(Fts5Global));
pGlobal->db = db;
- pGlobal->api.iVersion = 2;
+ pGlobal->api.iVersion = 3;
pGlobal->api.xCreateFunction = fts5CreateAux;
pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
pGlobal->api.xFindTokenizer = fts5FindTokenizer;
+ pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2;
+ pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2;
+
+ /* Initialize pGlobal->aLocaleHdr[] to a 128-bit pseudo-random vector.
+ ** The constants below were generated randomly. */
+ wx_sqlite3_randomness(sizeof(pGlobal->aLocaleHdr), pGlobal->aLocaleHdr);
+ pGlobal->aLocaleHdr[0] ^= 0xF924976D;
+ pGlobal->aLocaleHdr[1] ^= 0x16596E13;
+ pGlobal->aLocaleHdr[2] ^= 0x7C80BEAA;
+ pGlobal->aLocaleHdr[3] ^= 0x9B03A67F;
+ assert( sizeof(pGlobal->aLocaleHdr)==16 );
+
rc = wx_sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
if( rc==SQLITE_OK ) rc = wx_sqlite3Fts5IndexInit(db);
if( rc==SQLITE_OK ) rc = wx_sqlite3Fts5ExprInit(pGlobal, db);
@@ -240457,6 +255321,13 @@ static int fts5Init(wx_sqlite3 *db){
p, fts5SourceIdFunc, 0, 0
);
}
+ if( rc==SQLITE_OK ){
+ rc = wx_sqlite3_create_function(
+ db, "fts5_locale", 2,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE,
+ p, fts5LocaleFunc, 0, 0
+ );
+ }
}
/* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
@@ -240531,13 +255402,40 @@ SQLITE_PRIVATE int wx_sqlite3Fts5Init(wx_sqlite3 *db){
/* #include "fts5Int.h" */
+/*
+** pSavedRow:
+** SQL statement FTS5_STMT_LOOKUP2 is a copy of FTS5_STMT_LOOKUP, it
+** does a by-rowid lookup to retrieve a single row from the %_content
+** table or equivalent external-content table/view.
+**
+** However, FTS5_STMT_LOOKUP2 is only used when retrieving the original
+** values for a row being UPDATEd. In that case, the SQL statement is
+** not reset and pSavedRow is set to point at it. This is so that the
+** insert operation that follows the delete may access the original
+** row values for any new values for which wx_sqlite3_value_nochange() returns
+** true. i.e. if the user executes:
+**
+** CREATE VIRTUAL TABLE ft USING fts5(a, b, c, locale=1);
+** ...
+** UPDATE fts SET a=?, b=? WHERE rowid=?;
+**
+** then the value passed to the xUpdate() method of this table as the
+** new.c value is an wx_sqlite3_value_nochange() value. So in this case it
+** must be read from the saved row stored in Fts5Storage.pSavedRow.
+**
+** This is necessary - using wx_sqlite3_value_nochange() instead of just having
+** SQLite pass the original value back via xUpdate() - so as not to discard
+** any locale information associated with such values.
+**
+*/
struct Fts5Storage {
Fts5Config *pConfig;
Fts5Index *pIndex;
int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */
i64 nTotalRow; /* Total number of rows in FTS table */
i64 *aTotalSize; /* Total sizes of each column */
- wx_sqlite3_stmt *aStmt[11];
+ wx_sqlite3_stmt *pSavedRow;
+ wx_sqlite3_stmt *aStmt[12];
};
@@ -240551,14 +255449,15 @@ struct Fts5Storage {
# error "FTS5_STMT_LOOKUP mismatch"
#endif
-#define FTS5_STMT_INSERT_CONTENT 3
-#define FTS5_STMT_REPLACE_CONTENT 4
-#define FTS5_STMT_DELETE_CONTENT 5
-#define FTS5_STMT_REPLACE_DOCSIZE 6
-#define FTS5_STMT_DELETE_DOCSIZE 7
-#define FTS5_STMT_LOOKUP_DOCSIZE 8
-#define FTS5_STMT_REPLACE_CONFIG 9
-#define FTS5_STMT_SCAN 10
+#define FTS5_STMT_LOOKUP2 3
+#define FTS5_STMT_INSERT_CONTENT 4
+#define FTS5_STMT_REPLACE_CONTENT 5
+#define FTS5_STMT_DELETE_CONTENT 6
+#define FTS5_STMT_REPLACE_DOCSIZE 7
+#define FTS5_STMT_DELETE_DOCSIZE 8
+#define FTS5_STMT_LOOKUP_DOCSIZE 9
+#define FTS5_STMT_REPLACE_CONFIG 10
+#define FTS5_STMT_SCAN 11
/*
** Prepare the two insert statements - Fts5Storage.pInsertContent and
@@ -240588,14 +255487,15 @@ static int fts5StorageGetStmt(
"SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
"SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
"SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */
+ "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP2 */
"INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
"REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
"DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */
- "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", /* REPLACE_DOCSIZE */
+ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?%s)", /* REPLACE_DOCSIZE */
"DELETE FROM %Q.'%q_docsize' WHERE id=?", /* DELETE_DOCSIZE */
- "SELECT sz FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */
+ "SELECT sz%s FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */
"REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */
"SELECT %s FROM %s AS T", /* SCAN */
@@ -240603,6 +255503,8 @@ static int fts5StorageGetStmt(
Fts5Config *pC = p->pConfig;
char *zSql = 0;
+ assert( ArraySize(azStmt)==ArraySize(p->aStmt) );
+
switch( eStmt ){
case FTS5_STMT_SCAN:
zSql = wx_sqlite3_mprintf(azStmt[eStmt],
@@ -240619,6 +255521,7 @@ static int fts5StorageGetStmt(
break;
case FTS5_STMT_LOOKUP:
+ case FTS5_STMT_LOOKUP2:
zSql = wx_sqlite3_mprintf(azStmt[eStmt],
pC->zContentExprlist, pC->zContent, pC->zContentRowid
);
@@ -240626,23 +255529,51 @@ static int fts5StorageGetStmt(
case FTS5_STMT_INSERT_CONTENT:
case FTS5_STMT_REPLACE_CONTENT: {
- int nCol = pC->nCol + 1;
- char *zBind;
+ char *zBind = 0;
int i;
- zBind = wx_sqlite3_malloc64(1 + nCol*2);
- if( zBind ){
- for(i=0; i<nCol; i++){
- zBind[i*2] = '?';
- zBind[i*2 + 1] = ',';
+ assert( pC->eContent==FTS5_CONTENT_NORMAL
+ || pC->eContent==FTS5_CONTENT_UNINDEXED
+ );
+
+ /* Add bindings for the "c*" columns - those that store the actual
+ ** table content. If eContent==NORMAL, then there is one binding
+ ** for each column. Or, if eContent==UNINDEXED, then there are only
+ ** bindings for the UNINDEXED columns. */
+ for(i=0; rc==SQLITE_OK && i<(pC->nCol+1); i++){
+ if( !i || pC->eContent==FTS5_CONTENT_NORMAL || pC->abUnindexed[i-1] ){
+ zBind = wx_sqlite3Fts5Mprintf(&rc, "%z%s?%d", zBind, zBind?",":"",i+1);
+ }
+ }
+
+ /* Add bindings for any "l*" columns. Only non-UNINDEXED columns
+ ** require these. */
+ if( pC->bLocale && pC->eContent==FTS5_CONTENT_NORMAL ){
+ for(i=0; rc==SQLITE_OK && i<pC->nCol; i++){
+ if( pC->abUnindexed[i]==0 ){
+ zBind = wx_sqlite3Fts5Mprintf(&rc, "%z,?%d", zBind, pC->nCol+i+2);
+ }
}
- zBind[i*2-1] = '\0';
- zSql = wx_sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind);
- wx_sqlite3_free(zBind);
}
+
+ zSql = wx_sqlite3Fts5Mprintf(&rc, azStmt[eStmt], pC->zDb, pC->zName,zBind);
+ wx_sqlite3_free(zBind);
break;
}
+ case FTS5_STMT_REPLACE_DOCSIZE:
+ zSql = wx_sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName,
+ (pC->bContentlessDelete ? ",?" : "")
+ );
+ break;
+
+ case FTS5_STMT_LOOKUP_DOCSIZE:
+ zSql = wx_sqlite3_mprintf(azStmt[eStmt],
+ (pC->bContentlessDelete ? ",origin" : ""),
+ pC->zDb, pC->zName
+ );
+ break;
+
default:
zSql = wx_sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName);
break;
@@ -240652,7 +255583,7 @@ static int fts5StorageGetStmt(
rc = SQLITE_NOMEM;
}else{
int f = SQLITE_PREPARE_PERSISTENT;
- if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB;
+ if( eStmt>FTS5_STMT_LOOKUP2 ) f |= SQLITE_PREPARE_NO_VTAB;
p->pConfig->bLock++;
rc = wx_sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
p->pConfig->bLock--;
@@ -240812,9 +255743,11 @@ static int wx_sqlite3Fts5StorageOpen(
p->pIndex = pIndex;
if( bCreate ){
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
int nDefn = 32 + pConfig->nCol*10;
- char *zDefn = wx_sqlite3_malloc64(32 + (wx_sqlite3_int64)pConfig->nCol * 10);
+ char *zDefn = wx_sqlite3_malloc64(32 + (wx_sqlite3_int64)pConfig->nCol * 20);
if( zDefn==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -240823,8 +255756,20 @@ static int wx_sqlite3Fts5StorageOpen(
wx_sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
iOff = (int)strlen(zDefn);
for(i=0; i<pConfig->nCol; i++){
- wx_sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
- iOff += (int)strlen(&zDefn[iOff]);
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->abUnindexed[i]
+ ){
+ wx_sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
+ iOff += (int)strlen(&zDefn[iOff]);
+ }
+ }
+ if( pConfig->bLocale ){
+ for(i=0; i<pConfig->nCol; i++){
+ if( pConfig->abUnindexed[i]==0 ){
+ wx_sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i);
+ iOff += (int)strlen(&zDefn[iOff]);
+ }
+ }
}
rc = wx_sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
}
@@ -240832,9 +255777,11 @@ static int wx_sqlite3Fts5StorageOpen(
}
if( rc==SQLITE_OK && pConfig->bColumnsize ){
- rc = wx_sqlite3Fts5CreateTable(
- pConfig, "docsize", "id INTEGER PRIMARY KEY, sz BLOB", 0, pzErr
- );
+ const char *zCols = "id INTEGER PRIMARY KEY, sz BLOB";
+ if( pConfig->bContentlessDelete ){
+ zCols = "id INTEGER PRIMARY KEY, sz BLOB, origin INTEGER";
+ }
+ rc = wx_sqlite3Fts5CreateTable(pConfig, "docsize", zCols, 0, pzErr);
}
if( rc==SQLITE_OK ){
rc = wx_sqlite3Fts5CreateTable(
@@ -240900,56 +255847,114 @@ static int fts5StorageInsertCallback(
}
/*
+** This function is used as part of an UPDATE statement that modifies the
+** rowid of a row. In that case, this function is called first to set
+** Fts5Storage.pSavedRow to point to a statement that may be used to
+** access the original values of the row being deleted - iDel.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+** It is not considered an error if row iDel does not exist. In this case
+** pSavedRow is not set and SQLITE_OK returned.
+*/
+static int wx_sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){
+ int rc = SQLITE_OK;
+ wx_sqlite3_stmt *pSeek = 0;
+
+ assert( p->pSavedRow==0 );
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+1, &pSeek, 0);
+ if( rc==SQLITE_OK ){
+ wx_sqlite3_bind_int64(pSeek, 1, iDel);
+ if( wx_sqlite3_step(pSeek)!=SQLITE_ROW ){
+ rc = wx_sqlite3_reset(pSeek);
+ }else{
+ p->pSavedRow = pSeek;
+ }
+ }
+
+ return rc;
+}
+
+/*
** If a row with rowid iDel is present in the %_content table, add the
** delete-markers to the FTS index necessary to delete it. Do not actually
** remove the %_content row at this time though.
+**
+** If parameter bSaveRow is true, then Fts5Storage.pSavedRow is left
+** pointing to a statement (FTS5_STMT_LOOKUP2) that may be used to access
+** the original values of the row being deleted. This is used by UPDATE
+** statements.
*/
static int fts5StorageDeleteFromIndex(
Fts5Storage *p,
i64 iDel,
- wx_sqlite3_value **apVal
+ wx_sqlite3_value **apVal,
+ int bSaveRow /* True to set pSavedRow */
){
Fts5Config *pConfig = p->pConfig;
wx_sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
int rc2; /* wx_sqlite3_reset() return code */
int iCol;
Fts5InsertCtx ctx;
+ assert( bSaveRow==0 || apVal==0 );
+ assert( bSaveRow==0 || bSaveRow==1 );
+ assert( FTS5_STMT_LOOKUP2==FTS5_STMT_LOOKUP+1 );
+
if( apVal==0 ){
- rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
- if( rc!=SQLITE_OK ) return rc;
- wx_sqlite3_bind_int64(pSeek, 1, iDel);
- if( wx_sqlite3_step(pSeek)!=SQLITE_ROW ){
- return wx_sqlite3_reset(pSeek);
+ if( p->pSavedRow && bSaveRow ){
+ pSeek = p->pSavedRow;
+ p->pSavedRow = 0;
+ }else{
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+bSaveRow, &pSeek, 0);
+ if( rc!=SQLITE_OK ) return rc;
+ wx_sqlite3_bind_int64(pSeek, 1, iDel);
+ if( wx_sqlite3_step(pSeek)!=SQLITE_ROW ){
+ return wx_sqlite3_reset(pSeek);
+ }
}
}
ctx.pStorage = p;
ctx.iCol = -1;
- rc = wx_sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
if( pConfig->abUnindexed[iCol-1]==0 ){
- const char *zText;
- int nText;
+ wx_sqlite3_value *pVal = 0;
+ const char *pText = 0;
+ int nText = 0;
+ const char *pLoc = 0;
+ int nLoc = 0;
+
assert( pSeek==0 || apVal==0 );
assert( pSeek!=0 || apVal!=0 );
if( pSeek ){
- zText = (const char*)wx_sqlite3_column_text(pSeek, iCol);
- nText = wx_sqlite3_column_bytes(pSeek, iCol);
- }else if( ALWAYS(apVal) ){
- zText = (const char*)wx_sqlite3_value_text(apVal[iCol-1]);
- nText = wx_sqlite3_value_bytes(apVal[iCol-1]);
+ pVal = wx_sqlite3_column_value(pSeek, iCol);
}else{
- continue;
+ pVal = apVal[iCol-1];
}
- ctx.szCol = 0;
- rc = wx_sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
- zText, nText, (void*)&ctx, fts5StorageInsertCallback
- );
- p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
- if( p->aTotalSize[iCol-1]<0 ){
- rc = FTS5_CORRUPT;
+
+ if( pConfig->bLocale && wx_sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ rc = wx_sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ }else{
+ pText = (const char*)wx_sqlite3_value_text(pVal);
+ nText = wx_sqlite3_value_bytes(pVal);
+ if( pConfig->bLocale && pSeek ){
+ pLoc = (const char*)wx_sqlite3_column_text(pSeek, iCol + pConfig->nCol);
+ nLoc = wx_sqlite3_column_bytes(pSeek, iCol + pConfig->nCol);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ wx_sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ ctx.szCol = 0;
+ rc = wx_sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
+ pText, nText, (void*)&ctx, fts5StorageInsertCallback
+ );
+ p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
+ if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){
+ rc = FTS5_CORRUPT;
+ }
+ wx_sqlite3Fts5ClearLocale(pConfig);
}
}
}
@@ -240959,11 +255964,62 @@ static int fts5StorageDeleteFromIndex(
p->nTotalRow--;
}
- rc2 = wx_sqlite3_reset(pSeek);
- if( rc==SQLITE_OK ) rc = rc2;
+ if( rc==SQLITE_OK && bSaveRow ){
+ assert( p->pSavedRow==0 );
+ p->pSavedRow = pSeek;
+ }else{
+ rc2 = wx_sqlite3_reset(pSeek);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
return rc;
}
+/*
+** Reset any saved statement pSavedRow. Zero pSavedRow as well. This
+** should be called by the xUpdate() method of the fts5 table before
+** returning from any operation that may have set Fts5Storage.pSavedRow.
+*/
+static void wx_sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){
+ assert( pStorage->pSavedRow==0
+ || pStorage->pSavedRow==pStorage->aStmt[FTS5_STMT_LOOKUP2]
+ );
+ wx_sqlite3_reset(pStorage->pSavedRow);
+ pStorage->pSavedRow = 0;
+}
+
+/*
+** This function is called to process a DELETE on a contentless_delete=1
+** table. It adds the tombstone required to delete the entry with rowid
+** iDel. If successful, SQLITE_OK is returned. Or, if an error occurs,
+** an SQLite error code.
+*/
+static int fts5StorageContentlessDelete(Fts5Storage *p, i64 iDel){
+ i64 iOrigin = 0;
+ wx_sqlite3_stmt *pLookup = 0;
+ int rc = SQLITE_OK;
+
+ assert( p->pConfig->bContentlessDelete );
+ assert( p->pConfig->eContent==FTS5_CONTENT_NONE
+ || p->pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ );
+
+ /* Look up the origin of the document in the %_docsize table. Store
+ ** this in stack variable iOrigin. */
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
+ if( rc==SQLITE_OK ){
+ wx_sqlite3_bind_int64(pLookup, 1, iDel);
+ if( SQLITE_ROW==wx_sqlite3_step(pLookup) ){
+ iOrigin = wx_sqlite3_column_int64(pLookup, 1);
+ }
+ rc = wx_sqlite3_reset(pLookup);
+ }
+
+ if( rc==SQLITE_OK && iOrigin!=0 ){
+ rc = wx_sqlite3Fts5IndexContentlessDelete(p->pIndex, iOrigin, iDel);
+ }
+
+ return rc;
+}
/*
** Insert a record into the %_docsize table. Specifically, do:
@@ -240984,6 +256040,13 @@ static int fts5StorageInsertDocsize(
rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
if( rc==SQLITE_OK ){
wx_sqlite3_bind_int64(pReplace, 1, iRowid);
+ if( p->pConfig->bContentlessDelete ){
+ i64 iOrigin = 0;
+ rc = wx_sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin);
+ wx_sqlite3_bind_int64(pReplace, 3, iOrigin);
+ }
+ }
+ if( rc==SQLITE_OK ){
wx_sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
wx_sqlite3_step(pReplace);
rc = wx_sqlite3_reset(pReplace);
@@ -241041,7 +256104,12 @@ static int fts5StorageSaveTotals(Fts5Storage *p){
/*
** Remove a row from the FTS table.
*/
-static int wx_sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, wx_sqlite3_value **apVal){
+static int wx_sqlite3Fts5StorageDelete(
+ Fts5Storage *p, /* Storage object */
+ i64 iDel, /* Rowid to delete from table */
+ wx_sqlite3_value **apVal, /* Optional - values to remove from index */
+ int bSaveRow /* If true, set pSavedRow for deleted row */
+){
Fts5Config *pConfig = p->pConfig;
int rc;
wx_sqlite3_stmt *pDel = 0;
@@ -241051,7 +256119,21 @@ static int wx_sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, wx_sqlite3_valu
/* Delete the index records */
if( rc==SQLITE_OK ){
- rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
+ rc = wx_sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
+ }
+
+ if( rc==SQLITE_OK ){
+ if( p->pConfig->bContentlessDelete ){
+ rc = fts5StorageContentlessDelete(p, iDel);
+ if( rc==SQLITE_OK
+ && bSaveRow
+ && p->pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
+ rc = wx_sqlite3Fts5StorageFindDeleteRow(p, iDel);
+ }
+ }else{
+ rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow);
+ }
}
/* Delete the %_docsize record */
@@ -241065,7 +256147,9 @@ static int wx_sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, wx_sqlite3_valu
}
/* Delete the %_content record */
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
if( rc==SQLITE_OK ){
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
}
@@ -241097,8 +256181,13 @@ static int wx_sqlite3Fts5StorageDeleteAll(Fts5Storage *p){
);
if( rc==SQLITE_OK && pConfig->bColumnsize ){
rc = fts5ExecPrintf(pConfig->db, 0,
- "DELETE FROM %Q.'%q_docsize';",
- pConfig->zDb, pConfig->zName
+ "DELETE FROM %Q.'%q_docsize';", pConfig->zDb, pConfig->zName
+ );
+ }
+
+ if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_UNINDEXED ){
+ rc = fts5ExecPrintf(pConfig->db, 0,
+ "DELETE FROM %Q.'%q_content';", pConfig->zDb, pConfig->zName
);
}
@@ -241128,7 +256217,7 @@ static int wx_sqlite3Fts5StorageRebuild(Fts5Storage *p){
}
if( rc==SQLITE_OK ){
- rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
+ rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, pConfig->pzErrmsg);
}
while( rc==SQLITE_OK && SQLITE_ROW==wx_sqlite3_step(pScan) ){
@@ -241139,14 +256228,36 @@ static int wx_sqlite3Fts5StorageRebuild(Fts5Storage *p){
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
- const char *zText = (const char*)wx_sqlite3_column_text(pScan, ctx.iCol+1);
- int nText = wx_sqlite3_column_bytes(pScan, ctx.iCol+1);
- rc = wx_sqlite3Fts5Tokenize(pConfig,
- FTS5_TOKENIZE_DOCUMENT,
- zText, nText,
- (void*)&ctx,
- fts5StorageInsertCallback
- );
+ int nText = 0; /* Size of pText in bytes */
+ const char *pText = 0; /* Pointer to buffer containing text value */
+ int nLoc = 0; /* Size of pLoc in bytes */
+ const char *pLoc = 0; /* Pointer to buffer containing text value */
+
+ wx_sqlite3_value *pVal = wx_sqlite3_column_value(pScan, ctx.iCol+1);
+ if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && wx_sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ rc = wx_sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ }else{
+ pText = (const char*)wx_sqlite3_value_text(pVal);
+ nText = wx_sqlite3_value_bytes(pVal);
+ if( pConfig->bLocale ){
+ int iCol = ctx.iCol + 1 + pConfig->nCol;
+ pLoc = (const char*)wx_sqlite3_column_text(pScan, iCol);
+ nLoc = wx_sqlite3_column_bytes(pScan, iCol);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ wx_sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ rc = wx_sqlite3Fts5Tokenize(pConfig,
+ FTS5_TOKENIZE_DOCUMENT,
+ pText, nText,
+ (void*)&ctx,
+ fts5StorageInsertCallback
+ );
+ wx_sqlite3Fts5ClearLocale(pConfig);
+ }
}
wx_sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
@@ -241212,6 +256323,7 @@ static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){
*/
static int wx_sqlite3Fts5StorageContentInsert(
Fts5Storage *p,
+ int bReplace, /* True to use REPLACE instead of INSERT */
wx_sqlite3_value **apVal,
i64 *piRowid
){
@@ -241219,7 +256331,9 @@ static int wx_sqlite3Fts5StorageContentInsert(
int rc = SQLITE_OK;
/* Insert the new row into the %_content table. */
- if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent!=FTS5_CONTENT_NORMAL
+ && pConfig->eContent!=FTS5_CONTENT_UNINDEXED
+ ){
if( wx_sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
*piRowid = wx_sqlite3_value_int64(apVal[1]);
}else{
@@ -241228,9 +256342,52 @@ static int wx_sqlite3Fts5StorageContentInsert(
}else{
wx_sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
int i; /* Counter variable */
- rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
- for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
- rc = wx_sqlite3_bind_value(pInsert, i, apVal[i]);
+
+ assert( FTS5_STMT_INSERT_CONTENT+1==FTS5_STMT_REPLACE_CONTENT );
+ assert( bReplace==0 || bReplace==1 );
+ rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT+bReplace, &pInsert, 0);
+ if( pInsert ) wx_sqlite3_clear_bindings(pInsert);
+
+ /* Bind the rowid value */
+ wx_sqlite3_bind_value(pInsert, 1, apVal[1]);
+
+ /* Loop through values for user-defined columns. i=2 is the leftmost
+ ** user-defined column. As is column 1 of pSavedRow. */
+ for(i=2; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
+ int bUnindexed = pConfig->abUnindexed[i-2];
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL || bUnindexed ){
+ wx_sqlite3_value *pVal = apVal[i];
+
+ if( wx_sqlite3_value_nochange(pVal) && p->pSavedRow ){
+ /* This is an UPDATE statement, and user-defined column (i-2) was not
+ ** modified. Retrieve the value from Fts5Storage.pSavedRow. */
+ pVal = wx_sqlite3_column_value(p->pSavedRow, i-1);
+ if( pConfig->bLocale && bUnindexed==0 ){
+ wx_sqlite3_bind_value(pInsert, pConfig->nCol + i,
+ wx_sqlite3_column_value(p->pSavedRow, pConfig->nCol + i - 1)
+ );
+ }
+ }else if( wx_sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ const char *pText = 0;
+ const char *pLoc = 0;
+ int nText = 0;
+ int nLoc = 0;
+ assert( pConfig->bLocale );
+
+ rc = wx_sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ if( rc==SQLITE_OK ){
+ wx_sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
+ if( bUnindexed==0 ){
+ int iLoc = pConfig->nCol + i;
+ wx_sqlite3_bind_text(pInsert, iLoc, pLoc, nLoc, SQLITE_TRANSIENT);
+ }
+ }
+
+ continue;
+ }
+
+ rc = wx_sqlite3_bind_value(pInsert, i, pVal);
+ }
}
if( rc==SQLITE_OK ){
wx_sqlite3_step(pInsert);
@@ -241265,14 +256422,38 @@ static int wx_sqlite3Fts5StorageIndexInsert(
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
- const char *zText = (const char*)wx_sqlite3_value_text(apVal[ctx.iCol+2]);
- int nText = wx_sqlite3_value_bytes(apVal[ctx.iCol+2]);
- rc = wx_sqlite3Fts5Tokenize(pConfig,
- FTS5_TOKENIZE_DOCUMENT,
- zText, nText,
- (void*)&ctx,
- fts5StorageInsertCallback
- );
+ int nText = 0; /* Size of pText in bytes */
+ const char *pText = 0; /* Pointer to buffer containing text value */
+ int nLoc = 0; /* Size of pText in bytes */
+ const char *pLoc = 0; /* Pointer to buffer containing text value */
+
+ wx_sqlite3_value *pVal = apVal[ctx.iCol+2];
+ if( p->pSavedRow && wx_sqlite3_value_nochange(pVal) ){
+ pVal = wx_sqlite3_column_value(p->pSavedRow, ctx.iCol+1);
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
+ int iCol = ctx.iCol + 1 + pConfig->nCol;
+ pLoc = (const char*)wx_sqlite3_column_text(p->pSavedRow, iCol);
+ nLoc = wx_sqlite3_column_bytes(p->pSavedRow, iCol);
+ }
+ }else{
+ pVal = apVal[ctx.iCol+2];
+ }
+
+ if( pConfig->bLocale && wx_sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ rc = wx_sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ }else{
+ pText = (const char*)wx_sqlite3_value_text(pVal);
+ nText = wx_sqlite3_value_bytes(pVal);
+ }
+
+ if( rc==SQLITE_OK ){
+ wx_sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ rc = wx_sqlite3Fts5Tokenize(pConfig,
+ FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx,
+ fts5StorageInsertCallback
+ );
+ wx_sqlite3Fts5ClearLocale(pConfig);
+ }
}
wx_sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
@@ -241436,29 +256617,61 @@ static int wx_sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){
rc = wx_sqlite3Fts5TermsetNew(&ctx.pTermset);
}
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
- if( pConfig->abUnindexed[i] ) continue;
- ctx.iCol = i;
- ctx.szCol = 0;
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
- rc = wx_sqlite3Fts5TermsetNew(&ctx.pTermset);
- }
- if( rc==SQLITE_OK ){
- const char *zText = (const char*)wx_sqlite3_column_text(pScan, i+1);
- int nText = wx_sqlite3_column_bytes(pScan, i+1);
- rc = wx_sqlite3Fts5Tokenize(pConfig,
- FTS5_TOKENIZE_DOCUMENT,
- zText, nText,
- (void*)&ctx,
- fts5StorageIntegrityCallback
- );
- }
- if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
- rc = FTS5_CORRUPT;
- }
- aTotalSize[i] += ctx.szCol;
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
- wx_sqlite3Fts5TermsetFree(ctx.pTermset);
- ctx.pTermset = 0;
+ if( pConfig->abUnindexed[i]==0 ){
+ const char *pText = 0;
+ int nText = 0;
+ const char *pLoc = 0;
+ int nLoc = 0;
+ wx_sqlite3_value *pVal = wx_sqlite3_column_value(pScan, i+1);
+
+ if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && wx_sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ rc = wx_sqlite3Fts5DecodeLocaleValue(
+ pVal, &pText, &nText, &pLoc, &nLoc
+ );
+ }else{
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
+ int iCol = i + 1 + pConfig->nCol;
+ pLoc = (const char*)wx_sqlite3_column_text(pScan, iCol);
+ nLoc = wx_sqlite3_column_bytes(pScan, iCol);
+ }
+ pText = (const char*)wx_sqlite3_value_text(pVal);
+ nText = wx_sqlite3_value_bytes(pVal);
+ }
+
+ ctx.iCol = i;
+ ctx.szCol = 0;
+
+ if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
+ rc = wx_sqlite3Fts5TermsetNew(&ctx.pTermset);
+ }
+
+ if( rc==SQLITE_OK ){
+ wx_sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ rc = wx_sqlite3Fts5Tokenize(pConfig,
+ FTS5_TOKENIZE_DOCUMENT,
+ pText, nText,
+ (void*)&ctx,
+ fts5StorageIntegrityCallback
+ );
+ wx_sqlite3Fts5ClearLocale(pConfig);
+ }
+
+ /* If this is not a columnsize=0 database, check that the number
+ ** of tokens in the value matches the aColSize[] value read from
+ ** the %_docsize table. */
+ if( rc==SQLITE_OK
+ && pConfig->bColumnsize
+ && ctx.szCol!=aColSize[i]
+ ){
+ rc = FTS5_CORRUPT;
+ }
+ aTotalSize[i] += ctx.szCol;
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
+ wx_sqlite3Fts5TermsetFree(ctx.pTermset);
+ ctx.pTermset = 0;
+ }
}
}
wx_sqlite3Fts5TermsetFree(ctx.pTermset);
@@ -241639,7 +256852,9 @@ static int wx_sqlite3Fts5StorageSync(Fts5Storage *p){
i64 iLastRowid = wx_sqlite3_last_insert_rowid(p->pConfig->db);
if( p->bTotalsValid ){
rc = fts5StorageSaveTotals(p);
- p->bTotalsValid = 0;
+ if( rc==SQLITE_OK ){
+ p->bTotalsValid = 0;
+ }
}
if( rc==SQLITE_OK ){
rc = wx_sqlite3Fts5IndexSync(p->pIndex);
@@ -241882,7 +257097,7 @@ static const unsigned char wx_sqlite3Utf8Trans1[] = {
c = *(zIn++); \
if( c>=0xc0 ){ \
c = wx_sqlite3Utf8Trans1[c-0xc0]; \
- while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
+ while( zIn<zTerm && (*zIn & 0xc0)==0x80 ){ \
c = (c<<6) + (0x3f & *(zIn++)); \
} \
if( c<0x80 \
@@ -241913,6 +257128,12 @@ static const unsigned char wx_sqlite3Utf8Trans1[] = {
#endif /* ifndef SQLITE_AMALGAMATION */
+#define FTS5_SKIP_UTF8(zIn) { \
+ if( ((unsigned char)(*(zIn++)))>=0xc0 ){ \
+ while( (((unsigned char)*zIn) & 0xc0)==0x80 ){ zIn++; } \
+ } \
+}
+
typedef struct Unicode61Tokenizer Unicode61Tokenizer;
struct Unicode61Tokenizer {
unsigned char aTokenChar[128]; /* ASCII range token characters */
@@ -242064,7 +257285,6 @@ static int fts5UnicodeCreate(
zCat = azArg[i+1];
}
}
-
if( rc==SQLITE_OK ){
rc = unicodeSetCategories(p, zCat);
}
@@ -242094,7 +257314,6 @@ static int fts5UnicodeCreate(
rc = SQLITE_ERROR;
}
}
-
}else{
rc = SQLITE_NOMEM;
}
@@ -242233,7 +257452,7 @@ static int fts5UnicodeTokenize(
typedef struct PorterTokenizer PorterTokenizer;
struct PorterTokenizer {
- fts5_tokenizer tokenizer; /* Parent tokenizer module */
+ fts5_tokenizer_v2 tokenizer_v2; /* Parent tokenizer module */
Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */
char aBuf[FTS5_PORTER_MAX_TOKEN + 64];
};
@@ -242245,7 +257464,7 @@ static void fts5PorterDelete(Fts5Tokenizer *pTok){
if( pTok ){
PorterTokenizer *p = (PorterTokenizer*)pTok;
if( p->pTokenizer ){
- p->tokenizer.xDelete(p->pTokenizer);
+ p->tokenizer_v2.xDelete(p->pTokenizer);
}
wx_sqlite3_free(p);
}
@@ -242264,6 +257483,7 @@ static int fts5PorterCreate(
PorterTokenizer *pRet;
void *pUserdata = 0;
const char *zBase = "unicode61";
+ fts5_tokenizer_v2 *pV2 = 0;
if( nArg>0 ){
zBase = azArg[0];
@@ -242272,14 +257492,15 @@ static int fts5PorterCreate(
pRet = (PorterTokenizer*)wx_sqlite3_malloc(sizeof(PorterTokenizer));
if( pRet ){
memset(pRet, 0, sizeof(PorterTokenizer));
- rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer);
+ rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2);
}else{
rc = SQLITE_NOMEM;
}
if( rc==SQLITE_OK ){
int nArg2 = (nArg>0 ? nArg-1 : 0);
- const char **azArg2 = (nArg2 ? &azArg[1] : 0);
- rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer);
+ const char **az2 = (nArg2 ? &azArg[1] : 0);
+ memcpy(&pRet->tokenizer_v2, pV2, sizeof(fts5_tokenizer_v2));
+ rc = pRet->tokenizer_v2.xCreate(pUserdata, az2, nArg2, &pRet->pTokenizer);
}
if( rc!=SQLITE_OK ){
@@ -242930,6 +258151,7 @@ static int fts5PorterTokenize(
void *pCtx,
int flags,
const char *pText, int nText,
+ const char *pLoc, int nLoc,
int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
){
PorterTokenizer *p = (PorterTokenizer*)pTokenizer;
@@ -242937,8 +258159,8 @@ static int fts5PorterTokenize(
sCtx.xToken = xToken;
sCtx.pCtx = pCtx;
sCtx.aBuf = p->aBuf;
- return p->tokenizer.xTokenize(
- p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb
+ return p->tokenizer_v2.xTokenize(
+ p->pTokenizer, (void*)&sCtx, flags, pText, nText, pLoc, nLoc, fts5PorterCb
);
}
@@ -242948,6 +258170,7 @@ static int fts5PorterTokenize(
typedef struct TrigramTokenizer TrigramTokenizer;
struct TrigramTokenizer {
int bFold; /* True to fold to lower-case */
+ int iFoldParam; /* Parameter to pass to Fts5UnicodeFold() */
};
/*
@@ -242967,28 +258190,46 @@ static int fts5TriCreate(
Fts5Tokenizer **ppOut
){
int rc = SQLITE_OK;
- TrigramTokenizer *pNew = (TrigramTokenizer*)wx_sqlite3_malloc(sizeof(*pNew));
+ TrigramTokenizer *pNew = 0;
UNUSED_PARAM(pUnused);
- if( pNew==0 ){
- rc = SQLITE_NOMEM;
+ if( nArg%2 ){
+ rc = SQLITE_ERROR;
}else{
int i;
- pNew->bFold = 1;
- for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
- const char *zArg = azArg[i+1];
- if( 0==wx_sqlite3_stricmp(azArg[i], "case_sensitive") ){
- if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
- rc = SQLITE_ERROR;
+ pNew = (TrigramTokenizer*)wx_sqlite3_malloc(sizeof(*pNew));
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pNew->bFold = 1;
+ pNew->iFoldParam = 0;
+
+ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
+ const char *zArg = azArg[i+1];
+ if( 0==wx_sqlite3_stricmp(azArg[i], "case_sensitive") ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
+ rc = SQLITE_ERROR;
+ }else{
+ pNew->bFold = (zArg[0]=='0');
+ }
+ }else if( 0==wx_sqlite3_stricmp(azArg[i], "remove_diacritics") ){
+ if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
+ rc = SQLITE_ERROR;
+ }else{
+ pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
+ }
}else{
- pNew->bFold = (zArg[0]=='0');
+ rc = SQLITE_ERROR;
}
- }else{
+ }
+
+ if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
rc = SQLITE_ERROR;
}
- }
- if( rc!=SQLITE_OK ){
- fts5TriDelete((Fts5Tokenizer*)pNew);
- pNew = 0;
+
+ if( rc!=SQLITE_OK ){
+ fts5TriDelete((Fts5Tokenizer*)pNew);
+ pNew = 0;
+ }
}
}
*ppOut = (Fts5Tokenizer*)pNew;
@@ -243008,40 +258249,62 @@ static int fts5TriTokenize(
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
int rc = SQLITE_OK;
char aBuf[32];
+ char *zOut = aBuf;
+ int ii;
const unsigned char *zIn = (const unsigned char*)pText;
const unsigned char *zEof = &zIn[nText];
u32 iCode;
+ int aStart[3]; /* Input offset of each character in aBuf[] */
UNUSED_PARAM(unusedFlags);
- while( 1 ){
- char *zOut = aBuf;
- int iStart = zIn - (const unsigned char*)pText;
- const unsigned char *zNext;
-
- READ_UTF8(zIn, zEof, iCode);
- if( iCode==0 ) break;
- zNext = zIn;
- if( zIn<zEof ){
- if( p->bFold ) iCode = wx_sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
+
+ /* Populate aBuf[] with the characters for the first trigram. */
+ for(ii=0; ii<3; ii++){
+ do {
+ aStart[ii] = zIn - (const unsigned char*)pText;
READ_UTF8(zIn, zEof, iCode);
- if( iCode==0 ) break;
- }else{
- break;
- }
- if( zIn<zEof ){
- if( p->bFold ) iCode = wx_sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
+ if( iCode==0 ) return SQLITE_OK;
+ if( p->bFold ) iCode = wx_sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
+ }while( iCode==0 );
+ WRITE_UTF8(zOut, iCode);
+ }
+
+ /* At the start of each iteration of this loop:
+ **
+ ** aBuf: Contains 3 characters. The 3 characters of the next trigram.
+ ** zOut: Points to the byte following the last character in aBuf.
+ ** aStart[3]: Contains the byte offset in the input text corresponding
+ ** to the start of each of the three characters in the buffer.
+ */
+ assert( zIn<=zEof );
+ while( 1 ){
+ int iNext; /* Start of character following current tri */
+ const char *z1;
+
+ /* Read characters from the input up until the first non-diacritic */
+ do {
+ iNext = zIn - (const unsigned char*)pText;
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
- if( p->bFold ) iCode = wx_sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
- }else{
- break;
- }
- rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf);
- if( rc!=SQLITE_OK ) break;
- zIn = zNext;
+ if( p->bFold ) iCode = wx_sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
+ }while( iCode==0 );
+
+ /* Pass the current trigram back to fts5 */
+ rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext);
+ if( iCode==0 || rc!=SQLITE_OK ) break;
+
+ /* Remove the first character from buffer aBuf[]. Append the character
+ ** with codepoint iCode. */
+ z1 = aBuf;
+ FTS5_SKIP_UTF8(z1);
+ memmove(aBuf, z1, zOut - z1);
+ zOut -= (z1 - aBuf);
+ WRITE_UTF8(zOut, iCode);
+
+ /* Update the aStart[] array */
+ aStart[0] = aStart[1];
+ aStart[1] = aStart[2];
+ aStart[2] = iNext;
}
return rc;
@@ -243064,12 +258327,24 @@ static int wx_sqlite3Fts5TokenizerPattern(
){
if( xCreate==fts5TriCreate ){
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
- return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
+ if( p->iFoldParam==0 ){
+ return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
+ }
}
return FTS5_PATTERN_NONE;
}
/*
+** Return true if the tokenizer described by p->azArg[] is the trigram
+** tokenizer. This tokenizer needs to be loaded before xBestIndex is
+** called for the first time in order to correctly handle LIKE/GLOB.
+*/
+static int wx_sqlite3Fts5TokenizerPreload(Fts5TokenizerConfig *p){
+ return (p->nArg>=1 && 0==wx_sqlite3_stricmp(p->azArg[0], "trigram"));
+}
+
+
+/*
** Register all built-in tokenizers with FTS5.
*/
static int wx_sqlite3Fts5TokenizerInit(fts5_api *pApi){
@@ -243079,7 +258354,6 @@ static int wx_sqlite3Fts5TokenizerInit(fts5_api *pApi){
} aBuiltin[] = {
{ "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
{ "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
- { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
{ "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}},
};
@@ -243094,7 +258368,20 @@ static int wx_sqlite3Fts5TokenizerInit(fts5_api *pApi){
0
);
}
-
+ if( rc==SQLITE_OK ){
+ fts5_tokenizer_v2 sPorter = {
+ 2,
+ fts5PorterCreate,
+ fts5PorterDelete,
+ fts5PorterTokenize
+ };
+ rc = pApi->xCreateTokenizer_v2(pApi,
+ "porter",
+ (void*)pApi,
+ &sPorter,
+ 0
+ );
+ }
return rc;
}
@@ -243464,6 +258751,9 @@ static int wx_sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
default: return 1; }
break;
+
+ default:
+ return 1;
}
return 0;
}
@@ -244288,6 +259578,7 @@ struct Fts5VocabCursor {
int nLeTerm; /* Size of zLeTerm in bytes */
char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
+ int colUsed; /* Copy of wx_sqlite3_index_info.colUsed */
/* These are used by 'col' tables only */
int iCol;
@@ -244314,9 +259605,11 @@ struct Fts5VocabCursor {
/*
** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
*/
-#define FTS5_VOCAB_TERM_EQ 0x01
-#define FTS5_VOCAB_TERM_GE 0x02
-#define FTS5_VOCAB_TERM_LE 0x04
+#define FTS5_VOCAB_TERM_EQ 0x0100
+#define FTS5_VOCAB_TERM_GE 0x0200
+#define FTS5_VOCAB_TERM_LE 0x0400
+
+#define FTS5_VOCAB_COLUSED_MASK 0xFF
/*
@@ -244493,11 +259786,13 @@ static int fts5VocabBestIndexMethod(
int iTermEq = -1;
int iTermGe = -1;
int iTermLe = -1;
- int idxNum = 0;
+ int idxNum = (int)pInfo->colUsed;
int nArg = 0;
UNUSED_PARAM(pUnused);
+ assert( (pInfo->colUsed & FTS5_VOCAB_COLUSED_MASK)==pInfo->colUsed );
+
for(i=0; i<pInfo->nConstraint; i++){
struct wx_sqlite3_index_constraint *p = &pInfo->aConstraint[i];
if( p->usable==0 ) continue;
@@ -244589,7 +259884,7 @@ static int fts5VocabOpenMethod(
if( rc==SQLITE_OK ){
pVTab->zErrMsg = wx_sqlite3_mprintf(
"no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
- );
+ );
rc = SQLITE_ERROR;
}
}else{
@@ -244749,9 +260044,19 @@ static int fts5VocabNextMethod(wx_sqlite3_vtab_cursor *pCursor){
switch( pTab->eType ){
case FTS5_VOCAB_ROW:
- if( eDetail==FTS5_DETAIL_FULL ){
- while( 0==wx_sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
- pCsr->aCnt[0]++;
+ /* Do not bother counting the number of instances if the "cnt"
+ ** column is not being read (according to colUsed). */
+ if( eDetail==FTS5_DETAIL_FULL && (pCsr->colUsed & 0x04) ){
+ while( iPos<nPos ){
+ u32 ii;
+ fts5FastGetVarint32(pPos, iPos, ii);
+ if( ii==1 ){
+ /* New column in the position list */
+ fts5FastGetVarint32(pPos, iPos, ii);
+ }else{
+ /* An instance - increment pCsr->aCnt[] */
+ pCsr->aCnt[0]++;
+ }
}
}
pCsr->aDoc[0]++;
@@ -244849,11 +260154,12 @@ static int fts5VocabFilterMethod(
if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++];
if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++];
if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++];
+ pCsr->colUsed = (idxNum & FTS5_VOCAB_COLUSED_MASK);
if( pEq ){
zTerm = (const char *)wx_sqlite3_value_text(pEq);
nTerm = wx_sqlite3_value_bytes(pEq);
- f = 0;
+ f = FTS5INDEX_QUERY_NOTOKENDATA;
}else{
if( pGe ){
zTerm = (const char *)wx_sqlite3_value_text(pGe);
@@ -245007,7 +260313,8 @@ static int wx_sqlite3Fts5VocabInit(Fts5Global *pGlobal, wx_sqlite3 *db){
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
- /* xShadowName */ 0
+ /* xShadowName */ 0,
+ /* xIntegrity */ 0
};
void *p = (void*)pGlobal;
@@ -245015,7 +260322,7 @@ static int wx_sqlite3Fts5VocabInit(Fts5Global *pGlobal, wx_sqlite3 *db){
}
-
+/* Here ends the fts5.c composite file. */
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
/************** End of fts5.c ************************************************/
@@ -245336,6 +260643,7 @@ static wx_sqlite3_module stmtModule = {
0, /* xRelease */
0, /* xRollbackTo */
0, /* xShadowName */
+ 0 /* xIntegrity */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -245375,7 +260683,7 @@ SQLITE_API const char *wx_sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
/*
-** Include SQLite3MultiCipher components
+** Include SQLite3MultiCipher components
*/
/* #include "wx_sqlite3mc_config.h" */
/*** Begin of #include "wx_sqlite3mc_config.h" ***/
@@ -245384,7 +260692,7 @@ SQLITE_API const char *wx_sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
** Purpose: Header file for SQLite3 Multiple Ciphers compile-time configuration
** Author: Ulrich Telle
** Created: 2021-09-27
-** Copyright: (c) 2019-2022 Ulrich Telle
+** Copyright: (c) 2019-2024 Ulrich Telle
** License: MIT
*/
@@ -245418,6 +260726,10 @@ SQLITE_API const char *wx_sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
#define HAVE_CIPHER_RC4 WXSQLITE3_HAVE_CIPHER_RC4
#endif
+#ifdef WXSQLITE3_HAVE_CIPHER_ASCON128
+#define HAVE_CIPHER_ASCON128 WXSQLITE3_HAVE_CIPHER_ASCON128
+#endif
+
/*
** Actual definitions of supported ciphers
*/
@@ -245441,6 +260753,18 @@ SQLITE_API const char *wx_sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
#define HAVE_CIPHER_RC4 1
#endif
+#ifndef HAVE_CIPHER_ASCON128
+#define HAVE_CIPHER_ASCON128 1
+#endif
+
+/*
+** Define whether dynamic ciphers will be used
+*/
+
+#ifndef SQLITE3MC_HAVE_DYNAMIC_CIPHERS
+#define SQLITE3MC_HAVE_DYNAMIC_CIPHERS 0
+#endif
+
/*
** Disable all built-in ciphers on request
*/
@@ -245455,21 +260779,25 @@ SQLITE_API const char *wx_sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
#undef HAVE_CIPHER_CHACHA20
#undef HAVE_CIPHER_SQLCIPHER
#undef HAVE_CIPHER_RC4
+#undef HAVE_CIPHER_ASCON128
#define HAVE_CIPHER_AES_128_CBC 0
#define HAVE_CIPHER_AES_256_CBC 0
#define HAVE_CIPHER_CHACHA20 0
#define HAVE_CIPHER_SQLCIPHER 0
#define HAVE_CIPHER_RC4 0
+#define HAVE_CIPHER_ASCON128 0
#endif
/*
** Check that at least one cipher is be supported
*/
-#if HAVE_CIPHER_AES_128_CBC == 0 && \
+#if SQLITE3MC_HAVE_DYNAMIC_CIPHERS == 0 && \
+ HAVE_CIPHER_AES_128_CBC == 0 && \
HAVE_CIPHER_AES_256_CBC == 0 && \
HAVE_CIPHER_CHACHA20 == 0 && \
HAVE_CIPHER_SQLCIPHER == 0 && \
- HAVE_CIPHER_RC4 == 0
+ HAVE_CIPHER_RC4 == 0 && \
+ HAVE_CIPHER_ASCON128 == 0
#pragma message ("wx_sqlite3mc_config.h: WARNING - No built-in cipher scheme enabled!")
#endif
@@ -245549,7 +260877,7 @@ SQLITE_API const char *wx_sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
** Purpose: Header file for SQLite3 Multiple Ciphers support
** Author: Ulrich Telle
** Created: 2020-03-01
-** Copyright: (c) 2019-2022 Ulrich Telle
+** Copyright: (c) 2019-2024 Ulrich Telle
** License: MIT
*/
@@ -245566,7 +260894,7 @@ SQLITE_API const char *wx_sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
** Purpose: SQLite3 Multiple Ciphers version numbers
** Author: Ulrich Telle
** Created: 2020-08-05
-** Copyright: (c) 2020-2023 Ulrich Telle
+** Copyright: (c) 2020-2024 Ulrich Telle
** License: MIT
*/
@@ -245576,10 +260904,10 @@ SQLITE_API const char *wx_sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
#define SQLITE3MC_VERSION_H_
#define SQLITE3MC_VERSION_MAJOR 1
-#define SQLITE3MC_VERSION_MINOR 6
+#define SQLITE3MC_VERSION_MINOR 9
#define SQLITE3MC_VERSION_RELEASE 2
#define SQLITE3MC_VERSION_SUBRELEASE 0
-#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.6.2"
+#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.9.2"
#endif /* SQLITE3MC_VERSION_H_ */
/*** End of #include "wx_sqlite3mc_version.h" ***/
@@ -245738,9 +261066,9 @@ extern "C" {
** [wx_sqlite3_libversion_number()], [wx_sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.41.2"
-#define SQLITE_VERSION_NUMBER 3041002
-#define SQLITE_SOURCE_ID "2023-03-22 11:56:21 0d1fc92f94cb6b76bffe3ec34d69cffde2924203304e8ffc4155597af0c191da"
+#define SQLITE_VERSION "3.47.2"
+#define SQLITE_VERSION_NUMBER 3047002
+#define SQLITE_SOURCE_ID "2024-12-07 20:39:59 2aabe05e2e8cae4847a802ee2daddc1d7413d8fc560254d93ee3e72c14685b6c"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -246012,6 +261340,8 @@ typedef int (*wx_sqlite3_callback)(void*,int,char**, char**);
** the 1st parameter to wx_sqlite3_exec() while wx_sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into
** the 2nd parameter of wx_sqlite3_exec() while wx_sqlite3_exec() is running.
+** <li> The application must not dereference the arrays or string pointers
+** passed as the 3rd and 4th callback parameters after it returns.
** </ul>
*/
SQLITE_API int wx_sqlite3_exec(
@@ -246120,6 +261450,7 @@ SQLITE_API int wx_sqlite3_exec(
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
+#define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
@@ -246241,6 +261572,13 @@ SQLITE_API int wx_sqlite3_exec(
** filesystem supports doing multiple write operations atomically when those
** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
+**
+** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read
+** from the database file in amounts that are not a multiple of the
+** page size and that do not begin at a page boundary. Without this
+** property, SQLite is careful to only do full-page reads and write
+** on aligned pages, with the one exception that it will do a sub-page
+** read of the first page to access the database header.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -246257,6 +261595,7 @@ SQLITE_API int wx_sqlite3_exec(
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
+#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000
/*
** CAPI3REF: File Locking Levels
@@ -246353,16 +261692,16 @@ struct wx_sqlite3_file {
** </ul>
** xLock() upgrades the database file lock. In other words, xLock() moves the
** database file lock in the direction NONE toward EXCLUSIVE. The argument to
-** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
+** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
** SQLITE_LOCK_NONE. If the database file lock is already at or above the
** requested lock, then the call to xLock() is a no-op.
** xUnlock() downgrades the database file lock to either SHARED or NONE.
-* If the lock is already at or below the requested lock state, then the call
+** If the lock is already at or below the requested lock state, then the call
** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
-** PENDING, or EXCLUSIVE lock on the file. It returns true
-** if such a lock exists and false otherwise.
+** PENDING, or EXCLUSIVE lock on the file. It returns, via its output
+** pointer parameter, true if such a lock exists and false otherwise.
**
** The xFileControl() method is a generic interface that allows custom
** VFS implementations to directly control an open file using the
@@ -246403,6 +261742,7 @@ struct wx_sqlite3_file {
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
** <li> [SQLITE_IOCAP_IMMUTABLE]
** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
+** <li> [SQLITE_IOCAP_SUBPAGE_READ]
** </ul>
**
** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -246782,7 +262122,7 @@ struct wx_sqlite3_io_methods {
** by clients within the current process, only within other processes.
**
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
-** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use interally by the
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the
** [checksum VFS shim] only.
**
** <li>[[SQLITE_FCNTL_RESET_CACHE]]
@@ -247247,20 +262587,23 @@ SQLITE_API int wx_sqlite3_os_end(void);
** must ensure that no other SQLite interfaces are invoked by other
** threads while wx_sqlite3_config() is running.</b>
**
-** The wx_sqlite3_config() interface
-** may only be invoked prior to library initialization using
-** [wx_sqlite3_initialize()] or after shutdown by [wx_sqlite3_shutdown()].
-** ^If wx_sqlite3_config() is called after [wx_sqlite3_initialize()] and before
-** [wx_sqlite3_shutdown()] then it will return SQLITE_MISUSE.
-** Note, however, that ^wx_sqlite3_config() can be called as part of the
-** implementation of an application-defined [wx_sqlite3_os_init()].
-**
** The first argument to wx_sqlite3_config() is an integer
** [configuration option] that determines
** what property of SQLite is to be configured. Subsequent arguments
** vary depending on the [configuration option]
** in the first argument.
**
+** For most configuration options, the wx_sqlite3_config() interface
+** may only be invoked prior to library initialization using
+** [wx_sqlite3_initialize()] or after shutdown by [wx_sqlite3_shutdown()].
+** The exceptional configuration options that may be invoked at any time
+** are called "anytime configuration options".
+** ^If wx_sqlite3_config() is called after [wx_sqlite3_initialize()] and before
+** [wx_sqlite3_shutdown()] with a first argument that is not an anytime
+** configuration option, then the wx_sqlite3_config() call will return SQLITE_MISUSE.
+** Note, however, that ^wx_sqlite3_config() can be called as part of the
+** implementation of an application-defined [wx_sqlite3_os_init()].
+**
** ^When a configuration option is set, wx_sqlite3_config() returns [SQLITE_OK].
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
@@ -247368,6 +262711,23 @@ struct wx_sqlite3_mem_methods {
** These constants are the available integer configuration options that
** can be passed as the first argument to the [wx_sqlite3_config()] interface.
**
+** Most of the configuration options for wx_sqlite3_config()
+** will only work if invoked prior to [wx_sqlite3_initialize()] or after
+** [wx_sqlite3_shutdown()]. The few exceptions to this rule are called
+** "anytime configuration options".
+** ^Calling [wx_sqlite3_config()] with a first argument that is not an
+** anytime configuration option in between calls to [wx_sqlite3_initialize()] and
+** [wx_sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE.
+**
+** The set of anytime configuration options can change (by insertions
+** and/or deletions) from one release of SQLite to the next.
+** As of SQLite version 3.42.0, the complete set of anytime configuration
+** options is:
+** <ul>
+** <li> SQLITE_CONFIG_LOG
+** <li> SQLITE_CONFIG_PCACHE_HDRSZ
+** </ul>
+**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
** should check the return code from [wx_sqlite3_config()] to make sure that
@@ -247698,7 +263058,7 @@ struct wx_sqlite3_mem_methods {
** is stored in each sorted record and the required column values loaded
** from the database as records are returned in sorted order. The default
** value for this option is to never use this optimization. Specifying a
-** negative value for this option restores the default behaviour.
+** negative value for this option restores the default behavior.
** This option is only available if SQLite is compiled with the
** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
**
@@ -247712,30 +263072,46 @@ struct wx_sqlite3_mem_methods {
** configuration setting is never used, then the default maximum is determined
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
** compile-time option is not set, then the default maximum is 1073741824.
+**
+** [[SQLITE_CONFIG_ROWID_IN_VIEW]]
+** <dt>SQLITE_CONFIG_ROWID_IN_VIEW
+** <dd>The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability
+** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is
+** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability
+** defaults to on. This configuration option queries the current setting or
+** changes the setting to off or on. The argument is a pointer to an integer.
+** If that integer initially holds a value of 1, then the ability for VIEWs to
+** have ROWIDs is activated. If the integer initially holds zero, then the
+** ability is deactivated. Any other initial value for the integer leaves the
+** setting unchanged. After changes, if any, the integer is written with
+** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite
+** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and
+** recommended case) then the integer is always filled with zero, regardless
+** if its initial value.
** </dl>
*/
-#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
-#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
-#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* wx_sqlite3_mem_methods* */
-#define SQLITE_CONFIG_GETMALLOC 5 /* wx_sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
-#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
-#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
-#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
-#define SQLITE_CONFIG_MUTEX 10 /* wx_sqlite3_mutex_methods* */
-#define SQLITE_CONFIG_GETMUTEX 11 /* wx_sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
-#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#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 /* wx_sqlite3_pcache_methods2* */
-#define SQLITE_CONFIG_GETPCACHE2 19 /* wx_sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
+#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
+#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
+#define SQLITE_CONFIG_MALLOC 4 /* wx_sqlite3_mem_methods* */
+#define SQLITE_CONFIG_GETMALLOC 5 /* wx_sqlite3_mem_methods* */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
+#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
+#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
+#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
+#define SQLITE_CONFIG_MUTEX 10 /* wx_sqlite3_mutex_methods* */
+#define SQLITE_CONFIG_GETMUTEX 11 /* wx_sqlite3_mutex_methods* */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
+#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 /* wx_sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* wx_sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
-#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
-#define SQLITE_CONFIG_MMAP_SIZE 22 /* wx_sqlite3_int64, wx_sqlite3_int64 */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* wx_sqlite3_int64, wx_sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
@@ -247743,6 +263119,7 @@ struct wx_sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* wx_sqlite3_int64 */
+#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -247873,7 +263250,7 @@ struct wx_sqlite3_mem_methods {
** database handle, SQLite checks if this will mean that there are now no
** connections at all to the database. If so, it performs a checkpoint
** operation before closing the connection. This option may be used to
-** override this behaviour. The first parameter passed to this operation
+** override this behavior. The first parameter passed to this operation
** is an integer - positive to disable checkpoints-on-close, or zero (the
** default) to enable them, and negative to leave the setting unchanged.
** The second parameter is a pointer to an integer
@@ -247970,7 +263347,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
-** <dt>SQLITE_DBCONFIG_DQS_DML</td>
+** <dt>SQLITE_DBCONFIG_DQS_DML</dt>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@@ -247979,7 +263356,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
-** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
+** <dt>SQLITE_DBCONFIG_DQS_DDL</dt>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
@@ -247988,7 +263365,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
-** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
+** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@@ -248008,7 +263385,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
-** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
+** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
@@ -248017,7 +263394,7 @@ struct wx_sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
-** is now scarcely any need to generated database files that are compatible
+** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version
@@ -248026,8 +263403,40 @@ struct wx_sqlite3_mem_methods {
** the [VACUUM] command will fail with an obscure error when attempting to
** process a table with generated columns and a descending index. This is
** not considered a bug since SQLite versions 3.3.0 and earlier do not support
-** either generated columns or decending indexes.
+** either generated columns or descending indexes.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
+** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
+** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
+** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
+** a flag that enables collection of the wx_sqlite3_stmt_scanstatus_v2()
+** statistics. For statistics to be collected, the flag must be set on
+** the database handle both when the SQL statement is prepared and when it
+** is stepped. The flag is set (collection of statistics is enabled)
+** by default. This option takes two arguments: an integer and a pointer to
+** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the statement scanstatus option. If the second argument
+** is not NULL, then the value of the statement scanstatus setting after
+** processing the first argument is written into the integer that the second
+** argument points to.
** </dd>
+**
+** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
+** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
+** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
+** in which tables and indexes are scanned so that the scans start at the end
+** and work toward the beginning rather than starting at the beginning and
+** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
+** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** two arguments which are an integer and a pointer to an integer. The first
+** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
+** reverse scan order flag, respectively. If the second argument is not NULL,
+** then 0 or 1 is written into the integer that the second argument points to
+** depending on if the reverse scan order flag is set after processing the
+** first argument.
+** </dd>
+**
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -248048,7 +263457,9 @@ struct wx_sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
+#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -248273,6 +263684,7 @@ SQLITE_API wx_sqlite3_int64 wx_sqlite3_total_changes64(wx_sqlite3*);
**
** ^The [wx_sqlite3_is_interrupted(D)] interface can be used to determine whether
** or not an interrupt is currently in effect for [database connection] D.
+** It returns 1 if an interrupt is currently in effect, or 0 otherwise.
*/
SQLITE_API void wx_sqlite3_interrupt(wx_sqlite3*);
SQLITE_API int wx_sqlite3_is_interrupted(wx_sqlite3*);
@@ -248822,8 +264234,8 @@ SQLITE_API int wx_sqlite3_set_authorizer(
#define SQLITE_RECURSIVE 33 /* NULL NULL */
/*
-** CAPI3REF: Tracing And Profiling Functions
-** METHOD: wx_sqlite3
+** CAPI3REF: Deprecated Tracing And Profiling Functions
+** DEPRECATED
**
** These routines are deprecated. Use the [wx_sqlite3_trace_v2()] interface
** instead of the routines described here.
@@ -248926,8 +264338,10 @@ SQLITE_API SQLITE_DEPRECATED void *wx_sqlite3_profile(wx_sqlite3*,
** M argument should be the bitwise OR-ed combination of
** zero or more [SQLITE_TRACE] constants.
**
-** ^Each call to either wx_sqlite3_trace() or wx_sqlite3_trace_v2() overrides
-** (cancels) any prior calls to wx_sqlite3_trace() or wx_sqlite3_trace_v2().
+** ^Each call to either wx_sqlite3_trace(D,X,P) or wx_sqlite3_trace_v2(D,M,X,P)
+** overrides (cancels) all prior calls to wx_sqlite3_trace(D,X,P) or
+** wx_sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each
+** database connection may have at most one trace callback.
**
** ^The X callback is invoked whenever any of the events identified by
** mask M occur. ^The integer return value from the callback is currently
@@ -249085,8 +264499,8 @@ SQLITE_API void wx_sqlite3_progress_handler(wx_sqlite3*, int, int(*)(void*), voi
**
** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt>
** <dd>The database connection comes up in "extended result code mode".
-** In other words, the database behaves has if
-** [wx_sqlite3_extended_result_codes(db,1)] where called on the database
+** In other words, the database behaves as if
+** [wx_sqlite3_extended_result_codes(db,1)] were called on the database
** connection as soon as the connection is created. In addition to setting
** the extended result code mode, this flag also causes [wx_sqlite3_open_v2()]
** to return an extended result code.</dd>
@@ -249296,7 +264710,7 @@ SQLITE_API int wx_sqlite3_open_v2(
** as F) must be one of:
** <ul>
** <li> A database filename pointer created by the SQLite core and
-** passed into the xOpen() method of a VFS implemention, or
+** passed into the xOpen() method of a VFS implementation, or
** <li> A filename obtained from [wx_sqlite3_db_filename()], or
** <li> A new filename constructed using [wx_sqlite3_create_filename()].
** </ul>
@@ -249409,7 +264823,7 @@ SQLITE_API wx_sqlite3_file *wx_sqlite3_database_file_object(const char*);
/*
** CAPI3REF: Create and Destroy VFS Filenames
**
-** These interfces are provided for use by [VFS shim] implementations and
+** These interfaces are provided for use by [VFS shim] implementations and
** are not useful outside of that context.
**
** The wx_sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
@@ -249488,14 +264902,17 @@ SQLITE_API void wx_sqlite3_free_filename(wx_sqlite3_filename);
** </ul>
**
** ^The wx_sqlite3_errmsg() and wx_sqlite3_errmsg16() return English-language
-** text that describes the error, as either UTF-8 or UTF-16 respectively.
+** text that describes the error, as either UTF-8 or UTF-16 respectively,
+** or NULL if no error message is available.
+** (See how SQLite handles [invalid UTF] for exceptions to this rule.)
** ^(Memory to hold the error message string is managed internally.
** The application does not need to worry about freeing the result.
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
-** ^The wx_sqlite3_errstr() interface returns the English-language text
-** that describes the [result code], as UTF-8.
+** ^The wx_sqlite3_errstr(E) interface returns the English-language text
+** that describes the [result code] E, as UTF-8, or NULL if E is not an
+** result code for which a text error message is available.
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
@@ -249734,13 +265151,17 @@ SQLITE_API int wx_sqlite3_limit(wx_sqlite3*, int id, int newVal);
** and wx_sqlite3_prepare16_v3() use UTF-16.
**
** ^If the nByte argument is negative, then zSql is read up to the
-** first zero terminator. ^If nByte is positive, then it is the
-** number of bytes read from zSql. ^If nByte is zero, then no prepared
+** first zero terminator. ^If nByte is positive, then it is the maximum
+** number of bytes read from zSql. When nByte is positive, zSql is read
+** up to the first zero terminator or until the nByte bytes have been read,
+** whichever comes first. ^If nByte is zero, then no prepared
** statement is generated.
** If the caller knows that the supplied string is nul-terminated, then
** there is a small performance advantage to passing an nByte parameter that
** is the number of bytes in the input string <i>including</i>
** the nul-terminator.
+** Note that nByte measure the length of the input in bytes, not
+** characters, even for the UTF-16 interfaces.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only
@@ -249957,6 +265378,41 @@ SQLITE_API int wx_sqlite3_stmt_readonly(wx_sqlite3_stmt *pStmt);
SQLITE_API int wx_sqlite3_stmt_isexplain(wx_sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement
+** METHOD: wx_sqlite3_stmt
+**
+** The wx_sqlite3_stmt_explain(S,E) interface changes the EXPLAIN
+** setting for [prepared statement] S. If E is zero, then S becomes
+** a normal prepared statement. If E is 1, then S behaves as if
+** its SQL text began with "[EXPLAIN]". If E is 2, then S behaves as if
+** its SQL text began with "[EXPLAIN QUERY PLAN]".
+**
+** Calling wx_sqlite3_stmt_explain(S,E) might cause S to be reprepared.
+** SQLite tries to avoid a reprepare, but a reprepare might be necessary
+** on the first transition into EXPLAIN or EXPLAIN QUERY PLAN mode.
+**
+** Because of the potential need to reprepare, a call to
+** wx_sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be
+** reprepared because it was created using [wx_sqlite3_prepare()] instead of
+** the newer [wx_sqlite3_prepare_v2()] or [wx_sqlite3_prepare_v3()] interfaces and
+** hence has no saved SQL text with which to reprepare.
+**
+** Changing the explain setting for a prepared statement does not change
+** the original SQL text for the statement. Hence, if the SQL text originally
+** began with EXPLAIN or EXPLAIN QUERY PLAN, but wx_sqlite3_stmt_explain(S,0)
+** is called to convert the statement into an ordinary statement, the EXPLAIN
+** or EXPLAIN QUERY PLAN keywords will still appear in the wx_sqlite3_sql(S)
+** output, even though the statement now acts like a normal SQL statement.
+**
+** This routine returns SQLITE_OK if the explain mode is successfully
+** changed, or an error code if the explain mode could not be changed.
+** The explain mode cannot be changed while a statement is active.
+** Hence, it is good practice to call [wx_sqlite3_reset(S)]
+** immediately prior to calling wx_sqlite3_stmt_explain(S,E).
+*/
+SQLITE_API int wx_sqlite3_stmt_explain(wx_sqlite3_stmt *pStmt, int eMode);
+
+/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: wx_sqlite3_stmt
**
@@ -250119,7 +265575,7 @@ typedef struct wx_sqlite3_context wx_sqlite3_context;
** with it may be passed. ^It is called to dispose of the BLOB or string even
** if the call to the bind API fails, except the destructor is not called if
** the third parameter is a NULL pointer or the fourth parameter is negative.
-** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that
+** ^ (2) The special constant, [SQLITE_STATIC], may be passed to indicate that
** the application remains responsible for disposing of the object. ^In this
** case, the object and the provided pointer to it must remain valid until
** either the prepared statement is finalized or the same SQL parameter is
@@ -250798,20 +266254,33 @@ SQLITE_API int wx_sqlite3_finalize(wx_sqlite3_stmt *pStmt);
** ^The [wx_sqlite3_reset(S)] interface resets the [prepared statement] S
** back to the beginning of its program.
**
-** ^If the most recent call to [wx_sqlite3_step(S)] for the
-** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
-** or if [wx_sqlite3_step(S)] has never before been called on S,
-** then [wx_sqlite3_reset(S)] returns [SQLITE_OK].
+** ^The return code from [wx_sqlite3_reset(S)] indicates whether or not
+** the previous evaluation of prepared statement S completed successfully.
+** ^If [wx_sqlite3_step(S)] has never before been called on S or if
+** [wx_sqlite3_step(S)] has not been called since the previous call
+** to [wx_sqlite3_reset(S)], then [wx_sqlite3_reset(S)] will return
+** [SQLITE_OK].
**
** ^If the most recent call to [wx_sqlite3_step(S)] for the
** [prepared statement] S indicated an error, then
** [wx_sqlite3_reset(S)] returns an appropriate [error code].
+** ^The [wx_sqlite3_reset(S)] interface might also return an [error code]
+** if there were no prior errors but the process of resetting
+** the prepared statement caused a new error. ^For example, if an
+** [INSERT] statement with a [RETURNING] clause is only stepped one time,
+** that one call to [wx_sqlite3_step(S)] might return SQLITE_ROW but
+** the overall statement might still fail and the [wx_sqlite3_reset(S)] call
+** might return SQLITE_BUSY if locking constraints prevent the
+** database change from committing. Therefore, it is important that
+** applications check the return code from [wx_sqlite3_reset(S)] even if
+** no prior call to [wx_sqlite3_step(S)] indicated a problem.
**
** ^The [wx_sqlite3_reset(S)] interface does not change the values
** of any [wx_sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int wx_sqlite3_reset(wx_sqlite3_stmt *pStmt);
+
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
@@ -251022,7 +266491,7 @@ SQLITE_API int wx_sqlite3_create_window_function(
** [application-defined SQL function]
** that has side-effects or that could potentially leak sensitive information.
** This will prevent attacks in which an application is tricked
-** into using a database file that has had its schema surreptiously
+** into using a database file that has had its schema surreptitiously
** modified to invoke the application-defined function in ways that are
** harmful.
** <p>
@@ -251058,13 +266527,36 @@ SQLITE_API int wx_sqlite3_create_window_function(
** </dd>
**
** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd>
-** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
+** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
** [wx_sqlite3_value_subtype()] to inspect the sub-types of its arguments.
-** Specifying this flag makes no difference for scalar or aggregate user
-** functions. However, if it is not specified for a user-defined window
-** function, then any sub-types belonging to arguments passed to the window
-** function may be discarded before the window function is called (i.e.
-** wx_sqlite3_value_subtype() will always return 0).
+** This flag instructs SQLite to omit some corner-case optimizations that
+** might disrupt the operation of the [wx_sqlite3_value_subtype()] function,
+** causing it to return zero rather than the correct subtype().
+** All SQL functions that invoke [wx_sqlite3_value_subtype()] should have this
+** property. If the SQLITE_SUBTYPE property is omitted, then the return
+** value from [wx_sqlite3_value_subtype()] might sometimes be zero even though
+** a non-zero subtype was specified by the function argument expression.
+**
+** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
+** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call
+** [wx_sqlite3_result_subtype()] to cause a sub-type to be associated with its
+** result.
+** Every function that invokes [wx_sqlite3_result_subtype()] should have this
+** property. If it does not, then the call to [wx_sqlite3_result_subtype()]
+** might become a no-op if the function is used as term in an
+** [expression index]. On the other hand, SQL functions that never invoke
+** [wx_sqlite3_result_subtype()] should avoid setting this property, as the
+** purpose of this property is to disable certain optimizations that are
+** incompatible with subtypes.
+**
+** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
+** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
+** that internally orders the values provided to the first argument. The
+** ordered-set aggregate SQL notation with a single ORDER BY term can be
+** used to invoke this function. If the ordered-set aggregate notation is
+** used on a function that lacks this flag, then an error is raised. Note
+** that the ordered-set aggregate syntax is only available if SQLite is
+** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
** </dd>
** </dl>
*/
@@ -251072,6 +266564,8 @@ SQLITE_API int wx_sqlite3_create_window_function(
#define SQLITE_DIRECTONLY 0x000080000
#define SQLITE_SUBTYPE 0x000100000
#define SQLITE_INNOCUOUS 0x000200000
+#define SQLITE_RESULT_SUBTYPE 0x001000000
+#define SQLITE_SELFORDER1 0x002000000
/*
** CAPI3REF: Deprecated Functions
@@ -251268,6 +266762,12 @@ SQLITE_API int wx_sqlite3_value_encoding(wx_sqlite3_value*);
** information can be used to pass a limited amount of context from
** one SQL function to another. Use the [wx_sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
+**
+** Every [application-defined SQL function] that invokes this interface
+** should include the [SQLITE_SUBTYPE] property in the text
+** encoding argument when the function is [wx_sqlite3_create_function|registered].
+** If the [SQLITE_SUBTYPE] property is omitted, then wx_sqlite3_value_subtype()
+** might return zero instead of the upstream subtype in some corner cases.
*/
SQLITE_API unsigned int wx_sqlite3_value_subtype(wx_sqlite3_value*);
@@ -251366,48 +266866,56 @@ SQLITE_API wx_sqlite3 *wx_sqlite3_context_db_handle(wx_sqlite3_context*);
** METHOD: wx_sqlite3_context
**
** These functions may be used by (non-aggregate) SQL functions to
-** associate metadata with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated metadata may be preserved. An example
-** of where this might be useful is in a regular-expression matching
-** function. The compiled version of the regular expression can be stored as
-** metadata associated with the pattern string.
+** associate auxiliary data with argument values. If the same argument
+** value is passed to multiple invocations of the same SQL function during
+** query execution, under some circumstances the associated auxiliary data
+** might be preserved. An example of where this might be useful is in a
+** regular-expression matching function. The compiled version of the regular
+** expression can be stored as auxiliary data associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The wx_sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** ^The wx_sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
** associated by the wx_sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
** value to the application-defined function. ^N is zero for the left-most
-** function argument. ^If there is no metadata
+** function argument. ^If there is no auxiliary data
** associated with the function argument, the wx_sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
-** ^The wx_sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
-** argument of the application-defined function. ^Subsequent
+** ^The wx_sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
+** N-th argument of the application-defined function. ^Subsequent
** calls to wx_sqlite3_get_auxdata(C,N) return P from the most recent
-** wx_sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or
-** NULL if the metadata has been discarded.
+** wx_sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or
+** NULL if the auxiliary data has been discarded.
** ^After each call to wx_sqlite3_set_auxdata(C,N,P,X) where X is not NULL,
** SQLite will invoke the destructor function X with parameter P exactly
-** once, when the metadata is discarded.
-** SQLite is free to discard the metadata at any time, including: <ul>
+** once, when the auxiliary data is discarded.
+** SQLite is free to discard the auxiliary data at any time, including: <ul>
** <li> ^(when the corresponding function parameter changes)^, or
** <li> ^(when [wx_sqlite3_reset()] or [wx_sqlite3_finalize()] is called for the
** SQL statement)^, or
** <li> ^(when wx_sqlite3_set_auxdata() is invoked again on the same
** parameter)^, or
** <li> ^(during the original wx_sqlite3_set_auxdata() call when a memory
-** allocation error occurs.)^ </ul>
+** allocation error occurs.)^
+** <li> ^(during the original wx_sqlite3_set_auxdata() call if the function
+** is evaluated during query planning instead of during query execution,
+** as sometimes happens with [SQLITE_ENABLE_STAT4].)^ </ul>
**
-** Note the last bullet in particular. The destructor X in
+** Note the last two bullets in particular. The destructor X in
** wx_sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
** wx_sqlite3_set_auxdata() interface even returns. Hence wx_sqlite3_set_auxdata()
** should be called near the end of the function implementation and the
** function implementation should not make any use of P after
-** wx_sqlite3_set_auxdata() has been called.
-**
-** ^(In practice, metadata is preserved between function calls for
+** wx_sqlite3_set_auxdata() has been called. Furthermore, a call to
+** wx_sqlite3_get_auxdata() that occurs immediately after a corresponding call
+** to wx_sqlite3_set_auxdata() might still return NULL if an out-of-memory
+** condition occurred during the wx_sqlite3_set_auxdata() call or if the
+** function is being evaluated during query planning rather than during
+** query execution.
+**
+** ^(In practice, auxiliary data is preserved between function calls for
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
**
@@ -251417,10 +266925,67 @@ SQLITE_API wx_sqlite3 *wx_sqlite3_context_db_handle(wx_sqlite3_context*);
**
** These routines must be called from the same thread in which
** the SQL function is running.
+**
+** See also: [wx_sqlite3_get_clientdata()] and [wx_sqlite3_set_clientdata()].
*/
SQLITE_API void *wx_sqlite3_get_auxdata(wx_sqlite3_context*, int N);
SQLITE_API void wx_sqlite3_set_auxdata(wx_sqlite3_context*, int N, void*, void (*)(void*));
+/*
+** CAPI3REF: Database Connection Client Data
+** METHOD: wx_sqlite3
+**
+** These functions are used to associate one or more named pointers
+** with a [database connection].
+** A call to wx_sqlite3_set_clientdata(D,N,P,X) causes the pointer P
+** to be attached to [database connection] D using name N. Subsequent
+** calls to wx_sqlite3_get_clientdata(D,N) will return a copy of pointer P
+** or a NULL pointer if there were no prior calls to
+** wx_sqlite3_set_clientdata() with the same values of D and N.
+** Names are compared using strcmp() and are thus case sensitive.
+**
+** If P and X are both non-NULL, then the destructor X is invoked with
+** argument P on the first of the following occurrences:
+** <ul>
+** <li> An out-of-memory error occurs during the call to
+** wx_sqlite3_set_clientdata() which attempts to register pointer P.
+** <li> A subsequent call to wx_sqlite3_set_clientdata(D,N,P,X) is made
+** with the same D and N parameters.
+** <li> The database connection closes. SQLite does not make any guarantees
+** about the order in which destructors are called, only that all
+** destructors will be called exactly once at some point during the
+** database connection closing process.
+** </ul>
+**
+** SQLite does not do anything with client data other than invoke
+** destructors on the client data at the appropriate time. The intended
+** use for client data is to provide a mechanism for wrapper libraries
+** to store additional information about an SQLite database connection.
+**
+** There is no limit (other than available memory) on the number of different
+** client data pointers (with different names) that can be attached to a
+** single database connection. However, the implementation is optimized
+** for the case of having only one or two different client data names.
+** Applications and wrapper libraries are discouraged from using more than
+** one client data name each.
+**
+** There is no way to enumerate the client data pointers
+** associated with a database connection. The N parameter can be thought
+** of as a secret key such that only code that knows the secret key is able
+** to access the associated data.
+**
+** Security Warning: These interfaces should not be exposed in scripting
+** languages or in other circumstances where it might be possible for an
+** an attacker to invoke them. Any agent that can invoke these interfaces
+** can probably also take control of the process.
+**
+** Database connection client data is only available for SQLite
+** version 3.44.0 ([dateof:3.44.0]) and later.
+**
+** See also: [wx_sqlite3_set_auxdata()] and [wx_sqlite3_get_auxdata()].
+*/
+SQLITE_API void *wx_sqlite3_get_clientdata(wx_sqlite3*,const char*);
+SQLITE_API int wx_sqlite3_set_clientdata(wx_sqlite3*, const char*, void*, void(*)(void*));
/*
** CAPI3REF: Constants Defining Special Destructor Behavior
@@ -251622,6 +267187,20 @@ SQLITE_API int wx_sqlite3_result_zeroblob64(wx_sqlite3_context*, wx_sqlite3_uint
** higher order bits are discarded.
** The number of subtype bytes preserved by SQLite might increase
** in future releases of SQLite.
+**
+** Every [application-defined SQL function] that invokes this interface
+** should include the [SQLITE_RESULT_SUBTYPE] property in its
+** text encoding argument when the SQL function is
+** [wx_sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE]
+** property is omitted from the function that invokes wx_sqlite3_result_subtype(),
+** then in some cases the wx_sqlite3_result_subtype() might fail to set
+** the result subtype.
+**
+** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any
+** SQL function that invokes the wx_sqlite3_result_subtype() interface
+** and that does not have the SQLITE_RESULT_SUBTYPE property will raise
+** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1
+** by default.
*/
SQLITE_API void wx_sqlite3_result_subtype(wx_sqlite3_context*,unsigned int);
@@ -251793,6 +267372,13 @@ SQLITE_API void wx_sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of wx_sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
+**
+** If a negative argument is passed to wx_sqlite3_sleep() the results vary by
+** VFS and operating system. Some system treat a negative argument as an
+** instruction to sleep forever. Others understand it to mean do not sleep
+** at all. ^In SQLite version 3.42.0 and later, a negative
+** argument passed into wx_sqlite3_sleep() is changed to zero before it is relayed
+** down into the xSleep method of the VFS.
*/
SQLITE_API int wx_sqlite3_sleep(int);
@@ -252046,7 +267632,7 @@ SQLITE_API int wx_sqlite3_db_readonly(wx_sqlite3 *db, const char *zDbName);
SQLITE_API int wx_sqlite3_txn_state(wx_sqlite3*,const char *zSchema);
/*
-** CAPI3REF: Allowed return values from [wx_sqlite3_txn_state()]
+** CAPI3REF: Allowed return values from wx_sqlite3_txn_state()
** KEYWORDS: {transaction state}
**
** These constants define the current transaction state of a database file.
@@ -252178,7 +267764,7 @@ SQLITE_API void *wx_sqlite3_rollback_hook(wx_sqlite3*, void(*)(void *), void*);
** ^Each call to the wx_sqlite3_autovacuum_pages() interface overrides all
** previous invocations for that database connection. ^If the callback
** argument (C) to wx_sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer,
-** then the autovacuum steps callback is cancelled. The return value
+** then the autovacuum steps callback is canceled. The return value
** from wx_sqlite3_autovacuum_pages() is normally SQLITE_OK, but might
** be some other error code if something goes wrong. The current
** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other
@@ -252244,6 +267830,12 @@ SQLITE_API int wx_sqlite3_autovacuum_pages(
** The exceptions defined in this paragraph might change in a future
** release of SQLite.
**
+** Whether the update hook is invoked before or after the
+** corresponding change is currently unspecified and may differ
+** depending on the type of change. Do not rely on the order of the
+** hook call with regards to the final result of the operation which
+** triggers the hook.
+**
** The update hook implementation must not do anything that will modify
** the database connection that invoked the update hook. Any actions
** to modify the database connection must be deferred until after the
@@ -252697,6 +268289,10 @@ struct wx_sqlite3_module {
/* The methods above are in versions 1 and 2 of the sqlite_module object.
** Those below are for version 3 and greater. */
int (*xShadowName)(const char*);
+ /* The methods above are in versions 1 through 3 of the sqlite_module object.
+ ** Those below are for version 4 and greater. */
+ int (*xIntegrity)(wx_sqlite3_vtab *pVTab, const char *zSchema,
+ const char *zTabName, int mFlags, char **pzErr);
};
/*
@@ -252774,9 +268370,11 @@ struct wx_sqlite3_module {
** will be returned by the strategy.
**
** The xBestIndex method may optionally populate the idxFlags field with a
-** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
-** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
-** assumes that the strategy may visit at most one row.
+** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
+** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
+** output to show the idxNum has hex instead of as decimal. Another flag is
+** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
+** return at most one row.
**
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
** SQLite also assumes that if a call to the xUpdate() method is made as
@@ -252840,7 +268438,9 @@ struct wx_sqlite3_index_info {
** [wx_sqlite3_index_info].idxFlags field to some combination of
** these bits.
*/
-#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
+#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */
+#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */
+ /* in EXPLAIN QUERY PLAN */
/*
** CAPI3REF: Virtual Table Constraint Operator Codes
@@ -253184,7 +268784,7 @@ SQLITE_API int wx_sqlite3_blob_reopen(wx_sqlite3_blob *, wx_sqlite3_int64);
** code is returned and the transaction rolled back.
**
** Calling this function with an argument that is not a NULL pointer or an
-** open blob handle results in undefined behaviour. ^Calling this routine
+** open blob handle results in undefined behavior. ^Calling this routine
** with a null pointer (such as would be returned by a failed call to
** [wx_sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
** is passed a valid open blob handle, the values returned by the
@@ -253411,18 +269011,20 @@ SQLITE_API int wx_sqlite3_vfs_unregister(wx_sqlite3_vfs*);
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by wx_sqlite3_mutex_try(). On those systems, wx_sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** wx_sqlite3_mutex_try() as an optimization so this is acceptable
-** behavior.)^
+** will always return SQLITE_BUSY. In most cases the SQLite core only uses
+** wx_sqlite3_mutex_try() as an optimization, so this is acceptable
+** behavior. The exceptions are unix builds that set the
+** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working
+** wx_sqlite3_mutex_try() is required.)^
**
** ^The wx_sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated.
**
-** ^If the argument to wx_sqlite3_mutex_enter(), wx_sqlite3_mutex_try(), or
-** wx_sqlite3_mutex_leave() is a NULL pointer, then all three routines
-** behave as no-ops.
+** ^If the argument to wx_sqlite3_mutex_enter(), wx_sqlite3_mutex_try(),
+** wx_sqlite3_mutex_leave(), or wx_sqlite3_mutex_free() is a NULL pointer,
+** then any of the four routines behaves as a no-op.
**
** See also: [wx_sqlite3_mutex_held()] and [wx_sqlite3_mutex_notheld()].
*/
@@ -253664,6 +269266,7 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
+#define SQLITE_TESTCTRL_FK_NO_ACTION 7
#define SQLITE_TESTCTRL_BITVEC_TEST 8
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
@@ -253671,8 +269274,10 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ASSERT 12
#define SQLITE_TESTCTRL_ALWAYS 13
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
+#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
+#define SQLITE_TESTCTRL_GETOPT 16
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
@@ -253692,7 +269297,8 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33
-#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
+#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -253705,7 +269311,7 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
** The wx_sqlite3_keyword_count() interface returns the number of distinct
** keywords understood by SQLite.
**
-** The wx_sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and
+** The wx_sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and
** makes *Z point to that keyword expressed as UTF8 and writes the number
** of bytes in the keyword into *L. The string that *Z points to is not
** zero-terminated. The wx_sqlite3_keyword_name(N,Z,L) routine returns
@@ -254667,6 +270273,16 @@ typedef struct wx_sqlite3_backup wx_sqlite3_backup;
** APIs are not strictly speaking threadsafe. If they are invoked at the
** same time as another thread is invoking wx_sqlite3_backup_step() it is
** possible that they return invalid values.
+**
+** <b>Alternatives To Using The Backup API</b>
+**
+** Other techniques for safely creating a consistent backup of an SQLite
+** database include:
+**
+** <ul>
+** <li> The [VACUUM INTO] command.
+** <li> The [wx_sqlite3_rsync] utility program.
+** </ul>
*/
SQLITE_API wx_sqlite3_backup *wx_sqlite3_backup_init(
wx_sqlite3 *pDest, /* Destination database handle */
@@ -255148,7 +270764,7 @@ SQLITE_API int wx_sqlite3_vtab_config(wx_sqlite3*, int op, ...);
** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
** <dd>Calls of the form
** [wx_sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** prohibits that virtual table from being used from within triggers and
** views.
** </dd>
@@ -255156,18 +270772,28 @@ SQLITE_API int wx_sqlite3_vtab_config(wx_sqlite3*, int op, ...);
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [wx_sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
+**
+** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
+** <dd>Calls of the form
+** [wx_sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
+** instruct the query planner to begin at least a read transaction on
+** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
+** virtual table is used.
+** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3
+#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -255274,24 +270900,45 @@ SQLITE_API const char *wx_sqlite3_vtab_collation(wx_sqlite3_index_info*,int);
** <li value="2"><p>
** ^(If the wx_sqlite3_vtab_distinct() interface returns 2, that means
** that the query planner does not need the rows returned in any particular
-** order, as long as rows with the same values in all "aOrderBy" columns
-** are adjacent.)^ ^(Furthermore, only a single row for each particular
-** combination of values in the columns identified by the "aOrderBy" field
-** needs to be returned.)^ ^It is always ok for two or more rows with the same
-** values in all "aOrderBy" columns to be returned, as long as all such rows
-** are adjacent. ^The virtual table may, if it chooses, omit extra rows
-** that have the same value for all columns identified by "aOrderBy".
-** ^However omitting the extra rows is optional.
+** order, as long as rows with the same values in all columns identified
+** by "aOrderBy" are adjacent.)^ ^(Furthermore, when two or more rows
+** contain the same values for all columns identified by "colUsed", all but
+** one such row may optionally be omitted from the result.)^
+** The virtual table is not required to omit rows that are duplicates
+** over the "colUsed" columns, but if the virtual table can do that without
+** too much extra effort, it could potentially help the query to run faster.
** This mode is used for a DISTINCT query.
** <li value="3"><p>
-** ^(If the wx_sqlite3_vtab_distinct() interface returns 3, that means
-** that the query planner needs only distinct rows but it does need the
-** rows to be sorted.)^ ^The virtual table implementation is free to omit
-** rows that are identical in all aOrderBy columns, if it wants to, but
-** it is not required to omit any rows. This mode is used for queries
+** ^(If the wx_sqlite3_vtab_distinct() interface returns 3, that means the
+** virtual table must return rows in the order defined by "aOrderBy" as
+** if the wx_sqlite3_vtab_distinct() interface had returned 0. However if
+** two or more rows in the result have the same values for all columns
+** identified by "colUsed", then all but one such row may optionally be
+** omitted.)^ Like when the return value is 2, the virtual table
+** is not required to omit rows that are duplicates over the "colUsed"
+** columns, but if the virtual table can do that without
+** too much extra effort, it could potentially help the query to run faster.
+** This mode is used for queries
** that have both DISTINCT and ORDER BY clauses.
** </ol>
**
+** <p>The following table summarizes the conditions under which the
+** virtual table is allowed to set the "orderByConsumed" flag based on
+** the value returned by wx_sqlite3_vtab_distinct(). This table is a
+** restatement of the previous four paragraphs:
+**
+** <table border=1 cellspacing=0 cellpadding=10 width="90%">
+** <tr>
+** <td valign="top">wx_sqlite3_vtab_distinct() return value
+** <td valign="top">Rows are returned in aOrderBy order
+** <td valign="top">Rows with the same value in all aOrderBy columns are adjacent
+** <td valign="top">Duplicates over all colUsed columns may be omitted
+** <tr><td>0<td>yes<td>yes<td>no
+** <tr><td>1<td>no<td>yes<td>no
+** <tr><td>2<td>no<td>yes<td>yes
+** <tr><td>3<td>yes<td>yes<td>yes
+** </table>
+**
** ^For the purposes of comparing virtual table output values to see if the
** values are same value for sorting purposes, two NULL values are considered
** to be the same. In other words, the comparison operator is "IS"
@@ -255328,7 +270975,7 @@ SQLITE_API int wx_sqlite3_vtab_distinct(wx_sqlite3_index_info*);
** communicated to the xBestIndex method as a
** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use
** this constraint, it must set the corresponding
-** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under
+** aConstraintUsage[].argvIndex to a positive integer. ^(Then, under
** the usual mode of handling IN operators, SQLite generates [bytecode]
** that invokes the [xFilter|xFilter() method] once for each value
** on the right-hand side of the IN operator.)^ Thus the virtual table
@@ -255757,7 +271404,7 @@ SQLITE_API int wx_sqlite3_db_cacheflush(wx_sqlite3*);
** When the [wx_sqlite3_blob_write()] API is used to update a blob column,
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
** in this case the new values are not available. In this case, when a
-** callback made with op==SQLITE_DELETE is actuall a write using the
+** callback made with op==SQLITE_DELETE is actually a write using the
** wx_sqlite3_blob_write() API, the [wx_sqlite3_preupdate_blobwrite()] returns
** the index of the column being written. In other cases, where the
** pre-update hook is being invoked for some other reason, including a
@@ -255835,6 +271482,14 @@ typedef struct wx_sqlite3_snapshot {
** If there is not already a read-transaction open on schema S when
** this function is called, one is opened automatically.
**
+** If a read-transaction is opened by this function, then it is guaranteed
+** that the returned snapshot object may not be invalidated by a database
+** writer or checkpointer until after the read-transaction is closed. This
+** is not guaranteed if a read-transaction is already open when this
+** function is called. In that case, any subsequent write or checkpoint
+** operation on the database may invalidate the returned snapshot handle,
+** even while the read-transaction remains open.
+**
** The following must be true for this function to succeed. If any of
** the following statements are false when wx_sqlite3_snapshot_get() is
** called, SQLITE_ERROR is returned. The final value of *P is undefined
@@ -256018,6 +271673,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int wx_sqlite3_snapshot_recover(wx_sqlite3 *db, c
** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
** of the database exists.
**
+** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set,
+** the returned buffer content will remain accessible and unchanged
+** until either the next write operation on the connection or when
+** the connection is closed, and applications must not modify the
+** buffer. If the bit had been clear, the returned buffer will not
+** be accessed by SQLite after the call.
+**
** A call to wx_sqlite3_serialize(D,S,P,F) might return NULL even if the
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
** allocation error occurs.
@@ -256066,6 +271728,9 @@ SQLITE_API unsigned char *wx_sqlite3_serialize(
** SQLite will try to increase the buffer size using wx_sqlite3_realloc64()
** if writes on the database cause it to grow larger than M bytes.
**
+** Applications must not modify the buffer P or invalidate it before
+** the database connection D is closed.
+**
** The wx_sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
** database is currently in a read transaction or is involved in a backup
** operation.
@@ -256074,6 +271739,13 @@ SQLITE_API unsigned char *wx_sqlite3_serialize(
** S argument to wx_sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
** function returns SQLITE_ERROR.
**
+** The deserialized database should not be in [WAL mode]. If the database
+** is in WAL mode, then any attempt to use the database file will result
+** in an [SQLITE_CANTOPEN] error. The application can set the
+** [file format version numbers] (bytes 18 and 19) of the input database P
+** to 0x01 prior to invoking wx_sqlite3_deserialize(D,S,P,N,M,F) to force the
+** database file into rollback mode and work around this limitation.
+**
** If wx_sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
** [wx_sqlite3_free()] is invoked on argument P prior to returning.
@@ -256126,8 +271798,6 @@ SQLITE_API int wx_sqlite3_deserialize(
#if defined(__wasi__)
# undef SQLITE_WASI
# define SQLITE_WASI 1
-# undef SQLITE_OMIT_WAL
-# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
# ifndef SQLITE_OMIT_LOAD_EXTENSION
# define SQLITE_OMIT_LOAD_EXTENSION
# endif
@@ -256342,16 +272012,20 @@ SQLITE_API int wx_sqlite3session_create(
SQLITE_API void wx_sqlite3session_delete(wx_sqlite3_session *pSession);
/*
-** CAPIREF: Conigure a Session Object
+** CAPI3REF: Configure a Session Object
** METHOD: wx_sqlite3_session
**
** This method is used to configure a session object after it has been
-** created. At present the only valid value for the second parameter is
-** [SQLITE_SESSION_OBJCONFIG_SIZE].
+** created. At present the only valid values for the second parameter are
+** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
**
-** Arguments for wx_sqlite3session_object_config()
+*/
+SQLITE_API int wx_sqlite3session_object_config(wx_sqlite3_session*, int op, void *pArg);
+
+/*
+** CAPI3REF: Options for wx_sqlite3session_object_config
**
-** The following values may passed as the the 4th parameter to
+** The following values may passed as the the 2nd parameter to
** wx_sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
@@ -256367,12 +272041,21 @@ SQLITE_API void wx_sqlite3session_delete(wx_sqlite3_session *pSession);
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
+**
+** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd>
+** This option is used to set, clear or query the flag that enables
+** collection of data for tables with no explicit PRIMARY KEY.
+**
+** Normally, tables with no explicit PRIMARY KEY are simply ignored
+** by the sessions module. However, if this flag is set, it behaves
+** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
+** as their leftmost columns.
+**
+** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
+** the first table has been attached to the session object.
*/
-SQLITE_API int wx_sqlite3session_object_config(wx_sqlite3_session*, int op, void *pArg);
-
-/*
-*/
-#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/*
** CAPI3REF: Enable Or Disable A Session Object
@@ -257134,6 +272817,18 @@ SQLITE_API int wx_sqlite3changeset_concat(
/*
+** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
+*/
+SQLITE_API int wx_sqlite3changeset_upgrade(
+ wx_sqlite3 *db,
+ const char *zDb,
+ int nIn, const void *pIn, /* Input changeset */
+ int *pnOut, void **ppOut /* OUT: Inverse of input */
+);
+
+
+
+/*
** CAPI3REF: Changegroup Handle
**
** A changegroup is an object used to combine two or more
@@ -257180,6 +272875,38 @@ typedef struct wx_sqlite3_changegroup wx_sqlite3_changegroup;
SQLITE_API int wx_sqlite3changegroup_new(wx_sqlite3_changegroup **pp);
/*
+** CAPI3REF: Add a Schema to a Changegroup
+** METHOD: wx_sqlite3_changegroup_schema
+**
+** This method may be used to optionally enforce the rule that the changesets
+** added to the changegroup handle must match the schema of database zDb
+** ("main", "temp", or the name of an attached database). If
+** wx_sqlite3changegroup_add() is called to add a changeset that is not compatible
+** with the configured schema, SQLITE_SCHEMA is returned and the changegroup
+** object is left in an undefined state.
+**
+** A changeset schema is considered compatible with the database schema in
+** the same way as for wx_sqlite3changeset_apply(). Specifically, for each
+** table in the changeset, there exists a database table with:
+**
+** <ul>
+** <li> The name identified by the changeset, and
+** <li> at least as many columns as recorded in the changeset, and
+** <li> the primary key columns in the same position as recorded in
+** the changeset.
+** </ul>
+**
+** The output of the changegroup object always has the same schema as the
+** database nominated using this function. In cases where changesets passed
+** to wx_sqlite3changegroup_add() have fewer columns than the corresponding table
+** in the database schema, these are filled in using the default column
+** values from the database schema. This makes it possible to combined
+** changesets that have different numbers of columns for a single table
+** within a changegroup, provided that they are otherwise compatible.
+*/
+SQLITE_API int wx_sqlite3changegroup_schema(wx_sqlite3_changegroup*, wx_sqlite3*, const char *zDb);
+
+/*
** CAPI3REF: Add A Changeset To A Changegroup
** METHOD: wx_sqlite3_changegroup
**
@@ -257247,17 +272974,46 @@ SQLITE_API int wx_sqlite3changegroup_new(wx_sqlite3_changegroup **pp);
** If the new changeset contains changes to a table that is already present
** in the changegroup, then the number of columns and the position of the
** primary key columns for the table must be consistent. If this is not the
-** case, this function fails with SQLITE_SCHEMA. If the input changeset
-** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
-** returned. Or, if an out-of-memory condition occurs during processing, this
-** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
-** of the final contents of the changegroup is undefined.
+** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup
+** object has been configured with a database schema using the
+** wx_sqlite3changegroup_schema() API, then it is possible to combine changesets
+** with different numbers of columns for a single table, provided that
+** they are otherwise compatible.
+**
+** If the input changeset appears to be corrupt and the corruption is
+** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition
+** occurs during processing, this function returns SQLITE_NOMEM.
**
-** If no error occurs, SQLITE_OK is returned.
+** In all cases, if an error occurs the state of the final contents of the
+** changegroup is undefined. If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int wx_sqlite3changegroup_add(wx_sqlite3_changegroup*, int nData, void *pData);
/*
+** CAPI3REF: Add A Single Change To A Changegroup
+** METHOD: wx_sqlite3_changegroup
+**
+** This function adds the single change currently indicated by the iterator
+** passed as the second argument to the changegroup object. The rules for
+** adding the change are just as described for [wx_sqlite3changegroup_add()].
+**
+** If the change is successfully added to the changegroup, SQLITE_OK is
+** returned. Otherwise, an SQLite error code is returned.
+**
+** The iterator must point to a valid entry when this function is called.
+** If it does not, SQLITE_ERROR is returned and no change is added to the
+** changegroup. Additionally, the iterator must not have been opened with
+** the SQLITE_CHANGESETAPPLY_INVERT flag. In this case SQLITE_ERROR is also
+** returned.
+*/
+SQLITE_API int wx_sqlite3changegroup_add_change(
+ wx_sqlite3_changegroup*,
+ wx_sqlite3_changeset_iter*
+);
+
+
+
+/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
** METHOD: wx_sqlite3_changegroup
**
@@ -257505,9 +273261,30 @@ SQLITE_API int wx_sqlite3changeset_apply_v2(
** Invert the changeset before applying it. This is equivalent to inverting
** a changeset using wx_sqlite3changeset_invert() before applying it. It is
** an error to specify this flag with a patchset.
+**
+** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd>
+** Do not invoke the conflict handler callback for any changes that
+** would not actually modify the database even if they were applied.
+** Specifically, this means that the conflict handler is not invoked
+** for:
+** <ul>
+** <li>a delete change if the row being deleted cannot be found,
+** <li>an update change if the modified fields are already set to
+** their new values in the conflicting row, or
+** <li>an insert change if all fields of the conflicting row match
+** the row being inserted.
+** </ul>
+**
+** <dt>SQLITE_CHANGESETAPPLY_FKNOACTION <dd>
+** If this flag it set, then all foreign key constraints in the target
+** database behave as if they were declared with "ON UPDATE NO ACTION ON
+** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL
+** or SET DEFAULT.
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
+#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
+#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008
/*
** CAPI3REF: Constants Passed To The Conflict Handler
@@ -258040,8 +273817,8 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
-** registered with.
+** Return a copy of the pUserData pointer passed to the xCreateFunction()
+** API when the extension function was registered.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
@@ -258073,8 +273850,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the text of column iCol of
+** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -258084,8 +273864,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of phrases in the current query, as returned by xPhraseCount,
+** 0 is returned. Otherwise, this function returns the number of tokens in
+** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -258101,12 +273883,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
+** output by xInstCount(). If iIdx is less than zero or greater than
+** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
+** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. Returns SQLITE_OK if successful, or an error
-** code (i.e. SQLITE_NOMEM) if an error occurs.
+** first token of the phrase. SQLITE_OK is returned if successful, or an
+** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -258132,6 +273915,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
+** If parameter iPhrase is less than zero, or greater than or equal to
+** the number of phrases in the query, as returned by xPhraseCount(),
+** this function returns SQLITE_RANGE.
+**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -258213,6 +274000,10 @@ struct Fts5PhraseIter {
** (i.e. if it is a contentless table), then this API always iterates
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
**
+** In all cases, matches are visited in (column ASC, offset ASC) order.
+** i.e. all those in column 0, sorted by offset, followed by those in
+** column 1, etc.
+**
** xPhraseNext()
** See xPhraseFirst above.
**
@@ -258246,9 +274037,65 @@ struct Fts5PhraseIter {
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
+**
+** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase iPhrase of the current
+** query. Before returning, output parameter *ppToken is set to point
+** to a buffer containing the requested token, and *pnToken to the
+** size of this buffer in bytes.
+**
+** If iPhrase or iToken are less than zero, or if iPhrase is greater than
+** or equal to the number of phrases in the query as reported by
+** xPhraseCount(), or if iToken is equal to or greater than the number of
+** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
+ are both zeroed.
+**
+** The output text is not a copy of the query text that specified the
+** token. It is the output of the tokenizer module. For tokendata=1
+** tables, this includes any embedded 0x00 and trailing data.
+**
+** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase hit iIdx within the
+** current row. If iIdx is less than zero or greater than or equal to the
+** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
+** output variable (*ppToken) is set to point to a buffer containing the
+** matching document token, and (*pnToken) to the size of that buffer in
+** bytes. This API is not available if the specified token matches a
+** prefix query term. In that case both output variables are always set
+** to 0.
+**
+** The output text is not a copy of the document text that was tokenized.
+** It is the output of the tokenizer module. For tokendata=1 tables, this
+** includes any embedded 0x00 and trailing data.
+**
+** This API can be quite slow if used with an FTS5 table created with the
+** "detail=none" or "detail=column" option.
+**
+** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the locale associated
+** with column iCol of the current row. Usually, there is no associated
+** locale, and output parameters (*pzLocale) and (*pnLocale) are set
+** to NULL and 0, respectively. However, if the fts5_locale() function
+** was used to associate a locale with the value when it was inserted
+** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
+** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
+** is set to the size in bytes of the buffer, not including the
+** nul-terminator.
+**
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an
+** SQLite error code is returned. The final value of the output parameters
+** is undefined in this case.
+**
+** xTokenize_v2:
+** Tokenize text using the tokenizer belonging to the FTS5 table. This
+** API is the same as the xTokenize() API, except that it allows a tokenizer
+** locale to be specified.
*/
struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
+ int iVersion; /* Currently always set to 4 */
void *(*xUserData)(Fts5Context*);
@@ -258283,6 +274130,22 @@ struct Fts5ExtensionApi {
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
+
+ /* Below this point are iVersion>=3 only */
+ int (*xQueryToken)(Fts5Context*,
+ int iPhrase, int iToken,
+ const char **ppToken, int *pnToken
+ );
+ int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
+
+ /* Below this point are iVersion>=4 only */
+ int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
+ int (*xTokenize_v2)(Fts5Context*,
+ const char *pText, int nText, /* Text to tokenize */
+ const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
+ void *pCtx, /* Context passed to xToken() */
+ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
+ );
};
/*
@@ -258303,7 +274166,7 @@ struct Fts5ExtensionApi {
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
-** pointer provided by the application when the fts5_tokenizer object
+** pointer provided by the application when the fts5_tokenizer_v2 object
** was registered with FTS5 (the third argument to xCreateTokenizer()).
** The second and third arguments are an array of nul-terminated strings
** containing the tokenizer arguments, if any, specified following the
@@ -258327,7 +274190,7 @@ struct Fts5ExtensionApi {
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
**
-** The second argument indicates the reason that FTS5 is requesting
+** The third argument indicates the reason that FTS5 is requesting
** tokenization of the supplied text. This is always one of the following
** four values:
**
@@ -258351,6 +274214,13 @@ struct Fts5ExtensionApi {
** on a columnsize=0 database.
** </ul>
**
+** The sixth and seventh arguments passed to xTokenize() - pLocale and
+** nLocale - are a pointer to a buffer containing the locale to use for
+** tokenization (e.g. "en_US") and its size in bytes, respectively. The
+** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
+** which case nLocale is always 0) to indicate that the tokenizer should
+** use its default locale.
+**
** For each token in the input string, the supplied callback xToken() must
** be invoked. The first argument to it should be a copy of the pointer
** passed as the second argument to xTokenize(). The third and fourth
@@ -258374,6 +274244,30 @@ struct Fts5ExtensionApi {
** may abandon the tokenization and return any error code other than
** SQLITE_OK or SQLITE_DONE.
**
+** If the tokenizer is registered using an fts5_tokenizer_v2 object,
+** then the xTokenize() method has two additional arguments - pLocale
+** and nLocale. These specify the locale that the tokenizer should use
+** for the current request. If pLocale and nLocale are both 0, then the
+** tokenizer should use its default locale. Otherwise, pLocale points to
+** an nLocale byte buffer containing the name of the locale to use as utf-8
+** text. pLocale is not nul-terminated.
+**
+** FTS5_TOKENIZER
+**
+** There is also an fts5_tokenizer object. This is an older, deprecated,
+** version of fts5_tokenizer_v2. It is similar except that:
+**
+** <ul>
+** <li> There is no "iVersion" field, and
+** <li> The xTokenize() method does not take a locale argument.
+** </ul>
+**
+** Legacy fts5_tokenizer tokenizers must be registered using the
+** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
+**
+** Tokenizer implementations registered using either API may be retrieved
+** using both xFindTokenizer() and xFindTokenizer_v2().
+**
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
@@ -258477,11 +274371,38 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
+typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
+struct fts5_tokenizer_v2 {
+ int iVersion; /* Currently always 2 */
+
+ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
+ void (*xDelete)(Fts5Tokenizer*);
+ int (*xTokenize)(Fts5Tokenizer*,
+ void *pCtx,
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
+ const char *pText, int nText,
+ const char *pLocale, int nLocale,
+ int (*xToken)(
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
+ const char *pToken, /* Pointer to buffer containing token */
+ int nToken, /* Size of token in bytes */
+ int iStart, /* Byte offset of token within input text */
+ int iEnd /* Byte offset of end of token within input text */
+ )
+ );
+};
+
+/*
+** New code should use the fts5_tokenizer_v2 type to define tokenizer
+** implementations. The following type is included for legacy applications
+** that still use it.
+*/
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
@@ -258501,6 +274422,7 @@ struct fts5_tokenizer {
);
};
+
/* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002
@@ -258520,13 +274442,13 @@ struct fts5_tokenizer {
*/
typedef struct fts5_api fts5_api;
struct fts5_api {
- int iVersion; /* Currently always set to 2 */
+ int iVersion; /* Currently always set to 3 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -258535,7 +274457,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -258543,10 +274465,29 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
+
+ /* APIs below this point are only available if iVersion>=3 */
+
+ /* Create a new tokenizer */
+ int (*xCreateTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void *pUserData,
+ fts5_tokenizer_v2 *pTokenizer,
+ void (*xDestroy)(void*)
+ );
+
+ /* Find an existing tokenizer */
+ int (*xFindTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void **ppUserData,
+ fts5_tokenizer_v2 **ppTokenizer
+ );
};
/*
@@ -258605,7 +274546,7 @@ extern "C" {
** If the SQLITE_USER table is not present in the database file, then
** this interface is a harmless no-op returnning SQLITE_OK.
*/
-int wx_sqlite3_user_authenticate(
+SQLITE_API int wx_sqlite3_user_authenticate(
wx_sqlite3 *db, /* The database connection */
const char *zUsername, /* Username */
const char *aPW, /* Password or credentials */
@@ -258622,7 +274563,7 @@ int wx_sqlite3_user_authenticate(
** for any ATTACH-ed databases. Any call to wx_sqlite3_user_add() by a
** non-admin user results in an error.
*/
-int wx_sqlite3_user_add(
+SQLITE_API int wx_sqlite3_user_add(
wx_sqlite3 *db, /* Database connection */
const char *zUsername, /* Username to be added */
const char *aPW, /* Password or credentials */
@@ -258634,10 +274575,10 @@ int wx_sqlite3_user_add(
** The wx_sqlite3_user_change() interface can be used to change a users
** login credentials or admin privilege. Any user can change their own
** login credentials. Only an admin user can change another users login
-** credentials or admin privilege setting. No user may change their own
+** credentials or admin privilege setting. No user may change their own
** admin privilege setting.
*/
-int wx_sqlite3_user_change(
+SQLITE_API int wx_sqlite3_user_change(
wx_sqlite3 *db, /* Database connection */
const char *zUsername, /* Username to change */
const char *aPW, /* New password or credentials */
@@ -258652,7 +274593,7 @@ int wx_sqlite3_user_change(
** the database cannot be converted into a no-authentication-required
** database.
*/
-int wx_sqlite3_user_delete(
+SQLITE_API int wx_sqlite3_user_delete(
wx_sqlite3 *db, /* Database connection */
const char *zUsername /* Username to remove */
);
@@ -258675,7 +274616,8 @@ int wx_sqlite3_user_delete(
#define CODEC_TYPE_CHACHA20 3
#define CODEC_TYPE_SQLCIPHER 4
#define CODEC_TYPE_RC4 5
-#define CODEC_TYPE_MAX_BUILTIN 5
+#define CODEC_TYPE_ASCON128 6
+#define CODEC_TYPE_MAX_BUILTIN 6
/*
** Definition of API functions
@@ -258774,7 +274716,7 @@ SQLITE_API unsigned char* wxwx_sqlite3_codec_data(wx_sqlite3* db, const char* zD
*/
typedef struct _CipherParams
{
- char* m_name;
+ const char* m_name;
int m_value;
int m_default;
int m_minValue;
@@ -258807,13 +274749,13 @@ typedef int (*GetLegacy_t)(void* cipher);
typedef int (*GetPageSize_t)(void* cipher);
typedef int (*GetReserved_t)(void* cipher);
typedef unsigned char* (*GetSalt_t)(void* cipher);
-typedef void (*GenerateKey_t)(void* cipher, BtSharedMC* pBt, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt);
+typedef void (*GenerateKey_t)(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt);
typedef int (*EncryptPage_t)(void* cipher, int page, unsigned char* data, int len, int reserved);
typedef int (*DecryptPage_t)(void* cipher, int page, unsigned char* data, int len, int reserved, int hmacCheck);
typedef struct _CipherDescriptor
{
- char* m_name;
+ const char* m_name;
AllocateCipher_t m_allocateCipher;
FreeCipher_t m_freeCipher;
CloneCipher_t m_cloneCipher;
@@ -258867,6 +274809,7 @@ extern "C" {
#ifndef SQLITE_PRIVATE
#define SQLITE_PRIVATE
#endif
+
SQLITE_PRIVATE int wx_sqlite3mcCheckVfs(const char* zVfs);
SQLITE_API int wx_sqlite3mc_vfs_create(const char* zVfsReal, int makeDefault);
@@ -258899,6 +274842,27 @@ wx_sqlite3mcVersion(wx_sqlite3_context* context, int argc, wx_sqlite3_value** ar
wx_sqlite3_result_text(context, wx_sqlite3mc_version(), -1, 0);
}
+#ifndef SQLITE3MC_SECURE_MEMORY
+#define SQLITE3MC_SECURE_MEMORY 0
+#endif
+
+#if SQLITE3MC_SECURE_MEMORY
+
+#define SECURE_MEMORY_NONE 0
+#define SECURE_MEMORY_FILL 1
+#define SECURE_MEMORY_LOCK 2
+
+SQLITE_PRIVATE void wx_sqlite3mcSetMemorySecurity(int value);
+SQLITE_PRIVATE int wx_sqlite3mcGetMemorySecurity();
+
+/* Memory locking is currently not supported */
+#ifdef SQLITE3MC_ENABLE_MEMLOCK
+#undef SQLITE3MC_ENABLE_MEMLOCK
+#endif
+#define SQLITE3MC_ENABLE_MEMLOCK 0
+
+#endif
+
/*
** Crypto algorithms
*/
@@ -258966,19 +274930,19 @@ static void MD5_Final(unsigned char *result, MD5_CTX *ctx);
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
* implementation.
*/
-#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
-#define H(x, y, z) (((x) ^ (y)) ^ (z))
-#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
-#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z) (((x) ^ (y)) ^ (z))
+#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
/*
* The MD5 transformation for all four rounds.
*/
#define STEP(f, a, b, c, d, x, t, s) \
- (a) += f((b), (c), (d)) + (x) + (t); \
- (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
- (a) += (b);
+ (a) += f((b), (c), (d)) + (x) + (t); \
+ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+ (a) += (b);
/*
* SET reads 4 input bytes in little-endian byte order and stores them
@@ -258990,18 +274954,18 @@ static void MD5_Final(unsigned char *result, MD5_CTX *ctx);
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) \
- (*(MD5_u32plus *)&ptr[(n) * 4])
+ (*(MD5_u32plus *)&ptr[(n) * 4])
#define GET(n) \
- SET(n)
+ SET(n)
#else
#define SET(n) \
- (ctx->block[(n)] = \
- (MD5_u32plus)ptr[(n) * 4] | \
- ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
- ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
- ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
+ (ctx->block[(n)] = \
+ (MD5_u32plus)ptr[(n) * 4] | \
+ ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
+ ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
+ ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
#define GET(n) \
- (ctx->block[(n)])
+ (ctx->block[(n)])
#endif
/*
@@ -259229,10 +275193,10 @@ Still 100% Public Domain
Corrected a problem which generated improper hash values on 16 bit machines
Routine SHA1Update changed from
- void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
len)
to
- void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
long len)
The 'len' parameter was declared an int which works fine on 32 bit machines.
@@ -259325,7 +275289,7 @@ typedef unsigned long long uint64_t;
#define UINT8_MAX 255
#define UINT16_MAX 65535
#define UINT32_MAX 0xffffffffU /* 4294967295U */
-#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
+#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
#else
#include <stdint.h>
#endif
@@ -259344,6 +275308,10 @@ typedef unsigned long long uint64_t;
#ifndef SHA1_H_
#define SHA1_H_ (1)
+#ifndef SQLITE_PRIVATE
+#define SQLITE_PRIVATE
+#endif
+
/** SHA-1 Context */
typedef struct {
uint32_t h[5];
@@ -259357,13 +275325,13 @@ typedef struct {
/** SHA-1 Digest size in bytes */
#define SHA1_DIGEST_SIZE 20
-void sha1_init(sha1_ctx *context);
+SQLITE_PRIVATE void sha1_init(sha1_ctx *context);
-void sha1_update(sha1_ctx *context, const void *p, size_t len);
+SQLITE_PRIVATE void sha1_update(sha1_ctx *context, const void *p, size_t len);
-void sha1_final(sha1_ctx *context, uint8_t digest[SHA1_DIGEST_SIZE]);
+SQLITE_PRIVATE void sha1_final(sha1_ctx *context, uint8_t digest[SHA1_DIGEST_SIZE]);
-void sha1_transform(sha1_ctx *context, const uint8_t buffer[64]);
+SQLITE_PRIVATE void sha1_transform(sha1_ctx *context, const uint8_t buffer[64]);
#endif /* SHA1_H_ */
/*** End of #include "sha1.h" ***/
@@ -259418,6 +275386,7 @@ void sha1_transform(sha1_ctx *context, const uint8_t buffer[64]);
z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
/* Hash a single 512-bit block. This is the core of the algorithm. */
+SQLITE_PRIVATE
void sha1_transform(sha1_ctx *context, const uint8_t buffer[64])
{
uint32_t a, b, c, d, e;
@@ -259482,6 +275451,7 @@ void sha1_transform(sha1_ctx *context, const uint8_t buffer[64])
*
* @param context SHA1-Context
*/
+SQLITE_PRIVATE
void sha1_init(sha1_ctx *context)
{
/* SHA1 initialization constants */
@@ -259501,6 +275471,7 @@ void sha1_init(sha1_ctx *context)
* @param p Buffer to run SHA1 on
* @param len Number of bytes
*/
+SQLITE_PRIVATE
void sha1_update(sha1_ctx *context, const void *p, size_t len)
{
const uint8_t *data = p;
@@ -259536,6 +275507,7 @@ void sha1_update(sha1_ctx *context, const void *p, size_t len)
* @param digest Generated message digest
* @param context SHA1-Context
*/
+SQLITE_PRIVATE
void sha1_final(sha1_ctx *context, uint8_t digest[SHA1_DIGEST_SIZE])
{
uint32_t i;
@@ -259647,6 +275619,10 @@ void sha1_final(sha1_ctx *context, uint8_t digest[SHA1_DIGEST_SIZE])
#ifndef SHA2_H
#define SHA2_H
+#ifndef SQLITE_PRIVATE
+#define SQLITE_PRIVATE
+#endif
+
#define SHA224_DIGEST_SIZE ( 224 / 8)
#define SHA256_DIGEST_SIZE ( 256 / 8)
#define SHA384_DIGEST_SIZE ( 384 / 8)
@@ -259668,7 +275644,7 @@ typedef wx_sqlite3_uint64 uint64;
#define li_64(h) 0x##h##ui64
#else
#define li_64(h) 0x##h##ull
-#endif
+#endif
#if 0 /* Start of original int64 defines */
@@ -259740,35 +275716,27 @@ typedef struct {
typedef sha512_ctx sha384_ctx;
typedef sha256_ctx sha224_ctx;
-void sha224_init(sha224_ctx *ctx);
-void sha224_update(sha224_ctx *ctx, const unsigned char *message,
- unsigned int len);
-void sha224_final(sha224_ctx *ctx, unsigned char *digest);
-void sha224(const unsigned char *message, unsigned int len,
- unsigned char *digest);
+SQLITE_PRIVATE void sha224_init(sha224_ctx *ctx);
+SQLITE_PRIVATE void sha224_update(sha224_ctx *ctx, const unsigned char *message, unsigned int len);
+SQLITE_PRIVATE void sha224_final(sha224_ctx *ctx, unsigned char *digest);
+SQLITE_PRIVATE void sha224(const unsigned char *message, unsigned int len, unsigned char *digest);
-void sha256_init(sha256_ctx * ctx);
-void sha256_update(sha256_ctx *ctx, const unsigned char *message,
- unsigned int len);
-void sha256_final(sha256_ctx *ctx, unsigned char *digest);
-void sha256_transform(sha256_ctx *ctx, const unsigned char *message);
-void sha256(const unsigned char *message, unsigned int len,
- unsigned char *digest);
+SQLITE_PRIVATE void sha256_init(sha256_ctx * ctx);
+SQLITE_PRIVATE void sha256_update(sha256_ctx *ctx, const unsigned char *message, unsigned int len);
+SQLITE_PRIVATE void sha256_final(sha256_ctx *ctx, unsigned char *digest);
+SQLITE_PRIVATE void sha256_transform(sha256_ctx *ctx, const unsigned char *message);
+SQLITE_PRIVATE void sha256(const unsigned char *message, unsigned int len, unsigned char *digest);
-void sha384_init(sha384_ctx *ctx);
-void sha384_update(sha384_ctx *ctx, const unsigned char *message,
- unsigned int len);
-void sha384_final(sha384_ctx *ctx, unsigned char *digest);
-void sha384(const unsigned char *message, unsigned int len,
- unsigned char *digest);
+SQLITE_PRIVATE void sha384_init(sha384_ctx *ctx);
+SQLITE_PRIVATE void sha384_update(sha384_ctx *ctx, const unsigned char *message, unsigned int len);
+SQLITE_PRIVATE void sha384_final(sha384_ctx *ctx, unsigned char *digest);
+SQLITE_PRIVATE void sha384(const unsigned char *message, unsigned int len, unsigned char *digest);
-void sha512_init(sha512_ctx *ctx);
-void sha512_update(sha512_ctx *ctx, const unsigned char *message,
- unsigned int len);
-void sha512_final(sha512_ctx *ctx, unsigned char *digest);
-void sha512_transform(sha512_ctx *ctx, const unsigned char *message);
-void sha512(const unsigned char *message, unsigned int len,
- unsigned char *digest);
+SQLITE_PRIVATE void sha512_init(sha512_ctx *ctx);
+SQLITE_PRIVATE void sha512_update(sha512_ctx *ctx, const unsigned char *message, unsigned int len);
+SQLITE_PRIVATE void sha512_final(sha512_ctx *ctx, unsigned char *digest);
+SQLITE_PRIVATE void sha512_transform(sha512_ctx *ctx, const unsigned char *message);
+SQLITE_PRIVATE void sha512(const unsigned char *message, unsigned int len, unsigned char *digest);
#ifdef __cplusplus
}
@@ -259871,27 +275839,27 @@ void sha512(const unsigned char *message, unsigned int len,
wv[h] = t1 + t2; \
}
-uint32 sha224_h0[8] =
+static uint32 sha224_h0[8] =
{0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4};
-uint32 sha256_h0[8] =
+static uint32 sha256_h0[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
-uint64 sha384_h0[8] =
+static uint64 sha384_h0[8] =
{li_64(cbbb9d5dc1059ed8), li_64(629a292a367cd507),
li_64(9159015a3070dd17), li_64(152fecd8f70e5939),
li_64(67332667ffc00b31), li_64(8eb44a8768581511),
li_64(db0c2e0d64f98fa7), li_64(47b5481dbefa4fa4)};
-uint64 sha512_h0[8] =
+static uint64 sha512_h0[8] =
{li_64(6a09e667f3bcc908), li_64(bb67ae8584caa73b),
li_64(3c6ef372fe94f82b), li_64(a54ff53a5f1d36f1),
li_64(510e527fade682d1), li_64(9b05688c2b3e6c1f),
li_64(1f83d9abfb41bd6b), li_64(5be0cd19137e2179)};
-uint32 sha256_k[64] =
+static uint32 sha256_k[64] =
{0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
@@ -259909,7 +275877,7 @@ uint32 sha256_k[64] =
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
-uint64 sha512_k[80] =
+static uint64 sha512_k[80] =
{li_64(428a2f98d728ae22), li_64(7137449123ef65cd),
li_64(b5c0fbcfec4d3b2f), li_64(e9b5dba58189dbbc),
li_64(3956c25bf348b538), li_64(59f111f1b605d019),
@@ -260069,11 +276037,13 @@ void sha256_transf(sha256_ctx *ctx, const unsigned char *message,
}
}
+SQLITE_PRIVATE
void sha256_transform(sha256_ctx *ctx, const unsigned char *message)
{
sha256_transf(ctx, message, 1);
}
+SQLITE_PRIVATE
void sha256(const unsigned char *message, unsigned int len, unsigned char *digest)
{
sha256_ctx ctx;
@@ -260083,6 +276053,7 @@ void sha256(const unsigned char *message, unsigned int len, unsigned char *diges
sha256_final(&ctx, digest);
}
+SQLITE_PRIVATE
void sha256_init(sha256_ctx *ctx)
{
#ifndef UNROLL_LOOPS
@@ -260101,6 +276072,7 @@ void sha256_init(sha256_ctx *ctx)
ctx->tot_len = 0;
}
+SQLITE_PRIVATE
void sha256_update(sha256_ctx *ctx, const unsigned char *message,
unsigned int len)
{
@@ -260135,6 +276107,7 @@ void sha256_update(sha256_ctx *ctx, const unsigned char *message,
ctx->tot_len += (block_nb + 1) << 6;
}
+SQLITE_PRIVATE
void sha256_final(sha256_ctx *ctx, unsigned char *digest)
{
unsigned int block_nb;
@@ -260271,11 +276244,13 @@ void sha512_transf(sha512_ctx *ctx, const unsigned char *message,
}
}
+SQLITE_PRIVATE
void sha512_transform(sha512_ctx *ctx, const unsigned char *message)
{
sha512_transf(ctx, message, 1);
}
+SQLITE_PRIVATE
void sha512(const unsigned char *message, unsigned int len,
unsigned char *digest)
{
@@ -260286,6 +276261,7 @@ void sha512(const unsigned char *message, unsigned int len,
sha512_final(&ctx, digest);
}
+SQLITE_PRIVATE
void sha512_init(sha512_ctx *ctx)
{
#ifndef UNROLL_LOOPS
@@ -260304,6 +276280,7 @@ void sha512_init(sha512_ctx *ctx)
ctx->tot_len = 0;
}
+SQLITE_PRIVATE
void sha512_update(sha512_ctx *ctx, const unsigned char *message,
unsigned int len)
{
@@ -260338,6 +276315,7 @@ void sha512_update(sha512_ctx *ctx, const unsigned char *message,
ctx->tot_len += (block_nb + 1) << 7;
}
+SQLITE_PRIVATE
void sha512_final(sha512_ctx *ctx, unsigned char *digest)
{
unsigned int block_nb;
@@ -260378,6 +276356,7 @@ void sha512_final(sha512_ctx *ctx, unsigned char *digest)
/* SHA-384 functions */
+SQLITE_PRIVATE
void sha384(const unsigned char *message, unsigned int len,
unsigned char *digest)
{
@@ -260388,6 +276367,7 @@ void sha384(const unsigned char *message, unsigned int len,
sha384_final(&ctx, digest);
}
+SQLITE_PRIVATE
void sha384_init(sha384_ctx *ctx)
{
#ifndef UNROLL_LOOPS
@@ -260406,6 +276386,7 @@ void sha384_init(sha384_ctx *ctx)
ctx->tot_len = 0;
}
+SQLITE_PRIVATE
void sha384_update(sha384_ctx *ctx, const unsigned char *message,
unsigned int len)
{
@@ -260440,6 +276421,7 @@ void sha384_update(sha384_ctx *ctx, const unsigned char *message,
ctx->tot_len += (block_nb + 1) << 7;
}
+SQLITE_PRIVATE
void sha384_final(sha384_ctx *ctx, unsigned char *digest)
{
unsigned int block_nb;
@@ -260478,6 +276460,7 @@ void sha384_final(sha384_ctx *ctx, unsigned char *digest)
/* SHA-224 functions */
+SQLITE_PRIVATE
void sha224(const unsigned char *message, unsigned int len,
unsigned char *digest)
{
@@ -260488,6 +276471,7 @@ void sha224(const unsigned char *message, unsigned int len,
sha224_final(&ctx, digest);
}
+SQLITE_PRIVATE
void sha224_init(sha224_ctx *ctx)
{
#ifndef UNROLL_LOOPS
@@ -260506,6 +276490,7 @@ void sha224_init(sha224_ctx *ctx)
ctx->tot_len = 0;
}
+SQLITE_PRIVATE
void sha224_update(sha224_ctx *ctx, const unsigned char *message,
unsigned int len)
{
@@ -260540,6 +276525,7 @@ void sha224_update(sha224_ctx *ctx, const unsigned char *message,
ctx->tot_len += (block_nb + 1) << 6;
}
+SQLITE_PRIVATE
void sha224_final(sha224_ctx *ctx, unsigned char *digest)
{
unsigned int block_nb;
@@ -260703,11 +276689,10 @@ int main()
}
#endif /* TEST_VECTORS */
-
/*** End of #include "sha2.c" ***/
-#if HAVE_CIPHER_CHACHA20 || HAVE_CIPHER_SQLCIPHER
+#if HAVE_CIPHER_CHACHA20 || HAVE_CIPHER_SQLCIPHER || HAVE_CIPHER_ASCON128
/* #include "fastpbkdf2.c" */
/*** Begin of #include "fastpbkdf2.c" ***/
/*
@@ -260743,6 +276728,10 @@ int main()
#ifndef FASTPBKDF2_H
#define FASTPBKDF2_H
+#ifndef SQLITE_PRIVATE
+#define SQLITE_PRIVATE
+#endif
+
#include <stdlib.h>
/* #include "mystdint.h" */
@@ -260760,6 +276749,7 @@ extern "C" {
*
* This function cannot fail; it does not report errors.
*/
+SQLITE_PRIVATE
void fastpbkdf2_hmac_sha1(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
@@ -260774,6 +276764,7 @@ void fastpbkdf2_hmac_sha1(const uint8_t *pw, size_t npw,
*
* This function cannot fail; it does not report errors.
*/
+SQLITE_PRIVATE
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
@@ -260788,6 +276779,7 @@ void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
*
* This function cannot fail; it does not report errors.
*/
+SQLITE_PRIVATE
void fastpbkdf2_hmac_sha512(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
@@ -260797,6 +276789,7 @@ void fastpbkdf2_hmac_sha512(const uint8_t *pw, size_t npw,
*
* This function cannot fail; it does not report errors.
*/
+SQLITE_PRIVATE
void sqlcipher_hmac(int algorithm,
unsigned char* key, int nkey,
unsigned char* in, int in_sz,
@@ -261190,6 +277183,7 @@ DECL_PBKDF2(sha512,
sha512_extract,
sha512_xor)
+SQLITE_PRIVATE
void fastpbkdf2_hmac_sha1(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
@@ -261201,6 +277195,7 @@ void fastpbkdf2_hmac_sha1(const uint8_t *pw, size_t npw,
#endif
}
+SQLITE_PRIVATE
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
@@ -261209,6 +277204,7 @@ void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
PBKDF2(sha256)(pw, npw, salt, nsalt, iterations, out, nout);
}
+SQLITE_PRIVATE
void fastpbkdf2_hmac_sha512(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
@@ -261217,6 +277213,7 @@ void fastpbkdf2_hmac_sha512(const uint8_t *pw, size_t npw,
PBKDF2(sha512)(pw, npw, salt, nsalt, iterations, out, nout);
}
+SQLITE_PRIVATE
void sqlcipher_hmac(int algorithm, unsigned char* key, int nkey, unsigned char* in, int in_sz, unsigned char* in2, int in2_sz, unsigned char* out)
{
switch (algorithm)
@@ -261266,10 +277263,10 @@ void sqlcipher_hmac(int algorithm, unsigned char* key, int nkey, unsigned char*
/* Prototypes for several crypto functions to make pedantic compilers happy */
-void chacha20_xor(void* data, size_t n, const uint8_t key[32], const uint8_t nonce[12], uint32_t counter);
-void poly1305(const uint8_t* msg, size_t n, const uint8_t key[32], uint8_t tag[16]);
-int poly1305_tagcmp(const uint8_t tag1[16], const uint8_t tag2[16]);
-void chacha20_rng(void* out, size_t n);
+SQLITE_PRIVATE void chacha20_xor(void* data, size_t n, const uint8_t key[32], const uint8_t nonce[12], uint32_t counter);
+SQLITE_PRIVATE void poly1305(const uint8_t* msg, size_t n, const uint8_t key[32], uint8_t tag[16]);
+SQLITE_PRIVATE int poly1305_tagcmp(const uint8_t tag1[16], const uint8_t tag2[16]);
+SQLITE_PRIVATE void chacha20_rng(void* out, size_t n);
/* #include "chacha20poly1305.c" */
/*** Begin of #include "chacha20poly1305.c" ***/
@@ -261350,6 +277347,7 @@ static void chacha20_block(uint32_t x[16])
#undef CC20QR
}
+SQLITE_PRIVATE
void chacha20_xor(void* buffer, size_t n, const uint8_t key[32],
const uint8_t nonce[12], uint32_t counter)
{
@@ -261417,6 +277415,7 @@ void chacha20_xor(void* buffer, size_t n, const uint8_t key[32],
/*
* Poly1305 authentication tags
*/
+SQLITE_PRIVATE
void poly1305(const uint8_t* msg, size_t n, const uint8_t key[32],
uint8_t tag[16])
{
@@ -261486,6 +277485,7 @@ process_block:
s4 = d4; STORE32_LE(tag + 12, s4);
}
+SQLITE_PRIVATE
int poly1305_tagcmp(const uint8_t tag1[16], const uint8_t tag2[16])
{
uint8_t d = 0;
@@ -261511,7 +277511,16 @@ int poly1305_tagcmp(const uint8_t tag1[16], const uint8_t tag2[16])
/*
* Platform-specific entropy functions for seeding RNG
*/
-#if defined(_WIN32) || defined(__CYGWIN__)
+#if defined(__WASM__)
+
+extern int getentropy(void* buf, size_t n);
+
+static size_t entropy(void* buf, size_t n)
+{
+ return (getentropy(buf, n) == 0) ? n : 0;
+}
+
+#elif defined(_WIN32) || defined(__CYGWIN__)
#if SQLITE3MC_USE_RAND_S
@@ -261553,7 +277562,7 @@ static size_t entropy(void* buf, size_t n)
}
#else
-
+
#include <windows.h>
#define RtlGenRandom SystemFunction036
BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
@@ -261646,14 +277655,14 @@ fail:
return 0;
}
-#if defined(__APPLE__) && defined(__MAC_10_12) && !defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
-#include <sys/random.h>
+#if defined(__APPLE__)
+#include <Security/SecRandom.h>
#endif
static size_t entropy(void* buf, size_t n)
{
-#if defined(__APPLE__) && defined(__MAC_10_12) && __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_12
- if (getentropy(buf, n) == 0)
+#if defined(__APPLE__)
+ if (SecRandomCopyBytes(kSecRandomDefault, n, (uint8_t*) buf) == 0)
return n;
#elif defined(__linux__) && defined(SYS_getrandom)
if (syscall(SYS_getrandom, buf, n, 0) == n)
@@ -261665,15 +277674,6 @@ static size_t entropy(void* buf, size_t n)
return read_urandom(buf, n);
}
-#elif defined(__WASM__)
-
-extern size_t getentropy(void* buf, size_t n);
-
-static size_t entropy(void* buf, size_t n)
-{
- return (getentropy(buf, n) == 0) ? n : 0;
-}
-
#else
# error "Secure pseudorandom number generator not implemented for this OS"
#endif
@@ -261681,6 +277681,7 @@ static size_t entropy(void* buf, size_t n)
/*
* ChaCha20 random number generator
*/
+SQLITE_PRIVATE
void chacha20_rng(void* out, size_t n)
{
static uint8_t key[32], nonce[12], buffer[64] = { 0 };
@@ -261921,7 +277922,7 @@ void wx_sqlite3CryptFunc(
** If the SQLITE_USER table is not present in the database file, then
** this interface is a harmless no-op returnning SQLITE_OK.
*/
-int wx_sqlite3_user_authenticate(
+SQLITE_API int wx_sqlite3_user_authenticate(
wx_sqlite3 *db, /* The database connection */
const char *zUsername, /* Username */
const char *zPW, /* Password or credentials */
@@ -261961,7 +277962,7 @@ int wx_sqlite3_user_authenticate(
** for any ATTACH-ed databases. Any call to wx_sqlite3_user_add() by a
** non-admin user results in an error.
*/
-int wx_sqlite3_user_add(
+SQLITE_API int wx_sqlite3_user_add(
wx_sqlite3 *db, /* Database connection */
const char *zUsername, /* Username to be added */
const char *aPW, /* Password or credentials */
@@ -261974,7 +277975,7 @@ int wx_sqlite3_user_add(
if( db->auth.authLevel<UAUTH_Admin ) return SQLITE_AUTH;
if( !userTableExists(db, "main") ){
if( !isAdmin ) return SQLITE_AUTH;
- pStmt = wx_sqlite3UserAuthPrepare(db,
+ pStmt = wx_sqlite3UserAuthPrepare(db,
"CREATE TABLE sqlite_user(\n"
" uname TEXT PRIMARY KEY,\n"
" isAdmin BOOLEAN,\n"
@@ -261985,7 +277986,7 @@ int wx_sqlite3_user_add(
rc = wx_sqlite3_finalize(pStmt);
if( rc ) return rc;
}
- pStmt = wx_sqlite3UserAuthPrepare(db,
+ pStmt = wx_sqlite3UserAuthPrepare(db,
"INSERT INTO sqlite_user(uname,isAdmin,pw)"
" VALUES(%Q,%d,sqlite_crypt(?1,NULL))",
zUsername, isAdmin!=0);
@@ -262005,10 +278006,10 @@ int wx_sqlite3_user_add(
** The wx_sqlite3_user_change() interface can be used to change a users
** login credentials or admin privilege. Any user can change their own
** login credentials. Only an admin user can change another users login
-** credentials or admin privilege setting. No user may change their own
+** credentials or admin privilege setting. No user may change their own
** admin privilege setting.
*/
-int wx_sqlite3_user_change(
+SQLITE_API int wx_sqlite3_user_change(
wx_sqlite3 *db, /* Database connection */
const char *zUsername, /* Username to change */
const char *aPW, /* Modified password or credentials */
@@ -262059,7 +278060,7 @@ int wx_sqlite3_user_change(
** the database cannot be converted into a no-authentication-required
** database.
*/
-int wx_sqlite3_user_delete(
+SQLITE_API int wx_sqlite3_user_delete(
wx_sqlite3 *db, /* Database connection */
const char *zUsername /* Username to remove */
){
@@ -262169,6 +278170,10 @@ mcRegisterCodecExtensions(wx_sqlite3* db, char** pzErrMsg, const wx_sqlite3_api_
#ifndef _RIJNDAEL_H_
#define _RIJNDAEL_H_
+#ifndef SQLITE_PRIVATE
+#define SQLITE_PRIVATE
+#endif
+
/*
// File : rijndael.h
// Creation date : Sun Nov 5 2000 03:21:05 CEST
@@ -262267,16 +278272,16 @@ typedef unsigned short UINT16;
*/
typedef struct _Rijndael
-{
- int m_state;
- int m_mode;
- int m_direction;
- UINT8 m_initVector[MAX_IV_SIZE];
- UINT32 m_uRounds;
- UINT8 m_expandedKey[_MAX_ROUNDS+1][4][4];
+{
+ int m_state;
+ int m_mode;
+ int m_direction;
+ UINT8 m_initVector[MAX_IV_SIZE];
+ UINT32 m_uRounds;
+ UINT8 m_expandedKey[_MAX_ROUNDS+1][4][4];
} Rijndael;
-void RijndaelCreate(Rijndael* rijndael);
+SQLITE_PRIVATE void RijndaelCreate(Rijndael* rijndael);
/*
//////////////////////////////////////////////////////////////////////////////////////////
@@ -262298,7 +278303,7 @@ void RijndaelCreate(Rijndael* rijndael);
// keyLen : Rijndael::Key16Bytes , Rijndael::Key24Bytes or Rijndael::Key32Bytes
// initVector: initialization vector, you will usually use 0 here
*/
-int RijndaelInit(Rijndael* rijndael, int mode, int dir, UINT8* key, int keyLen, UINT8* initVector);
+SQLITE_PRIVATE int RijndaelInit(Rijndael* rijndael, int mode, int dir, UINT8* key, int keyLen, UINT8* initVector);
/*
// Encrypts the input array (can be binary data)
@@ -262309,7 +278314,7 @@ int RijndaelInit(Rijndael* rijndael, int mode, int dir, UINT8* key, int keyLen,
// outBuffer must be at least inputLen / 8 bytes long.
// Returns the encrypted buffer length in BITS or an error code < 0 in case of error
*/
-int RijndaelBlockEncrypt(Rijndael* rijndael, UINT8 *input, int inputLen, UINT8 *outBuffer);
+SQLITE_PRIVATE int RijndaelBlockEncrypt(Rijndael* rijndael, UINT8 *input, int inputLen, UINT8 *outBuffer);
/*
// Encrypts the input array (can be binary data)
@@ -262318,7 +278323,7 @@ int RijndaelBlockEncrypt(Rijndael* rijndael, UINT8 *input, int inputLen, UINT8 *
// outBuffer must be at least (inputLen + 16) bytes long
// Returns the encrypted buffer length in BYTES or an error code < 0 in case of error
*/
-int RijndaelPadEncrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8 *outBuffer);
+SQLITE_PRIVATE int RijndaelPadEncrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8 *outBuffer);
/*
// Decrypts the input vector
@@ -262326,7 +278331,7 @@ int RijndaelPadEncrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8
// outBuffer must be at least inputLen / 8 bytes long
// Returns the decrypted buffer length in BITS and an error code < 0 in case of error
*/
-int RijndaelBlockDecrypt(Rijndael* rijndael, UINT8 *input, int inputLen, UINT8 *outBuffer);
+SQLITE_PRIVATE int RijndaelBlockDecrypt(Rijndael* rijndael, UINT8 *input, int inputLen, UINT8 *outBuffer);
/*
// Decrypts the input vector
@@ -262334,14 +278339,14 @@ int RijndaelBlockDecrypt(Rijndael* rijndael, UINT8 *input, int inputLen, UINT8 *
// outBuffer must be at least inputLen bytes long
// Returns the decrypted buffer length in BYTES and an error code < 0 in case of error
*/
-int RijndaelPadDecrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8 *outBuffer);
+SQLITE_PRIVATE int RijndaelPadDecrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8 *outBuffer);
+
+SQLITE_PRIVATE void RijndaelInvalidate(Rijndael* rijndael);
+SQLITE_PRIVATE void RijndaelKeySched(Rijndael* rijndael, UINT8 key[_MAX_KEY_COLUMNS][4]);
+SQLITE_PRIVATE void RijndaelKeyEncToDec(Rijndael* rijndael);
+SQLITE_PRIVATE void RijndaelEncrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16]);
+SQLITE_PRIVATE void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16]);
-void RijndaelInvalidate(Rijndael* rijndael);
-void RijndaelKeySched(Rijndael* rijndael, UINT8 key[_MAX_KEY_COLUMNS][4]);
-void RijndaelKeyEncToDec(Rijndael* rijndael);
-void RijndaelEncrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16]);
-void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16]);
-
#endif /* _RIJNDAEL_H_ */
/*** End of #include "rijndael.h" ***/
@@ -262400,6 +278405,8 @@ void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16]);
#define AES_HARDWARE_NI 1
#define AES_HARDWARE_NEON 2
+#ifndef SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT
+
#if defined __ARM_FEATURE_CRYPTO
#define HAS_AES_HARDWARE AES_HARDWARE_NEON
@@ -262457,6 +278464,14 @@ void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16]);
#endif
+#else /* SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT defined */
+
+/* Omit AES hardware support */
+#define HAS_AES_HARDWARE AES_HARDWARE_NONE
+
+#endif /* SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT */
+
+
#if HAS_AES_HARDWARE != AES_HARDWARE_NONE
/* --- Implementation of common data and functions for any AES hardware --- */
@@ -262479,6 +278494,37 @@ toUint32FromLE(const void* buffer)
#if HAS_AES_HARDWARE == AES_HARDWARE_NI
/* --- Implementation for AES-NI --- */
+/* Define SQLITE3MC_COMPILER_HAS_ATTRIBUTE */
+#if defined(__has_attribute)
+ #define SQLITE3MC_COMPILER_HAS_ATTRIBUTE(x) __has_attribute(x)
+ #define SQLITE3MC_COMPILER_ATTRIBUTE(x) __attribute__((x))
+#else
+ #define SQLITE3MC_COMPILER_HAS_ATTRIBUTE(x) 0
+ #define SQLITE3MC_COMPILER_ATTRIBUTE(x) /**/
+#endif
+
+/* Define SQLITE3MC_FORCE_INLINE */
+#if !defined(SQLITE3MC_FORCE_INLINE)
+ #if SQLITE3MC_COMPILER_HAS_ATTRIBUTE(always_inline)
+ #define SQLITE3MC_FORCE_INLINE inline SQLITE3MC_COMPILER_ATTRIBUTE(always_inline)
+ #elif defined(_MSC_VER)
+ #define SQLITE3MC_FORCE_INLINE __forceinline
+ #else
+ #define SQLITE3MC_FORCE_INLINE inline
+ #endif
+#endif
+
+/* Define SQLITE3MC_FUNC_ISA */
+#if SQLITE3MC_COMPILER_HAS_ATTRIBUTE(target)
+ #define SQLITE3MC_FUNC_ISA(isa) SQLITE3MC_COMPILER_ATTRIBUTE(target(isa))
+#else
+ #define SQLITE3MC_FUNC_ISA(isa)
+#endif
+
+/* Define SQLITE3MC_FUNC_ISA_INLINE */
+#define SQLITE3MC_FUNC_ISA_INLINE(isa) SQLITE3MC_FUNC_ISA(isa) SQLITE3MC_FORCE_INLINE
+
+
/*
** Define function for detecting hardware AES support at runtime
*/
@@ -262515,6 +278561,7 @@ aesHardwareCheck()
#include <wmmintrin.h>
#include <smmintrin.h>
+SQLITE3MC_FUNC_ISA("sse4.2,aes")
static int
aesGenKeyEncryptInternal(const unsigned char* userKey, const int bits, __m128i* keyData)
{
@@ -262568,12 +278615,13 @@ aesGenKeyEncryptInternal(const unsigned char* userKey, const int bits, __m128i*
return rc;
}
+SQLITE3MC_FUNC_ISA("sse4.2,aes")
static int
aesGenKeyEncrypt(const unsigned char* userKey, const int bits, unsigned char* keyData)
{
int numberOfRounds = (bits == 128) ? 10 : (bits == 192) ? 12 : (bits == 256) ? 14 : 0;
int rc = (!userKey || !keyData) ? -1 : (numberOfRounds > 0) ? 0 : -2;
-
+
if (rc == 0)
{
__m128i tempKey[_MAX_ROUNDS + 1];
@@ -262590,6 +278638,7 @@ aesGenKeyEncrypt(const unsigned char* userKey, const int bits, unsigned char* ke
return rc;
}
+SQLITE3MC_FUNC_ISA("sse4.2,aes")
static int
aesGenKeyDecrypt(const unsigned char* userKey, const int bits, unsigned char* keyData)
{
@@ -262624,6 +278673,7 @@ aesGenKeyDecrypt(const unsigned char* userKey, const int bits, unsigned char* ke
** AES CBC CTS Encryption
*/
+SQLITE3MC_FUNC_ISA("sse4.2,aes")
static void
aesEncryptCBC(const unsigned char* in,
unsigned char* out,
@@ -262691,6 +278741,7 @@ aesEncryptCBC(const unsigned char* in,
/*
** AES CBC CTS decryption
*/
+SQLITE3MC_FUNC_ISA("sse4.2,aes")
static void
aesDecryptCBC(const unsigned char* in,
unsigned char* out,
@@ -262722,7 +278773,7 @@ aesDecryptCBC(const unsigned char* in,
int offset;
--numBlocks;
offset = numBlocks * 16;
-
+
/* Decrypt the last plain block. */
last_in = _mm_loadu_si128(&((__m128i*) in)[numBlocks]);
data = _mm_xor_si128(last_in, key[numberOfRounds - 0]);
@@ -262852,7 +278903,7 @@ aesGenKeyEncryptInternal(const unsigned char* userKey, const int bits, uint8x16_
int i;
int j;
int numberOfRounds = (bits == 128) ? 10 : (bits == 192) ? 12 : (bits == 256) ? 14 : 0;
- int keyWords = bits / 32;
+ int keyWords = bits / 32;
int schedWords = (numberOfRounds + 1) * 4;
/*
@@ -262913,7 +278964,7 @@ aesGenKeyEncrypt(const unsigned char* userKey, const int bits, unsigned char* ke
{
int numberOfRounds = (bits == 128) ? 10 : (bits == 192) ? 12 : (bits == 256) ? 14 : 0;
int rc = (!userKey || !keyData) ? -1 : (numberOfRounds > 0) ? 0 : -2;
-
+
if (rc == 0)
{
uint8x16_t tempKey[_MAX_ROUNDS + 1];
@@ -263023,7 +279074,7 @@ aesEncryptCBC(const unsigned char* in,
}
feedback = vaeseq_u8(feedback, key[numberOfRounds-1]);
feedback = veorq_u8(feedback, key[numberOfRounds]); \
-
+
vst1q_u8(&out[(numBlocks-1)*16], feedback);
memcpy(&out[numBlocks*16], lastblock, lenFrag);
@@ -263064,7 +279115,7 @@ aesDecryptCBC(const unsigned char* in,
int offset;
--numBlocks;
offset = numBlocks * 16;
-
+
/* Decrypt the last plain block. */
last_in = vld1q_u8(&in[numBlocks*16]);
@@ -263160,21 +279211,21 @@ aesHardwareAvailable()
static UINT8 S[256]=
{
- 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
- 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
- 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
- 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
- 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
- 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
- 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
- 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
- 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
- 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
- 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
- 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
- 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
- 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
- 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
+ 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
+ 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
+ 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
+ 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
+ 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
+ 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
+ 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
+ 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
+ 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
+ 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
+ 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
+ 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
+ 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
+ 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
+ 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22
};
@@ -263245,7 +279296,7 @@ static UINT8 T1[256][4]=
{0x82,0x41,0x41,0xc3}, {0x29,0x99,0x99,0xb0}, {0x5a,0x2d,0x2d,0x77}, {0x1e,0x0f,0x0f,0x11},
{0x7b,0xb0,0xb0,0xcb}, {0xa8,0x54,0x54,0xfc}, {0x6d,0xbb,0xbb,0xd6}, {0x2c,0x16,0x16,0x3a}
};
-
+
static UINT8 T2[256][4]=
{
{0xa5,0xc6,0x63,0x63}, {0x84,0xf8,0x7c,0x7c}, {0x99,0xee,0x77,0x77}, {0x8d,0xf6,0x7b,0x7b},
@@ -263857,7 +279908,7 @@ static UINT8 U1[256][4]=
{0xa7,0x79,0xb4,0x92}, {0xa9,0x70,0xb9,0x99}, {0xbb,0x6b,0xae,0x84}, {0xb5,0x62,0xa3,0x8f},
{0x9f,0x5d,0x80,0xbe}, {0x91,0x54,0x8d,0xb5}, {0x83,0x4f,0x9a,0xa8}, {0x8d,0x46,0x97,0xa3}
};
-
+
static UINT8 U2[256][4]=
{
{0x00,0x00,0x00,0x00}, {0x0b,0x0e,0x09,0x0d}, {0x16,0x1c,0x12,0x1a}, {0x1d,0x12,0x1b,0x17},
@@ -264063,7 +280114,7 @@ static UINT8 U4[256][4]=
};
static UINT32 rcon[30]=
-{
+{
0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
@@ -264077,11 +280128,13 @@ static UINT32 rcon[30]=
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
+SQLITE_PRIVATE
void RijndaelCreate(Rijndael* rijndael)
{
rijndael->m_state = RIJNDAEL_State_Invalid;
}
+SQLITE_PRIVATE
int RijndaelInit(Rijndael* rijndael, int mode, int dir, UINT8* key, int keyLen, UINT8* initVector)
{
UINT32 uKeyLenInBytes;
@@ -264166,7 +280219,7 @@ int RijndaelInit(Rijndael* rijndael, int mode, int dir, UINT8* key, int keyLen,
#endif
}
}
-#ifndef TEST_AES_HW
+#ifndef TEST_AES_HW
else
#endif
#endif
@@ -264178,7 +280231,7 @@ int RijndaelInit(Rijndael* rijndael, int mode, int dir, UINT8* key, int keyLen,
if (rijndael->m_direction == RIJNDAEL_Direction_Decrypt) RijndaelKeyEncToDec(rijndael);
}
-#ifdef TEST_AES_HW
+#ifdef TEST_AES_HW
{
int cmpkeyexp = memcmp((unsigned char*) rijndael->m_expandedKey, aesKeySched, (rijndael->m_uRounds+1)*16);
int datalen = (rijndael->m_uRounds + 1) * 16;
@@ -264208,10 +280261,10 @@ int RijndaelBlockEncrypt(Rijndael* rijndael, UINT8* input, int inputLen, UINT8*
numBlocks = inputLen/128;
lenFrag = (inputLen % 128) / 8;
-
+
switch (rijndael->m_mode)
{
- case RIJNDAEL_Direction_Mode_ECB:
+ case RIJNDAEL_Direction_Mode_ECB:
for(i = numBlocks;i > 0;i--)
{
RijndaelEncrypt(rijndael, input, outBuffer);
@@ -264223,7 +280276,7 @@ int RijndaelBlockEncrypt(Rijndael* rijndael, UINT8* input, int inputLen, UINT8*
#if HAS_AES_HARDWARE
if (aesHardwareAvailable())
{
-#ifndef TEST_AES_HW
+#ifndef TEST_AES_HW
aesEncryptCBC(input, outBuffer, rijndael->m_initVector, inputLen/8, (unsigned char*) (rijndael->m_expandedKey), rijndael->m_uRounds);
#else
TEST_AES_HW_DEBUG_LOG("aes enc: hw enabled\n");
@@ -264269,8 +280322,8 @@ int RijndaelBlockEncrypt(Rijndael* rijndael, UINT8* input, int inputLen, UINT8*
}
break;
case RIJNDAEL_Direction_Mode_CFB1:
-#if STRICT_ALIGN
- memcpy(iv,rijndael->m_initVector,16);
+#if STRICT_ALIGN
+ memcpy(iv,rijndael->m_initVector,16);
#else /* !STRICT_ALIGN */
*((UINT32*)iv[0]) = *((UINT32*)(rijndael->m_initVector ));
*((UINT32*)iv[1]) = *((UINT32*)(rijndael->m_initVector + 4));
@@ -264314,7 +280367,7 @@ int RijndaelBlockEncrypt(Rijndael* rijndael, UINT8* input, int inputLen, UINT8*
break;
}
-#ifdef TEST_AES_HW
+#ifdef TEST_AES_HW
{
int cmpdata = memcmp((unsigned char*) outOrig, outBuffer2, inputLen/8);
TEST_AES_HW_DEBUG_LOG("aes enc: cmp=%d\n", cmpdata);
@@ -264322,10 +280375,11 @@ int RijndaelBlockEncrypt(Rijndael* rijndael, UINT8* input, int inputLen, UINT8*
TEST_AES_HW_DEBUG_HEX("aes enc HW:", outBuffer2, 16);
}
#endif
-
+
return 128 * numBlocks;
}
+SQLITE_PRIVATE
int RijndaelPadEncrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8 *outBuffer)
{
int i, numBlocks, padLen;
@@ -264340,7 +280394,7 @@ int RijndaelPadEncrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8
switch (rijndael->m_mode)
{
- case RIJNDAEL_Direction_Mode_ECB:
+ case RIJNDAEL_Direction_Mode_ECB:
for(i = numBlocks; i > 0; i--)
{
RijndaelEncrypt(rijndael, input, outBuffer);
@@ -264380,10 +280434,11 @@ int RijndaelPadEncrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8
return -1;
break;
}
-
+
return 16*(numBlocks + 1);
}
-
+
+SQLITE_PRIVATE
int RijndaelBlockDecrypt(Rijndael* rijndael, UINT8* input, int inputLen, UINT8* outBuffer)
{
int i, k, numBlocks, lenFrag;
@@ -264403,7 +280458,7 @@ int RijndaelBlockDecrypt(Rijndael* rijndael, UINT8* input, int inputLen, UINT8*
switch (rijndael->m_mode)
{
- case RIJNDAEL_Direction_Mode_ECB:
+ case RIJNDAEL_Direction_Mode_ECB:
for (i = numBlocks; i > 0; i--)
{
RijndaelDecrypt(rijndael, input, outBuffer);
@@ -264458,8 +280513,8 @@ int RijndaelBlockDecrypt(Rijndael* rijndael, UINT8* input, int inputLen, UINT8*
}
}
}
-#if STRICT_ALIGN
- memcpy(iv,rijndael->m_initVector,16);
+#if STRICT_ALIGN
+ memcpy(iv,rijndael->m_initVector,16);
#else
*((UINT32*)iv[0]) = *((UINT32*)(rijndael->m_initVector ));
*((UINT32*)iv[1]) = *((UINT32*)(rijndael->m_initVector+ 4));
@@ -264488,8 +280543,8 @@ int RijndaelBlockDecrypt(Rijndael* rijndael, UINT8* input, int inputLen, UINT8*
}
break;
case RIJNDAEL_Direction_Mode_CFB1:
-#if STRICT_ALIGN
- memcpy(iv, rijndael->m_initVector, 16);
+#if STRICT_ALIGN
+ memcpy(iv, rijndael->m_initVector, 16);
#else
*((UINT32*)iv[0]) = *((UINT32*)(rijndael->m_initVector));
*((UINT32*)iv[1]) = *((UINT32*)(rijndael->m_initVector+ 4));
@@ -264533,7 +280588,7 @@ int RijndaelBlockDecrypt(Rijndael* rijndael, UINT8* input, int inputLen, UINT8*
break;
}
-#ifdef TEST_AES_HW
+#ifdef TEST_AES_HW
{
int cmpdata = memcmp((unsigned char*) outOrig, outBuffer2, inputLen/8);
TEST_AES_HW_DEBUG_LOG("aes dec: cmp=%d\n", cmpdata);
@@ -264541,10 +280596,11 @@ int RijndaelBlockDecrypt(Rijndael* rijndael, UINT8* input, int inputLen, UINT8*
TEST_AES_HW_DEBUG_HEX("aes dec HW:", outBuffer2, 16);
}
#endif
-
+
return 128*numBlocks;
}
+SQLITE_PRIVATE
int RijndaelPadDecrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8 *outBuffer)
{
int i, numBlocks, padLen;
@@ -264578,7 +280634,7 @@ int RijndaelPadDecrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8
if (block[i] != padLen) return RIJNDAEL_CORRUPTED_DATA;
}
memcpy(outBuffer, block, 16 - padLen);
- break;
+ break;
case RIJNDAEL_Direction_Mode_CBC:
memcpy(iv, rijndael->m_initVector, 16);
/* all blocks but last */
@@ -264608,12 +280664,12 @@ int RijndaelPadDecrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8
}
memcpy(outBuffer, block, 16 - padLen);
break;
-
+
default:
return -1;
break;
}
-
+
return 16*numBlocks - padLen;
}
@@ -264623,6 +280679,7 @@ int RijndaelPadDecrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
+SQLITE_PRIVATE
void RijndaelKeySched(Rijndael* rijndael, UINT8 key[_MAX_KEY_COLUMNS][4])
{
int j,rconpointer = 0;
@@ -264659,7 +280716,7 @@ void RijndaelKeySched(Rijndael* rijndael, UINT8 key[_MAX_KEY_COLUMNS][4])
t = 0;
}
}
-
+
while(r <= rijndael->m_uRounds)
{
tempKey[0][0] ^= S[tempKey[uKeyColumns-1][1]];
@@ -264700,9 +280757,10 @@ void RijndaelKeySched(Rijndael* rijndael, UINT8 key[_MAX_KEY_COLUMNS][4])
t = 0;
}
}
- }
+ }
}
+SQLITE_PRIVATE
void RijndaelKeyEncToDec(Rijndael* rijndael)
{
UINT32 r;
@@ -264719,8 +280777,9 @@ void RijndaelKeyEncToDec(Rijndael* rijndael)
w = rijndael->m_expandedKey[r][3];
*((UINT32*)w) = *((UINT32*)U1[w[0]]) ^ *((UINT32*)U2[w[1]]) ^ *((UINT32*)U3[w[2]]) ^ *((UINT32*)U4[w[3]]);
}
-}
+}
+SQLITE_PRIVATE
void RijndaelEncrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16])
{
UINT32 r;
@@ -264732,19 +280791,19 @@ void RijndaelEncrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16])
*((UINT32*)temp[3]) = *((UINT32*)(a+12)) ^ *((UINT32*)rijndael->m_expandedKey[0][3]);
*((UINT32*)(b )) = *((UINT32*)T1[temp[0][0]])
^ *((UINT32*)T2[temp[1][1]])
- ^ *((UINT32*)T3[temp[2][2]])
+ ^ *((UINT32*)T3[temp[2][2]])
^ *((UINT32*)T4[temp[3][3]]);
*((UINT32*)(b + 4)) = *((UINT32*)T1[temp[1][0]])
^ *((UINT32*)T2[temp[2][1]])
- ^ *((UINT32*)T3[temp[3][2]])
+ ^ *((UINT32*)T3[temp[3][2]])
^ *((UINT32*)T4[temp[0][3]]);
*((UINT32*)(b + 8)) = *((UINT32*)T1[temp[2][0]])
^ *((UINT32*)T2[temp[3][1]])
- ^ *((UINT32*)T3[temp[0][2]])
+ ^ *((UINT32*)T3[temp[0][2]])
^ *((UINT32*)T4[temp[1][3]]);
*((UINT32*)(b +12)) = *((UINT32*)T1[temp[3][0]])
^ *((UINT32*)T2[temp[0][1]])
- ^ *((UINT32*)T3[temp[1][2]])
+ ^ *((UINT32*)T3[temp[1][2]])
^ *((UINT32*)T4[temp[2][3]]);
for(r = 1; r < rijndael->m_uRounds-1; r++)
{
@@ -264755,19 +280814,19 @@ void RijndaelEncrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16])
*((UINT32*)(b )) = *((UINT32*)T1[temp[0][0]])
^ *((UINT32*)T2[temp[1][1]])
- ^ *((UINT32*)T3[temp[2][2]])
+ ^ *((UINT32*)T3[temp[2][2]])
^ *((UINT32*)T4[temp[3][3]]);
*((UINT32*)(b + 4)) = *((UINT32*)T1[temp[1][0]])
^ *((UINT32*)T2[temp[2][1]])
- ^ *((UINT32*)T3[temp[3][2]])
+ ^ *((UINT32*)T3[temp[3][2]])
^ *((UINT32*)T4[temp[0][3]]);
*((UINT32*)(b + 8)) = *((UINT32*)T1[temp[2][0]])
^ *((UINT32*)T2[temp[3][1]])
- ^ *((UINT32*)T3[temp[0][2]])
+ ^ *((UINT32*)T3[temp[0][2]])
^ *((UINT32*)T4[temp[1][3]]);
*((UINT32*)(b +12)) = *((UINT32*)T1[temp[3][0]])
^ *((UINT32*)T2[temp[0][1]])
- ^ *((UINT32*)T3[temp[1][2]])
+ ^ *((UINT32*)T3[temp[1][2]])
^ *((UINT32*)T4[temp[2][3]]);
}
*((UINT32*)temp[0]) = *((UINT32*)(b )) ^ *((UINT32*)rijndael->m_expandedKey[rijndael->m_uRounds-1][0]);
@@ -264796,11 +280855,12 @@ void RijndaelEncrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16])
*((UINT32*)(b+12)) ^= *((UINT32*)rijndael->m_expandedKey[rijndael->m_uRounds][3]);
}
+SQLITE_PRIVATE
void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16])
{
int r;
UINT8 temp[4][4];
-
+
*((UINT32*)temp[0]) = *((UINT32*)(a )) ^ *((UINT32*)rijndael->m_expandedKey[rijndael->m_uRounds][0]);
*((UINT32*)temp[1]) = *((UINT32*)(a+ 4)) ^ *((UINT32*)rijndael->m_expandedKey[rijndael->m_uRounds][1]);
*((UINT32*)temp[2]) = *((UINT32*)(a+ 8)) ^ *((UINT32*)rijndael->m_expandedKey[rijndael->m_uRounds][2]);
@@ -264808,19 +280868,19 @@ void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16])
*((UINT32*)(b )) = *((UINT32*)T5[temp[0][0]])
^ *((UINT32*)T6[temp[3][1]])
- ^ *((UINT32*)T7[temp[2][2]])
+ ^ *((UINT32*)T7[temp[2][2]])
^ *((UINT32*)T8[temp[1][3]]);
*((UINT32*)(b+ 4)) = *((UINT32*)T5[temp[1][0]])
^ *((UINT32*)T6[temp[0][1]])
- ^ *((UINT32*)T7[temp[3][2]])
+ ^ *((UINT32*)T7[temp[3][2]])
^ *((UINT32*)T8[temp[2][3]]);
*((UINT32*)(b+ 8)) = *((UINT32*)T5[temp[2][0]])
^ *((UINT32*)T6[temp[1][1]])
- ^ *((UINT32*)T7[temp[0][2]])
+ ^ *((UINT32*)T7[temp[0][2]])
^ *((UINT32*)T8[temp[3][3]]);
*((UINT32*)(b+12)) = *((UINT32*)T5[temp[3][0]])
^ *((UINT32*)T6[temp[2][1]])
- ^ *((UINT32*)T7[temp[1][2]])
+ ^ *((UINT32*)T7[temp[1][2]])
^ *((UINT32*)T8[temp[0][3]]);
for(r = rijndael->m_uRounds-1; r > 1; r--)
{
@@ -264830,22 +280890,22 @@ void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16])
*((UINT32*)temp[3]) = *((UINT32*)(b+12)) ^ *((UINT32*)rijndael->m_expandedKey[r][3]);
*((UINT32*)(b )) = *((UINT32*)T5[temp[0][0]])
^ *((UINT32*)T6[temp[3][1]])
- ^ *((UINT32*)T7[temp[2][2]])
+ ^ *((UINT32*)T7[temp[2][2]])
^ *((UINT32*)T8[temp[1][3]]);
*((UINT32*)(b+ 4)) = *((UINT32*)T5[temp[1][0]])
^ *((UINT32*)T6[temp[0][1]])
- ^ *((UINT32*)T7[temp[3][2]])
+ ^ *((UINT32*)T7[temp[3][2]])
^ *((UINT32*)T8[temp[2][3]]);
*((UINT32*)(b+ 8)) = *((UINT32*)T5[temp[2][0]])
^ *((UINT32*)T6[temp[1][1]])
- ^ *((UINT32*)T7[temp[0][2]])
+ ^ *((UINT32*)T7[temp[0][2]])
^ *((UINT32*)T8[temp[3][3]]);
*((UINT32*)(b+12)) = *((UINT32*)T5[temp[3][0]])
^ *((UINT32*)T6[temp[2][1]])
- ^ *((UINT32*)T7[temp[1][2]])
+ ^ *((UINT32*)T7[temp[1][2]])
^ *((UINT32*)T8[temp[0][3]]);
}
-
+
*((UINT32*)temp[0]) = *((UINT32*)(b )) ^ *((UINT32*)rijndael->m_expandedKey[1][0]);
*((UINT32*)temp[1]) = *((UINT32*)(b+ 4)) ^ *((UINT32*)rijndael->m_expandedKey[1][1]);
*((UINT32*)temp[2]) = *((UINT32*)(b+ 8)) ^ *((UINT32*)rijndael->m_expandedKey[1][2]);
@@ -264872,6 +280932,7 @@ void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16])
*((UINT32*)(b+12)) ^= *((UINT32*)rijndael->m_expandedKey[0][3]);
}
+SQLITE_PRIVATE
void RijndaelInvalidate(Rijndael* rijndael)
{
rijndael->m_state = RIJNDAEL_State_Invalid;
@@ -264982,6 +281043,7 @@ typedef struct _Codec
unsigned char m_page[SQLITE_MAX_PAGE_SIZE + 24];
int m_pageSize;
int m_reserved;
+ int m_lastError;
int m_hasKeySalt;
unsigned char m_keySalt[KEYSALT_LENGTH];
} Codec;
@@ -265053,6 +281115,9 @@ SQLITE_PRIVATE int wx_sqlite3mcGetReservedWriteCipher(Codec* codec);
SQLITE_PRIVATE int wx_sqlite3mcReservedEqual(Codec* codec);
+SQLITE_PRIVATE void wx_sqlite3mcSetCodecLastError(Codec* codec, int error);
+SQLITE_PRIVATE int wx_sqlite3mcGetCodecLastError(Codec* codec);
+
SQLITE_PRIVATE unsigned char* wx_sqlite3mcGetSaltWriteCipher(Codec* codec);
SQLITE_PRIVATE int wx_sqlite3mcCodecCopy(Codec* codec, Codec* other);
@@ -265091,6 +281156,8 @@ SQLITE_PRIVATE int wx_sqlite3mcCodecAttach(wx_sqlite3* db, int nDb, const char*
SQLITE_PRIVATE void wx_sqlite3mcCodecGetKey(wx_sqlite3* db, int nDb, void** zKey, int* nKey);
+SQLITE_PRIVATE void wx_sqlite3mcSecureZeroMemory(void* v, size_t n);
+
/* Debugging */
#if 0
@@ -265275,7 +281342,7 @@ wx_sqlite3mcAES128(Rijndael* aesCtx, int page, int encrypt, unsigned char encryp
{
len = RijndaelBlockDecrypt(aesCtx, datain, datalen*8, dataout);
}
-
+
/* It is a good idea to check the error code */
if (len < 0)
{
@@ -265329,7 +281396,7 @@ wx_sqlite3mcAES256(Rijndael* aesCtx, int page, int encrypt, unsigned char encryp
{
len = RijndaelBlockDecrypt(aesCtx, datain, datalen*8, dataout);
}
-
+
/* It is a good idea to check the error code */
if (len < 0)
{
@@ -265386,7 +281453,7 @@ wx_sqlite3mcConvertHex2Bin(const unsigned char* hex, int len, unsigned char* bin
** Purpose: Implementation of cipher wxSQLite3 AES 128-bit
** Author: Ulrich Telle
** Created: 2020-02-02
-** Copyright: (c) 2006-2020 Ulrich Telle
+** Copyright: (c) 2006-2024 Ulrich Telle
** License: MIT
*/
@@ -265514,7 +281581,7 @@ GetSaltAES128Cipher(void* cipher)
}
static void
-GenerateKeyAES128Cipher(void* cipher, BtShared* pBt, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt)
+GenerateKeyAES128Cipher(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt)
{
AES128Cipher* aesCipher = (AES128Cipher*) cipher;
unsigned char userPad[32];
@@ -265674,7 +281741,7 @@ SQLITE_PRIVATE const CipherDescriptor mcAES128Descriptor =
** Purpose: Implementation of cipher wxSQLite3 AES 256-bit
** Author: Ulrich Telle
** Created: 2020-02-02
-** Copyright: (c) 2006-2020 Ulrich Telle
+** Copyright: (c) 2006-2024 Ulrich Telle
** License: MIT
*/
@@ -265808,7 +281875,7 @@ GetSaltAES256Cipher(void* cipher)
}
static void
-GenerateKeyAES256Cipher(void* cipher, BtShared* pBt, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt)
+GenerateKeyAES256Cipher(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt)
{
AES256Cipher* aesCipher = (AES256Cipher*) cipher;
unsigned char userPad[32];
@@ -265930,7 +281997,7 @@ SQLITE_PRIVATE const CipherDescriptor mcAES256Descriptor =
** Purpose: Implementation of cipher ChaCha20 - Poly1305
** Author: Ulrich Telle
** Created: 2020-02-02
-** Copyright: (c) 2006-2020 Ulrich Telle
+** Copyright: (c) 2006-2024 Ulrich Telle
** License: MIT
*/
@@ -266068,21 +282135,18 @@ GetSaltChaCha20Cipher(void* cipher)
}
static void
-GenerateKeyChaCha20Cipher(void* cipher, BtShared* pBt, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt)
+GenerateKeyChaCha20Cipher(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt)
{
ChaCha20Cipher* chacha20Cipher = (ChaCha20Cipher*) cipher;
int bypass = 0;
- Pager *pPager = pBt->pPager;
- wx_sqlite3_file* fd = (isOpen(pPager->fd)) ? pPager->fd : NULL;
-
int keyOnly = 1;
- if (rekey || fd == NULL || wx_sqlite3OsRead(fd, chacha20Cipher->m_salt, SALTLENGTH_CHACHA20, 0) != SQLITE_OK)
+ if (rekey || cipherSalt == NULL)
{
chacha20_rng(chacha20Cipher->m_salt, SALTLENGTH_CHACHA20);
keyOnly = 0;
}
- else if (cipherSalt != NULL)
+ else
{
memcpy(chacha20Cipher->m_salt, cipherSalt, SALTLENGTH_CHACHA20);
}
@@ -266202,7 +282266,8 @@ EncryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len,
return rc;
}
-int chacha20_ismemset(const void* v, unsigned char value, int len)
+static int
+chacha20_ismemset(const void* v, unsigned char value, int len)
{
const unsigned char* a = v;
int i = 0, result = 0;
@@ -266316,7 +282381,7 @@ SQLITE_PRIVATE const CipherDescriptor mcChaCha20Descriptor =
** Purpose: Implementation of cipher SQLCipher (version 1 to 4)
** Author: Ulrich Telle
** Created: 2020-02-02
-** Copyright: (c) 2006-2020 Ulrich Telle
+** Copyright: (c) 2006-2024 Ulrich Telle
** License: MIT
*/
@@ -266345,13 +282410,11 @@ SQLITE_PRIVATE const CipherDescriptor mcChaCha20Descriptor =
#define SQLCIPHER_HMAC_PGNO_NATIVE 0
#define SQLCIPHER_HMAC_SALT_MASK 0x3a
-#define SQLCIPHER_KDF_ALGORITHM_SHA1 0
-#define SQLCIPHER_KDF_ALGORITHM_SHA256 1
-#define SQLCIPHER_KDF_ALGORITHM_SHA512 2
+#define SQLCIPHER_ALGORITHM_SHA1 0
+#define SQLCIPHER_ALGORITHM_SHA256 1
+#define SQLCIPHER_ALGORITHM_SHA512 2
-#define SQLCIPHER_HMAC_ALGORITHM_SHA1 0
-#define SQLCIPHER_HMAC_ALGORITHM_SHA256 1
-#define SQLCIPHER_HMAC_ALGORITHM_SHA512 2
+#define SQLCIPHER_HMAC_ALGO_COMPAT 1
#define SQLCIPHER_VERSION_1 1
#define SQLCIPHER_VERSION_2 2
@@ -266372,13 +282435,13 @@ SQLITE_PRIVATE const CipherDescriptor mcChaCha20Descriptor =
#if SQLCIPHER_VERSION_DEFAULT < SQLCIPHER_VERSION_4
#define SQLCIPHER_KDF_ITER 64000
#define SQLCIPHER_LEGACY_PAGE_SIZE 1024
-#define SQLCIPHER_KDF_ALGORITHM SQLCIPHER_KDF_ALGORITHM_SHA1
-#define SQLCIPHER_HMAC_ALGORITHM SQLCIPHER_HMAC_ALGORITHM_SHA1
+#define SQLCIPHER_KDF_ALGORITHM SQLCIPHER_ALGORITHM_SHA1
+#define SQLCIPHER_HMAC_ALGORITHM SQLCIPHER_ALGORITHM_SHA1
#else
#define SQLCIPHER_KDF_ITER 256000
#define SQLCIPHER_LEGACY_PAGE_SIZE 4096
-#define SQLCIPHER_KDF_ALGORITHM SQLCIPHER_KDF_ALGORITHM_SHA512
-#define SQLCIPHER_HMAC_ALGORITHM SQLCIPHER_HMAC_ALGORITHM_SHA512
+#define SQLCIPHER_KDF_ALGORITHM SQLCIPHER_ALGORITHM_SHA512
+#define SQLCIPHER_HMAC_ALGORITHM SQLCIPHER_ALGORITHM_SHA512
#endif
SQLITE_PRIVATE CipherParams mcSQLCipherParams[] =
@@ -266392,6 +282455,7 @@ SQLITE_PRIVATE CipherParams mcSQLCipherParams[] =
{ "hmac_salt_mask", SQLCIPHER_HMAC_SALT_MASK, SQLCIPHER_HMAC_SALT_MASK, 0x00, 0xff },
{ "kdf_algorithm", SQLCIPHER_KDF_ALGORITHM, SQLCIPHER_KDF_ALGORITHM, 0, 2 },
{ "hmac_algorithm", SQLCIPHER_HMAC_ALGORITHM, SQLCIPHER_HMAC_ALGORITHM, 0, 2 },
+ { "hmac_algorithm_compat", SQLCIPHER_HMAC_ALGO_COMPAT, SQLCIPHER_HMAC_ALGO_COMPAT, 0, 1 },
{ "plaintext_header_size", 0, 0, 0, 100 /* restrict to db header size */ },
CIPHER_PARAMS_SENTINEL
};
@@ -266412,6 +282476,7 @@ typedef struct _sqlCipherCipher
int m_hmacSaltMask;
int m_kdfAlgorithm;
int m_hmacAlgorithm;
+ int m_hmacAlgorithmCompat;
int m_plaintextHeaderSize;
int m_keyLength;
uint8_t m_key[KEYLENGTH_SQLCIPHER];
@@ -266453,6 +282518,7 @@ AllocateSQLCipherCipher(wx_sqlite3* db)
sqlCipherCipher->m_hmacSaltMask = wx_sqlite3mcGetCipherParameter(cipherParams, "hmac_salt_mask");
sqlCipherCipher->m_kdfAlgorithm = wx_sqlite3mcGetCipherParameter(cipherParams, "kdf_algorithm");
sqlCipherCipher->m_hmacAlgorithm = wx_sqlite3mcGetCipherParameter(cipherParams, "hmac_algorithm");
+ sqlCipherCipher->m_hmacAlgorithmCompat = wx_sqlite3mcGetCipherParameter(cipherParams, "hmac_algorithm_compat");
if (sqlCipherCipher->m_legacy >= SQLCIPHER_VERSION_4)
{
int plaintextHeaderSize = wx_sqlite3mcGetCipherParameter(cipherParams, "plaintext_header_size");
@@ -266490,6 +282556,7 @@ CloneSQLCipherCipher(void* cipherTo, void* cipherFrom)
sqlCipherCipherTo->m_hmacSaltMask = sqlCipherCipherFrom->m_hmacSaltMask;
sqlCipherCipherTo->m_kdfAlgorithm = sqlCipherCipherFrom->m_kdfAlgorithm;
sqlCipherCipherTo->m_hmacAlgorithm = sqlCipherCipherFrom->m_hmacAlgorithm;
+ sqlCipherCipherTo->m_hmacAlgorithmCompat = sqlCipherCipherFrom->m_hmacAlgorithmCompat;
sqlCipherCipherTo->m_plaintextHeaderSize = sqlCipherCipherFrom->m_plaintextHeaderSize;
sqlCipherCipherTo->m_keyLength = sqlCipherCipherFrom->m_keyLength;
memcpy(sqlCipherCipherTo->m_key, sqlCipherCipherFrom->m_key, KEYLENGTH_SQLCIPHER);
@@ -266531,11 +282598,11 @@ GetReservedSQLCipherCipher(void* cipher)
{
switch (sqlCipherCipher->m_hmacAlgorithm)
{
- case SQLCIPHER_HMAC_ALGORITHM_SHA1:
- case SQLCIPHER_HMAC_ALGORITHM_SHA256:
+ case SQLCIPHER_ALGORITHM_SHA1:
+ case SQLCIPHER_ALGORITHM_SHA256:
reserved += SHA256_DIGEST_SIZE;
break;
- case SQLCIPHER_HMAC_ALGORITHM_SHA512:
+ case SQLCIPHER_ALGORITHM_SHA512:
default:
reserved += SHA512_DIGEST_SIZE;
break;
@@ -266552,18 +282619,15 @@ GetSaltSQLCipherCipher(void* cipher)
}
static void
-GenerateKeySQLCipherCipher(void* cipher, BtShared* pBt, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt)
+GenerateKeySQLCipherCipher(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt)
{
SQLCipherCipher* sqlCipherCipher = (SQLCipherCipher*) cipher;
- Pager *pPager = pBt->pPager;
- wx_sqlite3_file* fd = (isOpen(pPager->fd)) ? pPager->fd : NULL;
-
- if (rekey || fd == NULL || wx_sqlite3OsRead(fd, sqlCipherCipher->m_salt, SALTLENGTH_SQLCIPHER, 0) != SQLITE_OK)
+ if (rekey || cipherSalt == NULL)
{
chacha20_rng(sqlCipherCipher->m_salt, SALTLENGTH_SQLCIPHER);
}
- else if (cipherSalt != NULL)
+ else
{
memcpy(sqlCipherCipher->m_salt, cipherSalt, SALTLENGTH_SQLCIPHER);
}
@@ -266585,19 +282649,19 @@ GenerateKeySQLCipherCipher(void* cipher, BtShared* pBt, char* userPassword, int
{
switch (sqlCipherCipher->m_kdfAlgorithm)
{
- case SQLCIPHER_KDF_ALGORITHM_SHA1:
+ case SQLCIPHER_ALGORITHM_SHA1:
fastpbkdf2_hmac_sha1((unsigned char*) userPassword, passwordLength,
sqlCipherCipher->m_salt, SALTLENGTH_SQLCIPHER,
sqlCipherCipher->m_kdfIter,
sqlCipherCipher->m_key, KEYLENGTH_SQLCIPHER);
break;
- case SQLCIPHER_KDF_ALGORITHM_SHA256:
+ case SQLCIPHER_ALGORITHM_SHA256:
fastpbkdf2_hmac_sha256((unsigned char*) userPassword, passwordLength,
sqlCipherCipher->m_salt, SALTLENGTH_SQLCIPHER,
sqlCipherCipher->m_kdfIter,
sqlCipherCipher->m_key, KEYLENGTH_SQLCIPHER);
break;
- case SQLCIPHER_KDF_ALGORITHM_SHA512:
+ case SQLCIPHER_ALGORITHM_SHA512:
default:
fastpbkdf2_hmac_sha512((unsigned char*) userPassword, passwordLength,
sqlCipherCipher->m_salt, SALTLENGTH_SQLCIPHER,
@@ -266610,6 +282674,7 @@ GenerateKeySQLCipherCipher(void* cipher, BtShared* pBt, char* userPassword, int
if (sqlCipherCipher->m_hmacUse != 0)
{
int j;
+ int algorithm = (sqlCipherCipher->m_hmacAlgorithmCompat) ? sqlCipherCipher->m_kdfAlgorithm : sqlCipherCipher->m_hmacAlgorithm;
unsigned char hmacSaltMask = sqlCipherCipher->m_hmacSaltMask;
unsigned char hmacSalt[SALTLENGTH_SQLCIPHER];
memcpy(hmacSalt, sqlCipherCipher->m_salt, SALTLENGTH_SQLCIPHER);
@@ -266617,21 +282682,21 @@ GenerateKeySQLCipherCipher(void* cipher, BtShared* pBt, char* userPassword, int
{
hmacSalt[j] ^= hmacSaltMask;
}
- switch (sqlCipherCipher->m_hmacAlgorithm)
+ switch (algorithm)
{
- case SQLCIPHER_HMAC_ALGORITHM_SHA1:
+ case SQLCIPHER_ALGORITHM_SHA1:
fastpbkdf2_hmac_sha1(sqlCipherCipher->m_key, KEYLENGTH_SQLCIPHER,
hmacSalt, SALTLENGTH_SQLCIPHER,
sqlCipherCipher->m_fastKdfIter,
sqlCipherCipher->m_hmacKey, KEYLENGTH_SQLCIPHER);
break;
- case SQLCIPHER_HMAC_ALGORITHM_SHA256:
+ case SQLCIPHER_ALGORITHM_SHA256:
fastpbkdf2_hmac_sha256(sqlCipherCipher->m_key, KEYLENGTH_SQLCIPHER,
hmacSalt, SALTLENGTH_SQLCIPHER,
sqlCipherCipher->m_fastKdfIter,
sqlCipherCipher->m_hmacKey, KEYLENGTH_SQLCIPHER);
break;
- case SQLCIPHER_HMAC_ALGORITHM_SHA512:
+ case SQLCIPHER_ALGORITHM_SHA512:
default:
fastpbkdf2_hmac_sha512(sqlCipherCipher->m_key, KEYLENGTH_SQLCIPHER,
hmacSalt, SALTLENGTH_SQLCIPHER,
@@ -266648,11 +282713,13 @@ GetHmacSizeSQLCipherCipher(int algorithm)
int hmacSize = SHA512_DIGEST_SIZE;
switch (algorithm)
{
- case SQLCIPHER_HMAC_ALGORITHM_SHA1:
+ case SQLCIPHER_ALGORITHM_SHA1:
hmacSize = SHA1_DIGEST_SIZE;
break;
- case SQLCIPHER_HMAC_ALGORITHM_SHA256:
- case SQLCIPHER_HMAC_ALGORITHM_SHA512:
+ case SQLCIPHER_ALGORITHM_SHA256:
+ hmacSize = SHA256_DIGEST_SIZE;
+ break;
+ case SQLCIPHER_ALGORITHM_SHA512:
default:
hmacSize = SHA512_DIGEST_SIZE;
break;
@@ -266670,7 +282737,7 @@ EncryptPageSQLCipherCipher(void* cipher, int page, unsigned char* data, int len,
int n = len - nReserved;
int offset = (page == 1) ? (sqlCipherCipher->m_legacy != 0) ? 16 : 24 : 0;
int blen;
- unsigned char iv[64];
+ unsigned char iv[128];
int usePlaintextHeader = 0;
/* Check whether a plaintext header should be used */
@@ -266687,10 +282754,10 @@ EncryptPageSQLCipherCipher(void* cipher, int page, unsigned char* data, int len,
}
/* Generate nonce (64 bytes) */
- memset(iv, 0, 64);
+ memset(iv, 0, 128);
if (nReserved > 0)
{
- chacha20_rng(iv, 64);
+ chacha20_rng(iv, 128);
}
else
{
@@ -266838,7 +282905,7 @@ SQLITE_PRIVATE const CipherDescriptor mcSQLCipherDescriptor =
** Purpose: Implementation of cipher System.Data.SQLite3 RC4
** Author: Ulrich Telle
** Created: 2020-02-02
-** Copyright: (c) 2006-2020 Ulrich Telle
+** Copyright: (c) 2006-2024 Ulrich Telle
** License: MIT
*/
@@ -266952,7 +283019,7 @@ GetSaltRC4Cipher(void* cipher)
}
static void
-GenerateKeyRC4Cipher(void* cipher, BtShared* pBt, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt)
+GenerateKeyRC4Cipher(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt)
{
RC4Cipher* rc4Cipher = (RC4Cipher*) cipher;
unsigned char digest[SHA1_DIGEST_SIZE];
@@ -267008,6 +283075,1590 @@ SQLITE_PRIVATE const CipherDescriptor mcRC4Descriptor =
#endif
/*** End of #include "cipher_sds_rc4.c" ***/
+/* #include "cipher_ascon.c" */
+/*** Begin of #include "cipher_ascon.c" ***/
+/*
+** Name: cipher_ascon.c
+** Purpose: Implementation of cipher Ascon
+** Author: Ulrich Telle
+** Created: 2023-11-13
+** Copyright: (c) 2023-2024 Ulrich Telle
+** License: MIT
+*/
+
+/* #include "cipher_common.h" */
+
+
+/* --- Ascon --- */
+#if HAVE_CIPHER_ASCON128
+
+#define CIPHER_NAME_ASCON128 "ascon128"
+
+/*
+** Configuration parameters for "ascon128a"
+**
+** - kdf_iter : number of iterations for key derivation
+*/
+
+#define ASCON128_KDF_ITER_DEFAULT 64007
+
+/* #include "ascon/prolog.h" */
+/*** Begin of #include "ascon/prolog.h" ***/
+/*
+** Name: prolog.h
+** Purpose: Include important header files, before
+** Based on: Public domain Ascon reference implementation
+** and optimized variants for 32- and 64-bit
+** (see https://github.com/ascon/ascon-c)
+** Remarks: API functions adapted for use in SQLite3 Multiple Ciphers
+** Modified by: Ulrich Telle
+** Copyright: (c) 2023-2023 Ulrich Telle
+** License: MIT
+*/
+
+#ifndef PROLOG_H
+#define PROLOG_H
+
+/* #include "word.h" */
+/*** Begin of #include "word.h" ***/
+#ifndef WORD_H_
+#define WORD_H_
+
+#include <stdint.h>
+#include <string.h>
+
+/* #include "bendian.h" */
+/*** Begin of #include "bendian.h" ***/
+#ifndef ENDIAN_H_
+#define ENDIAN_H_
+
+#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+
+/* macros for big endian machines */
+#ifdef PRAGMA_ENDIAN
+#pragma message("Using macros for big endian machines")
+#endif
+#define ASCON_U64BIG(x) (x)
+#define ASCON_U32BIG(x) (x)
+#define ASCON_U16BIG(x) (x)
+
+#elif defined(_MSC_VER) || \
+ (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+
+/* macros for little endian machines */
+#ifdef PRAGMA_ENDIAN
+#pragma message("Using macros for little endian machines")
+#endif
+#define ASCON_U64BIG(x) \
+ (((0x00000000000000FFULL & (x)) << 56) | \
+ ((0x000000000000FF00ULL & (x)) << 40) | \
+ ((0x0000000000FF0000ULL & (x)) << 24) | \
+ ((0x00000000FF000000ULL & (x)) << 8) | \
+ ((0x000000FF00000000ULL & (x)) >> 8) | \
+ ((0x0000FF0000000000ULL & (x)) >> 24) | \
+ ((0x00FF000000000000ULL & (x)) >> 40) | \
+ ((0xFF00000000000000ULL & (x)) >> 56))
+#define ASCON_U32BIG(x) \
+ (((0x000000FF & (x)) << 24) | ((0x0000FF00 & (x)) << 8) | \
+ ((0x00FF0000 & (x)) >> 8) | ((0xFF000000 & (x)) >> 24))
+#define ASCON_U16BIG(x) (((0x00FF & (x)) << 8) | ((0xFF00 & (x)) >> 8))
+
+#else
+#error "Ascon byte order macros not defined in bendian.h"
+#endif
+
+#endif /* ENDIAN_H_ */
+/*** End of #include "bendian.h" ***/
+
+/* #include "forceinline.h" */
+/*** Begin of #include "forceinline.h" ***/
+#ifndef FORCEINLINE_H_
+#define FORCEINLINE_H_
+
+/* define forceinline macro */
+#ifdef _MSC_VER
+#define forceinline __forceinline
+#elif defined(__GNUC__)
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define forceinline inline __attribute__((__always_inline__))
+#else
+#define forceinline static inline
+#endif
+#elif defined(__CLANG__)
+#if __has_attribute(__always_inline__)
+#define forceinline inline __attribute__((__always_inline__))
+#else
+#define forceinline inline
+#endif
+#else
+#define forceinline inline
+#endif
+
+#endif /* FORCEINLINE_H_ */
+/*** End of #include "forceinline.h" ***/
+
+
+typedef union {
+ uint64_t x;
+ uint32_t w[2];
+ uint8_t b[8];
+} word_t;
+
+#define ASCON_U64TOWORD(x) ASCON_U64BIG(x)
+#define ASCON_WORDTOU64(x) ASCON_U64BIG(x)
+#define ASCON_LOAD(b, n) ASCON_LOADBYTES(b, n)
+#define ASCON_STORE(b, w, n) ASCON_STOREBYTES(b, w, n)
+
+forceinline uint64_t ASCON_ROR(uint64_t x, int n) { return x >> n | x << (-n & 63); }
+
+forceinline uint64_t ASCON_KEYROT(uint64_t lo2hi, uint64_t hi2lo) {
+ return lo2hi << 32 | hi2lo >> 32;
+}
+
+forceinline int ASCON_NOTZERO(uint64_t a, uint64_t b) {
+ uint64_t result = a | b;
+ result |= result >> 32;
+ result |= result >> 16;
+ result |= result >> 8;
+ return ((((int)(result & 0xff) - 1) >> 8) & 1) - 1;
+}
+
+forceinline uint64_t ASCON_PAD(int i) { return 0x80ull << (56 - 8 * i); }
+
+forceinline uint64_t ASCON_DSEP() { return 0x01; }
+
+forceinline uint64_t ASCON_PRFS_MLEN(uint64_t len) { return len << 51; }
+
+forceinline uint64_t ASCON_CLEAR(uint64_t w, int n) {
+ /* undefined for n == 0 */
+ uint64_t mask = ~0ull >> (8 * n);
+ return w & mask;
+}
+
+forceinline uint64_t ASCON_MASK(int n) {
+ /* undefined for n == 0 */
+ return ~0ull >> (64 - 8 * n);
+}
+
+forceinline uint64_t ASCON_LOADBYTES(const uint8_t* bytes, int n) {
+ uint64_t x = 0;
+ memcpy(&x, bytes, n);
+ return ASCON_U64TOWORD(x);
+}
+
+forceinline void ASCON_STOREBYTES(uint8_t* bytes, uint64_t w, int n) {
+ uint64_t x = ASCON_WORDTOU64(w);
+ memcpy(bytes, &x, n);
+}
+
+#endif /* WORD_H_ */
+/*** End of #include "word.h" ***/
+
+
+#endif
+/*** End of #include "ascon/prolog.h" ***/
+
+/* #include "ascon/aead.c" */
+/*** Begin of #include "ascon/aead.c" ***/
+/*
+** Name: aead.c
+** Purpose: Stream encryption/decryption with Ascon
+** Based on: Public domain Ascon reference implementation
+** and optimized variants for 32- and 64-bit
+** (see https://github.com/ascon/ascon-c)
+** Remarks: API functions adapted for use in SQLite3 Multiple Ciphers
+** Modified by: Ulrich Telle
+** Copyright: (c) 2023-2023 Ulrich Telle
+** License: MIT
+*/
+
+/* #include "api.h" */
+/*** Begin of #include "api.h" ***/
+/*
+** Name: api.h
+** Purpose: Definition of preprocessor symbols
+** Based on: Public domain Ascon reference implementation
+** and optimized variants for 32- and 64-bit
+** (see https://github.com/ascon/ascon-c)
+** Remarks: API functions adapted for use in SQLite3 Multiple Ciphers
+** Combined symbols from AEAD and HASH
+** Modified by: Ulrich Telle
+** Copyright: (c) 2023-2023 Ulrich Telle
+** License: MIT
+*/
+
+#define CRYPTO_VERSION "1.2.7"
+#define CRYPTO_KEYBYTES 16
+#define CRYPTO_NSECBYTES 0
+#define CRYPTO_NPUBBYTES 16
+#define CRYPTO_ABYTES 16
+#define CRYPTO_NOOVERLAP 1
+#define ASCON_AEAD_RATE 8
+
+#define CRYPTO_BYTES 32
+#define ASCON_HASH_BYTES 32 /* HASH */
+#define ASCON_HASH_ROUNDS 12
+
+#define ASCON_AEAD_KEY_LEN CRYPTO_KEYBYTES
+#define ASCON_AEAD_NONCE_LEN CRYPTO_NPUBBYTES
+#define ASCON_AEAD_TAG_LEN CRYPTO_ABYTES
+#define ASCON_SALT_LEN CRYPTO_NPUBBYTES
+/*** End of #include "api.h" ***/
+
+/* #include "ascon.h" */
+/*** Begin of #include "ascon.h" ***/
+#ifndef ASCON_H_
+#define ASCON_H_
+
+#include <stdint.h>
+
+/* #include "api.h" */
+
+/* #include "config.h" */
+/*** Begin of #include "config.h" ***/
+#ifndef CONFIG_H_
+#define CONFIG_H_
+
+/* inline the ascon mode */
+#ifndef ASCON_INLINE_MODE
+#define ASCON_INLINE_MODE 1
+#endif
+
+/* inline all permutations */
+#ifndef ASCON_INLINE_PERM
+#define ASCON_INLINE_PERM 1
+#endif
+
+/* unroll permutation loops */
+#ifndef ASCON_UNROLL_LOOPS
+#define ASCON_UNROLL_LOOPS 1
+#endif
+
+#endif /* CONFIG_H_ */
+/*** End of #include "config.h" ***/
+
+
+typedef union {
+ uint64_t x[5];
+ uint32_t w[5][2];
+ uint8_t b[5][8];
+} ascon_state_t;
+
+#ifdef ASCON_AEAD_RATE
+
+#define ASCON_KEYWORDS (CRYPTO_KEYBYTES + 7) / 8
+
+typedef union {
+ uint64_t x[ASCON_KEYWORDS];
+ uint32_t w[ASCON_KEYWORDS][2];
+ uint8_t b[ASCON_KEYWORDS][8];
+} ascon_key_t;
+
+#if !ASCON_INLINE_MODE
+
+void ascon_loadkey(ascon_key_t* key, const uint8_t* k);
+void ascon_initaead(ascon_state_t* s, const ascon_key_t* key,
+ const uint8_t* npub);
+void ascon_adata(ascon_state_t* s, const uint8_t* ad, uint64_t adlen);
+void ascon_encrypt(ascon_state_t* s, uint8_t* c, const uint8_t* m,
+ uint64_t mlen);
+void ascon_decrypt(ascon_state_t* s, uint8_t* m, const uint8_t* c,
+ uint64_t clen);
+void ascon_final(ascon_state_t* s, const ascon_key_t* k);
+
+#endif
+
+#endif
+
+#ifdef ASCON_HASH_BYTES
+
+#if !ASCON_INLINE_MODE
+
+void ascon_inithash(ascon_state_t* s);
+void ascon_absorb(ascon_state_t* s, const uint8_t* in, uint64_t inlen);
+void ascon_squeeze(ascon_state_t* s, uint8_t* out, uint64_t outlen);
+
+#endif
+
+#endif
+
+#endif /* ASCON_H_ */
+/*** End of #include "ascon.h" ***/
+
+/* #include "crypto_aead.h" */
+/*** Begin of #include "crypto_aead.h" ***/
+/*
+** Name: hash.c
+** Purpose: API definition for Hash algorithm with Ascon
+** Based on: Public domain Ascon reference implementation
+** and optimized variants for 32- and 64-bit
+** (see https://github.com/ascon/ascon-c)
+** Remarks: API functions adapted for use in SQLite3 Multiple Ciphers
+** Modified by: Ulrich Telle
+** Copyright: (c) 2023-2023 Ulrich Telle
+** License: MIT
+*/
+
+#ifndef CRYPTO_AEAD_H
+#define CRYPTO_AEAD_H
+
+#ifndef SQLITE_PRIVATE
+#define SQLITE_PRIVATE
+#endif
+
+#include <stddef.h>
+
+/*
+** Encryption using ASCON-AEAD.
+**
+** \param ctext Output buffer for encrypted text (same length as plain text)
+** \param tag Output buffer for tag with fixed length of ASCON_AEAD_TAG_LEN
+** \param mtext Input buffer with plain message text
+** \param mlen Length of message text
+** \param ad Input buffer with associated data
+** \param adlen Length of associated data
+** \param nonce Buffer with nonce data
+** \param k Buffer with key data
+*/
+SQLITE_PRIVATE
+int ascon_aead_encrypt(uint8_t* ctext, uint8_t tag[ASCON_AEAD_TAG_LEN],
+ const uint8_t* mtext, uint64_t mlen,
+ const uint8_t* ad, uint64_t adlen,
+ const uint8_t nonce[ASCON_AEAD_NONCE_LEN],
+ const uint8_t k[ASCON_AEAD_KEY_LEN]);
+
+/*
+** Encryption using ASCON-AEAD.
+**
+** \param mtext Output buffer with decrypted plain message text (same length as encrypted text)
+** \param ctext Input buffer for encrypted text
+** \param clen Length of encrypted text
+** \param ad Input buffer with associated data
+** \param adlen Length of associated data
+** \param tag Input buffer for expected tag with fixed length of ASCON_AEAD_TAG_LEN
+** \param nonce Buffer with nonce data
+** \param k Buffer with key data
+*/
+SQLITE_PRIVATE
+int ascon_aead_decrypt(uint8_t* mtext, const uint8_t* ctext, uint64_t clen,
+ const uint8_t* ad, uint64_t adlen,
+ const uint8_t tag[ASCON_AEAD_TAG_LEN],
+ const uint8_t nonce[ASCON_AEAD_NONCE_LEN],
+ const uint8_t k[ASCON_AEAD_KEY_LEN]);
+
+#endif
+/*** End of #include "crypto_aead.h" ***/
+
+/* #include "permutations.h" */
+/*** Begin of #include "permutations.h" ***/
+#ifndef PERMUTATIONS_H_
+#define PERMUTATIONS_H_
+
+#include <stdint.h>
+
+/* #include "api.h" */
+
+/* #include "ascon.h" */
+
+/* #include "config.h" */
+
+/* #include "constants.h" */
+/*** Begin of #include "constants.h" ***/
+#ifndef CONSTANTS_H_
+#define CONSTANTS_H_
+
+#include <stdint.h>
+
+#define ASCON_128_KEYBYTES 16
+#define ASCON_128A_KEYBYTES 16
+#define ASCON_80PQ_KEYBYTES 20
+
+#define ASCON_128_RATE 8
+#define ASCON_128A_RATE 16
+#define ASCON_HASH_RATE 8
+#define ASCON_PRF_IN_RATE 32
+#define ASCON_PRFA_IN_RATE 40
+#define ASCON_PRF_OUT_RATE 16
+
+#define ASCON_128_PA_ROUNDS 12
+#define ASCON_128_PB_ROUNDS 6
+#define ASCON_128A_PA_ROUNDS 12
+#define ASCON_128A_PB_ROUNDS 8
+
+#define ASCON_HASH_PA_ROUNDS 12
+#define ASCON_HASH_PB_ROUNDS 12
+#define ASCON_HASHA_PA_ROUNDS 12
+#define ASCON_HASHA_PB_ROUNDS 8
+
+#define ASCON_PRF_PA_ROUNDS 12
+#define ASCON_PRF_PB_ROUNDS 12
+#define ASCON_PRFA_PA_ROUNDS 12
+#define ASCON_PRFA_PB_ROUNDS 8
+
+#define ASCON_128_IV 0x80400c0600000000ull
+#define ASCON_128A_IV 0x80800c0800000000ull
+#define ASCON_80PQ_IV 0xa0400c0600000000ull
+
+#define ASCON_HASH_IV 0x00400c0000000100ull
+#define ASCON_HASHA_IV 0x00400c0400000100ull
+#define ASCON_XOF_IV 0x00400c0000000000ull
+#define ASCON_XOFA_IV 0x00400c0400000000ull
+
+#define ASCON_HASH_IV0 0xee9398aadb67f03dull
+#define ASCON_HASH_IV1 0x8bb21831c60f1002ull
+#define ASCON_HASH_IV2 0xb48a92db98d5da62ull
+#define ASCON_HASH_IV3 0x43189921b8f8e3e8ull
+#define ASCON_HASH_IV4 0x348fa5c9d525e140ull
+
+#define ASCON_HASHA_IV0 0x01470194fc6528a6ull
+#define ASCON_HASHA_IV1 0x738ec38ac0adffa7ull
+#define ASCON_HASHA_IV2 0x2ec8e3296c76384cull
+#define ASCON_HASHA_IV3 0xd6f6a54d7f52377dull
+#define ASCON_HASHA_IV4 0xa13c42a223be8d87ull
+
+#define ASCON_XOF_IV0 0xb57e273b814cd416ull
+#define ASCON_XOF_IV1 0x2b51042562ae2420ull
+#define ASCON_XOF_IV2 0x66a3a7768ddf2218ull
+#define ASCON_XOF_IV3 0x5aad0a7a8153650cull
+#define ASCON_XOF_IV4 0x4f3e0e32539493b6ull
+
+#define ASCON_XOFA_IV0 0x44906568b77b9832ull
+#define ASCON_XOFA_IV1 0xcd8d6cae53455532ull
+#define ASCON_XOFA_IV2 0xf7b5212756422129ull
+#define ASCON_XOFA_IV3 0x246885e1de0d225bull
+#define ASCON_XOFA_IV4 0xa8cb5ce33449973full
+
+#define ASCON_MAC_IV 0x80808c0000000080ull
+#define ASCON_MACA_IV 0x80808c0400000080ull
+#define ASCON_PRF_IV 0x80808c0000000000ull
+#define ASCON_PRFA_IV 0x80808c0400000000ull
+#define ASCON_PRFS_IV 0x80004c8000000000ull
+
+#define ASCON_RC0 0xf0
+#define ASCON_RC1 0xe1
+#define ASCON_RC2 0xd2
+#define ASCON_RC3 0xc3
+#define ASCON_RC4 0xb4
+#define ASCON_RC5 0xa5
+#define ASCON_RC6 0x96
+#define ASCON_RC7 0x87
+#define ASCON_RC8 0x78
+#define ASCON_RC9 0x69
+#define ASCON_RCa 0x5a
+#define ASCON_RCb 0x4b
+
+#define ASCON_RC(i) (i)
+
+#define ASCON_START(n) ((3 + (n)) << 4 | (12 - (n)))
+#define ASCON_INC -0x0f
+#define ASCON_END 0x3c
+
+#endif /* CONSTANTS_H_ */
+/*** End of #include "constants.h" ***/
+
+/* #include "printstate.h" */
+/*** Begin of #include "printstate.h" ***/
+#ifndef PRINTSTATE_H_
+#define PRINTSTATE_H_
+
+#ifdef ASCON_PRINT_STATE
+
+/* #include "ascon.h" */
+
+/* #include "word.h" */
+
+
+void ascon_printword(const char* text, const uint64_t x);
+void ascon_printstate(const char* text, const ascon_state_t* s);
+
+#else
+
+#define ascon_printword(text, w) \
+ do { \
+ } while (0)
+
+#define ascon_printstate(text, s) \
+ do { \
+ } while (0)
+
+#endif
+
+#endif /* PRINTSTATE_H_ */
+/*** End of #include "printstate.h" ***/
+
+/* #include "round.h" */
+/*** Begin of #include "round.h" ***/
+/*
+** Name: round.h
+** Purpose: Selector for Ascon implementation variant for 32- resp 64-bit
+** Based on: Public domain Ascon reference implementation
+** and optimized variants for 32- and 64-bit
+** (see https://github.com/ascon/ascon-c)
+** Remarks: API functions adapted for use in SQLite3 Multiple Ciphers
+** Modified by: Ulrich Telle
+** Copyright: (c) 2023-2023 Ulrich Telle
+** License: MIT
+*/
+
+#ifndef ROUND_H
+#define ROUND_H
+
+/* #include "forceinline.h" */
+
+
+#if defined(__LP64__) || defined(_WIN64)
+/* 64-bit machine, Windows or Linux or OS X */
+/* #include "round64.h" */
+/*** Begin of #include "round64.h" ***/
+#ifndef ROUND64_H_
+#define ROUND64_H_
+
+/* #include "ascon.h" */
+
+/* #include "constants.h" */
+
+/* #include "forceinline.h" */
+
+/* #include "printstate.h" */
+
+/* #include "word.h" */
+
+
+forceinline void ASCON_ROUND(ascon_state_t* s, uint8_t C) {
+ ascon_state_t t;
+ /* round constant */
+ s->x[2] ^= C;
+ /* s-box layer */
+ s->x[0] ^= s->x[4];
+ s->x[4] ^= s->x[3];
+ s->x[2] ^= s->x[1];
+ t.x[0] = s->x[0] ^ (~s->x[1] & s->x[2]);
+ t.x[2] = s->x[2] ^ (~s->x[3] & s->x[4]);
+ t.x[4] = s->x[4] ^ (~s->x[0] & s->x[1]);
+ t.x[1] = s->x[1] ^ (~s->x[2] & s->x[3]);
+ t.x[3] = s->x[3] ^ (~s->x[4] & s->x[0]);
+ t.x[1] ^= t.x[0];
+ t.x[3] ^= t.x[2];
+ t.x[0] ^= t.x[4];
+ /* linear layer */
+ s->x[2] = t.x[2] ^ ASCON_ROR(t.x[2], 6 - 1);
+ s->x[3] = t.x[3] ^ ASCON_ROR(t.x[3], 17 - 10);
+ s->x[4] = t.x[4] ^ ASCON_ROR(t.x[4], 41 - 7);
+ s->x[0] = t.x[0] ^ ASCON_ROR(t.x[0], 28 - 19);
+ s->x[1] = t.x[1] ^ ASCON_ROR(t.x[1], 61 - 39);
+ s->x[2] = t.x[2] ^ ASCON_ROR(s->x[2], 1);
+ s->x[3] = t.x[3] ^ ASCON_ROR(s->x[3], 10);
+ s->x[4] = t.x[4] ^ ASCON_ROR(s->x[4], 7);
+ s->x[0] = t.x[0] ^ ASCON_ROR(s->x[0], 19);
+ s->x[1] = t.x[1] ^ ASCON_ROR(s->x[1], 39);
+ s->x[2] = ~s->x[2];
+ ascon_printstate(" round output", s);
+}
+
+forceinline void ASCON_PROUNDS(ascon_state_t* s, int nr) {
+ int i = ASCON_START(nr);
+ do {
+ ASCON_ROUND(s, ASCON_RC(i));
+ i += ASCON_INC;
+ } while (i != ASCON_END);
+}
+
+#endif /* ROUND64_H_ */
+/*** End of #include "round64.h" ***/
+
+#else
+/* 32-bit machine, Windows or Linux or OS X */
+/* #include "round32.h" */
+/*** Begin of #include "round32.h" ***/
+#ifndef ROUND32_H_
+#define ROUND32_H_
+
+/* #include "ascon.h" */
+
+/* #include "constants.h" */
+
+/* #include "forceinline.h" */
+
+/* #include "printstate.h" */
+
+/* #include "word.h" */
+
+
+forceinline void ASCON_ROUND(ascon_state_t* s, uint8_t C) {
+ uint64_t xtemp;
+ /* round constant */
+ s->x[2] ^= C;
+ /* s-box layer */
+ s->x[0] ^= s->x[4];
+ s->x[4] ^= s->x[3];
+ s->x[2] ^= s->x[1];
+ xtemp = s->x[0] & ~s->x[4];
+ s->x[0] ^= s->x[2] & ~s->x[1];
+ s->x[2] ^= s->x[4] & ~s->x[3];
+ s->x[4] ^= s->x[1] & ~s->x[0];
+ s->x[1] ^= s->x[3] & ~s->x[2];
+ s->x[3] ^= xtemp;
+ s->x[1] ^= s->x[0];
+ s->x[3] ^= s->x[2];
+ s->x[0] ^= s->x[4];
+ s->x[2] = ~s->x[2];
+ /* linear layer */
+ s->x[0] ^=
+ (s->x[0] >> 19) ^ (s->x[0] << 45) ^ (s->x[0] >> 28) ^ (s->x[0] << 36);
+ s->x[1] ^=
+ (s->x[1] >> 61) ^ (s->x[1] << 3) ^ (s->x[1] >> 39) ^ (s->x[1] << 25);
+ s->x[2] ^=
+ (s->x[2] >> 1) ^ (s->x[2] << 63) ^ (s->x[2] >> 6) ^ (s->x[2] << 58);
+ s->x[3] ^=
+ (s->x[3] >> 10) ^ (s->x[3] << 54) ^ (s->x[3] >> 17) ^ (s->x[3] << 47);
+ s->x[4] ^=
+ (s->x[4] >> 7) ^ (s->x[4] << 57) ^ (s->x[4] >> 41) ^ (s->x[4] << 23);
+ ascon_printstate(" round output", s);
+}
+
+forceinline void ASCON_PROUNDS(ascon_state_t* s, int nr) {
+ int i = ASCON_START(nr);
+ do {
+ ASCON_ROUND(s, ASCON_RC(i));
+ i += ASCON_INC;
+ } while (i != ASCON_END);
+}
+
+#endif /* ROUND32_H_ */
+/*** End of #include "round32.h" ***/
+
+#endif
+
+#endif
+/*** End of #include "round.h" ***/
+
+
+forceinline void ASCON_P12ROUNDS(ascon_state_t* s) {
+ ASCON_ROUND(s, ASCON_RC0);
+ ASCON_ROUND(s, ASCON_RC1);
+ ASCON_ROUND(s, ASCON_RC2);
+ ASCON_ROUND(s, ASCON_RC3);
+ ASCON_ROUND(s, ASCON_RC4);
+ ASCON_ROUND(s, ASCON_RC5);
+ ASCON_ROUND(s, ASCON_RC6);
+ ASCON_ROUND(s, ASCON_RC7);
+ ASCON_ROUND(s, ASCON_RC8);
+ ASCON_ROUND(s, ASCON_RC9);
+ ASCON_ROUND(s, ASCON_RCa);
+ ASCON_ROUND(s, ASCON_RCb);
+}
+
+forceinline void ASCON_P8ROUNDS(ascon_state_t* s) {
+ ASCON_ROUND(s, ASCON_RC4);
+ ASCON_ROUND(s, ASCON_RC5);
+ ASCON_ROUND(s, ASCON_RC6);
+ ASCON_ROUND(s, ASCON_RC7);
+ ASCON_ROUND(s, ASCON_RC8);
+ ASCON_ROUND(s, ASCON_RC9);
+ ASCON_ROUND(s, ASCON_RCa);
+ ASCON_ROUND(s, ASCON_RCb);
+}
+
+forceinline void ASCON_P6ROUNDS(ascon_state_t* s) {
+ ASCON_ROUND(s, ASCON_RC6);
+ ASCON_ROUND(s, ASCON_RC7);
+ ASCON_ROUND(s, ASCON_RC8);
+ ASCON_ROUND(s, ASCON_RC9);
+ ASCON_ROUND(s, ASCON_RCa);
+ ASCON_ROUND(s, ASCON_RCb);
+}
+
+#if ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
+
+forceinline void ASCON_P(ascon_state_t* s, int nr) {
+ if (nr == 12) ASCON_P12ROUNDS(s);
+ if (nr == 8) ASCON_P8ROUNDS(s);
+ if (nr == 6) ASCON_P6ROUNDS(s);
+}
+
+#elif !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
+
+void ASCON_P12(ascon_state_t* s);
+void ASCON_P8(ascon_state_t* s);
+void ASCON_P6(ascon_state_t* s);
+
+forceinline void ASCON_P(ascon_state_t* s, int nr) {
+ if (nr == 12) ASCON_P12(s);
+ if (nr == 8) ASCON_P8(s);
+ if (nr == 6) ASCON_P6(s);
+}
+
+#elif ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS
+
+forceinline void ASCON_P(ascon_state_t* s, int nr) { ASCON_PROUNDS(s, nr); }
+
+#else /* !ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS */
+
+void ASCON_P(ascon_state_t* s, int nr);
+
+#endif
+
+#endif /* PERMUTATIONS_H_ */
+/*** End of #include "permutations.h" ***/
+
+/* #include "printstate.h" */
+
+
+#if !ASCON_INLINE_MODE
+#undef forceinline
+#define forceinline
+#endif
+
+#ifdef ASCON_AEAD_RATE
+
+forceinline void ascon_loadkey(ascon_key_t* key, const uint8_t* k) {
+#if CRYPTO_KEYBYTES == 16
+ key->x[0] = ASCON_LOAD(k, 8);
+ key->x[1] = ASCON_LOAD(k + 8, 8);
+#else /* CRYPTO_KEYBYTES == 20 */
+ key->x[0] = ASCON_KEYROT(0, ASCON_LOADBYTES(k, 4));
+ key->x[1] = ASCON_LOADBYTES(k + 4, 8);
+ key->x[2] = ASCON_LOADBYTES(k + 12, 8);
+#endif
+}
+
+forceinline void ascon_initaead(ascon_state_t* s, const ascon_key_t* key,
+ const uint8_t* npub) {
+#if CRYPTO_KEYBYTES == 16
+ if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
+ if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
+ s->x[1] = key->x[0];
+ s->x[2] = key->x[1];
+#else /* CRYPTO_KEYBYTES == 20 */
+ s->x[0] = key->x[0] ^ ASCON_80PQ_IV;
+ s->x[1] = key->x[1];
+ s->x[2] = key->x[2];
+#endif
+ s->x[3] = ASCON_LOAD(npub, 8);
+ s->x[4] = ASCON_LOAD(npub + 8, 8);
+ ascon_printstate("init 1st key xor", s);
+ ASCON_P(s, 12);
+#if CRYPTO_KEYBYTES == 16
+ s->x[3] ^= key->x[0];
+ s->x[4] ^= key->x[1];
+#else /* CRYPTO_KEYBYTES == 20 */
+ s->x[2] ^= key->x[0];
+ s->x[3] ^= key->x[1];
+ s->x[4] ^= key->x[2];
+#endif
+ ascon_printstate("init 2nd key xor", s);
+}
+
+forceinline void ascon_adata(ascon_state_t* s, const uint8_t* ad,
+ uint64_t adlen) {
+ const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
+ if (adlen) {
+ /* full associated data blocks */
+ while (adlen >= ASCON_AEAD_RATE) {
+ s->x[0] ^= ASCON_LOAD(ad, 8);
+ if (ASCON_AEAD_RATE == 16) s->x[1] ^= ASCON_LOAD(ad + 8, 8);
+ ascon_printstate("absorb adata", s);
+ ASCON_P(s, nr);
+ ad += ASCON_AEAD_RATE;
+ adlen -= ASCON_AEAD_RATE;
+ }
+ /* final associated data block */
+ uint64_t* px = &s->x[0];
+ if (ASCON_AEAD_RATE == 16 && adlen >= 8) {
+ s->x[0] ^= ASCON_LOAD(ad, 8);
+ px = &s->x[1];
+ ad += 8;
+ adlen -= 8;
+ }
+ *px ^= ASCON_PAD(adlen);
+ if (adlen) *px ^= ASCON_LOADBYTES(ad, adlen);
+ ascon_printstate("pad adata", s);
+ ASCON_P(s, nr);
+ }
+ /* domain separation */
+ s->x[4] ^= ASCON_DSEP();
+ ascon_printstate("domain separation", s);
+}
+
+forceinline void ascon_encrypt(ascon_state_t* s, uint8_t* c, const uint8_t* m,
+ uint64_t mlen) {
+ const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
+ /* full plaintext blocks */
+ while (mlen >= ASCON_AEAD_RATE) {
+ s->x[0] ^= ASCON_LOAD(m, 8);
+ ASCON_STORE(c, s->x[0], 8);
+ if (ASCON_AEAD_RATE == 16) {
+ s->x[1] ^= ASCON_LOAD(m + 8, 8);
+ ASCON_STORE(c + 8, s->x[1], 8);
+ }
+ ascon_printstate("absorb plaintext", s);
+ ASCON_P(s, nr);
+ m += ASCON_AEAD_RATE;
+ c += ASCON_AEAD_RATE;
+ mlen -= ASCON_AEAD_RATE;
+ }
+ /* final plaintext block */
+ uint64_t* px = &s->x[0];
+ if (ASCON_AEAD_RATE == 16 && mlen >= 8) {
+ s->x[0] ^= ASCON_LOAD(m, 8);
+ ASCON_STORE(c, s->x[0], 8);
+ px = &s->x[1];
+ m += 8;
+ c += 8;
+ mlen -= 8;
+ }
+ *px ^= ASCON_PAD(mlen);
+ if (mlen) {
+ *px ^= ASCON_LOADBYTES(m, mlen);
+ ASCON_STOREBYTES(c, *px, mlen);
+ }
+ ascon_printstate("pad plaintext", s);
+}
+
+forceinline void ascon_decrypt(ascon_state_t* s, uint8_t* m, const uint8_t* c,
+ uint64_t clen) {
+ const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
+ /* full ciphertext blocks */
+ while (clen >= ASCON_AEAD_RATE) {
+ uint64_t cx = ASCON_LOAD(c, 8);
+ s->x[0] ^= cx;
+ ASCON_STORE(m, s->x[0], 8);
+ s->x[0] = cx;
+ if (ASCON_AEAD_RATE == 16) {
+ cx = ASCON_LOAD(c + 8, 8);
+ s->x[1] ^= cx;
+ ASCON_STORE(m + 8, s->x[1], 8);
+ s->x[1] = cx;
+ }
+ ascon_printstate("insert ciphertext", s);
+ ASCON_P(s, nr);
+ m += ASCON_AEAD_RATE;
+ c += ASCON_AEAD_RATE;
+ clen -= ASCON_AEAD_RATE;
+ }
+ /* final ciphertext block */
+ uint64_t* px = &s->x[0];
+ if (ASCON_AEAD_RATE == 16 && clen >= 8) {
+ uint64_t cx = ASCON_LOAD(c, 8);
+ s->x[0] ^= cx;
+ ASCON_STORE(m, s->x[0], 8);
+ s->x[0] = cx;
+ px = &s->x[1];
+ m += 8;
+ c += 8;
+ clen -= 8;
+ }
+ *px ^= ASCON_PAD(clen);
+ if (clen) {
+ uint64_t cx = ASCON_LOADBYTES(c, clen);
+ *px ^= cx;
+ ASCON_STOREBYTES(m, *px, clen);
+ *px = ASCON_CLEAR(*px, clen);
+ *px ^= cx;
+ }
+ ascon_printstate("pad ciphertext", s);
+}
+
+forceinline void ascon_final(ascon_state_t* s, const ascon_key_t* key) {
+#if CRYPTO_KEYBYTES == 16
+ if (ASCON_AEAD_RATE == 8) {
+ s->x[1] ^= key->x[0];
+ s->x[2] ^= key->x[1];
+ } else {
+ s->x[2] ^= key->x[0];
+ s->x[3] ^= key->x[1];
+ }
+#else /* CRYPTO_KEYBYTES == 20 */
+ s->x[1] ^= KEYROT(key->x[0], key->x[1]);
+ s->x[2] ^= KEYROT(key->x[1], key->x[2]);
+ s->x[3] ^= KEYROT(key->x[2], 0);
+#endif
+ ascon_printstate("final 1st key xor", s);
+ ASCON_P(s, 12);
+#if CRYPTO_KEYBYTES == 16
+ s->x[3] ^= key->x[0];
+ s->x[4] ^= key->x[1];
+#else /* CRYPTO_KEYBYTES == 20 */
+ s->x[3] ^= key->x[1];
+ s->x[4] ^= key->x[2];
+#endif
+ ascon_printstate("final 2nd key xor", s);
+}
+
+SQLITE_PRIVATE
+int ascon_aead_encrypt(uint8_t* ctext,
+ uint8_t tag[ASCON_AEAD_TAG_LEN],
+ const uint8_t* mtext, uint64_t mlen,
+ const uint8_t* ad, uint64_t adlen,
+ const uint8_t nonce[ASCON_AEAD_NONCE_LEN],
+ const uint8_t k[ASCON_AEAD_KEY_LEN])
+{
+ ascon_state_t s;
+ /* perform ascon computation */
+ ascon_key_t key;
+ ascon_loadkey(&key, k);
+ ascon_initaead(&s, &key, nonce);
+ ascon_adata(&s, ad, adlen);
+ ascon_encrypt(&s, ctext, mtext, mlen);
+ ascon_final(&s, &key);
+ /* set tag */
+ ASCON_STOREBYTES(tag, s.x[3], 8);
+ ASCON_STOREBYTES(tag + 8, s.x[4], 8);
+ wx_sqlite3mcSecureZeroMemory(&s, sizeof(ascon_state_t));
+ wx_sqlite3mcSecureZeroMemory(&key, sizeof(ascon_key_t));
+ return 0;
+}
+
+SQLITE_PRIVATE
+int ascon_aead_decrypt(uint8_t* mtext,
+ const uint8_t* ctext, uint64_t clen,
+ const uint8_t* ad, uint64_t adlen,
+ const uint8_t tag[ASCON_AEAD_TAG_LEN],
+ const uint8_t nonce[ASCON_AEAD_NONCE_LEN],
+ const uint8_t k[ASCON_AEAD_KEY_LEN])
+{
+ int rc = 0;
+ ascon_state_t s;
+ if (clen < CRYPTO_ABYTES) return -1;
+ /* perform ascon computation */
+ ascon_key_t key;
+ ascon_loadkey(&key, k);
+ ascon_initaead(&s, &key, nonce);
+ ascon_adata(&s, ad, adlen);
+ ascon_decrypt(&s, mtext, ctext, clen);
+ ascon_final(&s, &key);
+ /* verify tag (should be constant time, check compiler output) */
+ s.x[3] ^= ASCON_LOADBYTES(tag, 8);
+ s.x[4] ^= ASCON_LOADBYTES(tag + 8, 8);
+ rc = ASCON_NOTZERO(s.x[3], s.x[4]);
+ wx_sqlite3mcSecureZeroMemory(&s, sizeof(ascon_state_t));
+ wx_sqlite3mcSecureZeroMemory(&key, sizeof(ascon_key_t));
+ return rc;
+}
+
+#endif
+/*** End of #include "ascon/aead.c" ***/
+
+/* #include "ascon/hash.c" */
+/*** Begin of #include "ascon/hash.c" ***/
+/*
+** Name: hash.c
+** Purpose: Hash algorithm with Ascon
+** Based on: Public domain Ascon reference implementation
+** and optimized variants for 32- and 64-bit
+** (see https://github.com/ascon/ascon-c)
+** Remarks: API functions adapted for use in SQLite3 Multiple Ciphers
+** Modified by: Ulrich Telle
+** Copyright: (c) 2023-2023 Ulrich Telle
+** License: MIT
+*/
+
+/* #include "api.h" */
+
+/* #include "ascon.h" */
+
+/* #include "crypto_hash.h" */
+/*** Begin of #include "crypto_hash.h" ***/
+/*
+** Name: hash.c
+** Purpose: API definition for Hash algorithm with Ascon
+** Based on: Public domain Ascon reference implementation
+** and optimized variants for 32- and 64-bit
+** (see https://github.com/ascon/ascon-c)
+** Remarks: API functions adapted for use in SQLite3 Multiple Ciphers
+** Modified by: Ulrich Telle
+** Copyright: (c) 2023-2023 Ulrich Telle
+** License: MIT
+*/
+
+#ifndef CRYPTO_HASH_H
+#define CRYPTO_HASH_H
+
+#ifndef SQLITE_PRIVATE
+#define SQLITE_PRIVATE
+#endif
+
+#include <stddef.h>
+
+/*
+** Derives hash value using ASCON-HASH.
+**
+** \param out Output buffer for hash with fixed length of ASCON_HASH_BYTES
+** \param in Buffer with input data
+** \param passwordlen Length of input data in bytes
+*/
+SQLITE_PRIVATE
+int ascon_hash(uint8_t* out, const uint8_t* in, uint64_t inlen);
+
+#endif
+/*** End of #include "crypto_hash.h" ***/
+
+/* #include "permutations.h" */
+
+/* #include "printstate.h" */
+
+
+#if !ASCON_INLINE_MODE
+#undef forceinline
+#define forceinline
+#endif
+
+#ifdef ASCON_HASH_BYTES
+
+forceinline void ascon_inithash(ascon_state_t* s) {
+ int i;
+ /* initialize */
+#ifdef ASCON_PRINT_STATE
+#if ASCON_HASH_BYTES == 32 && ASCON_HASH_ROUNDS == 12
+ s->x[0] = ASCON_HASH_IV;
+#elif ASCON_HASH_BYTES == 32 && ASCON_HASH_ROUNDS == 8
+ s->x[0] = ASCON_HASHA_IV;
+#elif ASCON_HASH_BYTES == 0 && ASCON_HASH_ROUNDS == 12
+ s->x[0] = ASCON_XOF_IV;
+#elif ASCON_HASH_BYTES == 0 && ASCON_HASH_ROUNDS == 8
+ s->x[0] = ASCON_XOFA_IV;
+#endif
+ for (i = 1; i < 5; ++i) s->x[i] = 0;
+ ascon_printstate("initial value", s);
+ ASCON_P(s, 12);
+#endif
+#if ASCON_HASH_BYTES == 32 && ASCON_HASH_ROUNDS == 12
+ const uint64_t iv[5] = {ASCON_HASH_IV0, ASCON_HASH_IV1, ASCON_HASH_IV2,
+ ASCON_HASH_IV3, ASCON_HASH_IV4};
+#elif ASCON_HASH_BYTES == 32 && ASCON_HASH_ROUNDS == 8
+ const uint64_t iv[5] = {ASCON_HASHA_IV0, ASCON_HASHA_IV1, ASCON_HASHA_IV2,
+ ASCON_HASHA_IV3, ASCON_HASHA_IV4};
+#elif ASCON_HASH_BYTES == 0 && ASCON_HASH_ROUNDS == 12
+ const uint64_t iv[5] = {ASCON_XOF_IV0, ASCON_XOF_IV1, ASCON_XOF_IV2,
+ ASCON_XOF_IV3, ASCON_XOF_IV4};
+#elif ASCON_HASH_BYTES == 0 && ASCON_HASH_ROUNDS == 8
+ const uint64_t iv[5] = {ASCON_XOFA_IV0, ASCON_XOFA_IV1, ASCON_XOFA_IV2,
+ ASCON_XOFA_IV3, ASCON_XOFA_IV4};
+#endif
+ for (i = 0; i < 5; ++i) s->x[i] = (iv[i]);
+ ascon_printstate("initialization", s);
+}
+
+forceinline void ascon_absorb(ascon_state_t* s, const uint8_t* in,
+ uint64_t inlen) {
+ /* absorb full plaintext blocks */
+ while (inlen >= ASCON_HASH_RATE) {
+ s->x[0] ^= ASCON_LOAD(in, 8);
+ ascon_printstate("absorb plaintext", s);
+ ASCON_P(s, ASCON_HASH_ROUNDS);
+ in += ASCON_HASH_RATE;
+ inlen -= ASCON_HASH_RATE;
+ }
+ /* absorb final plaintext block */
+ s->x[0] ^= ASCON_LOADBYTES(in, inlen);
+ s->x[0] ^= ASCON_PAD(inlen);
+ ascon_printstate("pad plaintext", s);
+}
+
+forceinline void ascon_squeeze(ascon_state_t* s, uint8_t* out,
+ uint64_t outlen) {
+ /* squeeze full output blocks */
+ ASCON_P(s, 12);
+ while (outlen > ASCON_HASH_RATE) {
+ ASCON_STORE(out, s->x[0], 8);
+ ascon_printstate("squeeze output", s);
+ ASCON_P(s, ASCON_HASH_ROUNDS);
+ out += ASCON_HASH_RATE;
+ outlen -= ASCON_HASH_RATE;
+ }
+ /* squeeze final output block */
+ ASCON_STOREBYTES(out, s->x[0], outlen);
+ ascon_printstate("squeeze output", s);
+}
+
+SQLITE_PRIVATE
+int ascon_hash(uint8_t* out, const uint8_t* in, uint64_t inlen)
+{
+ ascon_state_t s;
+ ascon_inithash(&s);
+ ascon_absorb(&s, in, inlen);
+ ascon_squeeze(&s, out, ASCON_HASH_BYTES);
+ wx_sqlite3mcSecureZeroMemory(&s, sizeof(ascon_state_t));
+ return 0;
+}
+
+#endif
+/*** End of #include "ascon/hash.c" ***/
+
+/* #include "ascon/pbkdf2.c" */
+/*** Begin of #include "ascon/pbkdf2.c" ***/
+/*
+** Name: pbkdf2.c
+** Purpose: Implementation of PBKDF2 algoritm with Ascon
+** Based on: Public domain Ascon reference implementation
+** and optimized variants for 32- and 64-bit
+** (see https://github.com/ascon/ascon-c)
+** and the paper "Additional Modes for ASCON Version 1.1"
+** by Rhys Weatherley, Southern Storm Software, Pty Ltd.
+** Remarks: API functions adapted for use in SQLite3 Multiple Ciphers
+** Created by: Ulrich Telle
+** Copyright: (c) 2023-2023 Ulrich Telle
+** License: MIT
+*/
+
+#define ASCON_HASH_SIZE 32
+#define ASCON_PBKDF2_SIZE 32
+
+SQLITE_PRIVATE
+void ascon_pbkdf2_init(ascon_state_t* state, const char* functionName,
+ const unsigned char* custom, uint32_t customlen, uint32_t outlen)
+{
+ /* Format the initial block with the function name and output length */
+ uint8_t initial[ASCON_HASH_SIZE];
+ size_t fnLength = functionName ? strlen(functionName) : 0;
+
+ if (fnLength == 0)
+ {
+ /* No function name specified */
+ memset(initial, 0, ASCON_HASH_SIZE);
+ }
+ else if (fnLength <= ASCON_HASH_SIZE)
+ {
+ /* Pad the function name with zeroes */
+ memcpy(initial, functionName, fnLength);
+ memset(initial + fnLength, 0, ASCON_HASH_SIZE - fnLength);
+ }
+ else
+ {
+ ascon_hash(initial, (const uint8_t*) functionName, fnLength);
+ }
+
+ state->x[0] = ASCON_HASH_IV;
+ state->x[1] = ASCON_LOAD(initial, 8);
+ state->x[2] = ASCON_LOAD(initial + 8, 8);
+ state->x[3] = ASCON_LOAD(initial + 16, 8);
+ state->x[4] = ASCON_LOAD(initial + 24, 8);
+ ASCON_P(state, 12);
+
+ if (customlen > 0)
+ {
+ ascon_absorb(state, custom, customlen);
+ ASCON_P(state, 12);
+ /* domain separation */
+ state->x[4] ^= 1;
+ }
+}
+
+/*
+ * Implementation of the "F" function from RFC 8018, section 5.2
+ *
+ * Note: Instead of HMAC like in RFC 8018, use the following PRF:
+ * PRF(P, X) = ASCON-cXOF(X, 256, "PBKDF2", P)
+ */
+static
+void ascon_pbkdf2_f(ascon_state_t* state,
+ uint8_t* T, /*uint8_t* U,*/
+ const uint8_t* salt, uint32_t saltlen,
+ uint32_t count, uint32_t blocknum)
+{
+ uint32_t asconSaltLen = (saltlen < ASCON_SALT_LEN) ? saltlen : ASCON_SALT_LEN;
+ uint8_t temp[ASCON_SALT_LEN+4];
+ ascon_state_t state2;
+ int j;
+
+ memset(temp, 0, ASCON_SALT_LEN);
+ memcpy(temp, salt, asconSaltLen);
+ STORE32_BE(temp+ASCON_SALT_LEN, blocknum);
+
+ /* Copy initial state */
+ for (j = 0; j < 5; ++j) state2.x[j] = state->x[j];
+
+ ascon_absorb(&state2, temp, ASCON_SALT_LEN+4);
+ ascon_squeeze(&state2, T, ASCON_PBKDF2_SIZE);
+ wx_sqlite3mcSecureZeroMemory(temp, sizeof(temp));
+
+ if (count > 1)
+ {
+ uint8_t U[ASCON_PBKDF2_SIZE];
+ memcpy(U, T, ASCON_PBKDF2_SIZE);
+ while (count > 1)
+ {
+ uint8_t* dst = T;
+ uint8_t* src = U;
+ uint32_t len = ASCON_PBKDF2_SIZE;
+ /* Copy initial state */
+ for (j = 0; j < 5; ++j) state2.x[j] = state->x[j];
+ /* Absorb U */
+ ascon_absorb(&state2, U, ASCON_PBKDF2_SIZE);
+ /* Squeeze next U */
+ ascon_squeeze(&state2, U, ASCON_PBKDF2_SIZE);
+ /* XOR T with U */
+ while (len > 0)
+ {
+ *dst++ ^= *src++;
+ --len;
+ }
+ --count;
+ }
+ wx_sqlite3mcSecureZeroMemory(U, sizeof(U));
+ }
+ wx_sqlite3mcSecureZeroMemory(&state2, sizeof(ascon_state_t));
+}
+
+SQLITE_PRIVATE
+void ascon_pbkdf2(uint8_t* out, uint32_t outlen,
+ const uint8_t* password, uint32_t passwordlen,
+ const uint8_t* salt, uint32_t saltlen, uint32_t count)
+{
+ ascon_state_t state;
+ uint32_t blocknum = 1;
+ ascon_pbkdf2_init(&state, "PBKDF2", password, passwordlen, ASCON_PBKDF2_SIZE);
+ while (outlen > 0)
+ {
+ if (outlen >= ASCON_PBKDF2_SIZE)
+ {
+ ascon_pbkdf2_f(&state, out, /*U,*/ salt, saltlen, count, blocknum);
+ out += ASCON_PBKDF2_SIZE;
+ outlen -= ASCON_PBKDF2_SIZE;
+ }
+ else
+ {
+ uint8_t T[ASCON_PBKDF2_SIZE];
+ ascon_pbkdf2_f(&state, T, /*U,*/ salt, saltlen, count, blocknum);
+ memcpy(out, T, outlen);
+ wx_sqlite3mcSecureZeroMemory(T, sizeof(T));
+ break;
+ }
+ ++blocknum;
+ }
+}
+/*** End of #include "ascon/pbkdf2.c" ***/
+
+
+SQLITE_PRIVATE CipherParams mcAscon128Params[] =
+{
+ { "kdf_iter", ASCON128_KDF_ITER_DEFAULT, ASCON128_KDF_ITER_DEFAULT, 1, 0x7fffffff },
+ CIPHER_PARAMS_SENTINEL
+};
+
+#define KEYLENGTH_ASCON128 32
+#define SALTLENGTH_ASCON128 16
+#define PAGE_NONCE_LEN_ASCON128 16
+#define PAGE_TAG_LEN_ASCON128 16
+#define PAGE_RESERVED_ASCON128 (PAGE_NONCE_LEN_ASCON128 + PAGE_TAG_LEN_ASCON128)
+
+typedef struct _ascon128Cipher
+{
+ int m_kdfIter;
+ int m_keyLength;
+ uint8_t m_key[KEYLENGTH_ASCON128];
+ uint8_t m_salt[SALTLENGTH_ASCON128];
+} Ascon128Cipher;
+
+static void*
+AllocateAscon128Cipher(wx_sqlite3* db)
+{
+ Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) wx_sqlite3_malloc(sizeof(Ascon128Cipher));
+ if (ascon128Cipher != NULL)
+ {
+ memset(ascon128Cipher, 0, sizeof(Ascon128Cipher));
+ ascon128Cipher->m_keyLength = KEYLENGTH_ASCON128;
+ memset(ascon128Cipher->m_key, 0, KEYLENGTH_ASCON128);
+ memset(ascon128Cipher->m_salt, 0, SALTLENGTH_ASCON128);
+ }
+ if (ascon128Cipher != NULL)
+ {
+ CipherParams* cipherParams = wx_sqlite3mcGetCipherParams(db, CIPHER_NAME_ASCON128);
+ ascon128Cipher->m_kdfIter = wx_sqlite3mcGetCipherParameter(cipherParams, "kdf_iter");
+ }
+ return ascon128Cipher;
+}
+
+static void
+FreeAscon128Cipher(void* cipher)
+{
+ Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) cipher;
+ memset(ascon128Cipher, 0, sizeof(Ascon128Cipher));
+ wx_sqlite3_free(ascon128Cipher);
+}
+
+static void
+CloneAscon128Cipher(void* cipherTo, void* cipherFrom)
+{
+ Ascon128Cipher* ascon128CipherTo = (Ascon128Cipher*) cipherTo;
+ Ascon128Cipher* ascon128CipherFrom = (Ascon128Cipher*) cipherFrom;
+ ascon128CipherTo->m_kdfIter = ascon128CipherFrom->m_kdfIter;
+ ascon128CipherTo->m_keyLength = ascon128CipherFrom->m_keyLength;
+ memcpy(ascon128CipherTo->m_key, ascon128CipherFrom->m_key, KEYLENGTH_ASCON128);
+ memcpy(ascon128CipherTo->m_salt, ascon128CipherFrom->m_salt, SALTLENGTH_ASCON128);
+}
+
+static int
+GetLegacyAscon128Cipher(void* cipher)
+{
+ Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*)cipher;
+ return 0;
+}
+
+static int
+GetPageSizeAscon128Cipher(void* cipher)
+{
+ Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) cipher;
+ int pageSize = 0;
+ return pageSize;
+}
+
+static int
+GetReservedAscon128Cipher(void* cipher)
+{
+ return PAGE_RESERVED_ASCON128;
+}
+
+static unsigned char*
+GetSaltAscon128Cipher(void* cipher)
+{
+ Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) cipher;
+ return ascon128Cipher->m_salt;
+}
+
+static void
+GenerateKeyAscon128Cipher(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt)
+{
+ Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) cipher;
+ int bypass = 0;
+
+ int keyOnly = 1;
+ if (rekey || cipherSalt == NULL)
+ {
+ chacha20_rng(ascon128Cipher->m_salt, SALTLENGTH_ASCON128);
+ keyOnly = 0;
+ }
+ else
+ {
+ memcpy(ascon128Cipher->m_salt, cipherSalt, SALTLENGTH_ASCON128);
+ }
+
+ /* Bypass key derivation if the key string starts with "raw:" */
+ if (passwordLength > 4 && !memcmp(userPassword, "raw:", 4))
+ {
+ const int nRaw = passwordLength - 4;
+ const unsigned char* zRaw = (const unsigned char*) userPassword + 4;
+ switch (nRaw)
+ {
+ /* Binary key (and salt) */
+ case KEYLENGTH_ASCON128 + SALTLENGTH_ASCON128:
+ if (!keyOnly)
+ {
+ memcpy(ascon128Cipher->m_salt, zRaw + KEYLENGTH_ASCON128, SALTLENGTH_ASCON128);
+ }
+ /* fall-through */
+ case KEYLENGTH_ASCON128:
+ memcpy(ascon128Cipher->m_key, zRaw, KEYLENGTH_ASCON128);
+ bypass = 1;
+ break;
+
+ /* Hex-encoded key */
+ case 2 * KEYLENGTH_ASCON128:
+ if (wx_sqlite3mcIsHexKey(zRaw, nRaw) != 0)
+ {
+ wx_sqlite3mcConvertHex2Bin(zRaw, nRaw, ascon128Cipher->m_key);
+ bypass = 1;
+ }
+ break;
+
+ /* Hex-encoded key and salt */
+ case 2 * (KEYLENGTH_ASCON128 + SALTLENGTH_ASCON128):
+ if (wx_sqlite3mcIsHexKey(zRaw, nRaw) != 0)
+ {
+ wx_sqlite3mcConvertHex2Bin(zRaw, 2 * KEYLENGTH_ASCON128, ascon128Cipher->m_key);
+ if (!keyOnly)
+ {
+ wx_sqlite3mcConvertHex2Bin(zRaw + 2 * KEYLENGTH_ASCON128, 2 * SALTLENGTH_ASCON128, ascon128Cipher->m_salt);
+ }
+ bypass = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!bypass)
+ {
+ ascon_pbkdf2(ascon128Cipher->m_key, KEYLENGTH_ASCON128,
+ (const uint8_t*) userPassword, passwordLength,
+ ascon128Cipher->m_salt, SALTLENGTH_ASCON128, ascon128Cipher->m_kdfIter);
+ }
+ SQLITE3MC_DEBUG_LOG("generate: codec=%p pFile=%p\n", ascon128Cipher, fd);
+ SQLITE3MC_DEBUG_HEX("generate key:", ascon128Cipher->m_key, KEYLENGTH_ASCON128);
+ SQLITE3MC_DEBUG_HEX("generate salt:", ascon128Cipher->m_salt, SALTLENGTH_ASCON128);
+}
+
+static int
+AsconGenOtk(uint8_t* out, const uint8_t* key, const uint8_t* nonce, int page)
+{
+ ascon_state_t s;
+ uint8_t temp[KEYLENGTH_ASCON128+PAGE_NONCE_LEN_ASCON128+4];
+ memcpy(temp, key, KEYLENGTH_ASCON128);
+ memcpy(temp+KEYLENGTH_ASCON128, nonce, PAGE_NONCE_LEN_ASCON128);
+ STORE32_BE(temp+KEYLENGTH_ASCON128+PAGE_NONCE_LEN_ASCON128, page);
+ ascon_inithash(&s);
+ ascon_absorb(&s, temp, KEYLENGTH_ASCON128+PAGE_NONCE_LEN_ASCON128+4);
+ ascon_squeeze(&s, out, ASCON_HASH_BYTES);
+ wx_sqlite3mcSecureZeroMemory(temp, sizeof(temp));
+ return 0;
+}
+
+static int
+EncryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, int reserved)
+{
+ Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) cipher;
+ int rc = SQLITE_OK;
+ int nReserved = (reserved == 0) ? 0 : GetReservedAscon128Cipher(cipher);
+ int n = len - nReserved;
+ uint64_t mlen = n;
+
+ /* Generate one-time keys */
+ uint8_t otk[ASCON_HASH_BYTES];
+ int offset;
+
+ /* Check whether number of required reserved bytes and actually reserved bytes match */
+ if (nReserved > reserved)
+ {
+ return SQLITE_CORRUPT;
+ }
+
+ if (nReserved > 0)
+ {
+ /* Encrypt and authenticate */
+ memset(otk, 0, ASCON_HASH_BYTES);
+ /* Generate nonce */
+ chacha20_rng(data + n + PAGE_TAG_LEN_ASCON128, PAGE_NONCE_LEN_ASCON128);
+ AsconGenOtk(otk, ascon128Cipher->m_key, data + n + PAGE_TAG_LEN_ASCON128, page);
+
+ offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
+ ascon_aead_encrypt(data + offset, data + n, data + offset, mlen - offset,
+ NULL /* ad */, 0 /* adlen*/,
+ data + n + PAGE_TAG_LEN_ASCON128, otk);
+ if (page == 1)
+ {
+ memcpy(data, ascon128Cipher->m_salt, SALTLENGTH_ASCON128);
+ }
+ }
+ else
+ {
+ /* Encrypt only */
+ uint8_t nonce[PAGE_NONCE_LEN_ASCON128];
+ uint8_t dummyTag[PAGE_TAG_LEN_ASCON128];
+ memset(dummyTag, 0, PAGE_TAG_LEN_ASCON128);
+ memset(otk, 0, ASCON_HASH_BYTES);
+ wx_sqlite3mcGenerateInitialVector(page, nonce);
+ AsconGenOtk(otk, ascon128Cipher->m_key, nonce, page);
+
+ /* Encrypt */
+ offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
+ ascon_aead_encrypt(data + offset, dummyTag, data + offset, mlen - offset,
+ NULL /* ad */, 0 /* adlen*/,
+ nonce, otk);
+ if (page == 1)
+ {
+ memcpy(data, ascon128Cipher->m_salt, SALTLENGTH_ASCON128);
+ }
+ }
+
+ return rc;
+}
+
+static int
+DecryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, int reserved, int hmacCheck)
+{
+ Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) cipher;
+ int rc = SQLITE_OK;
+ int nReserved = (reserved == 0) ? 0 : GetReservedAscon128Cipher(cipher);
+ int n = len - nReserved;
+ uint64_t clen = n;
+ int tagOk;
+
+ /* Generate one-time keys */
+ uint8_t otk[ASCON_HASH_BYTES];
+ int offset;
+
+ /* Check whether number of required reserved bytes and actually reserved bytes match */
+ if (nReserved > reserved)
+ {
+ return (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT;
+ }
+
+ if (nReserved > 0)
+ {
+ /* Decrypt and verify MAC */
+ memset(otk, 0, ASCON_HASH_BYTES);
+ AsconGenOtk(otk, ascon128Cipher->m_key, data + n + PAGE_TAG_LEN_ASCON128, page);
+
+ /* Determine MAC and decrypt */
+ offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
+ tagOk = ascon_aead_decrypt(data + offset, data + offset, clen - offset,
+ NULL /* ad */, 0 /* adlen */,
+ data + n, data + n + PAGE_TAG_LEN_ASCON128, otk);
+ if (hmacCheck != 0)
+ {
+ /* Verify the MAC */
+ if (tagOk != 0)
+ {
+ SQLITE3MC_DEBUG_LOG("decrypt: codec=%p page=%d\n", ascon128Cipher, page);
+ SQLITE3MC_DEBUG_HEX("decrypt key:", ascon128Cipher->m_key, 32);
+ SQLITE3MC_DEBUG_HEX("decrypt otk:", otk, 64);
+ SQLITE3MC_DEBUG_HEX("decrypt data+00:", data, 16);
+ SQLITE3MC_DEBUG_HEX("decrypt data+24:", data + 24, 16);
+ SQLITE3MC_DEBUG_HEX("decrypt data+n:", data + n, 16);
+ SQLITE3MC_DEBUG_HEX("decrypt tag r:", data + n + PAGE_NONCE_LEN_ASCON128, PAGE_TAG_LEN_ASCON128);
+ SQLITE3MC_DEBUG_HEX("decrypt tag c:", tag, PAGE_TAG_LEN_ASCON128);
+ /* Bad MAC */
+ rc = (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT;
+ }
+ }
+ if (page == 1 && rc == SQLITE_OK)
+ {
+ memcpy(data, SQLITE_FILE_HEADER, 16);
+ }
+ }
+ else
+ {
+ /* Decrypt only */
+ uint8_t nonce[PAGE_NONCE_LEN_ASCON128];
+ uint8_t dummyTag[PAGE_TAG_LEN_ASCON128];
+ memset(dummyTag, 0, PAGE_TAG_LEN_ASCON128);
+ memset(otk, 0, ASCON_HASH_BYTES);
+ wx_sqlite3mcGenerateInitialVector(page, nonce);
+ AsconGenOtk(otk, ascon128Cipher->m_key, nonce, page);
+
+ /* Decrypt */
+ offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0;
+ tagOk = ascon_aead_decrypt(data + offset, data + offset, clen - offset,
+ NULL /* ad */, 0 /* adlen */,
+ dummyTag, nonce, otk);
+ if (page == 1)
+ {
+ memcpy(data, SQLITE_FILE_HEADER, 16);
+ }
+ }
+
+ return rc;
+}
+
+SQLITE_PRIVATE const CipherDescriptor mcAscon128Descriptor =
+{
+ CIPHER_NAME_ASCON128,
+ AllocateAscon128Cipher,
+ FreeAscon128Cipher,
+ CloneAscon128Cipher,
+ GetLegacyAscon128Cipher,
+ GetPageSizeAscon128Cipher,
+ GetReservedAscon128Cipher,
+ GetSaltAscon128Cipher,
+ GenerateKeyAscon128Cipher,
+ EncryptPageAscon128Cipher,
+ DecryptPageAscon128Cipher
+};
+#endif
+/*** End of #include "cipher_ascon.c" ***/
+
/* #include "cipher_common.c" */
/*** Begin of #include "cipher_common.c" ***/
/*
@@ -267015,7 +284666,7 @@ SQLITE_PRIVATE const CipherDescriptor mcRC4Descriptor =
** Purpose: Implementation of SQLite codecs
** Author: Ulrich Telle
** Created: 2020-02-02
-** Copyright: (c) 2006-2022 Ulrich Telle
+** Copyright: (c) 2006-2024 Ulrich Telle
** License: MIT
*/
@@ -267157,7 +284808,7 @@ wx_sqlite3mcGetCipherType(wx_sqlite3* db)
{
CodecParameter* codecParams = (db != NULL) ? wx_sqlite3mcGetCodecParams(db) : globalCodecParameterTable;
CipherParams* cipherParamTable = (codecParams != NULL) ? codecParams[0].m_params : commonParams;
- int cipherType = CODEC_TYPE;
+ int cipherType = CODEC_TYPE_UNKNOWN;
CipherParams* cipher = cipherParamTable;
for (; cipher->m_name[0] != 0; ++cipher)
{
@@ -267220,6 +284871,7 @@ wx_sqlite3mcCodecInit(Codec* codec)
memset(codec->m_page, 0, sizeof(codec->m_page));
codec->m_pageSize = 0;
codec->m_reserved = 0;
+ codec->m_lastError = SQLITE_OK;
codec->m_hasKeySalt = 0;
memset(codec->m_keySalt, 0, sizeof(codec->m_keySalt));
}
@@ -267258,6 +284910,10 @@ wx_sqlite3mcCodecSetup(Codec* codec, int cipherType, char* userPassword, int pas
{
int rc = SQLITE_OK;
CipherParams* globalParams = wx_sqlite3mcGetCipherParams(codec->m_db, CIPHER_NAME_GLOBAL);
+ if (cipherType <= CODEC_TYPE_UNKNOWN)
+ {
+ return SQLITE_ERROR;
+ }
codec->m_isEncrypted = 1;
codec->m_hmacCheck = wx_sqlite3mcGetCipherParameter(globalParams, "hmac_check");
codec->m_walLegacy = wx_sqlite3mcGetCipherParameter(globalParams, "mc_legacy_wal");
@@ -267283,6 +284939,10 @@ wx_sqlite3mcSetupWriteCipher(Codec* codec, int cipherType, char* userPassword, i
{
int rc = SQLITE_OK;
CipherParams* globalParams = wx_sqlite3mcGetCipherParams(codec->m_db, CIPHER_NAME_GLOBAL);
+ if (cipherType <= CODEC_TYPE_UNKNOWN)
+ {
+ return SQLITE_ERROR;
+ }
if (codec->m_writeCipher != NULL)
{
globalCodecDescriptorTable[codec->m_writeCipherType-1].m_freeCipher(codec->m_writeCipher);
@@ -267427,7 +285087,7 @@ wx_sqlite3mcGetLegacyWriteCipher(Codec* codec)
SQLITE_PRIVATE int
wx_sqlite3mcGetPageSizeReadCipher(Codec* codec)
{
- int pageSize = (codec->m_hasReadCipher && codec->m_readCipher != NULL) ? globalCodecDescriptorTable[codec->m_readCipherType - 1].m_getPageSize(codec->m_readCipher) : 0;
+ int pageSize = (codec->m_hasReadCipher && codec->m_readCipher != NULL) ? globalCodecDescriptorTable[codec->m_readCipherType - 1].m_getPageSize(codec->m_readCipher) : -1;
return pageSize;
}
@@ -267460,6 +285120,21 @@ wx_sqlite3mcReservedEqual(Codec* codec)
return (readReserved == writeReserved);
}
+SQLITE_PRIVATE void
+wx_sqlite3mcSetCodecLastError(Codec* codec, int error)
+{
+ if (codec)
+ {
+ codec->m_lastError = error;
+ }
+}
+
+SQLITE_PRIVATE int
+wx_sqlite3mcGetCodecLastError(Codec* codec)
+{
+ return codec ? codec->m_lastError : SQLITE_OK;
+}
+
SQLITE_PRIVATE unsigned char*
wx_sqlite3mcGetSaltWriteCipher(Codec* codec)
{
@@ -267513,6 +285188,9 @@ wx_sqlite3mcCodecCopy(Codec* codec, Codec* other)
codec->m_bt = other->m_bt;
#endif
codec->m_btShared = other->m_btShared;
+
+ codec->m_lastError = SQLITE_OK;
+
return rc;
}
@@ -267583,16 +285261,30 @@ wx_sqlite3mcPadPassword(char* password, int pswdlen, unsigned char pswd[32])
}
}
+SQLITE_PRIVATE unsigned char* mcReadDatabaseHeader(Codec* codec, unsigned char* dbHeader)
+{
+ Pager* pPager = codec->m_btShared->pPager;
+ wx_sqlite3_file* fd = (isOpen(pPager->fd)) ? pPager->fd : NULL;
+ if (fd == NULL || wx_sqlite3OsRead(fd, dbHeader, KEYSALT_LENGTH, 0) != SQLITE_OK)
+ return NULL;
+ else
+ return dbHeader;
+}
+
SQLITE_PRIVATE void
wx_sqlite3mcGenerateReadKey(Codec* codec, char* userPassword, int passwordLength, unsigned char* cipherSalt)
{
- globalCodecDescriptorTable[codec->m_readCipherType-1].m_generateKey(codec->m_readCipher, codec->m_btShared, userPassword, passwordLength, 0, cipherSalt);
+ unsigned char dbHeader[KEYSALT_LENGTH];
+ unsigned char* pDbHeader = (cipherSalt == NULL) ? mcReadDatabaseHeader(codec, dbHeader) : cipherSalt;
+ globalCodecDescriptorTable[codec->m_readCipherType-1].m_generateKey(codec->m_readCipher, userPassword, passwordLength, 0, pDbHeader);
}
SQLITE_PRIVATE void
wx_sqlite3mcGenerateWriteKey(Codec* codec, char* userPassword, int passwordLength, unsigned char* cipherSalt)
{
- globalCodecDescriptorTable[codec->m_writeCipherType-1].m_generateKey(codec->m_writeCipher, codec->m_btShared, userPassword, passwordLength, 1, cipherSalt);
+ unsigned char dbHeader[KEYSALT_LENGTH];
+ unsigned char* pDbHeader = (cipherSalt == NULL) ? mcReadDatabaseHeader(codec, dbHeader) : cipherSalt;
+ globalCodecDescriptorTable[codec->m_writeCipherType-1].m_generateKey(codec->m_writeCipher, userPassword, passwordLength, 1, pDbHeader);
}
SQLITE_PRIVATE int
@@ -267623,10 +285315,10 @@ wx_sqlite3mcConfigureSQLCipherVersion(wx_sqlite3* db, int configDefault, int leg
static char* defNames[] = { "default:legacy_page_size", "default:kdf_iter", "default:hmac_use", "default:kdf_algorithm", "default:hmac_algorithm", NULL };
static int versionParams[SQLCIPHER_VERSION_MAX][5] =
{
- { 1024, 4000, 0, SQLCIPHER_KDF_ALGORITHM_SHA1, SQLCIPHER_HMAC_ALGORITHM_SHA1 },
- { 1024, 4000, 1, SQLCIPHER_KDF_ALGORITHM_SHA1, SQLCIPHER_HMAC_ALGORITHM_SHA1 },
- { 1024, 64000, 1, SQLCIPHER_KDF_ALGORITHM_SHA1, SQLCIPHER_HMAC_ALGORITHM_SHA1 },
- { 4096, 256000, 1, SQLCIPHER_KDF_ALGORITHM_SHA512, SQLCIPHER_HMAC_ALGORITHM_SHA512 }
+ { 1024, 4000, 0, SQLCIPHER_ALGORITHM_SHA1, SQLCIPHER_ALGORITHM_SHA1 },
+ { 1024, 4000, 1, SQLCIPHER_ALGORITHM_SHA1, SQLCIPHER_ALGORITHM_SHA1 },
+ { 1024, 64000, 1, SQLCIPHER_ALGORITHM_SHA1, SQLCIPHER_ALGORITHM_SHA1 },
+ { 4096, 256000, 1, SQLCIPHER_ALGORITHM_SHA512, SQLCIPHER_ALGORITHM_SHA512 }
};
if (legacyVersion > 0 && legacyVersion <= SQLCIPHER_VERSION_MAX)
{
@@ -267650,7 +285342,7 @@ wx_sqlite3mcConfigureSQLCipherVersion(wx_sqlite3* db, int configDefault, int leg
** Purpose: Configuration of SQLite codecs
** Author: Ulrich Telle
** Created: 2020-03-02
-** Copyright: (c) 2006-2023 Ulrich Telle
+** Copyright: (c) 2006-2024 Ulrich Telle
** License: MIT
*/
@@ -267677,7 +285369,7 @@ SQLITE_PRIVATE void wx_sqlite3mcConfigTable(wx_sqlite3_context* context, int arg
SQLITE_PRIVATE CodecParameter* wx_sqlite3mcGetCodecParams(wx_sqlite3* db);
/* Forward declaration */
-static unsigned char* wx_sqlite3mcGetSaltWriteCipher(Codec* codec);
+SQLITE_PRIVATE unsigned char* wx_sqlite3mcGetSaltWriteCipher(Codec* codec);
SQLITE_PRIVATE void wx_sqlite3mcCodecDataSql(wx_sqlite3_context* context, int argc, wx_sqlite3_value** argv);
SQLITE_PRIVATE void wx_sqlite3mcConfigParams(wx_sqlite3_context* context, int argc, wx_sqlite3_value** argv);
@@ -267736,6 +285428,10 @@ wx_sqlite3mc_config(wx_sqlite3* db, const char* paramName, int newValue)
int hasMaxPrefix = 0;
CipherParams* param;
+#ifndef SQLITE_OMIT_AUTOINIT
+ if (wx_sqlite3_initialize()) return value;
+#endif
+
if (paramName == NULL || (db == NULL && newValue >= 0))
{
return value;
@@ -267816,14 +285512,22 @@ wx_sqlite3mc_config(wx_sqlite3* db, const char* paramName, int newValue)
SQLITE_API int
wx_sqlite3mc_cipher_count()
{
+#ifndef SQLITE_OMIT_AUTOINIT
+ if (wx_sqlite3_initialize()) return 0;
+#endif
return wx_sqlite3mcGetGlobalCipherCount();
}
SQLITE_API int
wx_sqlite3mc_cipher_index(const char* cipherName)
{
- int count = wx_sqlite3mcGetGlobalCipherCount();
- int j = 0;
+ int count;
+ int j;
+#ifndef SQLITE_OMIT_AUTOINIT
+ if (wx_sqlite3_initialize()) return -1;
+#endif
+ count = wx_sqlite3mcGetGlobalCipherCount();
+ j = 0;
for (j = 0; j < count && globalCodecDescriptorTable[j].m_name[0] != 0; ++j)
{
if (wx_sqlite3_stricmp(cipherName, globalCodecDescriptorTable[j].m_name) == 0) break;
@@ -267835,8 +285539,13 @@ SQLITE_API const char*
wx_sqlite3mc_cipher_name(int cipherIndex)
{
static char cipherName[CIPHER_NAME_MAXLEN] = "";
- int count = wx_sqlite3mcGetGlobalCipherCount();
- int j = 0;
+ int count;
+ int j;
+#ifndef SQLITE_OMIT_AUTOINIT
+ if( wx_sqlite3_initialize() ) return cipherName;
+#endif
+ count = wx_sqlite3mcGetGlobalCipherCount();
+ j = 0;
cipherName[0] = '\0';
if (cipherIndex > 0 && cipherIndex <= count)
{
@@ -267853,6 +285562,21 @@ wx_sqlite3mc_cipher_name(int cipherIndex)
return cipherName;
}
+static
+int checkParameterValue(const char* paramName, int value)
+{
+ int ok = 1;
+ if (wx_sqlite3_stricmp(paramName, "legacy_page_size") == 0 && value > 0)
+ {
+ ok = value >= 512 && value <= SQLITE_MAX_PAGE_SIZE && ((value - 1) & value) == 0;
+ }
+ if (ok && wx_sqlite3_stricmp(paramName, "plaintext_header_size") == 0 && value > 0)
+ {
+ ok = value % 16 == 0;
+ }
+ return ok;
+}
+
SQLITE_API int
wx_sqlite3mc_config_cipher(wx_sqlite3* db, const char* cipherName, const char* paramName, int newValue)
{
@@ -267861,6 +285585,10 @@ wx_sqlite3mc_config_cipher(wx_sqlite3* db, const char* cipherName, const char* p
CipherParams* cipherParamTable = NULL;
int j = 0;
+#ifndef SQLITE_OMIT_AUTOINIT
+ if (wx_sqlite3_initialize()) return value;
+#endif
+
if (cipherName == NULL || paramName == NULL)
{
wx_sqlite3_log(SQLITE_WARNING,
@@ -267928,7 +285656,7 @@ wx_sqlite3mc_config_cipher(wx_sqlite3* db, const char* cipherName, const char* p
{
wx_sqlite3mcConfigureSQLCipherVersion(db, hasDefaultPrefix, newValue);
}
- else
+ else if (newValue != -1)
{
wx_sqlite3_log(SQLITE_WARNING,
"wx_sqlite3mc_config_cipher: SQLCipher legacy version %d out of range [%d..%d]",
@@ -267955,7 +285683,8 @@ wx_sqlite3mc_config_cipher(wx_sqlite3* db, const char* cipherName, const char* p
value = (hasDefaultPrefix) ? param->m_default : (hasMinPrefix) ? param->m_minValue : (hasMaxPrefix) ? param->m_maxValue : param->m_value;
if (!hasMinPrefix && !hasMaxPrefix)
{
- if (newValue >= 0 && newValue >= param->m_minValue && newValue <= param->m_maxValue)
+ if (newValue >= 0 && newValue >= param->m_minValue && newValue <= param->m_maxValue &&
+ checkParameterValue(paramName, newValue))
{
if (hasDefaultPrefix)
{
@@ -267964,7 +285693,7 @@ wx_sqlite3mc_config_cipher(wx_sqlite3* db, const char* cipherName, const char* p
param->m_value = newValue;
value = newValue;
}
- else
+ else if (newValue != -1)
{
wx_sqlite3_log(SQLITE_WARNING,
"wx_sqlite3mc_config_cipher: Value %d for parameter '%s' of cipher '%s' out of range [%d..%d]",
@@ -267988,6 +285717,9 @@ SQLITE_API unsigned char*
wx_sqlite3mc_codec_data(wx_sqlite3* db, const char* zDbName, const char* paramName)
{
unsigned char* result = NULL;
+#ifndef SQLITE_OMIT_AUTOINIT
+ if (wx_sqlite3_initialize()) return NULL;
+#endif
if (db != NULL && paramName != NULL)
{
int iDb = (zDbName != NULL) ? wx_sqlite3FindDbName(db, zDbName) : 0;
@@ -268430,11 +286162,11 @@ wx_sqlite3mcConfigureFromUri(wx_sqlite3* db, const char *zDbName, int configDefa
if (value >= 0)
{
/* Configure cipher parameter if it was given in the URI */
- char* param = (configDefault) ? wx_sqlite3_mprintf("default:%s", cipherParams[j].m_name) : cipherParams[j].m_name;
+ const char* param = (configDefault) ? wx_sqlite3_mprintf("default:%s", cipherParams[j].m_name) : cipherParams[j].m_name;
wx_sqlite3mc_config_cipher(db, cipherName, param, value);
if (configDefault)
{
- wx_sqlite3_free(param);
+ wx_sqlite3_free((char*) param);
}
}
}
@@ -268641,6 +286373,54 @@ wx_sqlite3mcFileControlPragma(wx_sqlite3* db, const char* zDbName, int op, void*
((char**)pArg)[0] = wx_sqlite3_mprintf("Malformed hex string");
}
}
+#if SQLITE3MC_SECURE_MEMORY
+ else if (wx_sqlite3StrICmp(pragmaName, "memory_security") == 0)
+ {
+ if (pragmaValue)
+ {
+ int intValue = -1;
+ if (0 == wx_sqlite3StrICmp(pragmaValue, "none"))
+ {
+ intValue = SECURE_MEMORY_NONE;
+ }
+ else if (0 == wx_sqlite3StrICmp(pragmaValue, "fill") )
+ {
+ intValue = SECURE_MEMORY_FILL;
+ }
+#if SQLITE3MC_ENABLE_MEMLOCK
+ else if (0 == wx_sqlite3StrICmp(pragmaValue, "lock") )
+ {
+ intValue = SECURE_MEMORY_LOCK;
+ }
+#endif
+ else
+ {
+ intValue = wx_sqlite3Atoi(pragmaValue);
+#if SQLITE3MC_ENABLE_MEMLOCK
+ intValue = (intValue >=0 && intValue <= 2) ? intValue : -1;
+#else
+ intValue = (intValue >=0 && intValue <= 1) ? intValue : -1;
+#endif
+ }
+ if (intValue >= 0)
+ {
+ wx_sqlite3mcSetMemorySecurity(intValue);
+ rc = SQLITE_OK;
+ ((char**)pArg)[0] = wx_sqlite3_mprintf("%d", intValue);
+ }
+ else
+ {
+ rc = SQLITE_ERROR;
+ ((char**) pArg)[0] = wx_sqlite3_mprintf("Secure memory option '%s' invalid.", pragmaValue);
+ }
+ }
+ else
+ {
+ rc = SQLITE_OK;
+ ((char**)pArg)[0] = wx_sqlite3_mprintf("%d", wx_sqlite3mcGetMemorySecurity());
+ }
+ }
+#endif /* SQLITE3MC_SECURE_MEMORY */
else
{
int j;
@@ -268867,7 +286647,7 @@ wx_sqlite3mcBtreeSetPageSize(Btree* p, int pageSize, int nReserve, int iFix)
** Change 4: Call wx_sqlite3mcBtreeSetPageSize instead of wx_sqlite3BtreeSetPageSize for main database
** (wx_sqlite3mcBtreeSetPageSize allows to reduce the number of reserved bytes)
**
-** This code is generated by the script rekeyvacuum.sh from SQLite version 3.41.2 amalgamation.
+** This code is generated by the script rekeyvacuum.sh from SQLite version 3.47.2 amalgamation.
*/
SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3mcRunVacuumForRekey(
char **pzErrMsg, /* Write error message here */
@@ -268890,6 +286670,9 @@ SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3mcRunVacuumForRekey(
const char *zDbMain; /* Schema name of database to vacuum */
const char *zOut; /* Name of output file */
u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
+ u64 iRandom; /* Random value used for zDbVacuum[] */
+ char zDbVacuum[42]; /* Name of the ATTACH-ed database used for vacuum */
+
if( !db->autoCommit ){
wx_sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -268930,27 +286713,29 @@ SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3mcRunVacuumForRekey(
pMain = db->aDb[iDb].pBt;
isMemDb = wx_sqlite3PagerIsMemdb(wx_sqlite3BtreePager(pMain));
- /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
+ /* Attach the temporary database as 'vacuum_XXXXXX'. The synchronous pragma
** can be set to 'off' for this file, as it is not recovered if a crash
** occurs anyway. The integrity of the database is maintained by a
** (possibly synchronous) transaction opened on the main database before
** wx_sqlite3BtreeCopyFile() is called.
**
- ** An optimisation would be to use a non-journaled pager.
- ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
+ ** An optimization would be to use a non-journaled pager.
+ ** (Later:) I tried setting "PRAGMA vacuum_XXXXXX.journal_mode=OFF" but
** that actually made the VACUUM run slower. Very little journalling
** actually occurs when doing a vacuum since the vacuum_db is initially
** empty. Only the journal header is written. Apparently it takes more
** time to parse and run the PRAGMA to turn journalling off than it does
** to write the journal header file.
*/
+ wx_sqlite3_randomness(sizeof(iRandom),&iRandom);
+ wx_sqlite3_snprintf(sizeof(zDbVacuum), zDbVacuum, "vacuum_%016llx", iRandom);
nDb = db->nDb;
- rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut);
+ rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS %s", zOut, zDbVacuum);
db->openFlags = saved_openFlags;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
assert( (db->nDb-1)==nDb );
pDb = &db->aDb[nDb];
- assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
+ assert( strcmp(pDb->zDbSName,zDbVacuum)==0 );
pTemp = pDb->pBt;
if( pOut ){
wx_sqlite3_file *id = wx_sqlite3PagerFile(wx_sqlite3BtreePager(pTemp));
@@ -269035,11 +286820,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3mcRunVacuumForRekey(
** the contents to the temporary database.
*/
rc = execSqlF(db, pzErrMsg,
- "SELECT'INSERT INTO vacuum_db.'||quote(name)"
+ "SELECT'INSERT INTO %s.'||quote(name)"
"||' SELECT*FROM\"%w\".'||quote(name)"
- "FROM vacuum_db.sqlite_schema "
+ "FROM %s.sqlite_schema "
"WHERE type='table'AND coalesce(rootpage,1)>0",
- zDbMain
+ zDbVacuum, zDbMain, zDbVacuum
);
assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
db->mDbFlags &= ~DBFLAG_Vacuum;
@@ -269051,11 +286836,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int wx_sqlite3mcRunVacuumForRekey(
** from the schema table.
*/
rc = execSqlF(db, pzErrMsg,
- "INSERT INTO vacuum_db.sqlite_schema"
+ "INSERT INTO %s.sqlite_schema"
" SELECT*FROM \"%w\".sqlite_schema"
" WHERE type IN('view','trigger')"
" OR(type='table'AND rootpage=0)",
- zDbMain
+ zDbVacuum, zDbMain
);
if( rc ) goto end_of_vacuum;
@@ -269157,7 +286942,7 @@ wx_sqlite3_activate_see(const char *info)
/*
** Free the encryption data structure associated with a pager instance.
-** (called from the modified code in pager.c)
+** (called from the modified code in pager.c)
*/
SQLITE_PRIVATE void
wx_sqlite3mcCodecFree(void *pCodecArg)
@@ -269187,12 +286972,15 @@ mcReportCodecError(BtShared* pBt, int error)
{
pBt->pPager->eState = PAGER_ERROR;
}
- setGetterMethod(pBt->pPager);
if (error == SQLITE_OK)
{
/* Clear cache to force reread of database after a new passphrase has been set */
wx_sqlite3PagerClearCache(pBt->pPager);
+ /* unlock required?
+ pager_unlock(pBt->pPager);
+ */
}
+ setGetterMethod(pBt->pPager);
}
/*
@@ -269211,6 +286999,7 @@ wx_sqlite3mcCodec(void* pCodecArg, void* data, Pgno nPageNum, int nMode)
codec = (Codec*) pCodecArg;
if (!wx_sqlite3mcIsEncrypted(codec))
{
+ wx_sqlite3mcSetCodecLastError(codec, rc);
return data;
}
@@ -269224,7 +287013,11 @@ wx_sqlite3mcCodec(void* pCodecArg, void* data, Pgno nPageNum, int nMode)
if (wx_sqlite3mcHasReadCipher(codec))
{
rc = wx_sqlite3mcDecrypt(codec, nPageNum, (unsigned char*) data, pageSize);
- if (rc != SQLITE_OK) mcReportCodecError(wx_sqlite3mcGetBtShared(codec), rc);
+ if (rc != SQLITE_OK)
+ {
+ mcReportCodecError(wx_sqlite3mcGetBtShared(codec), rc);
+ memset(data, 0, pageSize);
+ }
}
break;
@@ -269258,6 +287051,7 @@ wx_sqlite3mcCodec(void* pCodecArg, void* data, Pgno nPageNum, int nMode)
}
break;
}
+ wx_sqlite3mcSetCodecLastError(codec, rc);
return data;
}
@@ -269267,6 +287061,9 @@ wx_sqlite3mcGetMainCodec(wx_sqlite3* db);
SQLITE_PRIVATE void
wx_sqlite3mcSetCodec(wx_sqlite3* db, const char* zDbName, const char* zFileName, Codec* codec);
+SQLITE_PRIVATE int
+wx_sqlite3mcIsEncryptionSupported(wx_sqlite3* db, const char* zDbName);
+
static int
mcAdjustBtree(Btree* pBt, int nPageSize, int nReserved, int isLegacy)
{
@@ -269282,11 +287079,12 @@ mcAdjustBtree(Btree* pBt, int nPageSize, int nReserved, int isLegacy)
/* Adjust the page size and the reserved area */
if (pager->pageSize != pagesize || pager->nReserve != nReserved)
{
+ int reserved = (nReserved >= 0) ? nReserved : 0;
if (isLegacy != 0)
{
pBt->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
}
- rc = wx_sqlite3BtreeSetPageSize(pBt, pagesize, nReserved, 0);
+ rc = wx_sqlite3BtreeSetPageSize(pBt, pagesize, reserved, 0);
}
return rc;
}
@@ -269424,6 +287222,11 @@ SQLITE_API int
wx_sqlite3_key_v2(wx_sqlite3* db, const char* zDbName, const void* zKey, int nKey)
{
int rc = SQLITE_ERROR;
+ if (!wx_sqlite3mcIsEncryptionSupported(db, zDbName))
+ {
+ wx_sqlite3ErrorWithMsg(db, rc, "Setting key failed. Encryption is not supported by the VFS.");
+ return rc;
+ }
if (zKey != NULL && nKey < 0)
{
/* Key is zero-terminated string */
@@ -269476,7 +287279,15 @@ wx_sqlite3_rekey_v2(wx_sqlite3* db, const char* zDbName, const void* zKey, int n
int nReserved;
Pager* pPager;
Codec* codec;
+ int codecAllocated = 0;
int rc = SQLITE_ERROR;
+ char* err = NULL;
+
+ if (!wx_sqlite3mcIsEncryptionSupported(db, zDbName))
+ {
+ wx_sqlite3ErrorWithMsg(db, rc, "Rekeying failed. Encryption is not supported by the VFS.");
+ return rc;
+ }
if (zKey != NULL && nKey < 0)
{
/* Key is zero-terminated string */
@@ -269509,10 +287320,10 @@ wx_sqlite3_rekey_v2(wx_sqlite3* db, const char* zDbName, const void* zKey, int n
wx_sqlite3ErrorWithMsg(db, rc, "Rekeying is not supported in WAL journal mode.");
return rc;
}
-
+
if ((zKey == NULL || nKey == 0) && (codec == NULL || !wx_sqlite3mcIsEncrypted(codec)))
{
- /* Database not encrypted and key not specified, therefore do nothing */
+ /* Database not encrypted and key not specified, therefore do nothing */
return SQLITE_OK;
}
@@ -269520,9 +287331,10 @@ wx_sqlite3_rekey_v2(wx_sqlite3* db, const char* zDbName, const void* zKey, int n
if (codec == NULL || !wx_sqlite3mcIsEncrypted(codec))
{
- /* Database not encrypted, but key specified, therefore encrypt database */
+ /* Database not encrypted, but key specified, therefore encrypt database */
if (codec == NULL)
{
+ codecAllocated = 1;
codec = (Codec*) wx_sqlite3_malloc(sizeof(Codec));
rc = (codec != NULL) ? wx_sqlite3mcCodecInit(codec) : SQLITE_NOMEM;
}
@@ -269546,14 +287358,9 @@ wx_sqlite3_rekey_v2(wx_sqlite3* db, const char* zDbName, const void* zKey, int n
if (nReserved != nReservedWriteCipher)
{
/* Use VACUUM to change the number of reserved bytes */
- char* err = NULL;
wx_sqlite3mcSetReadReserved(codec, nReserved);
wx_sqlite3mcSetWriteReserved(codec, nReservedWriteCipher);
rc = wx_sqlite3mcRunVacuumForRekey(&err, db, dbIndex, NULL, nReservedWriteCipher);
- if (rc != SQLITE_OK && err != NULL)
- {
- wx_sqlite3ErrorWithMsg(db, rc, err);
- }
goto leave_rekey;
}
}
@@ -269561,12 +287368,17 @@ wx_sqlite3_rekey_v2(wx_sqlite3* db, const char* zDbName, const void* zKey, int n
{
/* Pagesize cannot be changed for an encrypted database */
rc = SQLITE_ERROR;
- wx_sqlite3ErrorWithMsg(db, rc, "Rekeying failed. Pagesize cannot be changed for an encrypted database.");
+ err = "Rekeying failed. Pagesize cannot be changed for an encrypted database.";
goto leave_rekey;
}
}
else
{
+ wx_sqlite3_mutex_leave(db->mutex);
+ if (codecAllocated)
+ {
+ wx_sqlite3mcCodecFree(codec);
+ }
return rc;
}
}
@@ -269582,10 +287394,6 @@ wx_sqlite3_rekey_v2(wx_sqlite3* db, const char* zDbName, const void* zKey, int n
wx_sqlite3mcSetReadReserved(codec, nReserved);
wx_sqlite3mcSetWriteReserved(codec, 0);
rc = wx_sqlite3mcRunVacuumForRekey(&err, db, dbIndex, NULL, 0);
- if (rc != SQLITE_OK && err != NULL)
- {
- wx_sqlite3ErrorWithMsg(db, rc, err);
- }
goto leave_rekey;
}
}
@@ -269607,10 +287415,6 @@ wx_sqlite3_rekey_v2(wx_sqlite3* db, const char* zDbName, const void* zKey, int n
wx_sqlite3mcSetReadReserved(codec, nReserved);
wx_sqlite3mcSetWriteReserved(codec, nReservedWriteCipher);
rc = wx_sqlite3mcRunVacuumForRekey(&err, db, dbIndex, NULL, nReservedWriteCipher);
- if (rc != SQLITE_OK && err != NULL)
- {
- wx_sqlite3ErrorWithMsg(db, rc, err);
- }
goto leave_rekey;
}
}
@@ -269618,14 +287422,14 @@ wx_sqlite3_rekey_v2(wx_sqlite3* db, const char* zDbName, const void* zKey, int n
{
/* Pagesize cannot be changed for an encrypted database */
rc = SQLITE_ERROR;
- wx_sqlite3ErrorWithMsg(db, rc, "Rekeying failed. Pagesize cannot be changed for an encrypted database.");
+ err = "Rekeying failed. Pagesize cannot be changed for an encrypted database.";
goto leave_rekey;
}
}
else
{
/* Setup of write cipher failed */
- wx_sqlite3ErrorWithMsg(db, rc, "Rekeying failed. Setup of write cipher failed.");
+ err = "Rekeying failed. Setup of write cipher failed.";
goto leave_rekey;
}
}
@@ -269676,8 +287480,15 @@ leave_rekey:
/* Set read key equal to write key if necessary */
if (wx_sqlite3mcHasWriteCipher(codec))
{
+ /* Set Read cipher equal to Write cipher */
wx_sqlite3mcCopyCipher(codec, 0);
wx_sqlite3mcSetHasReadCipher(codec, 1);
+
+ /* Enforce page size and number of reserved bytes per page */
+ int pageSize = wx_sqlite3mcGetPageSizeWriteCipher(codec);
+ int reserved = wx_sqlite3mcGetReservedWriteCipher(codec);
+ mcAdjustBtree(pBt, pageSize, reserved, wx_sqlite3mcGetLegacyWriteCipher(codec));
+ wx_sqlite3mcCodecSizeChange(codec, pageSize, reserved);
}
else
{
@@ -269705,6 +287516,10 @@ leave_rekey:
/* Remove codec for unencrypted database */
wx_sqlite3mcSetCodec(db, zDbName, dbFileName, NULL);
}
+ if (rc != SQLITE_OK && err != NULL)
+ {
+ wx_sqlite3ErrorWithMsg(db, rc, err);
+ }
return rc;
}
@@ -269717,6 +287532,202 @@ wx_sqlite3_rekey(wx_sqlite3 *db, const void *zKey, int nKey)
/*
+** Functions for securing allocated memory
+*/
+/* #include "memory_secure.c" */
+/*** Begin of #include "memory_secure.c" ***/
+/*
+** Name: mem_secure.c
+** Purpose: Memory manager for SQLite3 Multiple Ciphers
+** Author: Ulrich Telle
+** Created: 2023-09-17
+** Copyright: (c) 2023 Ulrich Telle
+** License: MIT
+*/
+
+/* For memset, memset_s */
+#include <string.h>
+
+#ifdef _WIN32
+/* For SecureZeroMemory */
+#include <windows.h>
+#include <winbase.h>
+#endif
+
+SQLITE_PRIVATE void wx_sqlite3mcSecureZeroMemory(void* v, size_t n)
+{
+#ifdef _WIN32
+ SecureZeroMemory(v, n);
+#elif defined(__DARWIN__) || defined(__STDC_LIB_EXT1__)
+ /* memset_s() is available since OS X 10.9, */
+ /* and may be available on other platforms. */
+ memset_s(v, n, 0, n);
+#elif defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 11)
+ /* Non-standard function */
+ explicit_bzero(v, n);
+#else
+ /* Generic implementation based on volatile pointers */
+ static void* (* const volatile memset_sec)(void*, int, size_t) = &memset;
+ memset_sec(v, 0, n);
+#endif
+}
+
+#if SQLITE3MC_SECURE_MEMORY
+
+/* Flag indicating whether securing memory allocations is initialized */
+static volatile int mcSecureMemoryInitialized = 0;
+/* Flag indicating whether memory allocations will be secured */
+static volatile int mcSecureMemoryFlag = 0;
+
+/* Map of default memory allocation methods */
+static volatile wx_sqlite3_mem_methods mcDefaultMemoryMethods;
+
+/*
+** Return the size of an allocation
+*/
+static int mcMemorySize(void* pBuf)
+{
+ return mcDefaultMemoryMethods.xSize(pBuf);
+}
+
+/*
+** Memory allocation function
+*/
+static void* mcMemoryAlloc(int nByte)
+{
+ return mcDefaultMemoryMethods.xMalloc(nByte);
+}
+
+/*
+** Free a prior allocation
+*/
+static void mcMemoryFree(void* pPrior)
+{
+ if (mcSecureMemoryFlag)
+ {
+ int nSize = mcMemorySize(pPrior);
+ wx_sqlite3mcSecureZeroMemory(pPrior, 0, nSize);
+ }
+ mcDefaultMemoryMethods.xFree(pPrior);
+}
+
+/*
+** Resize an allocation
+*/
+static void* mcMemoryRealloc(void* pPrior, int nByte)
+{
+ void* pNew = NULL;
+ if (mcSecureMemoryFlag)
+ {
+ int nPriorSize = mcMemorySize(pPrior);
+ if (nByte == 0)
+ {
+ /* New size = 0, just free prior memory */
+ mcMemoryFree(pPrior);
+ return NULL;
+ }
+ else if (!pPrior)
+ {
+ /* Prior size = 0, just allocate new memory */
+ return mcMemoryAlloc(nByte);
+ }
+ else if(nByte <= nPriorSize)
+ {
+ /* New size less or equal prior size, do nothing - we do not shrink allocations */
+ return pPrior;
+ }
+ else
+ {
+ /* New size greater than prior size, reallocate memory */
+ pNew = mcMemoryAlloc(nByte);
+ if (pNew)
+ {
+ memcpy(pNew, pPrior, nPriorSize);
+ mcMemoryFree(pPrior);
+ }
+ return pNew;
+ }
+ }
+ else
+ {
+ return mcDefaultMemoryMethods.xRealloc(pPrior, nByte);
+ }
+}
+
+/*
+** Round up request size to allocation size
+*/
+static int mcMemoryRoundup(int nByte)
+{
+ return mcDefaultMemoryMethods.xRoundup(nByte);
+}
+
+/*
+** Initialize the memory allocator
+*/
+static int mcMemoryInit(void* pAppData)
+{
+ return mcDefaultMemoryMethods.xInit(pAppData);
+}
+
+/*
+** Deinitialize the memory allocator
+*/
+static void mcMemoryShutdown(void* pAppData)
+{
+ mcDefaultMemoryMethods.xShutdown(pAppData);
+}
+
+static wx_sqlite3_mem_methods mcSecureMemoryMethods =
+{
+ mcMemoryAlloc,
+ mcMemoryFree,
+ mcMemoryRealloc,
+ mcMemorySize,
+ mcMemoryRoundup,
+ mcMemoryInit,
+ mcMemoryShutdown,
+ 0
+};
+
+SQLITE_PRIVATE void wx_sqlite3mcSetMemorySecurity(int value)
+{
+ /* memory security can be changed only, if locking is not enabled */
+ if (mcSecureMemoryFlag < 2)
+ {
+ mcSecureMemoryFlag = (value >= 0 && value <= 2) ? value : 0;
+ }
+}
+
+SQLITE_PRIVATE int wx_sqlite3mcGetMemorySecurity()
+{
+ return mcSecureMemoryFlag;
+}
+
+#endif /* SQLITE3MC_SECURE_MEMORY */
+
+SQLITE_PRIVATE void wx_sqlite3mcInitMemoryMethods()
+{
+#if SQLITE3MC_SECURE_MEMORY
+ if (!mcSecureMemoryInitialized)
+ {
+ if (wx_sqlite3_config(SQLITE_CONFIG_GETMALLOC, &mcDefaultMemoryMethods) != SQLITE_OK ||
+ wx_sqlite3_config(SQLITE_CONFIG_MALLOC, &mcSecureMemoryMethods) != SQLITE_OK)
+ {
+ mcSecureMemoryFlag = mcSecureMemoryInitialized = 0;
+ }
+ else
+ {
+ mcSecureMemoryInitialized = 1;
+ }
+ }
+#endif /* SQLITE3MC_SECURE_MEMORY */
+}
+
+/*** End of #include "memory_secure.c" ***/
+
+
+/*
** Extension functions
*/
#ifdef SQLITE_ENABLE_EXTFUNC
@@ -269780,7 +287791,7 @@ Usage instructions for the wx_sqlite3 program:
security measure; see "Security Considerations" in
http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions.
If the wx_sqlite3 program and library are built this
- way, you cannot use these functions from the program, you
+ way, you cannot use these functions from the program, you
must write your own program using the wx_sqlite3 API, and call
wx_sqlite3_enable_load_extension as described above, or else
rebuilt the wx_sqlite3 program to allow loadable extensions.
@@ -269851,7 +287862,7 @@ Original code 2006 June 05 by relicoder.
#define HAVE_ISBLANK 1
#endif
#define SQLITE_SOUNDEX 1
-#define HAVE_TRIM 1 /* LMH 2007-03-25 if sqlite has trim functions */
+#define HAVE_TRIM 1 /* LMH 2007-03-25 if sqlite has trim functions */
#ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE
/* #include "wx_sqlite3ext.h" */
@@ -269870,7 +287881,7 @@ Original code 2006 June 05 by relicoder.
** This header file defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance. Shared libraries that intend to be loaded
-** as extensions by SQLite should #include this file instead of
+** as extensions by SQLite should #include this file instead of
** wx_sqlite3.h.
*/
#ifndef SQLITE3EXT_H
@@ -270220,6 +288231,11 @@ struct wx_sqlite3_api_routines {
int (*value_encoding)(wx_sqlite3_value*);
/* Version 3.41.0 and later */
int (*is_interrupted)(wx_sqlite3*);
+ /* Version 3.43.0 and later */
+ int (*stmt_explain)(wx_sqlite3_stmt*,int);
+ /* Version 3.44.0 and later */
+ void *(*get_clientdata)(wx_sqlite3*,const char*);
+ int (*set_clientdata)(wx_sqlite3*, const char*, void*, void(*)(void*));
};
/*
@@ -270548,17 +288564,22 @@ typedef int (*wx_sqlite3_loadext_entry)(
#define wx_sqlite3_value_encoding wx_sqlite3_api->value_encoding
/* Version 3.41.0 and later */
#define wx_sqlite3_is_interrupted wx_sqlite3_api->is_interrupted
+/* Version 3.43.0 and later */
+#define wx_sqlite3_stmt_explain wx_sqlite3_api->stmt_explain
+/* Version 3.44.0 and later */
+#define wx_sqlite3_get_clientdata wx_sqlite3_api->get_clientdata
+#define wx_sqlite3_set_clientdata wx_sqlite3_api->set_clientdata
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
- /* This case when the file really is being compiled as a loadable
+ /* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const wx_sqlite3_api_routines *wx_sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v) wx_sqlite3_api=v;
# define SQLITE_EXTENSION_INIT3 \
extern const wx_sqlite3_api_routines *wx_sqlite3_api;
#else
- /* This case when the file is being statically linked into the
+ /* This case when the file is being statically linked into the
** application */
# define SQLITE_EXTENSION_INIT1 /*no-op*/
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
@@ -270579,7 +288600,7 @@ SQLITE_EXTENSION_INIT1
#include <math.h>
#include <string.h>
#include <stdio.h>
-#include <errno.h> /* LMH 2007-03-25 */
+#include <errno.h> /* LMH 2007-03-25 */
#include <stdlib.h>
#include <assert.h>
@@ -270759,7 +288780,7 @@ static int wx_sqlite3ReadUtf8(const unsigned char *z){
** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
** return the number of unicode characters in pZ up to (but not including)
** the first 0x00 byte. If nByte is not less than zero, return the
-** number of unicode characters in the first nByte of pZ (or up to
+** number of unicode characters in the first nByte of pZ (or up to
** the first 0x00, whichever comes first).
*/
static int wx_sqlite3Utf8CharLen(const char *z, int nByte){
@@ -270794,7 +288815,7 @@ static int wx_sqlite3Utf8CharLen(const char *z, int nByte){
**
** Could have been implemented using pointers to functions but this way it's inline
** and thus more efficient. Lower * ranking though...
-**
+**
** Parameters:
** name: function name to de defined (eg: sinFunc)
** function: function defined in math.h to wrap (eg: sin)
@@ -270840,7 +288861,7 @@ GEN_MATH_WRAP_DOUBLE_1(atanFunc, atan)
/*
** Many of systems don't have inverse hyperbolic trig functions so this will emulate
-** them on those systems in terms of log and sqrt (formulas are too trivial to demand
+** them on those systems in terms of log and sqrt (formulas are too trivial to demand
** written proof here)
*/
@@ -271012,7 +289033,7 @@ static void squareFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value *
** (see sqrt just before this). Here the result is always double
*/
/* LMH 2007-03-25 Changed to use errno; no pre-checking for errors. Also removes
- but that was present in the pre-checking that called wx_sqlite3_result_error on
+ but that was present in the pre-checking that called wx_sqlite3_result_error on
a non-positive first argument, which is not always an error. */
static void powerFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **argv){
double r1 = 0.0;
@@ -271020,9 +289041,9 @@ static void powerFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **
double val;
assert( argc==2 );
-
+
if( wx_sqlite3_value_type(argv[0]) == SQLITE_NULL || wx_sqlite3_value_type(argv[1]) == SQLITE_NULL ){
- wx_sqlite3_result_null(context);
+ wx_sqlite3_result_null(context);
}else{
r1 = wx_sqlite3_value_double(argv[0]);
r2 = wx_sqlite3_value_double(argv[1]);
@@ -271030,9 +289051,9 @@ static void powerFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **
val = pow(r1,r2);
if (errno == 0) {
wx_sqlite3_result_double(context, val);
- } else {
+ } else {
wx_sqlite3_result_error(context, strerror(errno), errno);
- }
+ }
}
}
@@ -271046,9 +289067,9 @@ static void atn2Func(wx_sqlite3_context *context, int argc, wx_sqlite3_value **a
double r2 = 0.0;
assert( argc==2 );
-
+
if( wx_sqlite3_value_type(argv[0]) == SQLITE_NULL || wx_sqlite3_value_type(argv[1]) == SQLITE_NULL ){
- wx_sqlite3_result_null(context);
+ wx_sqlite3_result_null(context);
}else{
r1 = wx_sqlite3_value_double(argv[0]);
r2 = wx_sqlite3_value_double(argv[1]);
@@ -271145,14 +289166,14 @@ static void floorFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
/*
-** Given a string (s) in the first argument and an integer (n) in the second returns the
+** Given a string (s) in the first argument and an integer (n) in the second returns the
** string that constains s contatenated n times
*/
static void replicateFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **argv){
unsigned char *z; /* input string */
unsigned char *zo; /* result string */
i64 iCount; /* times to repeat */
- i64 nLen; /* length of the input string (no multibyte considerations) */
+ i64 nLen; /* length of the input string (no multibyte considerations) */
i64 nTLen; /* length of the result string (no multibyte considerations) */
i64 i=0;
@@ -271187,7 +289208,7 @@ static void replicateFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_valu
}
}
-/*
+/*
** Some systems (win32 among others) don't have an isblank function, this will emulate it.
** This function is not UFT-8 safe since it only analyses a byte character.
*/
@@ -271252,9 +289273,9 @@ static void padlFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **a
char *zt;
assert( argc==2 );
-
+
if( wx_sqlite3_value_type(argv[0]) == SQLITE_NULL ){
- wx_sqlite3_result_null(context);
+ wx_sqlite3_result_null(context);
}else{
zi = (char *)wx_sqlite3_value_text(argv[0]);
ilen = wx_sqlite3_value_int64(argv[1]);
@@ -271306,9 +289327,9 @@ static void padrFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **a
char *zt;
assert( argc==2 );
-
+
if( wx_sqlite3_value_type(argv[0]) == SQLITE_NULL ){
- wx_sqlite3_result_null(context);
+ wx_sqlite3_result_null(context);
}else{
zi = (char *)wx_sqlite3_value_text(argv[0]);
ilen = wx_sqlite3_value_int64(argv[1]);
@@ -271361,9 +289382,9 @@ static void padcFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **a
char *zt;
assert( argc==2 );
-
+
if( wx_sqlite3_value_type(argv[0]) == SQLITE_NULL ){
- wx_sqlite3_result_null(context);
+ wx_sqlite3_result_null(context);
}else{
zi = (char *)wx_sqlite3_value_text(argv[0]);
ilen = wx_sqlite3_value_int64(argv[1]);
@@ -271420,17 +289441,17 @@ static void strfilterFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_valu
int c2 = 0;
assert( argc==2 );
-
+
if( wx_sqlite3_value_type(argv[0]) == SQLITE_NULL || wx_sqlite3_value_type(argv[1]) == SQLITE_NULL ){
- wx_sqlite3_result_null(context);
+ wx_sqlite3_result_null(context);
}else{
zi1 = (char *)wx_sqlite3_value_text(argv[0]);
zi2 = (char *)wx_sqlite3_value_text(argv[1]);
- /*
- ** maybe I could allocate less, but that would imply 2 passes, rather waste
+ /*
+ ** maybe I could allocate less, but that would imply 2 passes, rather waste
** (possibly) some memory
*/
- zo = wx_sqlite3_malloc((int) (strlen(zi1)+1));
+ zo = wx_sqlite3_malloc((int) (strlen(zi1)+1));
if (!zo){
wx_sqlite3_result_error_nomem(context);
return;
@@ -271474,11 +289495,11 @@ static int _substr(const char* z1, const char* z2, int s, const char** p){
if( '\0'==*z1 ){
return -1;
}
-
+
while( (sqliteCharVal((unsigned char *)z2) != 0) && (c++)<s){
sqliteNextChar(z2);
}
-
+
c = 0;
while( (sqliteCharVal((unsigned char *)z2)) != 0 ){
zt1 = z1;
@@ -271493,9 +289514,9 @@ static int _substr(const char* z1, const char* z2, int s, const char** p){
if( c1 == 0 ){
rVal = c;
- break;
+ break;
}
-
+
sqliteNextChar(z2);
++c;
}
@@ -271576,7 +289597,7 @@ static void leftFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **a
}
strncpy((char*) rz, (char*) z, zt-z);
*(rz+cc) = '\0';
- wx_sqlite3_result_text(context, (char*)rz, -1, SQLITE_TRANSIENT);
+ wx_sqlite3_result_text(context, (char*)rz, -1, SQLITE_TRANSIENT);
wx_sqlite3_free(rz);
}
@@ -271615,7 +289636,7 @@ static void rightFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **
cc=c-l;
if(cc<0)
cc=0;
-
+
while( cc-- > 0 ){
sqliteNextChar(zt);
}
@@ -271626,7 +289647,7 @@ static void rightFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **
return;
}
strcpy((char*) rz, (char*) (zt));
- wx_sqlite3_result_text(context, (char*)rz, -1, SQLITE_TRANSIENT);
+ wx_sqlite3_result_text(context, (char*)rz, -1, SQLITE_TRANSIENT);
wx_sqlite3_free(rz);
}
@@ -271664,7 +289685,7 @@ static void ltrimFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value **
return;
}
z = wx_sqlite3_value_text(argv[0]);
- wx_sqlite3_result_text(context, ltrim(z), -1, SQLITE_TRANSIENT);
+ wx_sqlite3_result_text(context, ltrim(z), -1, SQLITE_TRANSIENT);
}
/*
@@ -271905,7 +289926,7 @@ static void modeStep(wx_sqlite3_context *context, int argc, wx_sqlite3_value **a
if( type == SQLITE_NULL)
return;
-
+
p = wx_sqlite3_aggregate_context(context, sizeof(*p));
if( 0==(p->m) ){
@@ -271944,33 +289965,33 @@ static void modeIterate(void* e, i64 c, void* pp){
i64 ei;
double ed;
ModeCtx *p = (ModeCtx*)pp;
-
+
if( 0==p->is_double ){
ei = *(int*)(e);
- if( p->mcnt==c ){
+ if( p->mcnt==c ){
++p->mn;
}else if( p->mcnt<c ){
p->riM = ei;
p->mcnt = c;
- p->mn=1;
+ p->mn=1;
}
}else{
ed = *(double*)(e);
- if( p->mcnt==c ){
+ if( p->mcnt==c ){
++p->mn;
}else if(p->mcnt<c){
p->rdM = ed;
p->mcnt = c;
- p->mn=1;
+ p->mn=1;
}
}
}
/*
** Auxiliary function that iterates all elements in a map and finds the median
-** (the value such that the number of elements smaller is equal the the number of
+** (the value such that the number of elements smaller is equal the the number of
** elements larger)
*/
static void medianIterate(void* e, i64 c, void* pp){
@@ -272041,9 +290062,9 @@ static void _medianFinalize(wx_sqlite3_context *context){
if( 0==p->is_double )
if( 1==p->mn )
- wx_sqlite3_result_int64(context, p->riM);
+ wx_sqlite3_result_int64(context, p->riM);
else
- wx_sqlite3_result_double(context, p->riM*1.0/p->mn);
+ wx_sqlite3_result_double(context, p->riM*1.0/p->mn);
else
wx_sqlite3_result_double(context, p->rdM/p->mn);
}
@@ -272163,12 +290184,12 @@ static void differenceFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_val
const u8 *zIn2;
assert( argc==2 );
-
+
if( wx_sqlite3_value_type(argv[0])==SQLITE_NULL || wx_sqlite3_value_type(argv[1])==SQLITE_NULL ){
wx_sqlite3_result_null(context);
return;
}
-
+
zIn1 = (u8*)wx_sqlite3_value_text(argv[0]);
zIn2 = (u8*)wx_sqlite3_value_text(argv[1]);
@@ -272305,7 +290326,7 @@ int RegisterExtensionFunctions(wx_sqlite3 *db){
aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0);
#if 0
if( aFuncs[i].needCollSeq ){
- struct FuncDef *pFunc = wx_sqlite3FindFunction(db, aFuncs[i].zName,
+ struct FuncDef *pFunc = wx_sqlite3FindFunction(db, aFuncs[i].zName,
strlen(aFuncs[i].zName), aFuncs[i].nArg, aFuncs[i].eTextRep, 0);
if( pFunc && aFuncs[i].needCollSeq ){
pFunc->needCollSeq = 1;
@@ -272322,7 +290343,7 @@ int RegisterExtensionFunctions(wx_sqlite3 *db){
}
/* wx_sqlite3CreateFunc */
/* LMH no error checking */
- wx_sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
+ wx_sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
#if 0
if( aAggs[i].needCollSeq ){
@@ -272642,7 +290663,7 @@ static int csv_getc(CsvReader *p){
return ((unsigned char*)p->zIn)[p->iIn++];
}
-/* Increase the size of p->z and append character c to the end.
+/* Increase the size of p->z and append character c to the end.
** Return 0 on success and non-zero if there is an OOM error */
static CSV_NOINLINE int csv_resize_and_append(CsvReader *p, char c){
char *zNew;
@@ -272761,9 +290782,9 @@ static char *csv_read_one_field(CsvReader *p){
/* Forward references to the various virtual table methods implemented
** in this file. */
-static int csvtabCreate(wx_sqlite3*, void*, int, const char*const*,
+static int csvtabCreate(wx_sqlite3*, void*, int, const char*const*,
wx_sqlite3_vtab**,char**);
-static int csvtabConnect(wx_sqlite3*, void*, int, const char*const*,
+static int csvtabConnect(wx_sqlite3*, void*, int, const char*const*,
wx_sqlite3_vtab**,char**);
static int csvtabBestIndex(wx_sqlite3_vtab*,wx_sqlite3_index_info*);
static int csvtabDisconnect(wx_sqlite3_vtab*);
@@ -272948,7 +290969,7 @@ static int csv_boolean_parameter(
** columns=N Assume the CSV file contains N columns.
**
** Only available if compiled with SQLITE_TEST:
-**
+**
** testflags=N Bitmask of test flags. Optional
**
** If schema= is omitted, then the columns are named "c0", "c1", "c2",
@@ -272975,7 +290996,7 @@ static int csvtabConnect(
CsvReader sRdr; /* A CSV file reader used to store an error
** message and/or to count the number of columns */
static const char *azParam[] = {
- "filename", "data", "schema",
+ "filename", "data", "schema",
};
char *azPValue[3]; /* Parameter values */
# define CSV_FILENAME (azPValue[0])
@@ -273277,7 +291298,7 @@ static int csvtabEof(wx_sqlite3_vtab_cursor *cur){
** the beginning.
*/
static int csvtabFilter(
- wx_sqlite3_vtab_cursor *pVtabCursor,
+ wx_sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, wx_sqlite3_value **argv
){
@@ -273333,7 +291354,7 @@ static int csvtabBestIndex(
unsigned char op;
if( pIdxInfo->aConstraint[i].usable==0 ) continue;
op = pIdxInfo->aConstraint[i].op;
- if( op==SQLITE_INDEX_CONSTRAINT_EQ
+ if( op==SQLITE_INDEX_CONSTRAINT_EQ
|| op==SQLITE_INDEX_CONSTRAINT_LIKE
|| op==SQLITE_INDEX_CONSTRAINT_GLOB
){
@@ -273369,6 +291390,11 @@ static wx_sqlite3_module CsvModule = {
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
#ifdef SQLITE_TEST
@@ -273401,6 +291427,11 @@ static wx_sqlite3_module CsvModuleFauxWrite = {
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
#endif /* SQLITE_TEST */
@@ -273410,14 +291441,14 @@ static wx_sqlite3_module CsvModuleFauxWrite = {
#ifdef _WIN32
__declspec(dllexport)
#endif
-/*
+/*
** This routine is called when the extension is loaded. The new
** CSV virtual table module is registered with the calling database
** connection.
*/
int wx_sqlite3_csv_init(
- wx_sqlite3 *db,
- char **pzErrMsg,
+ wx_sqlite3 *db,
+ char **pzErrMsg,
const wx_sqlite3_api_routines *pApi
){
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -273619,8 +291650,8 @@ int wx_sqlite3_vsv_init(wx_sqlite3* db, char** pzErrMsg, const wx_sqlite3_api_ro
** (b) your platform/compiler does not
** support long double (treats it as a double)
** then a 64-bit integer will only be returned
-** if the value would fit in a 6-byte varint,
-** otherwise a double will be returned
+** for integers that can be represented in the
+** 53 bit significand of a double
**
** The nulls option will cause fields that do not contain anything
** to return NULL rather than an empty result. Two separators
@@ -273679,6 +291710,7 @@ SQLITE_EXTENSION_INIT1
#include <ctype.h>
#include <stdio.h>
#include <math.h>
+#include <limits.h>
#ifdef SQLITE_HAVE_ZLIB
#include <zlib.h>
@@ -273689,6 +291721,19 @@ SQLITE_EXTENSION_INIT1
#define ftell gztell
#endif
+#undef LONGDOUBLE_CONSTANT
+#undef LONGDOUBLE_TYPE
+#if defined(SQLITE_USE_QUADMATH) && defined(__GNUC__) && defined(_WIN64)
+#include <quadmath.h>
+#define LONGDOUBLE_TYPE __float128
+#define LONGDOUBLE_CONSTANT(x) x##Q
+#define modfl modfq
+#define strtold strtoflt128
+#else
+#define LONGDOUBLE_TYPE long double
+#define LONGDOUBLE_CONSTANT(x) x##L
+#endif
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
@@ -275068,6 +293113,7 @@ static int vsvtabColumn(
VsvTable *pTab = (VsvTable*)cur->pVtab;
long long dLen = pCur->dLen[i];
long long length = 0;
+ static int hasExtended = 0;
if (i>=0 && i<pTab->nCol && pCur->azVal[i]!=0 && dLen>-1)
{
@@ -275189,36 +293235,58 @@ static int vsvtabColumn(
{
case 1:
{
- wx_sqlite3_result_int64(ctx, strtoll(pCur->azVal[i], 0, 10));
- break;
+ sqlite_int64 ival;
+
+ ival = strtoll(pCur->azVal[i], 0, 10);
+ if (ival > LLONG_MIN && ival < LLONG_MAX) {
+ wx_sqlite3_result_int64(ctx, ival);
+ break;
+ }
+
}
case 2:
{
- long double dv, fp, ip;
+ LONGDOUBLE_TYPE dv, fp, ip;
+
+#if defined(SQLITE_USE_QUADMATH) && defined(__GNUC__) && defined(_WIN64)
+ if (!hasExtended) hasExtended = 1;
+#else
+ if (!hasExtended) {
+ if (sizeof(long double) > sizeof(double)) {
+ volatile unsigned long long i = ULLONG_MAX;
+ volatile long double l;
+ volatile double d;
+ l = i;
+ d = i;
+ hasExtended = (d == l) ? -1 : 1;
+ } else {
+ hasExtended = -1;
+ }
+ }
+#endif
dv = strtold(pCur->azVal[i], 0);
fp = modfl(dv, &ip);
- if (sizeof(long double)>sizeof(double))
+ if (hasExtended<0)
{
- if (fp==0.0L && dv >= -9223372036854775808.0L && dv <= 9223372036854775807.0L)
+ if (fp==0.0L && ip >= -9007199254740991LL && dv <= 9007199254740991LL)
{
- wx_sqlite3_result_int64(ctx, (long long)dv);
+ wx_sqlite3_result_int64(ctx, (long long)ip);
}
else
{
- wx_sqlite3_result_double(ctx, (double)dv);
+ wx_sqlite3_result_double(ctx, dv);
}
}
else
{
- // Only convert if it will fit in a 6-byte varint
- if (fp==0.0L && dv >= -140737488355328.0L && dv <= 140737488355328.0L)
+ if (fp==0.0L && ip >= LLONG_MIN && ip <= LLONG_MAX)
{
- wx_sqlite3_result_int64(ctx, (long long)dv);
+ wx_sqlite3_result_int64(ctx, (long long)ip);
}
else
{
- wx_sqlite3_result_double(ctx, (double)dv);
+ wx_sqlite3_result_double(ctx, dv);
}
}
break;
@@ -275444,6 +293512,10 @@ int wx_sqlite3_vsv_init(
return SQLITE_OK;
#endif
}
+
+#undef modfl
+#undef strtold
+
/*** End of #include "vsv.c" ***/
#endif
@@ -275471,14 +293543,25 @@ int wx_sqlite3_shathree_init(wx_sqlite3* db, char** pzErrMsg, const wx_sqlite3_a
**
******************************************************************************
**
-** This SQLite extension implements functions that compute SHA3 hashes.
+** This SQLite extension implements functions that compute SHA3 hashes
+** in the way described by the (U.S.) NIST FIPS 202 SHA-3 Standard.
** Two SQL functions are implemented:
**
** sha3(X,SIZE)
-** sha3_query(Y,SIZE)
+** sha3_agg(Y,SIZE)
+** sha3_query(Z,SIZE)
**
** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
-** X is NULL.
+** X is NULL. If inputs X is text, the UTF-8 rendering of that text is
+** used to compute the hash. If X is a BLOB, then the binary data of the
+** blob is used to compute the hash. If X is an integer or real number,
+** then that number if converted into UTF-8 text and the hash is computed
+** over the text.
+**
+** The sha3_agg(Y) function computes the SHA3 hash of all Y inputs. Since
+** order is important for the hash, it is recommended that the Y expression
+** by followed by an ORDER BY clause to guarantee that the inputs occur
+** in the desired order.
**
** The sha3_query(Y) function evaluates all queries in the SQL statements of Y
** and returns a hash of their results.
@@ -275486,6 +293569,68 @@ int wx_sqlite3_shathree_init(wx_sqlite3* db, char** pzErrMsg, const wx_sqlite3_a
** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm
** is used. If SIZE is included it must be one of the integers 224, 256,
** 384, or 512, to determine SHA3 hash variant that is computed.
+**
+** Because the sha3_agg() and sha3_query() functions compute a hash over
+** multiple values, the values are encode to use include type information.
+**
+** In sha3_agg(), the sequence of bytes that gets hashed for each input
+** Y depends on the datatype of Y:
+**
+** typeof(Y)='null' A single "N" is hashed. (One byte)
+**
+** typeof(Y)='integer' The data hash is the character "I" followed
+** by an 8-byte big-endian binary of the
+** 64-bit signed integer. (Nine bytes total.)
+**
+** typeof(Y)='real' The character "F" followed by an 8-byte
+** big-ending binary of the double. (Nine
+** bytes total.)
+**
+** typeof(Y)='text' The hash is over prefix "Tnnn:" followed
+** by the UTF8 encoding of the text. The "nnn"
+** in the prefix is the minimum-length decimal
+** representation of the octet_length of the text.
+** Notice the ":" at the end of the prefix, which
+** is needed to separate the prefix from the
+** content in cases where the content starts
+** with a digit.
+**
+** typeof(Y)='blob' The hash is taken over prefix "Bnnn:" followed
+** by the binary content of the blob. The "nnn"
+** in the prefix is the mimimum-length decimal
+** representation of the byte-length of the blob.
+**
+** According to the rules above, all of the following SELECT statements
+** should return TRUE:
+**
+** SELECT sha3(1) = sha3('1');
+**
+** SELECT sha3('hello') = sha3(x'68656c6c6f');
+**
+** WITH a(x) AS (VALUES('xyzzy'))
+** SELECT sha3_agg(x) = sha3('T5:xyzzy') FROM a;
+**
+** WITH a(x) AS (VALUES(x'010203'))
+** SELECT sha3_agg(x) = sha3(x'42333a010203') FROM a;
+**
+** WITH a(x) AS (VALUES(0x123456))
+** SELECT sha3_agg(x) = sha3(x'490000000000123456') FROM a;
+**
+** WITH a(x) AS (VALUES(100.015625))
+** SELECT sha3_agg(x) = sha3(x'464059010000000000') FROM a;
+**
+** WITH a(x) AS (VALUES(NULL))
+** SELECT sha3_agg(x) = sha3('N') FROM a;
+**
+**
+** In sha3_query(), individual column values are encoded as with
+** sha3_agg(), but with the addition that a single "R" character is
+** inserted at the start of each row.
+**
+** Note that sha3_agg() hashes rows for which Y is NULL. Add a FILTER
+** clause if NULL rows should be excluded:
+**
+** SELECT sha3_agg(x ORDER BY rowid) FILTER(WHERE x NOT NULL) FROM t1;
*/
/* #include "wx_sqlite3ext.h" */
@@ -275536,6 +293681,7 @@ struct SHA3Context {
unsigned nRate; /* Bytes of input accepted per Keccak iteration */
unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */
unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
+ unsigned iSize; /* 224, 256, 358, or 512 */
};
/*
@@ -275865,6 +294011,7 @@ static void KeccakF1600Step(SHA3Context *p){
*/
static void SHA3Init(SHA3Context *p, int iSize){
memset(p, 0, sizeof(*p));
+ p->iSize = iSize;
if( iSize>=128 && iSize<=512 ){
p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
}else{
@@ -275956,7 +294103,7 @@ static unsigned char *SHA3Final(SHA3Context *p){
** Implementation of the sha3(X,SIZE) function.
**
** Return a BLOB which is the SIZE-bit SHA3 hash of X. The default
-** size is 256. If X is a BLOB, it is hashed as is.
+** size is 256. If X is a BLOB, it is hashed as is.
** For all other non-NULL types of input, X is converted into a UTF-8 string
** and the string is hashed without the trailing 0x00 terminator. The hash
** of a NULL value is NULL.
@@ -276009,6 +294156,60 @@ static void sha3_step_vformat(
}
/*
+** Update a SHA3Context using a single wx_sqlite3_value.
+*/
+static void sha3UpdateFromValue(SHA3Context *p, wx_sqlite3_value *pVal){
+ switch( wx_sqlite3_value_type(pVal) ){
+ case SQLITE_NULL: {
+ SHA3Update(p, (const unsigned char*)"N",1);
+ break;
+ }
+ case SQLITE_INTEGER: {
+ wx_sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ wx_sqlite3_int64 v = wx_sqlite3_value_int64(pVal);
+ memcpy(&u, &v, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'I';
+ SHA3Update(p, x, 9);
+ break;
+ }
+ case SQLITE_FLOAT: {
+ wx_sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ double r = wx_sqlite3_value_double(pVal);
+ memcpy(&u, &r, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'F';
+ SHA3Update(p,x,9);
+ break;
+ }
+ case SQLITE_TEXT: {
+ int n2 = wx_sqlite3_value_bytes(pVal);
+ const unsigned char *z2 = wx_sqlite3_value_text(pVal);
+ sha3_step_vformat(p,"T%d:",n2);
+ SHA3Update(p, z2, n2);
+ break;
+ }
+ case SQLITE_BLOB: {
+ int n2 = wx_sqlite3_value_bytes(pVal);
+ const unsigned char *z2 = wx_sqlite3_value_blob(pVal);
+ sha3_step_vformat(p,"B%d:",n2);
+ SHA3Update(p, z2, n2);
+ break;
+ }
+ }
+}
+
+/*
** Implementation of the sha3_query(SQL,SIZE) function.
**
** This function compiles and runs the SQL statement(s) given in the
@@ -276097,54 +294298,7 @@ static void sha3QueryFunc(
while( SQLITE_ROW==wx_sqlite3_step(pStmt) ){
SHA3Update(&cx,(const unsigned char*)"R",1);
for(i=0; i<nCol; i++){
- switch( wx_sqlite3_column_type(pStmt,i) ){
- case SQLITE_NULL: {
- SHA3Update(&cx, (const unsigned char*)"N",1);
- break;
- }
- case SQLITE_INTEGER: {
- wx_sqlite3_uint64 u;
- int j;
- unsigned char x[9];
- wx_sqlite3_int64 v = wx_sqlite3_column_int64(pStmt,i);
- memcpy(&u, &v, 8);
- for(j=8; j>=1; j--){
- x[j] = u & 0xff;
- u >>= 8;
- }
- x[0] = 'I';
- SHA3Update(&cx, x, 9);
- break;
- }
- case SQLITE_FLOAT: {
- wx_sqlite3_uint64 u;
- int j;
- unsigned char x[9];
- double r = wx_sqlite3_column_double(pStmt,i);
- memcpy(&u, &r, 8);
- for(j=8; j>=1; j--){
- x[j] = u & 0xff;
- u >>= 8;
- }
- x[0] = 'F';
- SHA3Update(&cx,x,9);
- break;
- }
- case SQLITE_TEXT: {
- int n2 = wx_sqlite3_column_bytes(pStmt, i);
- const unsigned char *z2 = wx_sqlite3_column_text(pStmt, i);
- sha3_step_vformat(&cx,"T%d:",n2);
- SHA3Update(&cx, z2, n2);
- break;
- }
- case SQLITE_BLOB: {
- int n2 = wx_sqlite3_column_bytes(pStmt, i);
- const unsigned char *z2 = wx_sqlite3_column_blob(pStmt, i);
- sha3_step_vformat(&cx,"B%d:",n2);
- SHA3Update(&cx, z2, n2);
- break;
- }
- }
+ sha3UpdateFromValue(&cx, wx_sqlite3_column_value(pStmt,i));
}
}
wx_sqlite3_finalize(pStmt);
@@ -276152,6 +294306,44 @@ static void sha3QueryFunc(
wx_sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
}
+/*
+** xStep function for sha3_agg().
+*/
+static void sha3AggStep(
+ wx_sqlite3_context *context,
+ int argc,
+ wx_sqlite3_value **argv
+){
+ SHA3Context *p;
+ p = (SHA3Context*)wx_sqlite3_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ if( p->nRate==0 ){
+ int sz = 256;
+ if( argc==2 ){
+ sz = wx_sqlite3_value_int(argv[1]);
+ if( sz!=224 && sz!=384 && sz!=512 ){
+ sz = 256;
+ }
+ }
+ SHA3Init(p, sz);
+ }
+ sha3UpdateFromValue(p, argv[0]);
+}
+
+
+/*
+** xFinal function for sha3_agg().
+*/
+static void sha3AggFinal(wx_sqlite3_context *context){
+ SHA3Context *p;
+ p = (SHA3Context*)wx_sqlite3_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ if( p->iSize ){
+ wx_sqlite3_result_blob(context, SHA3Final(p), p->iSize/8, SQLITE_TRANSIENT);
+ }
+}
+
+
#ifdef _WIN32
__declspec(dllexport)
@@ -276173,6 +294365,16 @@ int wx_sqlite3_shathree_init(
0, sha3Func, 0, 0);
}
if( rc==SQLITE_OK ){
+ rc = wx_sqlite3_create_function(db, "sha3_agg", 1,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
+ 0, 0, sha3AggStep, sha3AggFinal);
+ }
+ if( rc==SQLITE_OK ){
+ rc = wx_sqlite3_create_function(db, "sha3_agg", 2,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
+ 0, 0, sha3AggStep, sha3AggFinal);
+ }
+ if( rc==SQLITE_OK ){
rc = wx_sqlite3_create_function(db, "sha3_query", 1,
SQLITE_UTF8 | SQLITE_DIRECTONLY,
0, sha3QueryFunc, 0, 0);
@@ -276247,7 +294449,7 @@ int wx_sqlite3_carray_init(wx_sqlite3* db, char** pzErrMsg, const wx_sqlite3_api
** ctype TEXT HIDDEN
** );
**
-** If the hidden columns "pointer" and "count" are unconstrained, then
+** If the hidden columns "pointer" and "count" are unconstrained, then
** the virtual table has no rows. Otherwise, the virtual table interprets
** the integer value of "pointer" as a pointer to the array and "count"
** as the number of elements in the array. The virtual table steps through
@@ -276266,7 +294468,7 @@ SQLITE_EXTENSION_INIT1
#else
# include <sys/uio.h>
#endif
-
+
/* Allowed values for the mFlags parameter to wx_sqlite3_carray_bind().
** Must exactly match the definitions in carray.h.
*/
@@ -276473,7 +294675,7 @@ static int carrayEof(wx_sqlite3_vtab_cursor *cur){
** to the first row of output.
*/
static int carrayFilter(
- wx_sqlite3_vtab_cursor *pVtabCursor,
+ wx_sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, wx_sqlite3_value **argv
){
@@ -276587,7 +294789,7 @@ static int carrayBestIndex(
}
/*
-** This following structure defines all the methods for the
+** This following structure defines all the methods for the
** carray virtual table.
*/
static wx_sqlite3_module carrayModule = {
@@ -276611,6 +294813,11 @@ static wx_sqlite3_module carrayModule = {
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadow */
+ 0 /* xIntegrity */
};
/*
@@ -276665,7 +294872,7 @@ SQLITE_API int wx_sqlite3_carray_bind(
for(i=0; i<nData; i++){
sz += ((struct iovec*)aData)[i].iov_len;
}
- }
+ }
pNew->aData = wx_sqlite3_malloc64( sz );
if( pNew->aData==0 ){
wx_sqlite3_free(pNew);
@@ -276739,8 +294946,8 @@ static void inttoptrFunc(
#endif /* SQLITE_OMIT_VIRTUALTABLE */
SQLITE_API int wx_sqlite3_carray_init(
- wx_sqlite3 *db,
- char **pzErrMsg,
+ wx_sqlite3 *db,
+ char **pzErrMsg,
const wx_sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
@@ -276945,7 +295152,7 @@ struct DIR {
#endif
/*
-** Provide the function prototype for the POSIX compatiable getenv()
+** Provide the function prototype for the POSIX compatible getenv()
** function. This function is not thread-safe.
*/
@@ -277184,7 +295391,7 @@ INT closedir(
** modification-time of the target file is set to this value before
** returning.
**
-** If three or more arguments are passed to this function and an
+** If five or more arguments are passed to this function and an
** error is encountered, an exception is raised.
**
** READFILE(FILE):
@@ -277213,8 +295420,8 @@ INT closedir(
** directory, NULL.
**
** If a non-NULL value is specified for the optional $dir parameter and
-** $path is a relative path, then $path is interpreted relative to $dir.
-** And the paths returned in the "name" column of the table are also
+** $path is a relative path, then $path is interpreted relative to $dir.
+** And the paths returned in the "name" column of the table are also
** relative to directory $dir.
**
** Notes on building this extension for Windows:
@@ -277256,6 +295463,13 @@ SQLITE_EXTENSION_INIT1
#include <time.h>
#include <errno.h>
+/* When used as part of the CLI, the wx_sqlite3_stdio.h module will have
+** been included before this one. In that case use the wx_sqlite3_stdio.h
+** #defines. If not, create our own for fopen().
+*/
+#ifndef _SQLITE3_STDIO_H_
+# define wx_sqlite3_fopen fopen
+#endif
/*
** Structure of the fsdir() table-valued function
@@ -277271,7 +295485,7 @@ SQLITE_EXTENSION_INIT1
/*
-** Set the result stored by context ctx to a blob containing the
+** Set the result stored by context ctx to a blob containing the
** contents of file zName. Or, leave the result unchanged (NULL)
** if the file does not exist or is unreadable.
**
@@ -277288,7 +295502,7 @@ static void readFileContents(wx_sqlite3_context *ctx, const char *zName){
wx_sqlite3 *db;
int mxBlob;
- in = fopen(zName, "rb");
+ in = wx_sqlite3_fopen(zName, "rb");
if( in==0 ){
/* File does not exist or is unreadable. Leave the result set to NULL. */
return;
@@ -277504,7 +295718,7 @@ static int makeDirectory(
}
/*
-** This function does the work for the writefile() UDF. Refer to
+** This function does the work for the writefile() UDF. Refer to
** header comments at the top of this file for details.
*/
static int writeFile(
@@ -277518,7 +295732,9 @@ static int writeFile(
#if !defined(_WIN32) && !defined(WIN32)
if( S_ISLNK(mode) ){
const char *zTo = (const char*)wx_sqlite3_value_text(pData);
- if( zTo==0 || symlink(zTo, zFile)<0 ) return 1;
+ if( zTo==0 ) return 1;
+ unlink(zFile);
+ if( symlink(zTo, zFile)<0 ) return 1;
}else
#endif
{
@@ -277541,7 +295757,7 @@ static int writeFile(
wx_sqlite3_int64 nWrite = 0;
const char *z;
int rc = 0;
- FILE *out = fopen(zFile, "wb");
+ FILE *out = wx_sqlite3_fopen(zFile, "wb");
if( out==0 ) return 1;
z = (const char*)wx_sqlite3_value_blob(pData);
if( z ){
@@ -277604,13 +295820,19 @@ static int writeFile(
return 1;
}
#else
- /* Legacy unix */
- struct timeval times[2];
- times[0].tv_usec = times[1].tv_usec = 0;
- times[0].tv_sec = time(0);
- times[1].tv_sec = mtime;
- if( utimes(zFile, times) ){
- return 1;
+ /* Legacy unix.
+ **
+ ** Do not use utimes() on a symbolic link - it sees through the link and
+ ** modifies the timestamps on the target. Or fails if the target does
+ ** not exist. */
+ if( 0==S_ISLNK(mode) ){
+ struct timeval times[2];
+ times[0].tv_usec = times[1].tv_usec = 0;
+ times[0].tv_sec = time(0);
+ times[1].tv_sec = mtime;
+ if( utimes(zFile, times) ){
+ return 1;
+ }
}
#endif
}
@@ -277619,7 +295841,7 @@ static int writeFile(
}
/*
-** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.
+** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.
** Refer to header comments at the top of this file for details.
*/
static void writefileFunc(
@@ -277633,7 +295855,7 @@ static void writefileFunc(
wx_sqlite3_int64 mtime = -1;
if( argc<2 || argc>4 ){
- wx_sqlite3_result_error(context,
+ wx_sqlite3_result_error(context,
"wrong number of arguments to function writefile()", -1
);
return;
@@ -277703,7 +295925,7 @@ static void lsModeFunc(
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/*
+/*
** Cursor type for recursively iterating through a directory structure.
*/
typedef struct fsdir_cursor fsdir_cursor;
@@ -277851,7 +296073,7 @@ static int fsdirNext(wx_sqlite3_vtab_cursor *cur){
}
pCur->iLvl = iNew;
pLvl = &pCur->aLvl[iNew];
-
+
pLvl->zDir = pCur->zPath;
pCur->zPath = 0;
pLvl->pDir = opendir(pLvl->zDir);
@@ -277982,7 +296204,7 @@ static int fsdirEof(wx_sqlite3_vtab_cursor *cur){
** idxNum==2 Both PATH and DIR supplied
*/
static int fsdirFilter(
- wx_sqlite3_vtab_cursor *cur,
+ wx_sqlite3_vtab_cursor *cur,
int idxNum, const char *idxStr,
int argc, wx_sqlite3_value **argv
){
@@ -278071,7 +296293,7 @@ static int fsdirBestIndex(
}
break;
}
- }
+ }
}
if( seenPath || seenDir ){
/* If input parameters are unusable, disallow this plan */
@@ -278129,6 +296351,7 @@ static int fsdirRegister(wx_sqlite3 *db){
0, /* xRelease */
0, /* xRollbackTo */
0, /* xShadowName */
+ 0 /* xIntegrity */
};
int rc = wx_sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
@@ -278142,14 +296365,14 @@ static int fsdirRegister(wx_sqlite3 *db){
__declspec(dllexport)
#endif
int wx_sqlite3_fileio_init(
- wx_sqlite3 *db,
- char **pzErrMsg,
+ wx_sqlite3 *db,
+ char **pzErrMsg,
const wx_sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
- rc = wx_sqlite3_create_function(db, "readfile", 1,
+ rc = wx_sqlite3_create_function(db, "readfile", 1,
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
readfileFunc, 0, 0);
if( rc==SQLITE_OK ){
@@ -278191,7 +296414,7 @@ int wx_sqlite3_series_init(wx_sqlite3* db, char** pzErrMsg, const wx_sqlite3_api
/* #include "series.c" */
/*** Begin of #include "series.c" ***/
/*
-** 2015-08-18
+** 2015-08-18, 2023-04-28
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -278204,7 +296427,19 @@ int wx_sqlite3_series_init(wx_sqlite3* db, char** pzErrMsg, const wx_sqlite3_api
**
** This file demonstrates how to create a table-valued-function using
** a virtual table. This demo implements the generate_series() function
-** which gives similar results to the eponymous function in PostgreSQL.
+** which gives the same results as the eponymous function in PostgreSQL,
+** within the limitation that its arguments are signed 64-bit integers.
+**
+** Considering its equivalents to generate_series(start,stop,step): A
+** value V[n] sequence is produced for integer n ascending from 0 where
+** ( V[n] == start + n * step && sgn(V[n] - stop) * sgn(step) >= 0 )
+** for each produced value (independent of production time ordering.)
+**
+** All parameters must be either integer or convertable to integer.
+** The start parameter is required.
+** The stop parameter defaults to (1<<32)-1 (aka 4294967295 or 0xffffffff)
+** The step parameter defaults to 1 and 0 is treated as 1.
+**
** Examples:
**
** SELECT * FROM generate_series(0,100,5);
@@ -278220,6 +296455,14 @@ int wx_sqlite3_series_init(wx_sqlite3* db, char** pzErrMsg, const wx_sqlite3_api
**
** Integers 20 through 29.
**
+** SELECT * FROM generate_series(0,-100,-5);
+**
+** Integers 0 -5 -10 ... -100.
+**
+** SELECT * FROM generate_series(0,-1);
+**
+** Empty sequence.
+**
** HOW IT WORKS
**
** The generate_series "function" is really a virtual table with the
@@ -278232,6 +296475,9 @@ int wx_sqlite3_series_init(wx_sqlite3* db, char** pzErrMsg, const wx_sqlite3_api
** step HIDDEN
** );
**
+** The virtual table also has a rowid, logically equivalent to n+1 where
+** "n" is the ascending integer in the aforesaid production definition.
+**
** Function arguments in queries against this virtual table are translated
** into equality constraints against successive hidden columns. In other
** words, the following pairs of queries are equivalent to each other:
@@ -278259,15 +296505,158 @@ int wx_sqlite3_series_init(wx_sqlite3* db, char** pzErrMsg, const wx_sqlite3_api
** and a very large cost if either start or stop are unavailable. This
** encourages the query planner to order joins such that the bounds of the
** series are well-defined.
+**
+** Update on 2024-08-22:
+** xBestIndex now also looks for equality and inequality constraints against
+** the value column and uses those constraints as additional bounds against
+** the sequence range. Thus, a query like this:
+**
+** SELECT value FROM generate_series($SA,$EA)
+** WHERE value BETWEEN $SB AND $EB;
+**
+** Is logically the same as:
+**
+** SELECT value FROM generate_series(max($SA,$SB),min($EA,$EB));
+**
+** Constraints on the value column can server as substitutes for constraints
+** on the hidden start and stop columns. So, the following two queries
+** are equivalent:
+**
+** SELECT value FROM generate_series($S,$E);
+** SELECT value FROM generate_series WHERE value BETWEEN $S and $E;
+**
*/
/* #include "wx_sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
+#include <limits.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Return that member of a generate_series(...) sequence whose 0-based
+** index is ix. The 0th member is given by smBase. The sequence members
+** progress per ix increment by smStep.
+*/
+static wx_sqlite3_int64 genSeqMember(
+ wx_sqlite3_int64 smBase,
+ wx_sqlite3_int64 smStep,
+ wx_sqlite3_uint64 ix
+){
+ static const wx_sqlite3_uint64 mxI64 =
+ ((wx_sqlite3_uint64)0x7fffffff)<<32 | 0xffffffff;
+ if( ix>=mxI64 ){
+ /* Get ix into signed i64 range. */
+ ix -= mxI64;
+ /* With 2's complement ALU, this next can be 1 step, but is split into
+ * 2 for UBSAN's satisfaction (and hypothetical 1's complement ALUs.) */
+ smBase += (mxI64/2) * smStep;
+ smBase += (mxI64 - mxI64/2) * smStep;
+ }
+ /* Under UBSAN (or on 1's complement machines), must do this last term
+ * in steps to avoid the dreaded (and harmless) signed multiply overlow. */
+ if( ix>=2 ){
+ wx_sqlite3_int64 ix2 = (wx_sqlite3_int64)ix/2;
+ smBase += ix2*smStep;
+ ix -= ix2;
+ }
+ return smBase + ((wx_sqlite3_int64)ix)*smStep;
+}
+
+typedef unsigned char u8;
+typedef struct SequenceSpec {
+ wx_sqlite3_int64 iOBase; /* Original starting value ("start") */
+ wx_sqlite3_int64 iOTerm; /* Original terminal value ("stop") */
+ wx_sqlite3_int64 iBase; /* Starting value to actually use */
+ wx_sqlite3_int64 iTerm; /* Terminal value to actually use */
+ wx_sqlite3_int64 iStep; /* Increment ("step") */
+ wx_sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */
+ wx_sqlite3_uint64 uSeqIndexNow; /* Current index during generation */
+ wx_sqlite3_int64 iValueNow; /* Current value during generation */
+ u8 isNotEOF; /* Sequence generation not exhausted */
+ u8 isReversing; /* Sequence is being reverse generated */
+} SequenceSpec;
+
+/*
+** Prepare a SequenceSpec for use in generating an integer series
+** given initialized iBase, iTerm and iStep values. Sequence is
+** initialized per given isReversing. Other members are computed.
+*/
+static void setupSequence( SequenceSpec *pss ){
+ int bSameSigns;
+ pss->uSeqIndexMax = 0;
+ pss->isNotEOF = 0;
+ bSameSigns = (pss->iBase < 0)==(pss->iTerm < 0);
+ if( pss->iTerm < pss->iBase ){
+ wx_sqlite3_uint64 nuspan = 0;
+ if( bSameSigns ){
+ nuspan = (wx_sqlite3_uint64)(pss->iBase - pss->iTerm);
+ }else{
+ /* Under UBSAN (or on 1's complement machines), must do this in steps.
+ * In this clause, iBase>=0 and iTerm<0 . */
+ nuspan = 1;
+ nuspan += pss->iBase;
+ nuspan += -(pss->iTerm+1);
+ }
+ if( pss->iStep<0 ){
+ pss->isNotEOF = 1;
+ if( nuspan==ULONG_MAX ){
+ pss->uSeqIndexMax = ( pss->iStep>LLONG_MIN )? nuspan/-pss->iStep : 1;
+ }else if( pss->iStep>LLONG_MIN ){
+ pss->uSeqIndexMax = nuspan/-pss->iStep;
+ }
+ }
+ }else if( pss->iTerm > pss->iBase ){
+ wx_sqlite3_uint64 puspan = 0;
+ if( bSameSigns ){
+ puspan = (wx_sqlite3_uint64)(pss->iTerm - pss->iBase);
+ }else{
+ /* Under UBSAN (or on 1's complement machines), must do this in steps.
+ * In this clause, iTerm>=0 and iBase<0 . */
+ puspan = 1;
+ puspan += pss->iTerm;
+ puspan += -(pss->iBase+1);
+ }
+ if( pss->iStep>0 ){
+ pss->isNotEOF = 1;
+ pss->uSeqIndexMax = puspan/pss->iStep;
+ }
+ }else if( pss->iTerm == pss->iBase ){
+ pss->isNotEOF = 1;
+ pss->uSeqIndexMax = 0;
+ }
+ pss->uSeqIndexNow = (pss->isReversing)? pss->uSeqIndexMax : 0;
+ pss->iValueNow = (pss->isReversing)
+ ? genSeqMember(pss->iBase, pss->iStep, pss->uSeqIndexMax)
+ : pss->iBase;
+}
+
+/*
+** Progress sequence generator to yield next value, if any.
+** Leave its state to either yield next value or be at EOF.
+** Return whether there is a next value, or 0 at EOF.
+*/
+static int progressSequence( SequenceSpec *pss ){
+ if( !pss->isNotEOF ) return 0;
+ if( pss->isReversing ){
+ if( pss->uSeqIndexNow > 0 ){
+ pss->uSeqIndexNow--;
+ pss->iValueNow -= pss->iStep;
+ }else{
+ pss->isNotEOF = 0;
+ }
+ }else{
+ if( pss->uSeqIndexNow < pss->uSeqIndexMax ){
+ pss->uSeqIndexNow++;
+ pss->iValueNow += pss->iStep;
+ }else{
+ pss->isNotEOF = 0;
+ }
+ }
+ return pss->isNotEOF;
+}
/* series_cursor is a subclass of wx_sqlite3_vtab_cursor which will
** serve as the underlying representation of a cursor that scans
@@ -278276,12 +296665,7 @@ SQLITE_EXTENSION_INIT1
typedef struct series_cursor series_cursor;
struct series_cursor {
wx_sqlite3_vtab_cursor base; /* Base class - must be first */
- int isDesc; /* True to count down rather than up */
- wx_sqlite3_int64 iRowid; /* The rowid */
- wx_sqlite3_int64 iValue; /* Current value ("value") */
- wx_sqlite3_int64 mnValue; /* Mimimum value ("start") */
- wx_sqlite3_int64 mxValue; /* Maximum value ("stop") */
- wx_sqlite3_int64 iStep; /* Increment ("step") */
+ SequenceSpec ss; /* (this) Derived class data */
};
/*
@@ -278363,12 +296747,7 @@ static int seriesClose(wx_sqlite3_vtab_cursor *cur){
*/
static int seriesNext(wx_sqlite3_vtab_cursor *cur){
series_cursor *pCur = (series_cursor*)cur;
- if( pCur->isDesc ){
- pCur->iValue -= pCur->iStep;
- }else{
- pCur->iValue += pCur->iStep;
- }
- pCur->iRowid++;
+ progressSequence( & pCur->ss );
return SQLITE_OK;
}
@@ -278384,23 +296763,29 @@ static int seriesColumn(
series_cursor *pCur = (series_cursor*)cur;
wx_sqlite3_int64 x = 0;
switch( i ){
- case SERIES_COLUMN_START: x = pCur->mnValue; break;
- case SERIES_COLUMN_STOP: x = pCur->mxValue; break;
- case SERIES_COLUMN_STEP: x = pCur->iStep; break;
- default: x = pCur->iValue; break;
+ case SERIES_COLUMN_START: x = pCur->ss.iOBase; break;
+ case SERIES_COLUMN_STOP: x = pCur->ss.iOTerm; break;
+ case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
+ default: x = pCur->ss.iValueNow; break;
}
wx_sqlite3_result_int64(ctx, x);
return SQLITE_OK;
}
+#ifndef LARGEST_UINT64
+#define LARGEST_INT64 (0xffffffff|(((wx_sqlite3_int64)0x7fffffff)<<32))
+#define LARGEST_UINT64 (0xffffffff|(((wx_sqlite3_uint64)0xffffffff)<<32))
+#define SMALLEST_INT64 (((wx_sqlite3_int64)-1) - LARGEST_INT64)
+#endif
+
/*
-** Return the rowid for the current row. In this implementation, the
-** first row returned is assigned rowid value 1, and each subsequent
-** row a value 1 more than that of the previous.
+** Return the rowid for the current row, logically equivalent to n+1 where
+** "n" is the ascending integer in the aforesaid production definition.
*/
static int seriesRowid(wx_sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
series_cursor *pCur = (series_cursor*)cur;
- *pRowid = pCur->iRowid;
+ wx_sqlite3_uint64 n = pCur->ss.uSeqIndexNow;
+ *pRowid = (wx_sqlite3_int64)((n<LARGEST_UINT64)? n+1 : 0);
return SQLITE_OK;
}
@@ -278410,14 +296795,10 @@ static int seriesRowid(wx_sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
*/
static int seriesEof(wx_sqlite3_vtab_cursor *cur){
series_cursor *pCur = (series_cursor*)cur;
- if( pCur->isDesc ){
- return pCur->iValue < pCur->mnValue;
- }else{
- return pCur->iValue > pCur->mxValue;
- }
+ return !pCur->ss.isNotEOF;
}
-/* True to cause run-time checking of the start=, stop=, and/or step=
+/* True to cause run-time checking of the start=, stop=, and/or step=
** parameters. The only reason to do this is for testing the
** constraint checking logic for virtual tables in the SQLite core.
*/
@@ -278428,74 +296809,185 @@ static int seriesEof(wx_sqlite3_vtab_cursor *cur){
/*
** This method is called to "rewind" the series_cursor object back
** to the first row of output. This method is always called at least
-** once prior to any call to seriesColumn() or seriesRowid() or
+** once prior to any call to seriesColumn() or seriesRowid() or
** seriesEof().
**
** The query plan selected by seriesBestIndex is passed in the idxNum
** parameter. (idxStr is not used in this implementation.) idxNum
** is a bitmask showing which constraints are available:
**
-** 1: start=VALUE
-** 2: stop=VALUE
-** 4: step=VALUE
-**
-** Also, if bit 8 is set, that means that the series should be output
-** in descending order rather than in ascending order. If bit 16 is
-** set, then output must appear in ascending order.
+** 0x0001: start=VALUE
+** 0x0002: stop=VALUE
+** 0x0004: step=VALUE
+** 0x0008: descending order
+** 0x0010: ascending order
+** 0x0020: LIMIT VALUE
+** 0x0040: OFFSET VALUE
+** 0x0080: value=VALUE
+** 0x0100: value>=VALUE
+** 0x0200: value>VALUE
+** 0x1000: value<=VALUE
+** 0x2000: value<VALUE
**
** This routine should initialize the cursor and position it so that it
** is pointing at the first row, or pointing off the end of the table
** (so that seriesEof() will return true) if the table is empty.
*/
static int seriesFilter(
- wx_sqlite3_vtab_cursor *pVtabCursor,
+ wx_sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStrUnused,
int argc, wx_sqlite3_value **argv
){
series_cursor *pCur = (series_cursor *)pVtabCursor;
int i = 0;
+ int returnNoRows = 0;
+ wx_sqlite3_int64 iMin = SMALLEST_INT64;
+ wx_sqlite3_int64 iMax = LARGEST_INT64;
+ wx_sqlite3_int64 iLimit = 0;
+ wx_sqlite3_int64 iOffset = 0;
+
(void)idxStrUnused;
- if( idxNum & 1 ){
- pCur->mnValue = wx_sqlite3_value_int64(argv[i++]);
+ if( idxNum & 0x01 ){
+ pCur->ss.iBase = wx_sqlite3_value_int64(argv[i++]);
}else{
- pCur->mnValue = 0;
+ pCur->ss.iBase = 0;
}
- if( idxNum & 2 ){
- pCur->mxValue = wx_sqlite3_value_int64(argv[i++]);
+ if( idxNum & 0x02 ){
+ pCur->ss.iTerm = wx_sqlite3_value_int64(argv[i++]);
}else{
- pCur->mxValue = 0xffffffff;
+ pCur->ss.iTerm = 0xffffffff;
}
- if( idxNum & 4 ){
- pCur->iStep = wx_sqlite3_value_int64(argv[i++]);
- if( pCur->iStep==0 ){
- pCur->iStep = 1;
- }else if( pCur->iStep<0 ){
- pCur->iStep = -pCur->iStep;
- if( (idxNum & 16)==0 ) idxNum |= 8;
+ if( idxNum & 0x04 ){
+ pCur->ss.iStep = wx_sqlite3_value_int64(argv[i++]);
+ if( pCur->ss.iStep==0 ){
+ pCur->ss.iStep = 1;
+ }else if( pCur->ss.iStep<0 ){
+ if( (idxNum & 0x10)==0 ) idxNum |= 0x08;
}
}else{
- pCur->iStep = 1;
+ pCur->ss.iStep = 1;
}
+
+ /* If there are constraints on the value column but there are
+ ** no constraints on the start, stop, and step columns, then
+ ** initialize the default range to be the entire range of 64-bit signed
+ ** integers. This range will contracted by the value column constraints
+ ** further below.
+ */
+ if( (idxNum & 0x05)==0 && (idxNum & 0x0380)!=0 ){
+ pCur->ss.iBase = SMALLEST_INT64;
+ }
+ if( (idxNum & 0x06)==0 && (idxNum & 0x3080)!=0 ){
+ pCur->ss.iTerm = LARGEST_INT64;
+ }
+ pCur->ss.iOBase = pCur->ss.iBase;
+ pCur->ss.iOTerm = pCur->ss.iTerm;
+
+ /* Extract the LIMIT and OFFSET values, but do not apply them yet.
+ ** The range must first be constrained by the limits on value.
+ */
+ if( idxNum & 0x20 ){
+ iLimit = wx_sqlite3_value_int64(argv[i++]);
+ if( idxNum & 0x40 ){
+ iOffset = wx_sqlite3_value_int64(argv[i++]);
+ }
+ }
+
+ if( idxNum & 0x3380 ){
+ /* Extract the maximum range of output values determined by
+ ** constraints on the "value" column.
+ */
+ if( idxNum & 0x0080 ){
+ iMin = iMax = wx_sqlite3_value_int64(argv[i++]);
+ }else{
+ if( idxNum & 0x0300 ){
+ iMin = wx_sqlite3_value_int64(argv[i++]);
+ if( idxNum & 0x0200 ){
+ if( iMin==LARGEST_INT64 ){
+ returnNoRows = 1;
+ }else{
+ iMin++;
+ }
+ }
+ }
+ if( idxNum & 0x3000 ){
+ iMax = wx_sqlite3_value_int64(argv[i++]);
+ if( idxNum & 0x2000 ){
+ if( iMax==SMALLEST_INT64 ){
+ returnNoRows = 1;
+ }else{
+ iMax--;
+ }
+ }
+ }
+ if( iMin>iMax ){
+ returnNoRows = 1;
+ }
+ }
+
+ /* Try to reduce the range of values to be generated based on
+ ** constraints on the "value" column.
+ */
+ if( pCur->ss.iStep>0 ){
+ wx_sqlite3_int64 szStep = pCur->ss.iStep;
+ if( pCur->ss.iBase<iMin ){
+ wx_sqlite3_uint64 d = iMin - pCur->ss.iBase;
+ pCur->ss.iBase += ((d+szStep-1)/szStep)*szStep;
+ }
+ if( pCur->ss.iTerm>iMax ){
+ wx_sqlite3_uint64 d = pCur->ss.iTerm - iMax;
+ pCur->ss.iTerm -= ((d+szStep-1)/szStep)*szStep;
+ }
+ }else{
+ wx_sqlite3_int64 szStep = -pCur->ss.iStep;
+ assert( szStep>0 );
+ if( pCur->ss.iBase>iMax ){
+ wx_sqlite3_uint64 d = pCur->ss.iBase - iMax;
+ pCur->ss.iBase -= ((d+szStep-1)/szStep)*szStep;
+ }
+ if( pCur->ss.iTerm<iMin ){
+ wx_sqlite3_uint64 d = iMin - pCur->ss.iTerm;
+ pCur->ss.iTerm += ((d+szStep-1)/szStep)*szStep;
+ }
+ }
+ }
+
+ /* Apply LIMIT and OFFSET constraints, if any */
+ if( idxNum & 0x20 ){
+ if( iOffset>0 ){
+ pCur->ss.iBase += pCur->ss.iStep*iOffset;
+ }
+ if( iLimit>=0 ){
+ wx_sqlite3_int64 iTerm;
+ iTerm = pCur->ss.iBase + (iLimit - 1)*pCur->ss.iStep;
+ if( pCur->ss.iStep<0 ){
+ if( iTerm>pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
+ }else{
+ if( iTerm<pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
+ }
+ }
+ }
+
+
for(i=0; i<argc; i++){
if( wx_sqlite3_value_type(argv[i])==SQLITE_NULL ){
/* If any of the constraints have a NULL value, then return no rows.
** See ticket https://www.sqlite.org/src/info/fac496b61722daf2 */
- pCur->mnValue = 1;
- pCur->mxValue = 0;
+ returnNoRows = 1;
break;
}
}
- if( idxNum & 8 ){
- pCur->isDesc = 1;
- pCur->iValue = pCur->mxValue;
- if( pCur->iStep>0 ){
- pCur->iValue -= (pCur->mxValue - pCur->mnValue)%pCur->iStep;
- }
+ if( returnNoRows ){
+ pCur->ss.iBase = 1;
+ pCur->ss.iTerm = 0;
+ pCur->ss.iStep = 1;
+ }
+ if( idxNum & 0x08 ){
+ pCur->ss.isReversing = pCur->ss.iStep > 0;
}else{
- pCur->isDesc = 0;
- pCur->iValue = pCur->mnValue;
+ pCur->ss.isReversing = pCur->ss.iStep < 0;
}
- pCur->iRowid = 1;
+ setupSequence( &pCur->ss );
return SQLITE_OK;
}
@@ -278510,10 +297002,35 @@ static int seriesFilter(
**
** The query plan is represented by bits in idxNum:
**
-** (1) start = $value -- constraint exists
-** (2) stop = $value -- constraint exists
-** (4) step = $value -- constraint exists
-** (8) output in descending order
+** 0x0001 start = $num
+** 0x0002 stop = $num
+** 0x0004 step = $num
+** 0x0008 output is in descending order
+** 0x0010 output is in ascending order
+** 0x0020 LIMIT $num
+** 0x0040 OFFSET $num
+** 0x0080 value = $num
+** 0x0100 value >= $num
+** 0x0200 value > $num
+** 0x1000 value <= $num
+** 0x2000 value < $num
+**
+** Only one of 0x0100 or 0x0200 will be returned. Similarly, only
+** one of 0x1000 or 0x2000 will be returned. If the 0x0080 is set, then
+** none of the 0xff00 bits will be set.
+**
+** The order of parameters passed to xFilter is as follows:
+**
+** * The argument to start= if bit 0x0001 is in the idxNum mask
+** * The argument to stop= if bit 0x0002 is in the idxNum mask
+** * The argument to step= if bit 0x0004 is in the idxNum mask
+** * The argument to LIMIT if bit 0x0020 is in the idxNum mask
+** * The argument to OFFSET if bit 0x0040 is in the idxNum mask
+** * The argument to value=, or value>= or value> if any of
+** bits 0x0380 are in the idxNum mask
+** * The argument to value<= or value< if either of bits 0x3000
+** are in the mask
+**
*/
static int seriesBestIndex(
wx_sqlite3_vtab *pVTab,
@@ -278521,10 +297038,14 @@ static int seriesBestIndex(
){
int i, j; /* Loop over constraints */
int idxNum = 0; /* The query plan bitmask */
+#ifndef ZERO_ARGUMENT_GENERATE_SERIES
int bStartSeen = 0; /* EQ constraint seen on the START column */
+#endif
int unusableMask = 0; /* Mask of unusable constraints */
int nArg = 0; /* Number of arguments that seriesFilter() expects */
- int aIdx[3]; /* Constraints on start, stop, and step */
+ int aIdx[7]; /* Constraints on start, stop, step, LIMIT, OFFSET,
+ ** and value. aIdx[5] covers value=, value>=, and
+ ** value>, aIdx[6] covers value<= and value< */
const struct wx_sqlite3_index_constraint *pConstraint;
/* This implementation assumes that the start, stop, and step columns
@@ -278532,28 +297053,105 @@ static int seriesBestIndex(
assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
- aIdx[0] = aIdx[1] = aIdx[2] = -1;
+ aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = aIdx[5] = aIdx[6] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
int iCol; /* 0 for start, 1 for stop, 2 for step */
int iMask; /* bitmask for those column */
- if( pConstraint->iColumn<SERIES_COLUMN_START ) continue;
+ int op = pConstraint->op;
+ if( op>=SQLITE_INDEX_CONSTRAINT_LIMIT
+ && op<=SQLITE_INDEX_CONSTRAINT_OFFSET
+ ){
+ if( pConstraint->usable==0 ){
+ /* do nothing */
+ }else if( op==SQLITE_INDEX_CONSTRAINT_LIMIT ){
+ aIdx[3] = i;
+ idxNum |= 0x20;
+ }else{
+ assert( op==SQLITE_INDEX_CONSTRAINT_OFFSET );
+ aIdx[4] = i;
+ idxNum |= 0x40;
+ }
+ continue;
+ }
+ if( pConstraint->iColumn<SERIES_COLUMN_START ){
+ if( pConstraint->iColumn==SERIES_COLUMN_VALUE && pConstraint->usable ){
+ switch( op ){
+ case SQLITE_INDEX_CONSTRAINT_EQ:
+ case SQLITE_INDEX_CONSTRAINT_IS: {
+ idxNum |= 0x0080;
+ idxNum &= ~0x3300;
+ aIdx[5] = i;
+ aIdx[6] = -1;
+#ifndef ZERO_ARGUMENT_GENERATE_SERIES
+ bStartSeen = 1;
+#endif
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_GE: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x0100;
+ idxNum &= ~0x0200;
+ aIdx[5] = i;
+#ifndef ZERO_ARGUMENT_GENERATE_SERIES
+ bStartSeen = 1;
+#endif
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_GT: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x0200;
+ idxNum &= ~0x0100;
+ aIdx[5] = i;
+#ifndef ZERO_ARGUMENT_GENERATE_SERIES
+ bStartSeen = 1;
+#endif
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_LE: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x1000;
+ idxNum &= ~0x2000;
+ aIdx[6] = i;
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_LT: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x2000;
+ idxNum &= ~0x1000;
+ aIdx[6] = i;
+ break;
+ }
+ }
+ }
+ continue;
+ }
iCol = pConstraint->iColumn - SERIES_COLUMN_START;
assert( iCol>=0 && iCol<=2 );
iMask = 1 << iCol;
- if( iCol==0 ) bStartSeen = 1;
+#ifndef ZERO_ARGUMENT_GENERATE_SERIES
+ if( iCol==0 && op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ bStartSeen = 1;
+ }
+#endif
if( pConstraint->usable==0 ){
unusableMask |= iMask;
continue;
- }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ }else if( op==SQLITE_INDEX_CONSTRAINT_EQ ){
idxNum |= iMask;
aIdx[iCol] = i;
}
}
- for(i=0; i<3; i++){
+ if( aIdx[3]==0 ){
+ /* Ignore OFFSET if LIMIT is omitted */
+ idxNum &= ~0x60;
+ aIdx[4] = 0;
+ }
+ for(i=0; i<7; i++){
if( (j = aIdx[i])>=0 ){
pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
- pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
+ pIdxInfo->aConstraintUsage[j].omit =
+ !SQLITE_SERIES_CONSTRAINT_VERIFY || i>=3;
}
}
/* The current generate_column() implementation requires at least one
@@ -278574,19 +297172,22 @@ static int seriesBestIndex(
** this plan is unusable */
return SQLITE_CONSTRAINT;
}
- if( (idxNum & 3)==3 ){
- /* Both start= and stop= boundaries are available. This is the
+ if( (idxNum & 0x03)==0x03 ){
+ /* Both start= and stop= boundaries are available. This is the
** the preferred case */
pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0));
pIdxInfo->estimatedRows = 1000;
if( pIdxInfo->nOrderBy>=1 && pIdxInfo->aOrderBy[0].iColumn==0 ){
if( pIdxInfo->aOrderBy[0].desc ){
- idxNum |= 8;
+ idxNum |= 0x08;
}else{
- idxNum |= 16;
+ idxNum |= 0x10;
}
pIdxInfo->orderByConsumed = 1;
}
+ }else if( (idxNum & 0x21)==0x21 ){
+ /* We have start= and LIMIT */
+ pIdxInfo->estimatedRows = 2500;
}else{
/* If either boundary is missing, we have to generate a huge span
** of numbers. Make this case very expensive so that the query
@@ -278594,11 +297195,14 @@ static int seriesBestIndex(
pIdxInfo->estimatedRows = 2147483647;
}
pIdxInfo->idxNum = idxNum;
+#ifdef SQLITE_INDEX_SCAN_HEX
+ pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_HEX;
+#endif
return SQLITE_OK;
}
/*
-** This following structure defines all the methods for the
+** This following structure defines all the methods for the
** generate_series virtual table.
*/
static wx_sqlite3_module seriesModule = {
@@ -278625,7 +297229,8 @@ static wx_sqlite3_module seriesModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -278634,8 +297239,8 @@ static wx_sqlite3_module seriesModule = {
__declspec(dllexport)
#endif
int wx_sqlite3_series_init(
- wx_sqlite3 *db,
- char **pzErrMsg,
+ wx_sqlite3 *db,
+ char **pzErrMsg,
const wx_sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
@@ -278888,7 +297493,7 @@ int wx_sqlite3_uuid_init(
rc = wx_sqlite3_create_function(db, "uuid", 0, SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
wx_sqlite3UuidFunc, 0, 0);
if( rc==SQLITE_OK ){
- rc = wx_sqlite3_create_function(db, "uuid_str", 1,
+ rc = wx_sqlite3_create_function(db, "uuid_str", 1,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
0, wx_sqlite3UuidStrFunc, 0, 0);
}
@@ -279086,7 +297691,7 @@ static void re_add_state(ReStateSet *pSet, int newState){
/* Extract the next unicode character from *pzIn and return it. Advance
** *pzIn to the first byte past the end of the character returned. To
-** be clear: this routine converts utf8 to unicode. This routine is
+** be clear: this routine converts utf8 to unicode. This routine is
** optimized for the common case where the next character is a single byte.
*/
static unsigned re_next_char(ReInput *p){
@@ -279157,7 +297762,7 @@ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
/* Look for the initial prefix match, if there is one. */
if( pRe->nInit ){
unsigned char x = pRe->zInit[0];
- while( in.i+pRe->nInit<=in.mx
+ while( in.i+pRe->nInit<=in.mx
&& (zIn[in.i]!=x ||
strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
){
@@ -279512,7 +298117,7 @@ static const char *re_subcompile_string(ReCompiled *p){
break;
}
case '[': {
- int iFirst = p->nState;
+ unsigned int iFirst = p->nState;
if( rePeek(p)=='^' ){
re_append(p, RE_OP_CC_EXC, 0);
p->sIn.i++;
@@ -279536,7 +298141,7 @@ static const char *re_subcompile_string(ReCompiled *p){
if( rePeek(p)==']' ){ p->sIn.i++; break; }
}
if( c==0 ) return "unclosed '['";
- p->aArg[iFirst] = p->nState - iFirst;
+ if( p->nState>iFirst ) p->aArg[iFirst] = p->nState - iFirst;
break;
}
case '\\': {
@@ -279627,7 +298232,7 @@ static const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
/* The following is a performance optimization. If the regex begins with
** ".*" (if the input regex lacks an initial "^") and afterwards there are
** one or more matching characters, enter those matching characters into
- ** zInit[]. The re_match() routine can then search ahead in the input
+ ** zInit[]. The re_match() routine can then search ahead in the input
** string looking for the initial match without having to run the whole
** regex engine over the string. Do not worry about trying to match
** unicode characters beyond plane 0 - those are very rare and this is
@@ -279770,14 +298375,14 @@ re_bytecode_func_err:
__declspec(dllexport)
#endif
int wx_sqlite3_regexp_init(
- wx_sqlite3 *db,
- char **pzErrMsg,
+ wx_sqlite3 *db,
+ char **pzErrMsg,
const wx_sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused */
- rc = wx_sqlite3_create_function(db, "regexp", 2,
+ rc = wx_sqlite3_create_function(db, "regexp", 2,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
0, re_sql_func, 0, 0);
if( rc==SQLITE_OK ){
@@ -279923,7 +298528,7 @@ int wx_sqlite3_regexp_init(
-/* Defines to completely disable specific portions of miniz.c:
+/* Defines to completely disable specific portions of miniz.c:
If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */
/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */
@@ -279946,7 +298551,7 @@ int wx_sqlite3_regexp_init(
/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */
/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */
-/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
+/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc
callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user
functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */
@@ -280382,7 +298987,7 @@ extern MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque, void *address, si
#ifdef __cplusplus
}
#endif
-
+
#ifdef __cplusplus
@@ -280572,7 +299177,7 @@ MINIZ_EXPORT void tdefl_compressor_free(tdefl_compressor *pComp);
#ifdef __cplusplus
}
#endif
-
+
/* ------------------- Low-level Decompression API Definitions */
@@ -280716,7 +299321,7 @@ struct tinfl_decompressor_tag
#ifdef __cplusplus
}
#endif
-
+
@@ -281034,13 +299639,13 @@ MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, c
#if 0
/* TODO */
- typedef void *mz_zip_streaming_extract_state_ptr;
- mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);
- uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
- uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
- mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs);
- size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size);
- mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
+ typedef void *mz_zip_streaming_extract_state_ptr;
+ mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);
+ uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
+ uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
+ mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs);
+ size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size);
+ mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
#endif
/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */
@@ -281102,8 +299707,8 @@ MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const cha
/* Adds the contents of a file to an archive. This function also records the disk file's modified time into the archive. */
/* File data is supplied via a read callback function. User mz_zip_writer_add_(c)file to add a file directly.*/
MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 max_size,
- const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len,
- const char *user_extra_data_central, mz_uint user_extra_data_central_len);
+ const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len,
+ const char *user_extra_data_central, mz_uint user_extra_data_central_len);
#ifndef MINIZ_NO_STDIO
@@ -282538,15 +301143,15 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush)
#ifdef MINIZ_UNALIGNED_USE_MEMCPY
static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p)
{
- mz_uint16 ret;
- memcpy(&ret, p, sizeof(mz_uint16));
- return ret;
+ mz_uint16 ret;
+ memcpy(&ret, p, sizeof(mz_uint16));
+ return ret;
}
static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p)
{
- mz_uint16 ret;
- memcpy(&ret, p, sizeof(mz_uint16));
- return ret;
+ mz_uint16 ret;
+ memcpy(&ret, p, sizeof(mz_uint16));
+ return ret;
}
#else
#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p)
@@ -282654,9 +301259,9 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe
#ifdef MINIZ_UNALIGNED_USE_MEMCPY
static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8* p)
{
- mz_uint32 ret;
- memcpy(&ret, p, sizeof(mz_uint32));
- return ret;
+ mz_uint32 ret;
+ memcpy(&ret, p, sizeof(mz_uint32));
+ return ret;
}
#else
#define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p)
@@ -282731,7 +301336,7 @@ static mz_bool tdefl_compress_fast(tdefl_compressor *d)
pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
#ifdef MINIZ_UNALIGNED_USE_MEMCPY
- memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist));
+ memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist));
#else
*(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
#endif
@@ -283900,7 +302505,7 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex
do
{
#ifdef MINIZ_UNALIGNED_USE_MEMCPY
- memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32)*2);
+ memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32)*2);
#else
((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
@@ -283927,7 +302532,7 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex
pOut_buf_cur[2] = pSrc[2];
pOut_buf_cur += 3;
pSrc += 3;
- counter -= 3;
+ counter -= 3;
}
if (counter > 0)
{
@@ -284865,47 +303470,47 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flag
if (extra_size_remaining)
{
- const mz_uint8 *pExtra_data;
- void* buf = NULL;
-
- if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n)
- {
- buf = MZ_MALLOC(ext_data_size);
- if(buf==NULL)
- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
-
- if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size)
- {
- MZ_FREE(buf);
- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
- }
-
- pExtra_data = (mz_uint8*)buf;
- }
- else
- {
- pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
- }
+ const mz_uint8 *pExtra_data;
+ void* buf = NULL;
+
+ if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n)
+ {
+ buf = MZ_MALLOC(ext_data_size);
+ if(buf==NULL)
+ return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+ if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size)
+ {
+ MZ_FREE(buf);
+ return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+ }
+
+ pExtra_data = (mz_uint8*)buf;
+ }
+ else
+ {
+ pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
+ }
do
{
mz_uint32 field_id;
mz_uint32 field_data_size;
- if (extra_size_remaining < (sizeof(mz_uint16) * 2))
- {
- MZ_FREE(buf);
- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
- }
+ if (extra_size_remaining < (sizeof(mz_uint16) * 2))
+ {
+ MZ_FREE(buf);
+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+ }
field_id = MZ_READ_LE16(pExtra_data);
field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
- if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)
- {
- MZ_FREE(buf);
- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
- }
+ if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)
+ {
+ MZ_FREE(buf);
+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+ }
if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
{
@@ -284919,7 +303524,7 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flag
extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
} while (extra_size_remaining);
- MZ_FREE(buf);
+ MZ_FREE(buf);
}
}
@@ -285124,7 +303729,7 @@ mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename,
if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
{
- MZ_FCLOSE(pFile);
+ MZ_FCLOSE(pFile);
return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
}
@@ -287336,16 +305941,16 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n
}
#endif /* #ifndef MINIZ_NO_TIME */
- if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
- {
- uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
- uncomp_size = buf_size;
- if (uncomp_size <= 3)
- {
- level = 0;
- store_data_uncompressed = MZ_TRUE;
- }
- }
+ if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
+ {
+ uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
+ uncomp_size = buf_size;
+ if (uncomp_size <= 3)
+ {
+ level = 0;
+ store_data_uncompressed = MZ_TRUE;
+ }
+ }
archive_name_size = strlen(pArchive_name);
if (archive_name_size > MZ_UINT16_MAX)
@@ -287361,9 +305966,9 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n
{
/* Bail early if the archive would obviously become too large */
if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size
- + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len +
- pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len
- + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF)
+ + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len +
+ pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len
+ + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF)
{
pState->m_zip64 = MZ_TRUE;
/*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
@@ -287462,13 +306067,13 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n
cur_archive_file_ofs += archive_name_size;
}
- if (user_extra_data_len > 0)
- {
- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+ if (user_extra_data_len > 0)
+ {
+ if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
+ return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
- cur_archive_file_ofs += user_extra_data_len;
- }
+ cur_archive_file_ofs += user_extra_data_len;
+ }
if (store_data_uncompressed)
{
@@ -287620,8 +306225,8 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA
{
/* Bail early if the archive would obviously become too large */
if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE
- + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024
- + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF)
+ + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024
+ + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF)
{
pState->m_zip64 = MZ_TRUE;
/*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
@@ -287863,7 +306468,7 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA
if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header,
(mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len),
- (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : uncomp_size,
+ (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : uncomp_size,
(max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : comp_size,
uncomp_crc32, method, gen_flags, dos_time, dos_date))
return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
@@ -287912,20 +306517,20 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA
static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
{
- MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque;
- mz_int64 cur_ofs = MZ_FTELL64(pSrc_file);
+ MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque;
+ mz_int64 cur_ofs = MZ_FTELL64(pSrc_file);
- if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET))))
- return 0;
+ if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET))))
+ return 0;
- return MZ_FREAD(pBuf, 1, n, pSrc_file);
+ return MZ_FREAD(pBuf, 1, n, pSrc_file);
}
mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
- const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)
+ const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)
{
- return mz_zip_writer_add_read_buf_callback(pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, max_size, pFile_time, pComment, comment_size, level_and_flags,
- user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len);
+ return mz_zip_writer_add_read_buf_callback(pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, max_size, pFile_time, pComment, comment_size, level_and_flags,
+ user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len);
}
mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
@@ -288247,11 +306852,11 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *
{
/* src is zip64, dest must be zip64 */
- /* name uint32_t's */
- /* id 1 (optional in zip64?) */
- /* crc 1 */
- /* comp_size 2 */
- /* uncomp_size 2 */
+ /* name uint32_t's */
+ /* id 1 (optional in zip64?) */
+ /* crc 1 */
+ /* comp_size 2 */
+ /* uncomp_size 2 */
if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6))
{
pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
@@ -289046,14 +307651,14 @@ static void uncompressFunc(
__declspec(dllexport)
#endif
int wx_sqlite3_compress_init(
- wx_sqlite3 *db,
- char **pzErrMsg,
+ wx_sqlite3 *db,
+ char **pzErrMsg,
const wx_sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
- rc = wx_sqlite3_create_function(db, "compress", 1,
+ rc = wx_sqlite3_create_function(db, "compress", 1,
SQLITE_UTF8 | SQLITE_INNOCUOUS,
0, compressFunc, 0, 0);
if( rc==SQLITE_OK ){
@@ -289162,7 +307767,7 @@ static void sqlarUncompressFunc(
wx_sqlite3_value **argv
){
uLong nData;
- uLongf sz;
+ wx_sqlite3_int64 sz;
assert( argc==2 );
sz = wx_sqlite3_value_int(argv[1]);
@@ -289170,14 +307775,15 @@ static void sqlarUncompressFunc(
if( sz<=0 || sz==(nData = wx_sqlite3_value_bytes(argv[0])) ){
wx_sqlite3_result_value(context, argv[0]);
}else{
+ uLongf szf = sz;
const Bytef *pData= wx_sqlite3_value_blob(argv[0]);
Bytef *pOut = wx_sqlite3_malloc(sz);
if( pOut==0 ){
wx_sqlite3_result_error_nomem(context);
- }else if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){
+ }else if( Z_OK!=uncompress(pOut, &szf, pData, nData) ){
wx_sqlite3_result_error(context, "error in uncompress()", -1);
}else{
- wx_sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT);
+ wx_sqlite3_result_blob(context, pOut, szf, SQLITE_TRANSIENT);
}
wx_sqlite3_free(pOut);
}
@@ -289187,14 +307793,14 @@ static void sqlarUncompressFunc(
__declspec(dllexport)
#endif
int wx_sqlite3_sqlar_init(
- wx_sqlite3 *db,
- char **pzErrMsg,
+ wx_sqlite3 *db,
+ char **pzErrMsg,
const wx_sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
- rc = wx_sqlite3_create_function(db, "sqlar_compress", 1,
+ rc = wx_sqlite3_create_function(db, "sqlar_compress", 1,
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
sqlarCompressFunc, 0, 0);
if( rc==SQLITE_OK ){
@@ -289250,10 +307856,21 @@ SQLITE_EXTENSION_INIT1
#include <stdio.h>
#include <string.h>
#include <assert.h>
+#ifndef SQLITE_NO_STDINT
+# include <stdint.h>
+#endif
/* #include "zlibwrap.h" */
+/* When used as part of the CLI, the wx_sqlite3_stdio.h module will have
+** been included before this one. In that case use the wx_sqlite3_stdio.h
+** #defines. If not, create our own for fopen().
+*/
+#ifndef _SQLITE3_STDIO_H_
+# define wx_sqlite3_fopen fopen
+#endif
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
#ifndef SQLITE_AMALGAMATION
@@ -289297,10 +307914,10 @@ typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
/*
** Definitions for mode bitmasks S_IFDIR, S_IFREG and S_IFLNK.
**
-** In some ways it would be better to obtain these values from system
+** In some ways it would be better to obtain these values from system
** header files. But, the dependency is undesirable and (a) these
** have been stable for decades, (b) the values are part of POSIX and
-** are also made explicit in [man stat], and (c) are part of the
+** are also made explicit in [man stat], and (c) are part of the
** file format for zip archives.
*/
#ifndef S_IFDIR
@@ -289313,7 +307930,7 @@ typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
# define S_IFLNK 0120000
#endif
-static const char ZIPFILE_SCHEMA[] =
+static const char ZIPFILE_SCHEMA[] =
"CREATE TABLE y("
"name PRIMARY KEY," /* 0: Name of file in zip archive */
"mode," /* 1: POSIX mode for file */
@@ -289334,8 +307951,8 @@ static const char ZIPFILE_SCHEMA[] =
**
** ZIPFILE_NEWENTRY_MADEBY:
** Use this value for the "version-made-by" field in new zip file
-** entries. The upper byte indicates "unix", and the lower byte
-** indicates that the zip file matches pkzip specification 3.0.
+** entries. The upper byte indicates "unix", and the lower byte
+** indicates that the zip file matches pkzip specification 3.0.
** This is what info-zip seems to do.
**
** ZIPFILE_NEWENTRY_REQUIRED:
@@ -289364,7 +307981,7 @@ static const char ZIPFILE_SCHEMA[] =
#define ZIPFILE_SIGNATURE_EOCD 0x06054b50
/*
-** The sizes of the fixed-size part of each of the three main data
+** The sizes of the fixed-size part of each of the three main data
** structures in a zip archive.
*/
#define ZIPFILE_LFH_FIXED_SZ 30
@@ -289457,7 +308074,7 @@ struct ZipfileCDS {
*** uncompressed size 4 bytes
*** file name length 2 bytes
*** extra field length 2 bytes
-***
+***
*/
typedef struct ZipfileLFH ZipfileLFH;
struct ZipfileLFH {
@@ -289483,7 +308100,7 @@ struct ZipfileEntry {
ZipfileEntry *pNext; /* Next element in in-memory CDS */
};
-/*
+/*
** Cursor type for zipfile tables.
*/
typedef struct ZipfileCsr ZipfileCsr;
@@ -289556,7 +308173,7 @@ static void zipfileDequote(char *zIn){
/*
** Construct a new ZipfileTab virtual table object.
-**
+**
** argv[0] -> module name ("zipfile")
** argv[1] -> database name
** argv[2] -> table name
@@ -289625,7 +308242,7 @@ static void zipfileEntryFree(ZipfileEntry *p){
}
/*
-** Release resources that should be freed at the end of a write
+** Release resources that should be freed at the end of a write
** transaction.
*/
static void zipfileCleanupTransaction(ZipfileTab *pTab){
@@ -289734,7 +308351,7 @@ static void zipfileCursorErr(ZipfileCsr *pCsr, const char *zFmt, ...){
/*
** Read nRead bytes of data from offset iOff of file pFile into buffer
** aRead[]. Return SQLITE_OK if successful, or an SQLite error code
-** otherwise.
+** otherwise.
**
** If an error does occur, output variable (*pzErrmsg) may be set to point
** to an English language error message. It is the responsibility of the
@@ -289942,7 +308559,7 @@ static int zipfileScanExtra(u8 *aExtra, int nExtra, u32 *pmTime){
** File modification date:
** Bits 00-04: day
** Bits 05-08: month (1-12)
-** Bits 09-15: years from 1980
+** Bits 09-15: years from 1980
**
** https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx
*/
@@ -290002,9 +308619,9 @@ static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mUnixTime){
pCds->mDate = pCds->mTime = 0;
}
- assert( mUnixTime<315507600
- || mUnixTime==zipfileMtime(pCds)
- || ((mUnixTime % 2) && mUnixTime-1==zipfileMtime(pCds))
+ assert( mUnixTime<315507600
+ || mUnixTime==zipfileMtime(pCds)
+ || ((mUnixTime % 2) && mUnixTime-1==zipfileMtime(pCds))
/* || (mUnixTime % 2) */
);
}
@@ -290072,7 +308689,7 @@ static int zipfileGetEntry(
if( rc==SQLITE_OK ){
u32 *pt = &pNew->mUnixTime;
- pNew->cds.zFile = wx_sqlite3_mprintf("%.*s", nFile, aRead);
+ pNew->cds.zFile = wx_sqlite3_mprintf("%.*s", nFile, aRead);
pNew->aExtra = (u8*)&pNew[1];
memcpy(pNew->aExtra, &aRead[nFile], nExtra);
if( pNew->cds.zFile==0 ){
@@ -290100,7 +308717,7 @@ static int zipfileGetEntry(
memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed);
}
}else{
- *pzErr = wx_sqlite3_mprintf("failed to read LFH at offset %d",
+ *pzErr = wx_sqlite3_mprintf("failed to read LFH at offset %d",
(int)pNew->cds.iOffset
);
}
@@ -290152,8 +308769,8 @@ static int zipfileNext(wx_sqlite3_vtab_cursor *cur){
return rc;
}
-static void zipfileFree(void *p) {
- wx_sqlite3_free(p);
+static void zipfileFree(void *p) {
+ wx_sqlite3_free(p);
}
/*
@@ -290203,7 +308820,7 @@ static void zipfileInflate(
** Buffer aIn (size nIn bytes) contains uncompressed data. This function
** compresses it and sets (*ppOut) to point to a buffer containing the
** compressed data. The caller is responsible for eventually calling
-** wx_sqlite3_free() to release buffer (*ppOut). Before returning, (*pnOut)
+** wx_sqlite3_free() to release buffer (*ppOut). Before returning, (*pnOut)
** is set to the size of buffer (*ppOut) in bytes.
**
** If no error occurs, SQLITE_OK is returned. Otherwise, an SQLite error
@@ -290319,7 +308936,10 @@ static int zipfileColumn(
** it to be a directory either if the mode suggests so, or if
** the final character in the name is '/'. */
u32 mode = pCDS->iExternalAttr >> 16;
- if( !(mode & S_IFDIR) && pCDS->zFile[pCDS->nFile-1]!='/' ){
+ if( !(mode & S_IFDIR)
+ && pCDS->nFile>=1
+ && pCDS->zFile[pCDS->nFile-1]!='/'
+ ){
wx_sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC);
}
}
@@ -290389,8 +309009,8 @@ static int zipfileReadEOCD(
/* Scan backwards looking for the signature bytes */
for(i=nRead-20; i>=0; i--){
- if( aRead[i]==0x50 && aRead[i+1]==0x4b
- && aRead[i+2]==0x05 && aRead[i+3]==0x06
+ if( aRead[i]==0x50 && aRead[i+1]==0x4b
+ && aRead[i+2]==0x05 && aRead[i+3]==0x06
){
break;
}
@@ -290415,14 +309035,14 @@ static int zipfileReadEOCD(
}
/*
-** Add object pNew to the linked list that begins at ZipfileTab.pFirstEntry
+** Add object pNew to the linked list that begins at ZipfileTab.pFirstEntry
** and ends with pLastEntry. If argument pBefore is NULL, then pNew is added
** to the end of the list. Otherwise, it is added to the list immediately
** before pBefore (which is guaranteed to be a part of said list).
*/
static void zipfileAddEntry(
- ZipfileTab *pTab,
- ZipfileEntry *pBefore,
+ ZipfileTab *pTab,
+ ZipfileEntry *pBefore,
ZipfileEntry *pNew
){
assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) );
@@ -290468,7 +309088,7 @@ static int zipfileLoadDirectory(ZipfileTab *pTab, const u8 *aBlob, int nBlob){
** xFilter callback.
*/
static int zipfileFilter(
- wx_sqlite3_vtab_cursor *cur,
+ wx_sqlite3_vtab_cursor *cur,
int idxNum, const char *idxStr,
int argc, wx_sqlite3_value **argv
){
@@ -290507,7 +309127,7 @@ static int zipfileFilter(
}
if( 0==pTab->pWriteFd && 0==bInMemory ){
- pCsr->pFile = zFile ? fopen(zFile, "rb") : 0;
+ pCsr->pFile = zFile ? wx_sqlite3_fopen(zFile, "rb") : 0;
if( pCsr->pFile==0 ){
zipfileCursorErr(pCsr, "cannot open file: %s", zFile);
rc = SQLITE_ERROR;
@@ -290631,7 +309251,7 @@ static int zipfileAppendEntry(
}
static int zipfileGetMode(
- wx_sqlite3_value *pVal,
+ wx_sqlite3_value *pVal,
int bIsDir, /* If true, default to directory */
u32 *pMode, /* OUT: Mode value */
char **pzErr /* OUT: Error message */
@@ -290694,10 +309314,10 @@ static int zipfileBegin(wx_sqlite3_vtab *pVtab){
}
/* Open a write fd on the file. Also load the entire central directory
- ** structure into memory. During the transaction any new file data is
+ ** structure into memory. During the transaction any new file data is
** appended to the archive file, but the central directory is accumulated
** in main-memory until the transaction is committed. */
- pTab->pWriteFd = fopen(pTab->zFile, "ab+");
+ pTab->pWriteFd = wx_sqlite3_fopen(pTab->zFile, "ab+");
if( pTab->pWriteFd==0 ){
pTab->base.zErrMsg = wx_sqlite3_mprintf(
"zipfile: failed to open file %s for writing", pTab->zFile
@@ -290756,9 +309376,19 @@ static u32 zipfileGetTime(wx_sqlite3_value *pVal){
*/
static void zipfileRemoveEntryFromList(ZipfileTab *pTab, ZipfileEntry *pOld){
if( pOld ){
- ZipfileEntry **pp;
- for(pp=&pTab->pFirstEntry; (*pp)!=pOld; pp=&((*pp)->pNext));
- *pp = (*pp)->pNext;
+ if( pTab->pFirstEntry==pOld ){
+ pTab->pFirstEntry = pOld->pNext;
+ if( pTab->pLastEntry==pOld ) pTab->pLastEntry = 0;
+ }else{
+ ZipfileEntry *p;
+ for(p=pTab->pFirstEntry; p; p=p->pNext){
+ if( p->pNext==pOld ){
+ p->pNext = pOld->pNext;
+ if( pTab->pLastEntry==pOld ) pTab->pLastEntry = p;
+ break;
+ }
+ }
+ }
zipfileEntryFree(pOld);
}
}
@@ -290767,9 +309397,9 @@ static void zipfileRemoveEntryFromList(ZipfileTab *pTab, ZipfileEntry *pOld){
** xUpdate method.
*/
static int zipfileUpdate(
- wx_sqlite3_vtab *pVtab,
- int nVal,
- wx_sqlite3_value **apVal,
+ wx_sqlite3_vtab *pVtab,
+ int nVal,
+ wx_sqlite3_value **apVal,
sqlite_int64 *pRowid
){
ZipfileTab *pTab = (ZipfileTab*)pVtab;
@@ -290824,7 +309454,7 @@ static int zipfileUpdate(
rc = SQLITE_CONSTRAINT;
}
if( wx_sqlite3_value_type(apVal[6])!=SQLITE_NULL ){
- zipfileTableErr(pTab, "rawdata must be NULL");
+ zipfileTableErr(pTab, "rawdata must be NULL");
rc = SQLITE_CONSTRAINT;
}
@@ -291409,13 +310039,14 @@ static int zipfileRegister(wx_sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollback */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
int rc = wx_sqlite3_create_module(db, "zipfile" , &zipfileModule, 0);
if( rc==SQLITE_OK ) rc = wx_sqlite3_overload_function(db, "zipfile_cds", -1);
if( rc==SQLITE_OK ){
- rc = wx_sqlite3_create_function(db, "zipfile", -1, SQLITE_UTF8, 0, 0,
+ rc = wx_sqlite3_create_function(db, "zipfile", -1, SQLITE_UTF8, 0, 0,
zipfileStep, zipfileFinal
);
}
@@ -291433,8 +310064,8 @@ static int zipfileRegister(wx_sqlite3 *db){
__declspec(dllexport)
#endif
int wx_sqlite3_zipfile_init(
- wx_sqlite3 *db,
- char **pzErrMsg,
+ wx_sqlite3 *db,
+ char **pzErrMsg,
const wx_sqlite3_api_routines *pApi
){
SQLITE_EXTENSION_INIT2(pApi);
@@ -291553,6 +310184,8 @@ static int mcIoUnfetch(wx_sqlite3_file* pFile, wx_sqlite3_int64 iOfst, void* p);
#define SQLITE3MC_VFS_NAME ("multipleciphers")
+#define SQLITE3MC_FCNTL_PVFS 0x3f98c078
+
/*
** Header sizes of WAL journal files
*/
@@ -291562,7 +310195,57 @@ static const int walFileHeaderSize = 32;
/*
** Global I/O method structure of SQLite3 Multiple Ciphers VFS
*/
-static wx_sqlite3_io_methods mcIoMethodsGlobal =
+
+#define IOMETHODS_VERSION_MIN 1
+#define IOMETHODS_VERSION_MAX 3
+
+static wx_sqlite3_io_methods mcIoMethodsGlobal1 =
+{
+ 1, /* iVersion */
+ mcIoClose, /* xClose */
+ mcIoRead, /* xRead */
+ mcIoWrite, /* xWrite */
+ mcIoTruncate, /* xTruncate */
+ mcIoSync, /* xSync */
+ mcIoFileSize, /* xFileSize */
+ mcIoLock, /* xLock */
+ mcIoUnlock, /* xUnlock */
+ mcIoCheckReservedLock, /* xCheckReservedLock */
+ mcIoFileControl, /* xFileControl */
+ mcIoSectorSize, /* xSectorSize */
+ mcIoDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, /* xShmMap */
+ 0, /* xShmLock */
+ 0, /* xShmBarrier */
+ 0, /* xShmUnmap */
+ 0, /* xFetch */
+ 0, /* xUnfetch */
+};
+
+static wx_sqlite3_io_methods mcIoMethodsGlobal2 =
+{
+ 2, /* iVersion */
+ mcIoClose, /* xClose */
+ mcIoRead, /* xRead */
+ mcIoWrite, /* xWrite */
+ mcIoTruncate, /* xTruncate */
+ mcIoSync, /* xSync */
+ mcIoFileSize, /* xFileSize */
+ mcIoLock, /* xLock */
+ mcIoUnlock, /* xUnlock */
+ mcIoCheckReservedLock, /* xCheckReservedLock */
+ mcIoFileControl, /* xFileControl */
+ mcIoSectorSize, /* xSectorSize */
+ mcIoDeviceCharacteristics, /* xDeviceCharacteristics */
+ mcIoShmMap, /* xShmMap */
+ mcIoShmLock, /* xShmLock */
+ mcIoShmBarrier, /* xShmBarrier */
+ mcIoShmUnmap, /* xShmUnmap */
+ 0, /* xFetch */
+ 0, /* xUnfetch */
+};
+
+static wx_sqlite3_io_methods mcIoMethodsGlobal3 =
{
3, /* iVersion */
mcIoClose, /* xClose */
@@ -291585,6 +310268,9 @@ static wx_sqlite3_io_methods mcIoMethodsGlobal =
mcIoUnfetch, /* xUnfetch */
};
+static wx_sqlite3_io_methods* mcIoMethodsGlobal[] =
+ { 0, &mcIoMethodsGlobal1 , &mcIoMethodsGlobal2 , &mcIoMethodsGlobal3 };
+
/*
** Internal functions
*/
@@ -291615,7 +310301,7 @@ static void mcMainListRemove(wx_sqlite3mc_file* pFile)
}
/*
-** Given that zFileName points to a buffer containing a database file name passed to
+** Given that zFileName points to a buffer containing a database file name passed to
** either the xOpen() or xAccess() VFS method, search the list of main database files
** for a file handle opened by the same database connection on the corresponding
** database file.
@@ -291644,37 +310330,30 @@ static wx_sqlite3mc_vfs* mcFindVfs(wx_sqlite3* db, const char* zDbName)
{
/*
** The top level VFS is not a Multiple Ciphers VFS.
- ** Retrieve the VFS names stack.
+ ** Retrieve the Multiple Ciphers VFS via file control function,
+ ** if it is included in the VFS stack.
*/
- char* zVfsNameStack = 0;
- if ((wx_sqlite3_file_control(db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsNameStack) == SQLITE_OK) && (zVfsNameStack != NULL))
+ wx_sqlite3mc_vfs* pVfs = NULL;
+ if ((wx_sqlite3_file_control(db, zDbName, SQLITE3MC_FCNTL_PVFS, &pVfs) == SQLITE_OK) &&
+ (pVfs && pVfs->base.xOpen == mcVfsOpen))
{
- /* Search for the name prefix of a Multiple Ciphers VFS. */
- char* zVfsName = strstr(zVfsNameStack, SQLITE3MC_VFS_NAME);
- if (zVfsName != NULL)
- {
- /* The prefix was found, now determine the full VFS name. */
- char* zVfsNameEnd = zVfsName + strlen(SQLITE3MC_VFS_NAME);
- if (*zVfsNameEnd == '-')
- {
- for (++zVfsNameEnd; *zVfsNameEnd != '/' && *zVfsNameEnd != 0; ++zVfsNameEnd);
- if (*zVfsNameEnd == '/') *zVfsNameEnd = 0;
-
- /* Find a pointer to the VFS with the determined name. */
- wx_sqlite3_vfs* pVfs = wx_sqlite3_vfs_find(zVfsName);
- if (pVfs && pVfs->xOpen == mcVfsOpen)
- {
- pVfsMC = (wx_sqlite3mc_vfs*) pVfs;
- }
- }
- }
- wx_sqlite3_free(zVfsNameStack);
+ pVfsMC = pVfs;
}
}
return pVfsMC;
}
/*
+** Check whether the VFS of the database file corresponding
+** to the database schema name supports encryption.
+*/
+SQLITE_PRIVATE int wx_sqlite3mcIsEncryptionSupported(wx_sqlite3* db, const char* zDbName)
+{
+ wx_sqlite3mc_vfs* pVfsMC = mcFindVfs(db, zDbName);
+ return (pVfsMC != NULL);
+}
+
+/*
** Find the codec of the database file
** corresponding to the database schema name.
*/
@@ -291703,6 +310382,30 @@ SQLITE_PRIVATE Codec* wx_sqlite3mcGetMainCodec(wx_sqlite3* db)
return wx_sqlite3mcGetCodec(db, "main");
}
+SQLITE_PRIVATE int wx_sqlite3mcIsBackupSupported(wx_sqlite3* pSrc, const char* zSrc, wx_sqlite3* pDest, const char* zDest)
+{
+ int ok = 1;
+ if (pSrc != pDest)
+ {
+ Codec* codecSrc = wx_sqlite3mcGetCodec(pSrc, zSrc);
+ Codec* codecDest = wx_sqlite3mcGetCodec(pDest, zDest);
+ if (codecSrc && codecDest)
+ {
+ /* Both databases have a codec, are encrypted, and have the same page size */
+ ok = wx_sqlite3mcIsEncrypted(codecSrc) && wx_sqlite3mcIsEncrypted(codecDest) &&
+ (wx_sqlite3mcGetPageSizeReadCipher(codecSrc) == wx_sqlite3mcGetPageSizeWriteCipher(codecDest)) &&
+ (wx_sqlite3mcGetReadReserved(codecSrc) == wx_sqlite3mcGetWriteReserved(codecDest));
+ }
+ else
+ {
+ /* At least one database has no codec */
+ /* Backup supported if both databases are plain databases */
+ ok = !codecSrc && !codecDest;
+ }
+ }
+ return ok;
+}
+
/*
** Set the codec of the database file with the given database file name.
**
@@ -291719,12 +310422,13 @@ SQLITE_PRIVATE void wx_sqlite3mcSetCodec(wx_sqlite3* db, const char* zDbName, co
wx_sqlite3mc_vfs* pVfsMC = mcFindVfs(db, zDbName);
if (pVfsMC)
{
- pDbMain = mcFindDbMainFileName((wx_sqlite3mc_vfs*)(db->pVfs), zFileName);
+ pDbMain = mcFindDbMainFileName(pVfsMC, zFileName);
}
if (pDbMain)
{
Codec* prevCodec = pDbMain->codec;
Codec* msgCodec = (codec) ? codec : prevCodec;
+ pDbMain->codec = codec;
if (msgCodec)
{
/* Reset error state of pager */
@@ -291737,7 +310441,6 @@ SQLITE_PRIVATE void wx_sqlite3mcSetCodec(wx_sqlite3* db, const char* zDbName, co
*/
wx_sqlite3mcCodecFree(prevCodec);
}
- pDbMain->codec = codec;
}
else
{
@@ -291759,7 +310462,9 @@ SQLITE_PRIVATE void* wx_sqlite3mcPagerCodec(PgHdrMC* pPg)
{
wx_sqlite3_file* pFile = wx_sqlite3PagerFile(pPg->pPager);
void* aData = 0;
- if (pFile->pMethods == &mcIoMethodsGlobal)
+ if (pFile->pMethods == &mcIoMethodsGlobal1 ||
+ pFile->pMethods == &mcIoMethodsGlobal2 ||
+ pFile->pMethods == &mcIoMethodsGlobal3)
{
wx_sqlite3mc_file* mcFile = (wx_sqlite3mc_file*) pFile;
Codec* codec = mcFile->codec;
@@ -291861,9 +310566,18 @@ static int mcVfsOpen(wx_sqlite3_vfs* pVfs, const char* zName, wx_sqlite3_file* p
if (rc == SQLITE_OK)
{
/*
- ** Real open succeeded, initialize methods, register main database files
+ ** Real open succeeded
+ ** Initialize methods (use same version number as underlying implementation
+ ** Register main database files
*/
- pFile->pMethods = &mcIoMethodsGlobal;
+ int ioMethodsVersion = mcFile->pFile->pMethods->iVersion;
+ if (ioMethodsVersion < IOMETHODS_VERSION_MIN ||
+ ioMethodsVersion > IOMETHODS_VERSION_MAX)
+ {
+ /* If version out of range, use highest known version */
+ ioMethodsVersion = IOMETHODS_VERSION_MAX;
+ }
+ pFile->pMethods = mcIoMethodsGlobal[ioMethodsVersion];
if (flags & SQLITE_OPEN_MAIN_DB)
{
mcMainListAdd(mcFile);
@@ -292023,6 +310737,7 @@ static int mcReadMainDb(wx_sqlite3_file* pFile, void* buffer, int count, wx_sqli
*/
pageNo = prevOffset / pageSize + 1;
bufferDecrypted = wx_sqlite3mcCodec(mcFile->codec, pageBuffer, pageNo, 3);
+ rc = wx_sqlite3mcGetCodecLastError(mcFile->codec);
/*
** Return the requested content
@@ -292051,6 +310766,7 @@ static int mcReadMainDb(wx_sqlite3_file* pFile, void* buffer, int count, wx_sqli
for (iPage = 0; iPage < nPages; ++iPage)
{
void* bufferDecrypted = wx_sqlite3mcCodec(mcFile->codec, data, pageNo, 3);
+ rc = wx_sqlite3mcGetCodecLastError(mcFile->codec);
data += pageSize;
offset += pageSize;
++pageNo;
@@ -292079,6 +310795,7 @@ static int mcReadMainJournal(wx_sqlite3_file* pFile, const void* buffer, int cou
** Decrypt the page buffer, but only if the page number is valid
*/
void* bufferDecrypted = wx_sqlite3mcCodec(codec, (char*) buffer, mcFile->pageNo, 3);
+ rc = wx_sqlite3mcGetCodecLastError(codec);
mcFile->pageNo = 0;
}
else if (count == 4)
@@ -292112,6 +310829,7 @@ static int mcReadSubJournal(wx_sqlite3_file* pFile, const void* buffer, int coun
** Decrypt the page buffer, but only if the page number is valid
*/
void* bufferDecrypted = wx_sqlite3mcCodec(codec, (char*) buffer, mcFile->pageNo, 3);
+ rc = wx_sqlite3mcGetCodecLastError(codec);
}
else if (count == 4)
{
@@ -292160,6 +310878,7 @@ static int mcReadWal(wx_sqlite3_file* pFile, const void* buffer, int count, wx_s
if (pageNo != 0)
{
void* bufferDecrypted = wx_sqlite3mcCodec(codec, (char*)buffer, pageNo, 3);
+ rc = wx_sqlite3mcGetCodecLastError(codec);
}
}
else if (codec->m_walLegacy != 0 && count == pageSize + walFrameHeaderSize)
@@ -292172,6 +310891,7 @@ static int mcReadWal(wx_sqlite3_file* pFile, const void* buffer, int count, wx_s
if (pageNo != 0)
{
void* bufferDecrypted = wx_sqlite3mcCodec(codec, (char*)buffer+walFrameHeaderSize, pageNo, 3);
+ rc = wx_sqlite3mcGetCodecLastError(codec);
}
}
}
@@ -292583,6 +311303,12 @@ static int mcIoFileControl(wx_sqlite3_file* pFile, int op, void* pArg)
switch (op)
{
+ case SQLITE3MC_FCNTL_PVFS:
+ {
+ *(wx_sqlite3mc_vfs**) pArg = p->pVfsMC;
+ doReal = 0;
+ }
+ break;
case SQLITE_FCNTL_PDB:
{
#if 0
@@ -292599,7 +311325,7 @@ static int mcIoFileControl(wx_sqlite3_file* pFile, int op, void* pArg)
*/
wx_sqlite3* db = *((wx_sqlite3**) pArg);
#endif
- }
+ }
break;
case SQLITE_FCNTL_PRAGMA:
{
@@ -292649,7 +311375,10 @@ static int mcIoFileControl(wx_sqlite3_file* pFile, int op, void* pArg)
static int mcIoSectorSize(wx_sqlite3_file* pFile)
{
- return REALFILE(pFile)->pMethods->xSectorSize(REALFILE(pFile));
+ if (REALFILE(pFile)->pMethods->xSectorSize)
+ return REALFILE(pFile)->pMethods->xSectorSize(REALFILE(pFile));
+ else
+ return SQLITE_DEFAULT_SECTOR_SIZE;
}
static int mcIoDeviceCharacteristics(wx_sqlite3_file* pFile)
@@ -292724,6 +311453,37 @@ wx_sqlite3mcCheckVfs(const char* zVfs)
return rc;
}
+SQLITE_PRIVATE int
+wx_sqlite3mcPagerHasCodec(PagerMC* pPager)
+{
+ int hasCodec = 0;
+ wx_sqlite3mc_vfs* pVfsMC = NULL;
+ wx_sqlite3_vfs* pVfs = pPager->pVfs;
+
+ /* Check whether the VFS stack of the pager contains a Multiple Ciphers VFS */
+ for (; pVfs; pVfs = pVfs->pNext)
+ {
+ if (pVfs && pVfs->xOpen == mcVfsOpen)
+ {
+ /* Multiple Ciphers VFS found */
+ pVfsMC = (wx_sqlite3mc_vfs*)(pVfs);
+ break;
+ }
+ }
+
+ /* Check whether codec is enabled for associated database file */
+ if (pVfsMC)
+ {
+ wx_sqlite3mc_file* mcFile = mcFindDbMainFileName(pVfsMC, pPager->zFilename);
+ if (mcFile)
+ {
+ Codec* codec = mcFile->codec;
+ hasCodec = (codec != 0 && wx_sqlite3mcIsEncrypted(codec));
+ }
+ }
+ return hasCodec;
+}
+
/*
** SQLite3 Multiple Ciphers external API functions
*/
@@ -292928,7 +311688,7 @@ wx_sqlite3_extfunc_init(wx_sqlite3 *db, char **pzErrMsg, const wx_sqlite3_api_ro
#endif
static int
-mcCheckValidName(char* name)
+mcCheckValidName(const char* name)
{
size_t nl;
if (!name)
@@ -293048,9 +311808,10 @@ wx_sqlite3mcRegisterCipher(const CipherDescriptor* desc, const CipherParams* par
/* Copy parameters */
for (n = 0; n < np; ++n)
{
+ char* paramName = (char*) wx_sqlite3_malloc((int)strlen(params[n].m_name) + 1);
+ strcpy(paramName, params[n].m_name);
cipherParams[n] = params[n];
- cipherParams[n].m_name = (char*) wx_sqlite3_malloc((int) strlen(params[n].m_name) + 1);
- strcpy(cipherParams[n].m_name, params[n].m_name);
+ cipherParams[n].m_name = paramName;
}
/* Add sentinel */
cipherParams[n] = params[n];
@@ -293133,14 +311894,15 @@ wx_sqlite3mcTermCipherTables()
CipherParams* params = globalCodecParameterTable[n].m_params;
for (k = 0; params[k].m_name[0] != 0; ++k)
{
- wx_sqlite3_free(params[k].m_name);
+ wx_sqlite3_free((char*) params[k].m_name);
}
wx_sqlite3_free(globalCodecParameterTable[n].m_params);
}
}
+ globalCipherCount = 0;
}
-int
+SQLITE_PRIVATE int
wx_sqlite3mc_initialize(const char* arg)
{
int rc = wx_sqlite3mcInitCipherTables();
@@ -293174,6 +311936,12 @@ wx_sqlite3mc_initialize(const char* arg)
rc = wx_sqlite3mcRegisterCipher(&mcRC4Descriptor, mcRC4Params, (CODEC_TYPE_RC4 == CODEC_TYPE));
}
#endif
+#if HAVE_CIPHER_ASCON128
+ if (rc == SQLITE_OK)
+ {
+ rc = wx_sqlite3mcRegisterCipher(&mcAscon128Descriptor, mcAscon128Params, (CODEC_TYPE_ASCON128 == CODEC_TYPE));
+ }
+#endif
/*
** Initialize and register MultiCipher VFS as default VFS
@@ -293266,7 +312034,7 @@ wx_sqlite3mc_initialize(const char* arg)
return rc;
}
-void
+SQLITE_PRIVATE void
wx_sqlite3mc_shutdown(void)
{
wx_sqlite3mc_vfs_shutdown();
@@ -293316,14 +312084,23 @@ wx_sqlite3mc_shutdown(void)
# include "msvc.h"
#endif
+/****** Copy of tclsqlite.h ******/
#if defined(INCLUDE_SQLITE_TCL_H)
-# include "sqlite_tcl.h"
+# include "sqlite_tcl.h" /* Special case for Windows using STDCALL */
#else
-# include "tcl.h"
+# include <tcl.h> /* All normal cases */
# ifndef SQLITE_TCLAPI
-# define SQLITE_TCLAPI
+# define SQLITE_TCLAPI
# endif
#endif
+/* Compatability between Tcl8.6 and Tcl9.0 */
+#if TCL_MAJOR_VERSION==9
+# define CONST const
+#else
+ typedef int Tcl_Size;
+#endif
+/**** End copy of tclsqlite.h ****/
+
#include <errno.h>
/*
@@ -293337,6 +312114,25 @@ wx_sqlite3mc_shutdown(void)
# include <string.h>
# include <assert.h>
typedef unsigned char u8;
+# ifndef SQLITE_PTRSIZE
+# if defined(__SIZEOF_POINTER__)
+# define SQLITE_PTRSIZE __SIZEOF_POINTER__
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(_M_ARM) || defined(__arm__) || defined(__x86) || \
+ (defined(__APPLE__) && defined(__POWERPC__)) || \
+ (defined(__TOS_AIX__) && !defined(__64BIT__))
+# define SQLITE_PTRSIZE 4
+# else
+# define SQLITE_PTRSIZE 8
+# endif
+# endif /* SQLITE_PTRSIZE */
+# if defined(HAVE_STDINT_H)
+ typedef uintptr_t uptr;
+# elif SQLITE_PTRSIZE==4
+ typedef unsigned int uptr;
+# else
+ typedef wx_sqlite3_uint64 uptr;
+# endif
#endif
#include <ctype.h>
@@ -293472,7 +312268,8 @@ struct SqliteDb {
struct IncrblobChannel {
wx_sqlite3_blob *pBlob; /* wx_sqlite3 blob handle */
SqliteDb *pDb; /* Associated database connection */
- int iSeek; /* Current seek offset */
+ wx_sqlite3_int64 iSeek; /* Current seek offset */
+ unsigned int isClosed; /* TCL_CLOSE_READ or TCL_CLOSE_WRITE */
Tcl_Channel channel; /* Channel identifier */
IncrblobChannel *pNext; /* Linked list of all open incrblob channels */
IncrblobChannel *pPrev; /* Linked list of all open incrblob channels */
@@ -293512,14 +312309,23 @@ static void closeIncrblobChannels(SqliteDb *pDb){
/*
** Close an incremental blob channel.
*/
-static int SQLITE_TCLAPI incrblobClose(
+static int SQLITE_TCLAPI incrblobClose2(
ClientData instanceData,
- Tcl_Interp *interp
+ Tcl_Interp *interp,
+ int flags
){
IncrblobChannel *p = (IncrblobChannel *)instanceData;
- int rc = wx_sqlite3_blob_close(p->pBlob);
+ int rc;
wx_sqlite3 *db = p->pDb->db;
+ if( flags ){
+ p->isClosed |= flags;
+ return TCL_OK;
+ }
+
+ /* If we reach this point, then we really do need to close the channel */
+ rc = wx_sqlite3_blob_close(p->pBlob);
+
/* Remove the channel from the SqliteDb.pIncrblob list. */
if( p->pNext ){
p->pNext->pPrev = p->pPrev;
@@ -293540,6 +312346,13 @@ static int SQLITE_TCLAPI incrblobClose(
}
return TCL_OK;
}
+static int SQLITE_TCLAPI incrblobClose(
+ ClientData instanceData,
+ Tcl_Interp *interp
+){
+ return incrblobClose2(instanceData, interp, 0);
+}
+
/*
** Read data from an incremental blob channel.
@@ -293551,9 +312364,9 @@ static int SQLITE_TCLAPI incrblobInput(
int *errorCodePtr
){
IncrblobChannel *p = (IncrblobChannel *)instanceData;
- int nRead = bufSize; /* Number of bytes to read */
- int nBlob; /* Total size of the blob */
- int rc; /* sqlite error code */
+ wx_sqlite3_int64 nRead = bufSize; /* Number of bytes to read */
+ wx_sqlite3_int64 nBlob; /* Total size of the blob */
+ int rc; /* sqlite error code */
nBlob = wx_sqlite3_blob_bytes(p->pBlob);
if( (p->iSeek+nRead)>nBlob ){
@@ -293563,7 +312376,7 @@ static int SQLITE_TCLAPI incrblobInput(
return 0;
}
- rc = wx_sqlite3_blob_read(p->pBlob, (void *)buf, nRead, p->iSeek);
+ rc = wx_sqlite3_blob_read(p->pBlob, (void *)buf, (int)nRead, (int)p->iSeek);
if( rc!=SQLITE_OK ){
*errorCodePtr = rc;
return -1;
@@ -293583,9 +312396,9 @@ static int SQLITE_TCLAPI incrblobOutput(
int *errorCodePtr
){
IncrblobChannel *p = (IncrblobChannel *)instanceData;
- int nWrite = toWrite; /* Number of bytes to write */
- int nBlob; /* Total size of the blob */
- int rc; /* sqlite error code */
+ wx_sqlite3_int64 nWrite = toWrite; /* Number of bytes to write */
+ wx_sqlite3_int64 nBlob; /* Total size of the blob */
+ int rc; /* sqlite error code */
nBlob = wx_sqlite3_blob_bytes(p->pBlob);
if( (p->iSeek+nWrite)>nBlob ){
@@ -293596,7 +312409,7 @@ static int SQLITE_TCLAPI incrblobOutput(
return 0;
}
- rc = wx_sqlite3_blob_write(p->pBlob, (void *)buf, nWrite, p->iSeek);
+ rc = wx_sqlite3_blob_write(p->pBlob, (void*)buf,(int)nWrite, (int)p->iSeek);
if( rc!=SQLITE_OK ){
*errorCodePtr = EIO;
return -1;
@@ -293606,12 +312419,19 @@ static int SQLITE_TCLAPI incrblobOutput(
return nWrite;
}
+/* The datatype of Tcl_DriverWideSeekProc changes between tcl8.6 and tcl9.0 */
+#if TCL_MAJOR_VERSION==9
+# define WideSeekProcType long long
+#else
+# define WideSeekProcType Tcl_WideInt
+#endif
+
/*
** Seek an incremental blob channel.
*/
-static int SQLITE_TCLAPI incrblobSeek(
+static WideSeekProcType SQLITE_TCLAPI incrblobWideSeek(
ClientData instanceData,
- long offset,
+ WideSeekProcType offset,
int seekMode,
int *errorCodePtr
){
@@ -293633,6 +312453,14 @@ static int SQLITE_TCLAPI incrblobSeek(
return p->iSeek;
}
+static int SQLITE_TCLAPI incrblobSeek(
+ ClientData instanceData,
+ long offset,
+ int seekMode,
+ int *errorCodePtr
+){
+ return incrblobWideSeek(instanceData,offset,seekMode,errorCodePtr);
+}
static void SQLITE_TCLAPI incrblobWatch(
@@ -293651,7 +312479,7 @@ static int SQLITE_TCLAPI incrblobHandle(
static Tcl_ChannelType IncrblobChannelType = {
"incrblob", /* typeName */
- TCL_CHANNEL_VERSION_2, /* version */
+ TCL_CHANNEL_VERSION_5, /* version */
incrblobClose, /* closeProc */
incrblobInput, /* inputProc */
incrblobOutput, /* outputProc */
@@ -293660,11 +312488,11 @@ static Tcl_ChannelType IncrblobChannelType = {
0, /* getOptionProc */
incrblobWatch, /* watchProc (this is a no-op) */
incrblobHandle, /* getHandleProc (always returns error) */
- 0, /* close2Proc */
+ incrblobClose2, /* close2Proc */
0, /* blockModeProc */
0, /* flushProc */
0, /* handlerProc */
- 0, /* wideSeekProc */
+ incrblobWideSeek, /* wideSeekProc */
};
/*
@@ -293696,8 +312524,9 @@ static int createIncrblobChannel(
}
p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel));
- p->iSeek = 0;
+ memset(p, 0, sizeof(*p));
p->pBlob = pBlob;
+ if( (flags & TCL_WRITABLE)==0 ) p->isClosed |= TCL_CLOSE_WRITE;
wx_sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count);
p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags);
@@ -293737,7 +312566,7 @@ static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){
** characters appear in pCmd, we will report the string as unsafe.
*/
const char *z;
- int n;
+ Tcl_Size n;
z = Tcl_GetStringFromObj(pCmd, &n);
while( n-- > 0 ){
int c = *(z++);
@@ -293957,7 +312786,7 @@ static int DbTraceV2Handler(
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
Tcl_IncrRefCount(pCmd);
Tcl_ListObjAppendElement(pDb->interp, pCmd,
- Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_NewWideIntObj((Tcl_WideInt)(uptr)pStmt));
Tcl_ListObjAppendElement(pDb->interp, pCmd,
Tcl_NewStringObj(zSql, -1));
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
@@ -293972,7 +312801,7 @@ static int DbTraceV2Handler(
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
Tcl_IncrRefCount(pCmd);
Tcl_ListObjAppendElement(pDb->interp, pCmd,
- Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_NewWideIntObj((Tcl_WideInt)(uptr)pStmt));
Tcl_ListObjAppendElement(pDb->interp, pCmd,
Tcl_NewWideIntObj((Tcl_WideInt)ns));
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
@@ -293986,7 +312815,7 @@ static int DbTraceV2Handler(
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
Tcl_IncrRefCount(pCmd);
Tcl_ListObjAppendElement(pDb->interp, pCmd,
- Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_NewWideIntObj((Tcl_WideInt)(uptr)pStmt));
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
Tcl_DecrRefCount(pCmd);
Tcl_ResetResult(pDb->interp);
@@ -293998,7 +312827,7 @@ static int DbTraceV2Handler(
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
Tcl_IncrRefCount(pCmd);
Tcl_ListObjAppendElement(pDb->interp, pCmd,
- Tcl_NewWideIntObj((Tcl_WideInt)db));
+ Tcl_NewWideIntObj((Tcl_WideInt)(uptr)db));
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
Tcl_DecrRefCount(pCmd);
Tcl_ResetResult(pDb->interp);
@@ -294244,7 +313073,7 @@ static void tclSqlFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value**
** be preserved and reused on the next invocation.
*/
Tcl_Obj **aArg;
- int nArg;
+ Tcl_Size nArg;
if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){
wx_sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
return;
@@ -294307,7 +313136,7 @@ static void tclSqlFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value**
wx_sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
}else{
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
- int n;
+ Tcl_Size n;
u8 *data;
const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
char c = zType[0];
@@ -294320,7 +313149,7 @@ static void tclSqlFunc(wx_sqlite3_context *context, int argc, wx_sqlite3_value**
eType = SQLITE_BLOB;
}else if( (c=='b' && strcmp(zType,"boolean")==0)
|| (c=='w' && strcmp(zType,"wideInt")==0)
- || (c=='i' && strcmp(zType,"int")==0)
+ || (c=='i' && strcmp(zType,"int")==0)
){
eType = SQLITE_INTEGER;
}else if( c=='d' && strcmp(zType,"double")==0 ){
@@ -294718,7 +313547,7 @@ static int dbPrepareAndBind(
}
}
if( pVar ){
- int n;
+ Tcl_Size n;
u8 *data;
const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
c = zType[0];
@@ -294732,8 +313561,9 @@ static int dbPrepareAndBind(
Tcl_IncrRefCount(pVar);
pPreStmt->apParm[iParm++] = pVar;
}else if( c=='b' && strcmp(zType,"boolean")==0 ){
- Tcl_GetIntFromObj(interp, pVar, &n);
- wx_sqlite3_bind_int(pStmt, i, n);
+ int nn;
+ Tcl_GetIntFromObj(interp, pVar, &nn);
+ wx_sqlite3_bind_int(pStmt, i, nn);
}else if( c=='d' && strcmp(zType,"double")==0 ){
double r;
Tcl_GetDoubleFromObj(interp, pVar, &r);
@@ -295062,7 +313892,7 @@ static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){
/*
** If using Tcl version 8.6 or greater, use the NR functions to avoid
-** recursive evalution of scripts by the [db eval] and [db trans]
+** recursive evaluation of scripts by the [db eval] and [db trans]
** commands. Even if the headers used while compiling the extension
** are 8.6 or newer, the code still tests the Tcl version at runtime.
** This allows stubs-enabled builds to be used with older Tcl libraries.
@@ -295120,9 +313950,9 @@ static int SQLITE_TCLAPI DbEvalNextCmd(
if( pArray==0 ){
Tcl_ObjSetVar2(interp, apColName[i], 0, dbEvalColumnValue(p,i), 0);
}else if( (p->evalFlags & SQLITE_EVAL_WITHOUTNULLS)!=0
- && wx_sqlite3_column_type(p->pPreStmt->pStmt, i)==SQLITE_NULL
+ && wx_sqlite3_column_type(p->pPreStmt->pStmt, i)==SQLITE_NULL
){
- Tcl_UnsetVar2(interp, Tcl_GetString(pArray),
+ Tcl_UnsetVar2(interp, Tcl_GetString(pArray),
Tcl_GetString(apColName[i]), 0);
}else{
Tcl_ObjSetVar2(interp, pArray, apColName[i], dbEvalColumnValue(p,i), 0);
@@ -295234,7 +314064,7 @@ static int SQLITE_TCLAPI DbObjCmd(
"timeout", "total_changes", "trace",
"trace_v2", "transaction", "unlock_notify",
"update_hook", "version", "wal_hook",
- 0
+ 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BACKUP, DB_BIND_FALLBACK,
@@ -295297,7 +314127,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}
}else{
char *zAuth;
- int len;
+ Tcl_Size len;
if( pDb->zAuth ){
Tcl_Free(pDb->zAuth);
}
@@ -295380,7 +314210,7 @@ static int SQLITE_TCLAPI DbObjCmd(
** value of the CALLBACK as the binding. If CALLBACK returns something
** other than TCL_OK or TCL_ERROR then bind a NULL.
**
- ** If CALLBACK is an empty string, then revert to the default behavior
+ ** If CALLBACK is an empty string, then revert to the default behavior
** which is to set the binding to NULL.
**
** If CALLBACK returns an error, that causes the statement execution to
@@ -295400,7 +314230,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}
}else{
char *zCallback;
- int len;
+ Tcl_Size len;
if( pDb->zBindFallback ){
Tcl_Free(pDb->zBindFallback);
}
@@ -295430,7 +314260,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}
}else{
char *zBusy;
- int len;
+ Tcl_Size len;
if( pDb->zBusy ){
Tcl_Free(pDb->zBusy);
}
@@ -295537,7 +314367,7 @@ static int SQLITE_TCLAPI DbObjCmd(
SqlCollate *pCollate;
char *zName;
char *zScript;
- int nScript;
+ Tcl_Size nScript;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
return TCL_ERROR;
@@ -295596,7 +314426,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}
}else{
const char *zCommit;
- int len;
+ Tcl_Size len;
if( pDb->zCommit ){
Tcl_Free(pDb->zCommit);
}
@@ -295723,7 +314553,7 @@ static int SQLITE_TCLAPI DbObjCmd(
**
** This command usage is equivalent to the sqlite2.x COPY statement,
** which imports file data into a table using the PostgreSQL COPY file format:
- ** $db copy $conflit_algo $table_name $filename \t \\N
+ ** $db copy $conflict_algorithm $table_name $filename \t \\N
*/
case DB_COPY: {
char *zTable; /* Insert data into this table */
@@ -295916,7 +314746,8 @@ static int SQLITE_TCLAPI DbObjCmd(
Tcl_Obj *pValue = 0;
unsigned char *pBA;
unsigned char *pData;
- int len, xrc;
+ Tcl_Size len;
+ int xrc;
wx_sqlite3_int64 mxSize = 0;
int i;
int isReadonly = 0;
@@ -295974,7 +314805,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}
deserialize_error:
#endif
- break;
+ break;
}
/*
@@ -296084,7 +314915,7 @@ deserialize_error:
objv++;
}
if( objc<3 || objc>5 ){
- Tcl_WrongNumArgs(interp, 2, objv,
+ Tcl_WrongNumArgs(interp, 2, objv,
"?OPTIONS? SQL ?ARRAY-NAME? ?SCRIPT?");
return TCL_ERROR;
}
@@ -296287,7 +315118,7 @@ deserialize_error:
return TCL_ERROR;
}
if( objc==3 ){
- int len;
+ Tcl_Size len;
char *zNull = Tcl_GetStringFromObj(objv[2], &len);
if( pDb->zNull ){
Tcl_Free(pDb->zNull);
@@ -296341,7 +315172,7 @@ deserialize_error:
#endif
}else if( objc==4 ){
char *zProgress;
- int len;
+ Tcl_Size len;
int N;
if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
return TCL_ERROR;
@@ -296387,7 +315218,7 @@ deserialize_error:
}
}else{
char *zProfile;
- int len;
+ Tcl_Size len;
if( pDb->zProfile ){
Tcl_Free(pDb->zProfile);
}
@@ -296487,7 +315318,7 @@ deserialize_error:
/*
** $db serialize ?DATABASE?
**
- ** Return a serialization of a database.
+ ** Return a serialization of a database.
*/
case DB_SERIALIZE: {
#ifdef SQLITE_OMIT_DESERIALIZE
@@ -296598,7 +315429,7 @@ deserialize_error:
}
}else{
char *zTrace;
- int len;
+ Tcl_Size len;
if( pDb->zTrace ){
Tcl_Free(pDb->zTrace);
}
@@ -296638,7 +315469,7 @@ deserialize_error:
}
}else{
char *zTraceV2;
- int len;
+ Tcl_Size len;
Tcl_WideInt wMask = 0;
if( objc==4 ){
static const char *TTYPE_strs[] = {
@@ -296709,7 +315540,7 @@ deserialize_error:
** Start a new transaction (if we are not already in the midst of a
** transaction) and execute the TCL script SCRIPT. After SCRIPT
** completes, either commit the transaction or roll it back if SCRIPT
- ** throws an exception. Or if no new transation was started, do nothing.
+ ** throws an exception. Or if no new transaction was started, do nothing.
** pass the exception on up the stack.
**
** This command was inspired by Dave Thomas's talk on Ruby at the
@@ -296813,7 +315644,7 @@ deserialize_error:
*/
case DB_PREUPDATE: {
#ifndef SQLITE_ENABLE_PREUPDATE_HOOK
- Tcl_AppendResult(interp, "preupdate_hook was omitted at compile-time",
+ Tcl_AppendResult(interp, "preupdate_hook was omitted at compile-time",
(char*)0);
rc = TCL_ERROR;
#else
@@ -296952,7 +315783,7 @@ deserialize_error:
return TCL_ERROR;
}
}
- if( i==2 ){
+ if( i==2 ){
Tcl_SetResult(interp, (char *)wx_sqlite3_libversion(), TCL_STATIC);
}
break;
@@ -297200,7 +316031,7 @@ static int SQLITE_TCLAPI DbMain(
** The EXTERN macros are required by TCL in order to work on windows.
*/
EXTERN int Sqlite3_Init(Tcl_Interp *interp){
- int rc = Tcl_InitStubs(interp, "8.4", 0) ? TCL_OK : TCL_ERROR;
+ int rc = Tcl_InitStubs(interp, "8.5-", 0) ? TCL_OK : TCL_ERROR;
if( rc==TCL_OK ){
Tcl_CreateObjCommand(interp, "wx_sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
#ifndef SQLITE_3_SUFFIX_ONLY
@@ -297224,14 +316055,25 @@ EXTERN int Tclwx_sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; }
EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;}
+/*
+** Versions of all of the above entry points that omit the "3" at the end
+** of the name. Years ago (circa 2004) the "3" was necessary to distinguish
+** SQLite version 3 from Sqlite version 2. But two decades have elapsed.
+** SQLite2 is not longer a conflict. So it is ok to omit the "3".
+**
+** Omitting the "3" helps TCL find the entry point.
+*/
+EXTERN int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}
+EXTERN int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
+EXTERN int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
+EXTERN int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
+EXTERN int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; }
+EXTERN int Sqlite_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;}
+/* Also variants with a lowercase "s" */
+EXTERN int wx_sqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}
+EXTERN int sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}
-#ifndef SQLITE_3_SUFFIX_ONLY
-int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
-int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
-int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
-int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
-#endif
/*
** If the TCLSH macro is defined, add code to make a stand-alone program.
@@ -297245,6 +316087,23 @@ int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
static const char *tclsh_main_loop(void){
static const char zMainloop[] =
"if {[llength $argv]>=1} {\n"
+#ifdef WIN32
+ "set new [list]\n"
+ "foreach arg $argv {\n"
+ "if {[string match -* $arg] || [file exists $arg]} {\n"
+ "lappend new $arg\n"
+ "} else {\n"
+ "set once 0\n"
+ "foreach match [lsort [glob -nocomplain $arg]] {\n"
+ "lappend new $match\n"
+ "set once 1\n"
+ "}\n"
+ "if {!$once} {lappend new $arg}\n"
+ "}\n"
+ "}\n"
+ "set argv $new\n"
+ "unset new\n"
+#endif
"set argv0 [lindex $argv 0]\n"
"set argv [lrange $argv 1 end]\n"
"source $argv0\n"
diff --git a/Plugins/DbSqliteWx/wxsqlite3.h b/Plugins/DbSqliteWx/wxsqlite3.h
index 35784e9..6520c73 100644
--- a/Plugins/DbSqliteWx/wxsqlite3.h
+++ b/Plugins/DbSqliteWx/wxsqlite3.h
@@ -3,7 +3,7 @@
** Purpose: Header file for SQLite3 Multiple Ciphers support
** Author: Ulrich Telle
** Created: 2020-03-01
-** Copyright: (c) 2019-2022 Ulrich Telle
+** Copyright: (c) 2019-2024 Ulrich Telle
** License: MIT
*/
@@ -20,7 +20,7 @@
** Purpose: SQLite3 Multiple Ciphers version numbers
** Author: Ulrich Telle
** Created: 2020-08-05
-** Copyright: (c) 2020-2023 Ulrich Telle
+** Copyright: (c) 2020-2024 Ulrich Telle
** License: MIT
*/
@@ -30,10 +30,10 @@
#define SQLITE3MC_VERSION_H_
#define SQLITE3MC_VERSION_MAJOR 1
-#define SQLITE3MC_VERSION_MINOR 6
+#define SQLITE3MC_VERSION_MINOR 9
#define SQLITE3MC_VERSION_RELEASE 2
#define SQLITE3MC_VERSION_SUBRELEASE 0
-#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.6.2"
+#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.9.2"
#endif /* SQLITE3MC_VERSION_H_ */
/*** End of #include "wx_sqlite3mc_version.h" ***/
@@ -192,9 +192,9 @@ extern "C" {
** [wx_sqlite3_libversion_number()], [wx_sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.41.2"
-#define SQLITE_VERSION_NUMBER 3041002
-#define SQLITE_SOURCE_ID "2023-03-22 11:56:21 0d1fc92f94cb6b76bffe3ec34d69cffde2924203304e8ffc4155597af0c191da"
+#define SQLITE_VERSION "3.47.2"
+#define SQLITE_VERSION_NUMBER 3047002
+#define SQLITE_SOURCE_ID "2024-12-07 20:39:59 2aabe05e2e8cae4847a802ee2daddc1d7413d8fc560254d93ee3e72c14685b6c"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -466,6 +466,8 @@ typedef int (*wx_sqlite3_callback)(void*,int,char**, char**);
** the 1st parameter to wx_sqlite3_exec() while wx_sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into
** the 2nd parameter of wx_sqlite3_exec() while wx_sqlite3_exec() is running.
+** <li> The application must not dereference the arrays or string pointers
+** passed as the 3rd and 4th callback parameters after it returns.
** </ul>
*/
SQLITE_API int wx_sqlite3_exec(
@@ -574,6 +576,7 @@ SQLITE_API int wx_sqlite3_exec(
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
+#define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
@@ -695,6 +698,13 @@ SQLITE_API int wx_sqlite3_exec(
** filesystem supports doing multiple write operations atomically when those
** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
+**
+** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read
+** from the database file in amounts that are not a multiple of the
+** page size and that do not begin at a page boundary. Without this
+** property, SQLite is careful to only do full-page reads and write
+** on aligned pages, with the one exception that it will do a sub-page
+** read of the first page to access the database header.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -711,6 +721,7 @@ SQLITE_API int wx_sqlite3_exec(
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
+#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000
/*
** CAPI3REF: File Locking Levels
@@ -807,16 +818,16 @@ struct wx_sqlite3_file {
** </ul>
** xLock() upgrades the database file lock. In other words, xLock() moves the
** database file lock in the direction NONE toward EXCLUSIVE. The argument to
-** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
+** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
** SQLITE_LOCK_NONE. If the database file lock is already at or above the
** requested lock, then the call to xLock() is a no-op.
** xUnlock() downgrades the database file lock to either SHARED or NONE.
-* If the lock is already at or below the requested lock state, then the call
+** If the lock is already at or below the requested lock state, then the call
** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
-** PENDING, or EXCLUSIVE lock on the file. It returns true
-** if such a lock exists and false otherwise.
+** PENDING, or EXCLUSIVE lock on the file. It returns, via its output
+** pointer parameter, true if such a lock exists and false otherwise.
**
** The xFileControl() method is a generic interface that allows custom
** VFS implementations to directly control an open file using the
@@ -857,6 +868,7 @@ struct wx_sqlite3_file {
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
** <li> [SQLITE_IOCAP_IMMUTABLE]
** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
+** <li> [SQLITE_IOCAP_SUBPAGE_READ]
** </ul>
**
** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -1236,7 +1248,7 @@ struct wx_sqlite3_io_methods {
** by clients within the current process, only within other processes.
**
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
-** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use interally by the
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the
** [checksum VFS shim] only.
**
** <li>[[SQLITE_FCNTL_RESET_CACHE]]
@@ -1701,20 +1713,23 @@ SQLITE_API int wx_sqlite3_os_end(void);
** must ensure that no other SQLite interfaces are invoked by other
** threads while wx_sqlite3_config() is running.</b>
**
-** The wx_sqlite3_config() interface
-** may only be invoked prior to library initialization using
-** [wx_sqlite3_initialize()] or after shutdown by [wx_sqlite3_shutdown()].
-** ^If wx_sqlite3_config() is called after [wx_sqlite3_initialize()] and before
-** [wx_sqlite3_shutdown()] then it will return SQLITE_MISUSE.
-** Note, however, that ^wx_sqlite3_config() can be called as part of the
-** implementation of an application-defined [wx_sqlite3_os_init()].
-**
** The first argument to wx_sqlite3_config() is an integer
** [configuration option] that determines
** what property of SQLite is to be configured. Subsequent arguments
** vary depending on the [configuration option]
** in the first argument.
**
+** For most configuration options, the wx_sqlite3_config() interface
+** may only be invoked prior to library initialization using
+** [wx_sqlite3_initialize()] or after shutdown by [wx_sqlite3_shutdown()].
+** The exceptional configuration options that may be invoked at any time
+** are called "anytime configuration options".
+** ^If wx_sqlite3_config() is called after [wx_sqlite3_initialize()] and before
+** [wx_sqlite3_shutdown()] with a first argument that is not an anytime
+** configuration option, then the wx_sqlite3_config() call will return SQLITE_MISUSE.
+** Note, however, that ^wx_sqlite3_config() can be called as part of the
+** implementation of an application-defined [wx_sqlite3_os_init()].
+**
** ^When a configuration option is set, wx_sqlite3_config() returns [SQLITE_OK].
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
@@ -1822,6 +1837,23 @@ struct wx_sqlite3_mem_methods {
** These constants are the available integer configuration options that
** can be passed as the first argument to the [wx_sqlite3_config()] interface.
**
+** Most of the configuration options for wx_sqlite3_config()
+** will only work if invoked prior to [wx_sqlite3_initialize()] or after
+** [wx_sqlite3_shutdown()]. The few exceptions to this rule are called
+** "anytime configuration options".
+** ^Calling [wx_sqlite3_config()] with a first argument that is not an
+** anytime configuration option in between calls to [wx_sqlite3_initialize()] and
+** [wx_sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE.
+**
+** The set of anytime configuration options can change (by insertions
+** and/or deletions) from one release of SQLite to the next.
+** As of SQLite version 3.42.0, the complete set of anytime configuration
+** options is:
+** <ul>
+** <li> SQLITE_CONFIG_LOG
+** <li> SQLITE_CONFIG_PCACHE_HDRSZ
+** </ul>
+**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
** should check the return code from [wx_sqlite3_config()] to make sure that
@@ -2152,7 +2184,7 @@ struct wx_sqlite3_mem_methods {
** is stored in each sorted record and the required column values loaded
** from the database as records are returned in sorted order. The default
** value for this option is to never use this optimization. Specifying a
-** negative value for this option restores the default behaviour.
+** negative value for this option restores the default behavior.
** This option is only available if SQLite is compiled with the
** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
**
@@ -2166,30 +2198,46 @@ struct wx_sqlite3_mem_methods {
** configuration setting is never used, then the default maximum is determined
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
** compile-time option is not set, then the default maximum is 1073741824.
+**
+** [[SQLITE_CONFIG_ROWID_IN_VIEW]]
+** <dt>SQLITE_CONFIG_ROWID_IN_VIEW
+** <dd>The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability
+** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is
+** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability
+** defaults to on. This configuration option queries the current setting or
+** changes the setting to off or on. The argument is a pointer to an integer.
+** If that integer initially holds a value of 1, then the ability for VIEWs to
+** have ROWIDs is activated. If the integer initially holds zero, then the
+** ability is deactivated. Any other initial value for the integer leaves the
+** setting unchanged. After changes, if any, the integer is written with
+** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite
+** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and
+** recommended case) then the integer is always filled with zero, regardless
+** if its initial value.
** </dl>
*/
-#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
-#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
-#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* wx_sqlite3_mem_methods* */
-#define SQLITE_CONFIG_GETMALLOC 5 /* wx_sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
-#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
-#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
-#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
-#define SQLITE_CONFIG_MUTEX 10 /* wx_sqlite3_mutex_methods* */
-#define SQLITE_CONFIG_GETMUTEX 11 /* wx_sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
-#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#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 /* wx_sqlite3_pcache_methods2* */
-#define SQLITE_CONFIG_GETPCACHE2 19 /* wx_sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
+#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
+#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
+#define SQLITE_CONFIG_MALLOC 4 /* wx_sqlite3_mem_methods* */
+#define SQLITE_CONFIG_GETMALLOC 5 /* wx_sqlite3_mem_methods* */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
+#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
+#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
+#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
+#define SQLITE_CONFIG_MUTEX 10 /* wx_sqlite3_mutex_methods* */
+#define SQLITE_CONFIG_GETMUTEX 11 /* wx_sqlite3_mutex_methods* */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
+#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 /* wx_sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* wx_sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
-#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
-#define SQLITE_CONFIG_MMAP_SIZE 22 /* wx_sqlite3_int64, wx_sqlite3_int64 */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* wx_sqlite3_int64, wx_sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
@@ -2197,6 +2245,7 @@ struct wx_sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* wx_sqlite3_int64 */
+#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2327,7 +2376,7 @@ struct wx_sqlite3_mem_methods {
** database handle, SQLite checks if this will mean that there are now no
** connections at all to the database. If so, it performs a checkpoint
** operation before closing the connection. This option may be used to
-** override this behaviour. The first parameter passed to this operation
+** override this behavior. The first parameter passed to this operation
** is an integer - positive to disable checkpoints-on-close, or zero (the
** default) to enable them, and negative to leave the setting unchanged.
** The second parameter is a pointer to an integer
@@ -2424,7 +2473,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
-** <dt>SQLITE_DBCONFIG_DQS_DML</td>
+** <dt>SQLITE_DBCONFIG_DQS_DML</dt>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@@ -2433,7 +2482,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
-** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
+** <dt>SQLITE_DBCONFIG_DQS_DDL</dt>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
@@ -2442,7 +2491,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
-** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
+** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@@ -2462,7 +2511,7 @@ struct wx_sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
-** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
+** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
@@ -2471,7 +2520,7 @@ struct wx_sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
-** is now scarcely any need to generated database files that are compatible
+** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version
@@ -2480,8 +2529,40 @@ struct wx_sqlite3_mem_methods {
** the [VACUUM] command will fail with an obscure error when attempting to
** process a table with generated columns and a descending index. This is
** not considered a bug since SQLite versions 3.3.0 and earlier do not support
-** either generated columns or decending indexes.
+** either generated columns or descending indexes.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
+** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
+** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
+** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
+** a flag that enables collection of the wx_sqlite3_stmt_scanstatus_v2()
+** statistics. For statistics to be collected, the flag must be set on
+** the database handle both when the SQL statement is prepared and when it
+** is stepped. The flag is set (collection of statistics is enabled)
+** by default. This option takes two arguments: an integer and a pointer to
+** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the statement scanstatus option. If the second argument
+** is not NULL, then the value of the statement scanstatus setting after
+** processing the first argument is written into the integer that the second
+** argument points to.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
+** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
+** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
+** in which tables and indexes are scanned so that the scans start at the end
+** and work toward the beginning rather than starting at the beginning and
+** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
+** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** two arguments which are an integer and a pointer to an integer. The first
+** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
+** reverse scan order flag, respectively. If the second argument is not NULL,
+** then 0 or 1 is written into the integer that the second argument points to
+** depending on if the reverse scan order flag is set after processing the
+** first argument.
** </dd>
+**
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2502,7 +2583,9 @@ struct wx_sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
+#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -2727,6 +2810,7 @@ SQLITE_API wx_sqlite3_int64 wx_sqlite3_total_changes64(wx_sqlite3*);
**
** ^The [wx_sqlite3_is_interrupted(D)] interface can be used to determine whether
** or not an interrupt is currently in effect for [database connection] D.
+** It returns 1 if an interrupt is currently in effect, or 0 otherwise.
*/
SQLITE_API void wx_sqlite3_interrupt(wx_sqlite3*);
SQLITE_API int wx_sqlite3_is_interrupted(wx_sqlite3*);
@@ -3276,8 +3360,8 @@ SQLITE_API int wx_sqlite3_set_authorizer(
#define SQLITE_RECURSIVE 33 /* NULL NULL */
/*
-** CAPI3REF: Tracing And Profiling Functions
-** METHOD: wx_sqlite3
+** CAPI3REF: Deprecated Tracing And Profiling Functions
+** DEPRECATED
**
** These routines are deprecated. Use the [wx_sqlite3_trace_v2()] interface
** instead of the routines described here.
@@ -3380,8 +3464,10 @@ SQLITE_API SQLITE_DEPRECATED void *wx_sqlite3_profile(wx_sqlite3*,
** M argument should be the bitwise OR-ed combination of
** zero or more [SQLITE_TRACE] constants.
**
-** ^Each call to either wx_sqlite3_trace() or wx_sqlite3_trace_v2() overrides
-** (cancels) any prior calls to wx_sqlite3_trace() or wx_sqlite3_trace_v2().
+** ^Each call to either wx_sqlite3_trace(D,X,P) or wx_sqlite3_trace_v2(D,M,X,P)
+** overrides (cancels) all prior calls to wx_sqlite3_trace(D,X,P) or
+** wx_sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each
+** database connection may have at most one trace callback.
**
** ^The X callback is invoked whenever any of the events identified by
** mask M occur. ^The integer return value from the callback is currently
@@ -3539,8 +3625,8 @@ SQLITE_API void wx_sqlite3_progress_handler(wx_sqlite3*, int, int(*)(void*), voi
**
** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt>
** <dd>The database connection comes up in "extended result code mode".
-** In other words, the database behaves has if
-** [wx_sqlite3_extended_result_codes(db,1)] where called on the database
+** In other words, the database behaves as if
+** [wx_sqlite3_extended_result_codes(db,1)] were called on the database
** connection as soon as the connection is created. In addition to setting
** the extended result code mode, this flag also causes [wx_sqlite3_open_v2()]
** to return an extended result code.</dd>
@@ -3750,7 +3836,7 @@ SQLITE_API int wx_sqlite3_open_v2(
** as F) must be one of:
** <ul>
** <li> A database filename pointer created by the SQLite core and
-** passed into the xOpen() method of a VFS implemention, or
+** passed into the xOpen() method of a VFS implementation, or
** <li> A filename obtained from [wx_sqlite3_db_filename()], or
** <li> A new filename constructed using [wx_sqlite3_create_filename()].
** </ul>
@@ -3863,7 +3949,7 @@ SQLITE_API wx_sqlite3_file *wx_sqlite3_database_file_object(const char*);
/*
** CAPI3REF: Create and Destroy VFS Filenames
**
-** These interfces are provided for use by [VFS shim] implementations and
+** These interfaces are provided for use by [VFS shim] implementations and
** are not useful outside of that context.
**
** The wx_sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
@@ -3942,14 +4028,17 @@ SQLITE_API void wx_sqlite3_free_filename(wx_sqlite3_filename);
** </ul>
**
** ^The wx_sqlite3_errmsg() and wx_sqlite3_errmsg16() return English-language
-** text that describes the error, as either UTF-8 or UTF-16 respectively.
+** text that describes the error, as either UTF-8 or UTF-16 respectively,
+** or NULL if no error message is available.
+** (See how SQLite handles [invalid UTF] for exceptions to this rule.)
** ^(Memory to hold the error message string is managed internally.
** The application does not need to worry about freeing the result.
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
-** ^The wx_sqlite3_errstr() interface returns the English-language text
-** that describes the [result code], as UTF-8.
+** ^The wx_sqlite3_errstr(E) interface returns the English-language text
+** that describes the [result code] E, as UTF-8, or NULL if E is not an
+** result code for which a text error message is available.
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
@@ -4188,13 +4277,17 @@ SQLITE_API int wx_sqlite3_limit(wx_sqlite3*, int id, int newVal);
** and wx_sqlite3_prepare16_v3() use UTF-16.
**
** ^If the nByte argument is negative, then zSql is read up to the
-** first zero terminator. ^If nByte is positive, then it is the
-** number of bytes read from zSql. ^If nByte is zero, then no prepared
+** first zero terminator. ^If nByte is positive, then it is the maximum
+** number of bytes read from zSql. When nByte is positive, zSql is read
+** up to the first zero terminator or until the nByte bytes have been read,
+** whichever comes first. ^If nByte is zero, then no prepared
** statement is generated.
** If the caller knows that the supplied string is nul-terminated, then
** there is a small performance advantage to passing an nByte parameter that
** is the number of bytes in the input string <i>including</i>
** the nul-terminator.
+** Note that nByte measure the length of the input in bytes, not
+** characters, even for the UTF-16 interfaces.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only
@@ -4411,6 +4504,41 @@ SQLITE_API int wx_sqlite3_stmt_readonly(wx_sqlite3_stmt *pStmt);
SQLITE_API int wx_sqlite3_stmt_isexplain(wx_sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement
+** METHOD: wx_sqlite3_stmt
+**
+** The wx_sqlite3_stmt_explain(S,E) interface changes the EXPLAIN
+** setting for [prepared statement] S. If E is zero, then S becomes
+** a normal prepared statement. If E is 1, then S behaves as if
+** its SQL text began with "[EXPLAIN]". If E is 2, then S behaves as if
+** its SQL text began with "[EXPLAIN QUERY PLAN]".
+**
+** Calling wx_sqlite3_stmt_explain(S,E) might cause S to be reprepared.
+** SQLite tries to avoid a reprepare, but a reprepare might be necessary
+** on the first transition into EXPLAIN or EXPLAIN QUERY PLAN mode.
+**
+** Because of the potential need to reprepare, a call to
+** wx_sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be
+** reprepared because it was created using [wx_sqlite3_prepare()] instead of
+** the newer [wx_sqlite3_prepare_v2()] or [wx_sqlite3_prepare_v3()] interfaces and
+** hence has no saved SQL text with which to reprepare.
+**
+** Changing the explain setting for a prepared statement does not change
+** the original SQL text for the statement. Hence, if the SQL text originally
+** began with EXPLAIN or EXPLAIN QUERY PLAN, but wx_sqlite3_stmt_explain(S,0)
+** is called to convert the statement into an ordinary statement, the EXPLAIN
+** or EXPLAIN QUERY PLAN keywords will still appear in the wx_sqlite3_sql(S)
+** output, even though the statement now acts like a normal SQL statement.
+**
+** This routine returns SQLITE_OK if the explain mode is successfully
+** changed, or an error code if the explain mode could not be changed.
+** The explain mode cannot be changed while a statement is active.
+** Hence, it is good practice to call [wx_sqlite3_reset(S)]
+** immediately prior to calling wx_sqlite3_stmt_explain(S,E).
+*/
+SQLITE_API int wx_sqlite3_stmt_explain(wx_sqlite3_stmt *pStmt, int eMode);
+
+/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: wx_sqlite3_stmt
**
@@ -4573,7 +4701,7 @@ typedef struct wx_sqlite3_context wx_sqlite3_context;
** with it may be passed. ^It is called to dispose of the BLOB or string even
** if the call to the bind API fails, except the destructor is not called if
** the third parameter is a NULL pointer or the fourth parameter is negative.
-** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that
+** ^ (2) The special constant, [SQLITE_STATIC], may be passed to indicate that
** the application remains responsible for disposing of the object. ^In this
** case, the object and the provided pointer to it must remain valid until
** either the prepared statement is finalized or the same SQL parameter is
@@ -5252,20 +5380,33 @@ SQLITE_API int wx_sqlite3_finalize(wx_sqlite3_stmt *pStmt);
** ^The [wx_sqlite3_reset(S)] interface resets the [prepared statement] S
** back to the beginning of its program.
**
-** ^If the most recent call to [wx_sqlite3_step(S)] for the
-** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
-** or if [wx_sqlite3_step(S)] has never before been called on S,
-** then [wx_sqlite3_reset(S)] returns [SQLITE_OK].
+** ^The return code from [wx_sqlite3_reset(S)] indicates whether or not
+** the previous evaluation of prepared statement S completed successfully.
+** ^If [wx_sqlite3_step(S)] has never before been called on S or if
+** [wx_sqlite3_step(S)] has not been called since the previous call
+** to [wx_sqlite3_reset(S)], then [wx_sqlite3_reset(S)] will return
+** [SQLITE_OK].
**
** ^If the most recent call to [wx_sqlite3_step(S)] for the
** [prepared statement] S indicated an error, then
** [wx_sqlite3_reset(S)] returns an appropriate [error code].
+** ^The [wx_sqlite3_reset(S)] interface might also return an [error code]
+** if there were no prior errors but the process of resetting
+** the prepared statement caused a new error. ^For example, if an
+** [INSERT] statement with a [RETURNING] clause is only stepped one time,
+** that one call to [wx_sqlite3_step(S)] might return SQLITE_ROW but
+** the overall statement might still fail and the [wx_sqlite3_reset(S)] call
+** might return SQLITE_BUSY if locking constraints prevent the
+** database change from committing. Therefore, it is important that
+** applications check the return code from [wx_sqlite3_reset(S)] even if
+** no prior call to [wx_sqlite3_step(S)] indicated a problem.
**
** ^The [wx_sqlite3_reset(S)] interface does not change the values
** of any [wx_sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int wx_sqlite3_reset(wx_sqlite3_stmt *pStmt);
+
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
@@ -5476,7 +5617,7 @@ SQLITE_API int wx_sqlite3_create_window_function(
** [application-defined SQL function]
** that has side-effects or that could potentially leak sensitive information.
** This will prevent attacks in which an application is tricked
-** into using a database file that has had its schema surreptiously
+** into using a database file that has had its schema surreptitiously
** modified to invoke the application-defined function in ways that are
** harmful.
** <p>
@@ -5512,13 +5653,36 @@ SQLITE_API int wx_sqlite3_create_window_function(
** </dd>
**
** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd>
-** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
+** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
** [wx_sqlite3_value_subtype()] to inspect the sub-types of its arguments.
-** Specifying this flag makes no difference for scalar or aggregate user
-** functions. However, if it is not specified for a user-defined window
-** function, then any sub-types belonging to arguments passed to the window
-** function may be discarded before the window function is called (i.e.
-** wx_sqlite3_value_subtype() will always return 0).
+** This flag instructs SQLite to omit some corner-case optimizations that
+** might disrupt the operation of the [wx_sqlite3_value_subtype()] function,
+** causing it to return zero rather than the correct subtype().
+** All SQL functions that invoke [wx_sqlite3_value_subtype()] should have this
+** property. If the SQLITE_SUBTYPE property is omitted, then the return
+** value from [wx_sqlite3_value_subtype()] might sometimes be zero even though
+** a non-zero subtype was specified by the function argument expression.
+**
+** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
+** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call
+** [wx_sqlite3_result_subtype()] to cause a sub-type to be associated with its
+** result.
+** Every function that invokes [wx_sqlite3_result_subtype()] should have this
+** property. If it does not, then the call to [wx_sqlite3_result_subtype()]
+** might become a no-op if the function is used as term in an
+** [expression index]. On the other hand, SQL functions that never invoke
+** [wx_sqlite3_result_subtype()] should avoid setting this property, as the
+** purpose of this property is to disable certain optimizations that are
+** incompatible with subtypes.
+**
+** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
+** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
+** that internally orders the values provided to the first argument. The
+** ordered-set aggregate SQL notation with a single ORDER BY term can be
+** used to invoke this function. If the ordered-set aggregate notation is
+** used on a function that lacks this flag, then an error is raised. Note
+** that the ordered-set aggregate syntax is only available if SQLite is
+** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
** </dd>
** </dl>
*/
@@ -5526,6 +5690,8 @@ SQLITE_API int wx_sqlite3_create_window_function(
#define SQLITE_DIRECTONLY 0x000080000
#define SQLITE_SUBTYPE 0x000100000
#define SQLITE_INNOCUOUS 0x000200000
+#define SQLITE_RESULT_SUBTYPE 0x001000000
+#define SQLITE_SELFORDER1 0x002000000
/*
** CAPI3REF: Deprecated Functions
@@ -5722,6 +5888,12 @@ SQLITE_API int wx_sqlite3_value_encoding(wx_sqlite3_value*);
** information can be used to pass a limited amount of context from
** one SQL function to another. Use the [wx_sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
+**
+** Every [application-defined SQL function] that invokes this interface
+** should include the [SQLITE_SUBTYPE] property in the text
+** encoding argument when the function is [wx_sqlite3_create_function|registered].
+** If the [SQLITE_SUBTYPE] property is omitted, then wx_sqlite3_value_subtype()
+** might return zero instead of the upstream subtype in some corner cases.
*/
SQLITE_API unsigned int wx_sqlite3_value_subtype(wx_sqlite3_value*);
@@ -5820,48 +5992,56 @@ SQLITE_API wx_sqlite3 *wx_sqlite3_context_db_handle(wx_sqlite3_context*);
** METHOD: wx_sqlite3_context
**
** These functions may be used by (non-aggregate) SQL functions to
-** associate metadata with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated metadata may be preserved. An example
-** of where this might be useful is in a regular-expression matching
-** function. The compiled version of the regular expression can be stored as
-** metadata associated with the pattern string.
+** associate auxiliary data with argument values. If the same argument
+** value is passed to multiple invocations of the same SQL function during
+** query execution, under some circumstances the associated auxiliary data
+** might be preserved. An example of where this might be useful is in a
+** regular-expression matching function. The compiled version of the regular
+** expression can be stored as auxiliary data associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The wx_sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** ^The wx_sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
** associated by the wx_sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
** value to the application-defined function. ^N is zero for the left-most
-** function argument. ^If there is no metadata
+** function argument. ^If there is no auxiliary data
** associated with the function argument, the wx_sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
-** ^The wx_sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
-** argument of the application-defined function. ^Subsequent
+** ^The wx_sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
+** N-th argument of the application-defined function. ^Subsequent
** calls to wx_sqlite3_get_auxdata(C,N) return P from the most recent
-** wx_sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or
-** NULL if the metadata has been discarded.
+** wx_sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or
+** NULL if the auxiliary data has been discarded.
** ^After each call to wx_sqlite3_set_auxdata(C,N,P,X) where X is not NULL,
** SQLite will invoke the destructor function X with parameter P exactly
-** once, when the metadata is discarded.
-** SQLite is free to discard the metadata at any time, including: <ul>
+** once, when the auxiliary data is discarded.
+** SQLite is free to discard the auxiliary data at any time, including: <ul>
** <li> ^(when the corresponding function parameter changes)^, or
** <li> ^(when [wx_sqlite3_reset()] or [wx_sqlite3_finalize()] is called for the
** SQL statement)^, or
** <li> ^(when wx_sqlite3_set_auxdata() is invoked again on the same
** parameter)^, or
** <li> ^(during the original wx_sqlite3_set_auxdata() call when a memory
-** allocation error occurs.)^ </ul>
+** allocation error occurs.)^
+** <li> ^(during the original wx_sqlite3_set_auxdata() call if the function
+** is evaluated during query planning instead of during query execution,
+** as sometimes happens with [SQLITE_ENABLE_STAT4].)^ </ul>
**
-** Note the last bullet in particular. The destructor X in
+** Note the last two bullets in particular. The destructor X in
** wx_sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
** wx_sqlite3_set_auxdata() interface even returns. Hence wx_sqlite3_set_auxdata()
** should be called near the end of the function implementation and the
** function implementation should not make any use of P after
-** wx_sqlite3_set_auxdata() has been called.
-**
-** ^(In practice, metadata is preserved between function calls for
+** wx_sqlite3_set_auxdata() has been called. Furthermore, a call to
+** wx_sqlite3_get_auxdata() that occurs immediately after a corresponding call
+** to wx_sqlite3_set_auxdata() might still return NULL if an out-of-memory
+** condition occurred during the wx_sqlite3_set_auxdata() call or if the
+** function is being evaluated during query planning rather than during
+** query execution.
+**
+** ^(In practice, auxiliary data is preserved between function calls for
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
**
@@ -5871,10 +6051,67 @@ SQLITE_API wx_sqlite3 *wx_sqlite3_context_db_handle(wx_sqlite3_context*);
**
** These routines must be called from the same thread in which
** the SQL function is running.
+**
+** See also: [wx_sqlite3_get_clientdata()] and [wx_sqlite3_set_clientdata()].
*/
SQLITE_API void *wx_sqlite3_get_auxdata(wx_sqlite3_context*, int N);
SQLITE_API void wx_sqlite3_set_auxdata(wx_sqlite3_context*, int N, void*, void (*)(void*));
+/*
+** CAPI3REF: Database Connection Client Data
+** METHOD: wx_sqlite3
+**
+** These functions are used to associate one or more named pointers
+** with a [database connection].
+** A call to wx_sqlite3_set_clientdata(D,N,P,X) causes the pointer P
+** to be attached to [database connection] D using name N. Subsequent
+** calls to wx_sqlite3_get_clientdata(D,N) will return a copy of pointer P
+** or a NULL pointer if there were no prior calls to
+** wx_sqlite3_set_clientdata() with the same values of D and N.
+** Names are compared using strcmp() and are thus case sensitive.
+**
+** If P and X are both non-NULL, then the destructor X is invoked with
+** argument P on the first of the following occurrences:
+** <ul>
+** <li> An out-of-memory error occurs during the call to
+** wx_sqlite3_set_clientdata() which attempts to register pointer P.
+** <li> A subsequent call to wx_sqlite3_set_clientdata(D,N,P,X) is made
+** with the same D and N parameters.
+** <li> The database connection closes. SQLite does not make any guarantees
+** about the order in which destructors are called, only that all
+** destructors will be called exactly once at some point during the
+** database connection closing process.
+** </ul>
+**
+** SQLite does not do anything with client data other than invoke
+** destructors on the client data at the appropriate time. The intended
+** use for client data is to provide a mechanism for wrapper libraries
+** to store additional information about an SQLite database connection.
+**
+** There is no limit (other than available memory) on the number of different
+** client data pointers (with different names) that can be attached to a
+** single database connection. However, the implementation is optimized
+** for the case of having only one or two different client data names.
+** Applications and wrapper libraries are discouraged from using more than
+** one client data name each.
+**
+** There is no way to enumerate the client data pointers
+** associated with a database connection. The N parameter can be thought
+** of as a secret key such that only code that knows the secret key is able
+** to access the associated data.
+**
+** Security Warning: These interfaces should not be exposed in scripting
+** languages or in other circumstances where it might be possible for an
+** an attacker to invoke them. Any agent that can invoke these interfaces
+** can probably also take control of the process.
+**
+** Database connection client data is only available for SQLite
+** version 3.44.0 ([dateof:3.44.0]) and later.
+**
+** See also: [wx_sqlite3_set_auxdata()] and [wx_sqlite3_get_auxdata()].
+*/
+SQLITE_API void *wx_sqlite3_get_clientdata(wx_sqlite3*,const char*);
+SQLITE_API int wx_sqlite3_set_clientdata(wx_sqlite3*, const char*, void*, void(*)(void*));
/*
** CAPI3REF: Constants Defining Special Destructor Behavior
@@ -6076,6 +6313,20 @@ SQLITE_API int wx_sqlite3_result_zeroblob64(wx_sqlite3_context*, wx_sqlite3_uint
** higher order bits are discarded.
** The number of subtype bytes preserved by SQLite might increase
** in future releases of SQLite.
+**
+** Every [application-defined SQL function] that invokes this interface
+** should include the [SQLITE_RESULT_SUBTYPE] property in its
+** text encoding argument when the SQL function is
+** [wx_sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE]
+** property is omitted from the function that invokes wx_sqlite3_result_subtype(),
+** then in some cases the wx_sqlite3_result_subtype() might fail to set
+** the result subtype.
+**
+** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any
+** SQL function that invokes the wx_sqlite3_result_subtype() interface
+** and that does not have the SQLITE_RESULT_SUBTYPE property will raise
+** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1
+** by default.
*/
SQLITE_API void wx_sqlite3_result_subtype(wx_sqlite3_context*,unsigned int);
@@ -6247,6 +6498,13 @@ SQLITE_API void wx_sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of wx_sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
+**
+** If a negative argument is passed to wx_sqlite3_sleep() the results vary by
+** VFS and operating system. Some system treat a negative argument as an
+** instruction to sleep forever. Others understand it to mean do not sleep
+** at all. ^In SQLite version 3.42.0 and later, a negative
+** argument passed into wx_sqlite3_sleep() is changed to zero before it is relayed
+** down into the xSleep method of the VFS.
*/
SQLITE_API int wx_sqlite3_sleep(int);
@@ -6500,7 +6758,7 @@ SQLITE_API int wx_sqlite3_db_readonly(wx_sqlite3 *db, const char *zDbName);
SQLITE_API int wx_sqlite3_txn_state(wx_sqlite3*,const char *zSchema);
/*
-** CAPI3REF: Allowed return values from [wx_sqlite3_txn_state()]
+** CAPI3REF: Allowed return values from wx_sqlite3_txn_state()
** KEYWORDS: {transaction state}
**
** These constants define the current transaction state of a database file.
@@ -6632,7 +6890,7 @@ SQLITE_API void *wx_sqlite3_rollback_hook(wx_sqlite3*, void(*)(void *), void*);
** ^Each call to the wx_sqlite3_autovacuum_pages() interface overrides all
** previous invocations for that database connection. ^If the callback
** argument (C) to wx_sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer,
-** then the autovacuum steps callback is cancelled. The return value
+** then the autovacuum steps callback is canceled. The return value
** from wx_sqlite3_autovacuum_pages() is normally SQLITE_OK, but might
** be some other error code if something goes wrong. The current
** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other
@@ -6698,6 +6956,12 @@ SQLITE_API int wx_sqlite3_autovacuum_pages(
** The exceptions defined in this paragraph might change in a future
** release of SQLite.
**
+** Whether the update hook is invoked before or after the
+** corresponding change is currently unspecified and may differ
+** depending on the type of change. Do not rely on the order of the
+** hook call with regards to the final result of the operation which
+** triggers the hook.
+**
** The update hook implementation must not do anything that will modify
** the database connection that invoked the update hook. Any actions
** to modify the database connection must be deferred until after the
@@ -7151,6 +7415,10 @@ struct wx_sqlite3_module {
/* The methods above are in versions 1 and 2 of the sqlite_module object.
** Those below are for version 3 and greater. */
int (*xShadowName)(const char*);
+ /* The methods above are in versions 1 through 3 of the sqlite_module object.
+ ** Those below are for version 4 and greater. */
+ int (*xIntegrity)(wx_sqlite3_vtab *pVTab, const char *zSchema,
+ const char *zTabName, int mFlags, char **pzErr);
};
/*
@@ -7228,9 +7496,11 @@ struct wx_sqlite3_module {
** will be returned by the strategy.
**
** The xBestIndex method may optionally populate the idxFlags field with a
-** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
-** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
-** assumes that the strategy may visit at most one row.
+** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
+** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
+** output to show the idxNum has hex instead of as decimal. Another flag is
+** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
+** return at most one row.
**
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
** SQLite also assumes that if a call to the xUpdate() method is made as
@@ -7294,7 +7564,9 @@ struct wx_sqlite3_index_info {
** [wx_sqlite3_index_info].idxFlags field to some combination of
** these bits.
*/
-#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
+#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */
+#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */
+ /* in EXPLAIN QUERY PLAN */
/*
** CAPI3REF: Virtual Table Constraint Operator Codes
@@ -7638,7 +7910,7 @@ SQLITE_API int wx_sqlite3_blob_reopen(wx_sqlite3_blob *, wx_sqlite3_int64);
** code is returned and the transaction rolled back.
**
** Calling this function with an argument that is not a NULL pointer or an
-** open blob handle results in undefined behaviour. ^Calling this routine
+** open blob handle results in undefined behavior. ^Calling this routine
** with a null pointer (such as would be returned by a failed call to
** [wx_sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
** is passed a valid open blob handle, the values returned by the
@@ -7865,18 +8137,20 @@ SQLITE_API int wx_sqlite3_vfs_unregister(wx_sqlite3_vfs*);
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by wx_sqlite3_mutex_try(). On those systems, wx_sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** wx_sqlite3_mutex_try() as an optimization so this is acceptable
-** behavior.)^
+** will always return SQLITE_BUSY. In most cases the SQLite core only uses
+** wx_sqlite3_mutex_try() as an optimization, so this is acceptable
+** behavior. The exceptions are unix builds that set the
+** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working
+** wx_sqlite3_mutex_try() is required.)^
**
** ^The wx_sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated.
**
-** ^If the argument to wx_sqlite3_mutex_enter(), wx_sqlite3_mutex_try(), or
-** wx_sqlite3_mutex_leave() is a NULL pointer, then all three routines
-** behave as no-ops.
+** ^If the argument to wx_sqlite3_mutex_enter(), wx_sqlite3_mutex_try(),
+** wx_sqlite3_mutex_leave(), or wx_sqlite3_mutex_free() is a NULL pointer,
+** then any of the four routines behaves as a no-op.
**
** See also: [wx_sqlite3_mutex_held()] and [wx_sqlite3_mutex_notheld()].
*/
@@ -8118,6 +8392,7 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
+#define SQLITE_TESTCTRL_FK_NO_ACTION 7
#define SQLITE_TESTCTRL_BITVEC_TEST 8
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
@@ -8125,8 +8400,10 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ASSERT 12
#define SQLITE_TESTCTRL_ALWAYS 13
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
+#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
+#define SQLITE_TESTCTRL_GETOPT 16
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
@@ -8146,7 +8423,8 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33
-#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
+#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -8159,7 +8437,7 @@ SQLITE_API int wx_sqlite3_test_control(int op, ...);
** The wx_sqlite3_keyword_count() interface returns the number of distinct
** keywords understood by SQLite.
**
-** The wx_sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and
+** The wx_sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and
** makes *Z point to that keyword expressed as UTF8 and writes the number
** of bytes in the keyword into *L. The string that *Z points to is not
** zero-terminated. The wx_sqlite3_keyword_name(N,Z,L) routine returns
@@ -9121,6 +9399,16 @@ typedef struct wx_sqlite3_backup wx_sqlite3_backup;
** APIs are not strictly speaking threadsafe. If they are invoked at the
** same time as another thread is invoking wx_sqlite3_backup_step() it is
** possible that they return invalid values.
+**
+** <b>Alternatives To Using The Backup API</b>
+**
+** Other techniques for safely creating a consistent backup of an SQLite
+** database include:
+**
+** <ul>
+** <li> The [VACUUM INTO] command.
+** <li> The [wx_sqlite3_rsync] utility program.
+** </ul>
*/
SQLITE_API wx_sqlite3_backup *wx_sqlite3_backup_init(
wx_sqlite3 *pDest, /* Destination database handle */
@@ -9602,7 +9890,7 @@ SQLITE_API int wx_sqlite3_vtab_config(wx_sqlite3*, int op, ...);
** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
** <dd>Calls of the form
** [wx_sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** prohibits that virtual table from being used from within triggers and
** views.
** </dd>
@@ -9610,18 +9898,28 @@ SQLITE_API int wx_sqlite3_vtab_config(wx_sqlite3*, int op, ...);
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [wx_sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
+**
+** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
+** <dd>Calls of the form
+** [wx_sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
+** instruct the query planner to begin at least a read transaction on
+** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
+** virtual table is used.
+** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3
+#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -9728,24 +10026,45 @@ SQLITE_API const char *wx_sqlite3_vtab_collation(wx_sqlite3_index_info*,int);
** <li value="2"><p>
** ^(If the wx_sqlite3_vtab_distinct() interface returns 2, that means
** that the query planner does not need the rows returned in any particular
-** order, as long as rows with the same values in all "aOrderBy" columns
-** are adjacent.)^ ^(Furthermore, only a single row for each particular
-** combination of values in the columns identified by the "aOrderBy" field
-** needs to be returned.)^ ^It is always ok for two or more rows with the same
-** values in all "aOrderBy" columns to be returned, as long as all such rows
-** are adjacent. ^The virtual table may, if it chooses, omit extra rows
-** that have the same value for all columns identified by "aOrderBy".
-** ^However omitting the extra rows is optional.
+** order, as long as rows with the same values in all columns identified
+** by "aOrderBy" are adjacent.)^ ^(Furthermore, when two or more rows
+** contain the same values for all columns identified by "colUsed", all but
+** one such row may optionally be omitted from the result.)^
+** The virtual table is not required to omit rows that are duplicates
+** over the "colUsed" columns, but if the virtual table can do that without
+** too much extra effort, it could potentially help the query to run faster.
** This mode is used for a DISTINCT query.
** <li value="3"><p>
-** ^(If the wx_sqlite3_vtab_distinct() interface returns 3, that means
-** that the query planner needs only distinct rows but it does need the
-** rows to be sorted.)^ ^The virtual table implementation is free to omit
-** rows that are identical in all aOrderBy columns, if it wants to, but
-** it is not required to omit any rows. This mode is used for queries
+** ^(If the wx_sqlite3_vtab_distinct() interface returns 3, that means the
+** virtual table must return rows in the order defined by "aOrderBy" as
+** if the wx_sqlite3_vtab_distinct() interface had returned 0. However if
+** two or more rows in the result have the same values for all columns
+** identified by "colUsed", then all but one such row may optionally be
+** omitted.)^ Like when the return value is 2, the virtual table
+** is not required to omit rows that are duplicates over the "colUsed"
+** columns, but if the virtual table can do that without
+** too much extra effort, it could potentially help the query to run faster.
+** This mode is used for queries
** that have both DISTINCT and ORDER BY clauses.
** </ol>
**
+** <p>The following table summarizes the conditions under which the
+** virtual table is allowed to set the "orderByConsumed" flag based on
+** the value returned by wx_sqlite3_vtab_distinct(). This table is a
+** restatement of the previous four paragraphs:
+**
+** <table border=1 cellspacing=0 cellpadding=10 width="90%">
+** <tr>
+** <td valign="top">wx_sqlite3_vtab_distinct() return value
+** <td valign="top">Rows are returned in aOrderBy order
+** <td valign="top">Rows with the same value in all aOrderBy columns are adjacent
+** <td valign="top">Duplicates over all colUsed columns may be omitted
+** <tr><td>0<td>yes<td>yes<td>no
+** <tr><td>1<td>no<td>yes<td>no
+** <tr><td>2<td>no<td>yes<td>yes
+** <tr><td>3<td>yes<td>yes<td>yes
+** </table>
+**
** ^For the purposes of comparing virtual table output values to see if the
** values are same value for sorting purposes, two NULL values are considered
** to be the same. In other words, the comparison operator is "IS"
@@ -9782,7 +10101,7 @@ SQLITE_API int wx_sqlite3_vtab_distinct(wx_sqlite3_index_info*);
** communicated to the xBestIndex method as a
** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use
** this constraint, it must set the corresponding
-** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under
+** aConstraintUsage[].argvIndex to a positive integer. ^(Then, under
** the usual mode of handling IN operators, SQLite generates [bytecode]
** that invokes the [xFilter|xFilter() method] once for each value
** on the right-hand side of the IN operator.)^ Thus the virtual table
@@ -10211,7 +10530,7 @@ SQLITE_API int wx_sqlite3_db_cacheflush(wx_sqlite3*);
** When the [wx_sqlite3_blob_write()] API is used to update a blob column,
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
** in this case the new values are not available. In this case, when a
-** callback made with op==SQLITE_DELETE is actuall a write using the
+** callback made with op==SQLITE_DELETE is actually a write using the
** wx_sqlite3_blob_write() API, the [wx_sqlite3_preupdate_blobwrite()] returns
** the index of the column being written. In other cases, where the
** pre-update hook is being invoked for some other reason, including a
@@ -10289,6 +10608,14 @@ typedef struct wx_sqlite3_snapshot {
** If there is not already a read-transaction open on schema S when
** this function is called, one is opened automatically.
**
+** If a read-transaction is opened by this function, then it is guaranteed
+** that the returned snapshot object may not be invalidated by a database
+** writer or checkpointer until after the read-transaction is closed. This
+** is not guaranteed if a read-transaction is already open when this
+** function is called. In that case, any subsequent write or checkpoint
+** operation on the database may invalidate the returned snapshot handle,
+** even while the read-transaction remains open.
+**
** The following must be true for this function to succeed. If any of
** the following statements are false when wx_sqlite3_snapshot_get() is
** called, SQLITE_ERROR is returned. The final value of *P is undefined
@@ -10472,6 +10799,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int wx_sqlite3_snapshot_recover(wx_sqlite3 *db, c
** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
** of the database exists.
**
+** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set,
+** the returned buffer content will remain accessible and unchanged
+** until either the next write operation on the connection or when
+** the connection is closed, and applications must not modify the
+** buffer. If the bit had been clear, the returned buffer will not
+** be accessed by SQLite after the call.
+**
** A call to wx_sqlite3_serialize(D,S,P,F) might return NULL even if the
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
** allocation error occurs.
@@ -10520,6 +10854,9 @@ SQLITE_API unsigned char *wx_sqlite3_serialize(
** SQLite will try to increase the buffer size using wx_sqlite3_realloc64()
** if writes on the database cause it to grow larger than M bytes.
**
+** Applications must not modify the buffer P or invalidate it before
+** the database connection D is closed.
+**
** The wx_sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
** database is currently in a read transaction or is involved in a backup
** operation.
@@ -10528,6 +10865,13 @@ SQLITE_API unsigned char *wx_sqlite3_serialize(
** S argument to wx_sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
** function returns SQLITE_ERROR.
**
+** The deserialized database should not be in [WAL mode]. If the database
+** is in WAL mode, then any attempt to use the database file will result
+** in an [SQLITE_CANTOPEN] error. The application can set the
+** [file format version numbers] (bytes 18 and 19) of the input database P
+** to 0x01 prior to invoking wx_sqlite3_deserialize(D,S,P,N,M,F) to force the
+** database file into rollback mode and work around this limitation.
+**
** If wx_sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
** [wx_sqlite3_free()] is invoked on argument P prior to returning.
@@ -10580,8 +10924,6 @@ SQLITE_API int wx_sqlite3_deserialize(
#if defined(__wasi__)
# undef SQLITE_WASI
# define SQLITE_WASI 1
-# undef SQLITE_OMIT_WAL
-# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
# ifndef SQLITE_OMIT_LOAD_EXTENSION
# define SQLITE_OMIT_LOAD_EXTENSION
# endif
@@ -10796,16 +11138,20 @@ SQLITE_API int wx_sqlite3session_create(
SQLITE_API void wx_sqlite3session_delete(wx_sqlite3_session *pSession);
/*
-** CAPIREF: Conigure a Session Object
+** CAPI3REF: Configure a Session Object
** METHOD: wx_sqlite3_session
**
** This method is used to configure a session object after it has been
-** created. At present the only valid value for the second parameter is
-** [SQLITE_SESSION_OBJCONFIG_SIZE].
+** created. At present the only valid values for the second parameter are
+** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
**
-** Arguments for wx_sqlite3session_object_config()
+*/
+SQLITE_API int wx_sqlite3session_object_config(wx_sqlite3_session*, int op, void *pArg);
+
+/*
+** CAPI3REF: Options for wx_sqlite3session_object_config
**
-** The following values may passed as the the 4th parameter to
+** The following values may passed as the the 2nd parameter to
** wx_sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
@@ -10821,12 +11167,21 @@ SQLITE_API void wx_sqlite3session_delete(wx_sqlite3_session *pSession);
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
+**
+** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd>
+** This option is used to set, clear or query the flag that enables
+** collection of data for tables with no explicit PRIMARY KEY.
+**
+** Normally, tables with no explicit PRIMARY KEY are simply ignored
+** by the sessions module. However, if this flag is set, it behaves
+** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
+** as their leftmost columns.
+**
+** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
+** the first table has been attached to the session object.
*/
-SQLITE_API int wx_sqlite3session_object_config(wx_sqlite3_session*, int op, void *pArg);
-
-/*
-*/
-#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/*
** CAPI3REF: Enable Or Disable A Session Object
@@ -11588,6 +11943,18 @@ SQLITE_API int wx_sqlite3changeset_concat(
/*
+** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
+*/
+SQLITE_API int wx_sqlite3changeset_upgrade(
+ wx_sqlite3 *db,
+ const char *zDb,
+ int nIn, const void *pIn, /* Input changeset */
+ int *pnOut, void **ppOut /* OUT: Inverse of input */
+);
+
+
+
+/*
** CAPI3REF: Changegroup Handle
**
** A changegroup is an object used to combine two or more
@@ -11634,6 +12001,38 @@ typedef struct wx_sqlite3_changegroup wx_sqlite3_changegroup;
SQLITE_API int wx_sqlite3changegroup_new(wx_sqlite3_changegroup **pp);
/*
+** CAPI3REF: Add a Schema to a Changegroup
+** METHOD: wx_sqlite3_changegroup_schema
+**
+** This method may be used to optionally enforce the rule that the changesets
+** added to the changegroup handle must match the schema of database zDb
+** ("main", "temp", or the name of an attached database). If
+** wx_sqlite3changegroup_add() is called to add a changeset that is not compatible
+** with the configured schema, SQLITE_SCHEMA is returned and the changegroup
+** object is left in an undefined state.
+**
+** A changeset schema is considered compatible with the database schema in
+** the same way as for wx_sqlite3changeset_apply(). Specifically, for each
+** table in the changeset, there exists a database table with:
+**
+** <ul>
+** <li> The name identified by the changeset, and
+** <li> at least as many columns as recorded in the changeset, and
+** <li> the primary key columns in the same position as recorded in
+** the changeset.
+** </ul>
+**
+** The output of the changegroup object always has the same schema as the
+** database nominated using this function. In cases where changesets passed
+** to wx_sqlite3changegroup_add() have fewer columns than the corresponding table
+** in the database schema, these are filled in using the default column
+** values from the database schema. This makes it possible to combined
+** changesets that have different numbers of columns for a single table
+** within a changegroup, provided that they are otherwise compatible.
+*/
+SQLITE_API int wx_sqlite3changegroup_schema(wx_sqlite3_changegroup*, wx_sqlite3*, const char *zDb);
+
+/*
** CAPI3REF: Add A Changeset To A Changegroup
** METHOD: wx_sqlite3_changegroup
**
@@ -11701,17 +12100,46 @@ SQLITE_API int wx_sqlite3changegroup_new(wx_sqlite3_changegroup **pp);
** If the new changeset contains changes to a table that is already present
** in the changegroup, then the number of columns and the position of the
** primary key columns for the table must be consistent. If this is not the
-** case, this function fails with SQLITE_SCHEMA. If the input changeset
-** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
-** returned. Or, if an out-of-memory condition occurs during processing, this
-** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
-** of the final contents of the changegroup is undefined.
+** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup
+** object has been configured with a database schema using the
+** wx_sqlite3changegroup_schema() API, then it is possible to combine changesets
+** with different numbers of columns for a single table, provided that
+** they are otherwise compatible.
**
-** If no error occurs, SQLITE_OK is returned.
+** If the input changeset appears to be corrupt and the corruption is
+** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition
+** occurs during processing, this function returns SQLITE_NOMEM.
+**
+** In all cases, if an error occurs the state of the final contents of the
+** changegroup is undefined. If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int wx_sqlite3changegroup_add(wx_sqlite3_changegroup*, int nData, void *pData);
/*
+** CAPI3REF: Add A Single Change To A Changegroup
+** METHOD: wx_sqlite3_changegroup
+**
+** This function adds the single change currently indicated by the iterator
+** passed as the second argument to the changegroup object. The rules for
+** adding the change are just as described for [wx_sqlite3changegroup_add()].
+**
+** If the change is successfully added to the changegroup, SQLITE_OK is
+** returned. Otherwise, an SQLite error code is returned.
+**
+** The iterator must point to a valid entry when this function is called.
+** If it does not, SQLITE_ERROR is returned and no change is added to the
+** changegroup. Additionally, the iterator must not have been opened with
+** the SQLITE_CHANGESETAPPLY_INVERT flag. In this case SQLITE_ERROR is also
+** returned.
+*/
+SQLITE_API int wx_sqlite3changegroup_add_change(
+ wx_sqlite3_changegroup*,
+ wx_sqlite3_changeset_iter*
+);
+
+
+
+/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
** METHOD: wx_sqlite3_changegroup
**
@@ -11959,9 +12387,30 @@ SQLITE_API int wx_sqlite3changeset_apply_v2(
** Invert the changeset before applying it. This is equivalent to inverting
** a changeset using wx_sqlite3changeset_invert() before applying it. It is
** an error to specify this flag with a patchset.
+**
+** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd>
+** Do not invoke the conflict handler callback for any changes that
+** would not actually modify the database even if they were applied.
+** Specifically, this means that the conflict handler is not invoked
+** for:
+** <ul>
+** <li>a delete change if the row being deleted cannot be found,
+** <li>an update change if the modified fields are already set to
+** their new values in the conflicting row, or
+** <li>an insert change if all fields of the conflicting row match
+** the row being inserted.
+** </ul>
+**
+** <dt>SQLITE_CHANGESETAPPLY_FKNOACTION <dd>
+** If this flag it set, then all foreign key constraints in the target
+** database behave as if they were declared with "ON UPDATE NO ACTION ON
+** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL
+** or SET DEFAULT.
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
+#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
+#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008
/*
** CAPI3REF: Constants Passed To The Conflict Handler
@@ -12494,8 +12943,8 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
-** registered with.
+** Return a copy of the pUserData pointer passed to the xCreateFunction()
+** API when the extension function was registered.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
@@ -12527,8 +12976,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the text of column iCol of
+** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -12538,8 +12990,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of phrases in the current query, as returned by xPhraseCount,
+** 0 is returned. Otherwise, this function returns the number of tokens in
+** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -12555,12 +13009,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
+** output by xInstCount(). If iIdx is less than zero or greater than
+** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
+** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. Returns SQLITE_OK if successful, or an error
-** code (i.e. SQLITE_NOMEM) if an error occurs.
+** first token of the phrase. SQLITE_OK is returned if successful, or an
+** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -12586,6 +13041,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
+** If parameter iPhrase is less than zero, or greater than or equal to
+** the number of phrases in the query, as returned by xPhraseCount(),
+** this function returns SQLITE_RANGE.
+**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -12667,6 +13126,10 @@ struct Fts5PhraseIter {
** (i.e. if it is a contentless table), then this API always iterates
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
**
+** In all cases, matches are visited in (column ASC, offset ASC) order.
+** i.e. all those in column 0, sorted by offset, followed by those in
+** column 1, etc.
+**
** xPhraseNext()
** See xPhraseFirst above.
**
@@ -12700,9 +13163,65 @@ struct Fts5PhraseIter {
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
+**
+** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase iPhrase of the current
+** query. Before returning, output parameter *ppToken is set to point
+** to a buffer containing the requested token, and *pnToken to the
+** size of this buffer in bytes.
+**
+** If iPhrase or iToken are less than zero, or if iPhrase is greater than
+** or equal to the number of phrases in the query as reported by
+** xPhraseCount(), or if iToken is equal to or greater than the number of
+** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
+ are both zeroed.
+**
+** The output text is not a copy of the query text that specified the
+** token. It is the output of the tokenizer module. For tokendata=1
+** tables, this includes any embedded 0x00 and trailing data.
+**
+** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase hit iIdx within the
+** current row. If iIdx is less than zero or greater than or equal to the
+** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
+** output variable (*ppToken) is set to point to a buffer containing the
+** matching document token, and (*pnToken) to the size of that buffer in
+** bytes. This API is not available if the specified token matches a
+** prefix query term. In that case both output variables are always set
+** to 0.
+**
+** The output text is not a copy of the document text that was tokenized.
+** It is the output of the tokenizer module. For tokendata=1 tables, this
+** includes any embedded 0x00 and trailing data.
+**
+** This API can be quite slow if used with an FTS5 table created with the
+** "detail=none" or "detail=column" option.
+**
+** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the locale associated
+** with column iCol of the current row. Usually, there is no associated
+** locale, and output parameters (*pzLocale) and (*pnLocale) are set
+** to NULL and 0, respectively. However, if the fts5_locale() function
+** was used to associate a locale with the value when it was inserted
+** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
+** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
+** is set to the size in bytes of the buffer, not including the
+** nul-terminator.
+**
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an
+** SQLite error code is returned. The final value of the output parameters
+** is undefined in this case.
+**
+** xTokenize_v2:
+** Tokenize text using the tokenizer belonging to the FTS5 table. This
+** API is the same as the xTokenize() API, except that it allows a tokenizer
+** locale to be specified.
*/
struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
+ int iVersion; /* Currently always set to 4 */
void *(*xUserData)(Fts5Context*);
@@ -12737,6 +13256,22 @@ struct Fts5ExtensionApi {
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
+
+ /* Below this point are iVersion>=3 only */
+ int (*xQueryToken)(Fts5Context*,
+ int iPhrase, int iToken,
+ const char **ppToken, int *pnToken
+ );
+ int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
+
+ /* Below this point are iVersion>=4 only */
+ int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
+ int (*xTokenize_v2)(Fts5Context*,
+ const char *pText, int nText, /* Text to tokenize */
+ const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
+ void *pCtx, /* Context passed to xToken() */
+ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
+ );
};
/*
@@ -12757,7 +13292,7 @@ struct Fts5ExtensionApi {
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
-** pointer provided by the application when the fts5_tokenizer object
+** pointer provided by the application when the fts5_tokenizer_v2 object
** was registered with FTS5 (the third argument to xCreateTokenizer()).
** The second and third arguments are an array of nul-terminated strings
** containing the tokenizer arguments, if any, specified following the
@@ -12781,7 +13316,7 @@ struct Fts5ExtensionApi {
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
**
-** The second argument indicates the reason that FTS5 is requesting
+** The third argument indicates the reason that FTS5 is requesting
** tokenization of the supplied text. This is always one of the following
** four values:
**
@@ -12805,6 +13340,13 @@ struct Fts5ExtensionApi {
** on a columnsize=0 database.
** </ul>
**
+** The sixth and seventh arguments passed to xTokenize() - pLocale and
+** nLocale - are a pointer to a buffer containing the locale to use for
+** tokenization (e.g. "en_US") and its size in bytes, respectively. The
+** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
+** which case nLocale is always 0) to indicate that the tokenizer should
+** use its default locale.
+**
** For each token in the input string, the supplied callback xToken() must
** be invoked. The first argument to it should be a copy of the pointer
** passed as the second argument to xTokenize(). The third and fourth
@@ -12828,6 +13370,30 @@ struct Fts5ExtensionApi {
** may abandon the tokenization and return any error code other than
** SQLITE_OK or SQLITE_DONE.
**
+** If the tokenizer is registered using an fts5_tokenizer_v2 object,
+** then the xTokenize() method has two additional arguments - pLocale
+** and nLocale. These specify the locale that the tokenizer should use
+** for the current request. If pLocale and nLocale are both 0, then the
+** tokenizer should use its default locale. Otherwise, pLocale points to
+** an nLocale byte buffer containing the name of the locale to use as utf-8
+** text. pLocale is not nul-terminated.
+**
+** FTS5_TOKENIZER
+**
+** There is also an fts5_tokenizer object. This is an older, deprecated,
+** version of fts5_tokenizer_v2. It is similar except that:
+**
+** <ul>
+** <li> There is no "iVersion" field, and
+** <li> The xTokenize() method does not take a locale argument.
+** </ul>
+**
+** Legacy fts5_tokenizer tokenizers must be registered using the
+** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
+**
+** Tokenizer implementations registered using either API may be retrieved
+** using both xFindTokenizer() and xFindTokenizer_v2().
+**
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
@@ -12931,11 +13497,38 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
+typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
+struct fts5_tokenizer_v2 {
+ int iVersion; /* Currently always 2 */
+
+ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
+ void (*xDelete)(Fts5Tokenizer*);
+ int (*xTokenize)(Fts5Tokenizer*,
+ void *pCtx,
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
+ const char *pText, int nText,
+ const char *pLocale, int nLocale,
+ int (*xToken)(
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
+ const char *pToken, /* Pointer to buffer containing token */
+ int nToken, /* Size of token in bytes */
+ int iStart, /* Byte offset of token within input text */
+ int iEnd /* Byte offset of end of token within input text */
+ )
+ );
+};
+
+/*
+** New code should use the fts5_tokenizer_v2 type to define tokenizer
+** implementations. The following type is included for legacy applications
+** that still use it.
+*/
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
@@ -12955,6 +13548,7 @@ struct fts5_tokenizer {
);
};
+
/* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002
@@ -12974,13 +13568,13 @@ struct fts5_tokenizer {
*/
typedef struct fts5_api fts5_api;
struct fts5_api {
- int iVersion; /* Currently always set to 2 */
+ int iVersion; /* Currently always set to 3 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -12989,7 +13583,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -12997,10 +13591,29 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
+
+ /* APIs below this point are only available if iVersion>=3 */
+
+ /* Create a new tokenizer */
+ int (*xCreateTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void *pUserData,
+ fts5_tokenizer_v2 *pTokenizer,
+ void (*xDestroy)(void*)
+ );
+
+ /* Find an existing tokenizer */
+ int (*xFindTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void **ppUserData,
+ fts5_tokenizer_v2 **ppTokenizer
+ );
};
/*
@@ -13059,7 +13672,7 @@ extern "C" {
** If the SQLITE_USER table is not present in the database file, then
** this interface is a harmless no-op returnning SQLITE_OK.
*/
-int wx_sqlite3_user_authenticate(
+SQLITE_API int wx_sqlite3_user_authenticate(
wx_sqlite3 *db, /* The database connection */
const char *zUsername, /* Username */
const char *aPW, /* Password or credentials */
@@ -13076,7 +13689,7 @@ int wx_sqlite3_user_authenticate(
** for any ATTACH-ed databases. Any call to wx_sqlite3_user_add() by a
** non-admin user results in an error.
*/
-int wx_sqlite3_user_add(
+SQLITE_API int wx_sqlite3_user_add(
wx_sqlite3 *db, /* Database connection */
const char *zUsername, /* Username to be added */
const char *aPW, /* Password or credentials */
@@ -13088,10 +13701,10 @@ int wx_sqlite3_user_add(
** The wx_sqlite3_user_change() interface can be used to change a users
** login credentials or admin privilege. Any user can change their own
** login credentials. Only an admin user can change another users login
-** credentials or admin privilege setting. No user may change their own
+** credentials or admin privilege setting. No user may change their own
** admin privilege setting.
*/
-int wx_sqlite3_user_change(
+SQLITE_API int wx_sqlite3_user_change(
wx_sqlite3 *db, /* Database connection */
const char *zUsername, /* Username to change */
const char *aPW, /* New password or credentials */
@@ -13106,7 +13719,7 @@ int wx_sqlite3_user_change(
** the database cannot be converted into a no-authentication-required
** database.
*/
-int wx_sqlite3_user_delete(
+SQLITE_API int wx_sqlite3_user_delete(
wx_sqlite3 *db, /* Database connection */
const char *zUsername /* Username to remove */
);
@@ -13129,7 +13742,8 @@ int wx_sqlite3_user_delete(
#define CODEC_TYPE_CHACHA20 3
#define CODEC_TYPE_SQLCIPHER 4
#define CODEC_TYPE_RC4 5
-#define CODEC_TYPE_MAX_BUILTIN 5
+#define CODEC_TYPE_ASCON128 6
+#define CODEC_TYPE_MAX_BUILTIN 6
/*
** Definition of API functions
@@ -13228,7 +13842,7 @@ SQLITE_API unsigned char* wxwx_sqlite3_codec_data(wx_sqlite3* db, const char* zD
*/
typedef struct _CipherParams
{
- char* m_name;
+ const char* m_name;
int m_value;
int m_default;
int m_minValue;
@@ -13261,13 +13875,13 @@ typedef int (*GetLegacy_t)(void* cipher);
typedef int (*GetPageSize_t)(void* cipher);
typedef int (*GetReserved_t)(void* cipher);
typedef unsigned char* (*GetSalt_t)(void* cipher);
-typedef void (*GenerateKey_t)(void* cipher, BtSharedMC* pBt, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt);
+typedef void (*GenerateKey_t)(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt);
typedef int (*EncryptPage_t)(void* cipher, int page, unsigned char* data, int len, int reserved);
typedef int (*DecryptPage_t)(void* cipher, int page, unsigned char* data, int len, int reserved, int hmacCheck);
typedef struct _CipherDescriptor
{
- char* m_name;
+ const char* m_name;
AllocateCipher_t m_allocateCipher;
FreeCipher_t m_freeCipher;
CloneCipher_t m_cloneCipher;
@@ -13321,6 +13935,7 @@ extern "C" {
#ifndef SQLITE_PRIVATE
#define SQLITE_PRIVATE
#endif
+
SQLITE_PRIVATE int wx_sqlite3mcCheckVfs(const char* zVfs);
SQLITE_API int wx_sqlite3mc_vfs_create(const char* zVfsReal, int makeDefault);
diff --git a/Plugins/ScriptingPython/scriptingpython.cpp b/Plugins/ScriptingPython/scriptingpython.cpp
index 1dedb5c..a8de694 100644
--- a/Plugins/ScriptingPython/scriptingpython.cpp
+++ b/Plugins/ScriptingPython/scriptingpython.cpp
@@ -582,15 +582,25 @@ SqlQueryPtr ScriptingPython::dbCommonEval(PyObject* sqlArg, const char* fnName)
QVariant ScriptingPython::getVariable(const QString& name)
{
PyThreadState* state = PyThreadState_Get();
- if (!state->frame)
+#if PY_VERSION_HEX < 0x030a0000
+ PyFrameObject* frame = state->frame;
+#else
+ PyFrameObject* frame = PyThreadState_GetFrame(state);
+#endif
+ if (!frame)
return QVariant();
const char* varName = name.toUtf8().constData();
PyObject* obj = nullptr;
- PyFrame_FastToLocals(state->frame);
- PyObject* locals = state->frame->f_locals;
- PyObject* globals = state->frame->f_globals;
+ PyFrame_FastToLocals(frame);
+#if PY_VERSION_HEX < 0x030b0000
+ PyObject* locals = frame->f_locals;
+ PyObject* globals = frame->f_globals;
+#else
+ PyObject* locals = PyFrame_GetLocals(frame);
+ PyObject* globals = PyFrame_GetGlobals(frame);
+#endif
if (PyMapping_Check(locals))
obj = PyMapping_GetItemString(locals, varName);
else if (PyDict_Check(globals))
diff --git a/Plugins/ScriptingTcl/ScriptingTcl.pro b/Plugins/ScriptingTcl/ScriptingTcl.pro
index 80a11fe..de6990c 100644
--- a/Plugins/ScriptingTcl/ScriptingTcl.pro
+++ b/Plugins/ScriptingTcl/ScriptingTcl.pro
@@ -91,31 +91,44 @@ macx: {
message("Found tclsh: $$TCLSH (version: $$TCL_VERSION)")
# Find tclConfig.sh
- TCL_CONFIG = $$system(echo "puts [::tcl::pkgconfig get libdir,runtime]" | tclsh)/tclConfig.sh
+ !exists($$TCL_CONFIG) {
+ TCL_CONFIG = $$system(echo "puts [::tcl::pkgconfig get libdir,runtime]" | tclsh)/tclConfig.sh
+ !exists($$TCL_CONFIG) {
+ TCL_CONFIG = $$system(echo "puts [::tcl::pkgconfig get libdir,install]" | tclsh)/tclConfig.sh
+ message("Looking for $$TCL_CONFIG")
+ }
+ !exists($$TCL_CONFIG) {
+ error("Could not find tclConfig.sh file. You can define its absolute path by qmake parameter: TCL_CONFIG=/path/to/tclConfig.sh")
+ }
+ }
+ message("Using tclConfig: $$TCL_CONFIG")
# Define other libs required when linking with Tcl
eval($$system(cat $$TCL_CONFIG | grep TCL_LIBS))
eval(LIBS += $$TCL_LIBS)
+ message("TCL_LIBS: $$TCL_LIBS")
# Define headers dir
eval($$system(cat $$TCL_CONFIG | grep TCL_INCLUDE_SPEC))
INCLUDEPATH += $$replace(TCL_INCLUDE_SPEC, -I/, /)
DEPENDPATH += $$replace(TCL_INCLUDE_SPEC, -I/, /)
+ message("TCL_INCLUDE_SPEC: $$TCL_INCLUDE_SPEC")
# Find static library
eval($$system(cat $$TCL_CONFIG | grep TCL_STUB_LIB_PATH))
STATIC_LIB = $$replace(TCL_STUB_LIB_PATH, tclstub, tcl)
+ message("TCL_STUB_LIB_PATH: $$TCL_STUB_LIB_PATH")
# If found static lib, we link statically
exists($$STATIC_LIB) {
- #message("Static linking of libtcl: $$STATIC_LIB")
+ message("Static linking of libtcl: $$STATIC_LIB")
LIBS += $$STATIC_LIB
}
# If not found, use dynamic linking flags
!exists($$STATIC_LIB) {
eval($$system(cat $$TCL_CONFIG | grep TCL_LIB_SPEC))
- #message("Dynamic linking of libtcl: $$TCL_LIB_SPEC")
+ message("Dynamic linking of libtcl: $$TCL_LIB_SPEC")
eval(LIBS += $$TCL_LIB_SPEC)
}
}
diff --git a/Plugins/SqlEnterpriseFormatter/formatcreatetable.cpp b/Plugins/SqlEnterpriseFormatter/formatcreatetable.cpp
index 28020af..1fefbdd 100644
--- a/Plugins/SqlEnterpriseFormatter/formatcreatetable.cpp
+++ b/Plugins/SqlEnterpriseFormatter/formatcreatetable.cpp
@@ -199,8 +199,26 @@ void FormatCreateTableColumnConstraint::formatInternal()
break;
}
case SqliteCreateTable::Column::Constraint::NULL_:
- case SqliteCreateTable::Column::Constraint::NAME_ONLY:
+ {
+ // Is the default and unofficial. Pass through
+ withKeyword("NULL");
+ break;
+ }
case SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY:
+ {
+ // Pass through
+ if (constr->deferrable == SqliteDeferrable::NOT_DEFERRABLE)
+ withKeyword("NOT");
+ withKeyword("DEFERRABLE");
+ if (constr->initially != SqliteInitially::null)
+ {
+ withKeyword("INITIALLY");
+ withKeyword(constr->initially == SqliteInitially::DEFERRED ? "DEFERRED" : "IMMEDIATE");
+ }
+ break;
+ }
+ case SqliteCreateTable::Column::Constraint::NAME_ONLY:
+ // The CONSTRAINT <name> clause has already been output
break;
}
}